From 43da2bba64294d97788c0c62779e3a717bfaa9ce Mon Sep 17 00:00:00 2001 From: CodeAnarchist Date: Wed, 13 Aug 2025 21:23:27 +0200 Subject: [PATCH 01/23] remove l2l3ep, removed l3 in dispatcher --- kernel/networking/drivers/net_driver.hpp | 2 +- .../drivers/virtio_net_pci/virtio_net_pci.cpp | 8 ++- .../drivers/virtio_net_pci/virtio_net_pci.hpp | 2 +- kernel/networking/network.cpp | 6 +-- kernel/networking/network.h | 2 +- kernel/networking/network_dispatch.cpp | 4 +- kernel/networking/network_dispatch.hpp | 9 +--- kernel/networking/processes/net_proc.c | 16 ++---- shared/net/application_layer/dhcp_daemon.c | 21 ++++---- shared/net/internet_layer/icmp.c | 18 +++---- shared/net/internet_layer/icmp.h | 4 +- shared/net/internet_layer/ipv4.c | 4 +- shared/net/link_layer/arp.c | 54 ++++++++++--------- shared/net/link_layer/arp.h | 2 +- shared/net/network_types.h | 13 ----- 15 files changed, 70 insertions(+), 95 deletions(-) diff --git a/kernel/networking/drivers/net_driver.hpp b/kernel/networking/drivers/net_driver.hpp index df69b3d0..98056631 100644 --- a/kernel/networking/drivers/net_driver.hpp +++ b/kernel/networking/drivers/net_driver.hpp @@ -13,7 +13,7 @@ class NetDriver { virtual void handle_sent_packet() = 0; virtual void enable_verbose() = 0; virtual void send_packet(sizedptr packet) = 0; - virtual void get_mac(net_l2l3_endpoint *context) = 0; + virtual void get_mac(uint8_t out_mac[6]) = 0; virtual ~NetDriver() = default; diff --git a/kernel/networking/drivers/virtio_net_pci/virtio_net_pci.cpp b/kernel/networking/drivers/virtio_net_pci/virtio_net_pci.cpp index 76ff517c..08893679 100644 --- a/kernel/networking/drivers/virtio_net_pci/virtio_net_pci.cpp +++ b/kernel/networking/drivers/virtio_net_pci/virtio_net_pci.cpp @@ -106,13 +106,11 @@ bool VirtioNetDriver::init(){ } -void VirtioNetDriver::get_mac(net_l2l3_endpoint *context){ +void VirtioNetDriver::get_mac(uint8_t out_mac[6]){ virtio_net_config* net_config = (virtio_net_config*)vnp_net_dev.device_cfg; kprintfv("[VIRTIO_NET] %x:%x:%x:%x:%x:%x", net_config->mac[0], net_config->mac[1], net_config->mac[2], net_config->mac[3], net_config->mac[4], net_config->mac[5]); - - memcpy((void*)&context->mac,(void*)&net_config->mac,6); - - kprintfv("[VIRTIO_NET] %i virtqueue pairs",net_config->max_virtqueue_pairs); + memcpy(out_mac, net_config->mac, 6); + kprintfv("[VIRTIO_NET] %i virtqueue pairs", net_config->max_virtqueue_pairs); kprintfv("[VIRTIO_NET] %x speed", net_config->speed); kprintfv("[VIRTIO_NET] status = %x", net_config->status); } diff --git a/kernel/networking/drivers/virtio_net_pci/virtio_net_pci.hpp b/kernel/networking/drivers/virtio_net_pci/virtio_net_pci.hpp index 86550911..faf7b780 100644 --- a/kernel/networking/drivers/virtio_net_pci/virtio_net_pci.hpp +++ b/kernel/networking/drivers/virtio_net_pci/virtio_net_pci.hpp @@ -22,7 +22,7 @@ class VirtioNetDriver : public NetDriver { void send_packet(sizedptr packet) override; - void get_mac(net_l2l3_endpoint *context) override; + void get_mac(uint8_t out_mac[6]) override; ~VirtioNetDriver() = default; diff --git a/kernel/networking/network.cpp b/kernel/networking/network.cpp index 0a56442f..a21efa48 100644 --- a/kernel/networking/network.cpp +++ b/kernel/networking/network.cpp @@ -34,9 +34,9 @@ int net_rx_frame(sizedptr *out_frame) { return sz; } -const net_l2l3_endpoint* network_get_local_endpoint() { - static net_l2l3_endpoint dummy = {}; - return dispatch ? &dispatch->get_local_ep() : &dummy; +const uint8_t* network_get_local_mac() { + static uint8_t dummy[6] = {0}; + return dispatch ? dispatch->get_local_mac() : dummy; } void network_net_set_pid(uint16_t pid) { diff --git a/kernel/networking/network.h b/kernel/networking/network.h index 1726d7f7..a152f7c0 100644 --- a/kernel/networking/network.h +++ b/kernel/networking/network.h @@ -23,7 +23,7 @@ int network_net_task_entry(int argc, char* argv[]); int net_tx_frame(uintptr_t frame_ptr, uint32_t frame_len); int net_rx_frame(sizedptr *out_frame); -const net_l2l3_endpoint* network_get_local_endpoint(); +const uint8_t* network_get_local_mac(void); void network_update_local_ip(uint32_t ip); extern driver_module net_module; diff --git a/kernel/networking/network_dispatch.cpp b/kernel/networking/network_dispatch.cpp index 2a6a6de3..6941fff7 100644 --- a/kernel/networking/network_dispatch.cpp +++ b/kernel/networking/network_dispatch.cpp @@ -23,14 +23,14 @@ NetworkDispatch::NetworkDispatch() for (uint32_t i = 0; i <= UINT16_MAX; ++i) ports[i] = UINT16_MAX; - memset(local_mac.mac, 0, sizeof(local_mac.mac)); + memset(local_mac, 0, sizeof(local_mac)); } bool NetworkDispatch::init() { driver = VirtioNetDriver::try_init(); if (!driver) return false; - driver->get_mac(&local_mac); + driver->get_mac(local_mac); return true; } diff --git a/kernel/networking/network_dispatch.hpp b/kernel/networking/network_dispatch.hpp index 35bba52d..76d35554 100644 --- a/kernel/networking/network_dispatch.hpp +++ b/kernel/networking/network_dispatch.hpp @@ -22,12 +22,7 @@ class NetworkDispatch { uint16_t get_net_pid() const; - const net_l2l3_endpoint& get_local_ep() const { - static net_l2l3_endpoint ep; //TODO: locking/thread safe would be good - ep = local_mac; - ep.ip = ipv4_get_cfg()->ip; - return ep; - } + const uint8_t* get_local_mac() const { return local_mac; } NetDriver* driver_ptr() const { return driver; } @@ -38,7 +33,7 @@ class NetworkDispatch { IndexMap ports; //port pid map NetDriver* driver; - net_l2l3_endpoint local_mac; + uint8_t local_mac[6]; Queue tx_queue; Queue rx_queue; diff --git a/kernel/networking/processes/net_proc.c b/kernel/networking/processes/net_proc.c index a3db7903..5604e772 100644 --- a/kernel/networking/processes/net_proc.c +++ b/kernel/networking/processes/net_proc.c @@ -38,11 +38,7 @@ static uint32_t pick_probe_ip() { return ipv4_first_host(cfg->ip, cfg->mask); } -static int udp_probe_server(uint32_t probe_ip, uint16_t probe_port, net_l2l3_endpoint *out_l2, net_l4_endpoint *out_l4) { - const net_l2l3_endpoint *local = network_get_local_endpoint(); - if (!local) - return 0; - +static int udp_probe_server(uint32_t probe_ip, uint16_t probe_port, net_l4_endpoint *out_l4) { socket_handle_t sock = udp_socket_create(0, 0); if (!sock) return 0; @@ -78,8 +74,6 @@ static int udp_probe_server(uint32_t probe_ip, uint16_t probe_port, net_l2l3_end socket_close_udp(sock); socket_destroy_udp(sock); - memcpy(out_l2->mac, local->mac, 6); - out_l2->ip = resp_ip; out_l4->ip = resp_ip; out_l4->port = resp_port; @@ -274,7 +268,6 @@ static void print_info() { static void test_net() { const net_cfg_t *cfg = ipv4_get_cfg(); - net_l2l3_endpoint l2 = {0}; net_l4_endpoint srv = {0}; if (cfg && cfg->mode != NET_MODE_DISABLED && cfg->ip != 0) { @@ -286,7 +279,7 @@ static void test_net() { kprintf("[NET] probing broadcast %s", bcast_str); - if (udp_probe_server(bcast, 8080, &l2, &srv)) + if (udp_probe_server(bcast, 8080, &srv)) test_http(srv.ip); sleep(2000); @@ -298,7 +291,7 @@ static void test_net() { if (!fallback) fallback = (192<<24)|(168<<16)|(1<<8)|255; - if (udp_probe_server(fallback, 8080, &l2, &srv)) + if (udp_probe_server(fallback, 8080, &srv)) test_http(srv.ip); else kprintf("[NET] could not find update server\n"); @@ -323,7 +316,6 @@ static int ip_waiter_entry(int argc, char* argv[]) { return 0; } - process_t* launch_net_process() { const net_cfg_t *cfg = ipv4_get_cfg(); @@ -339,4 +331,4 @@ process_t* launch_net_process() { create_kernel_process("ip_waiter", ip_waiter_entry, 0, 0); return NULL; -} \ No newline at end of file +} diff --git a/shared/net/application_layer/dhcp_daemon.c b/shared/net/application_layer/dhcp_daemon.c index 8a9d0bed..6e6df077 100644 --- a/shared/net/application_layer/dhcp_daemon.c +++ b/shared/net/application_layer/dhcp_daemon.c @@ -41,7 +41,7 @@ typedef enum { } dhcp_state_t; static dhcp_state_t g_state = DHCP_S_INIT; -static net_l2l3_endpoint g_local_ep = {0}; +static uint8_t g_local_mac[6] = {0}; static volatile bool g_force_renew = false; static uint32_t g_t1_left_ms = 0; static uint32_t g_t2_left_ms = 0; @@ -73,7 +73,7 @@ static void dhcp_tx_packet(const dhcp_request *req, static void dhcp_send_discover(uint32_t xid){ kprintf("[DHCP] discover xid=%i", xid); dhcp_request req = {0}; - memcpy(req.mac, g_local_ep.mac, 6); + memcpy(req.mac, g_local_mac, 6); dhcp_tx_packet(&req, DHCPDISCOVER, xid, 0xFFFFFFFFu); } @@ -89,7 +89,7 @@ static void dhcp_send_request(const dhcp_request *req, static void dhcp_send_renew(uint32_t xid) { const net_cfg_t *cfg = ipv4_get_cfg(); dhcp_request req = {0}; - memcpy(req.mac, g_local_ep.mac, 6); + memcpy(req.mac, g_local_mac, 6); req.offered_ip = __builtin_bswap32(cfg->ip); req.server_ip = cfg->rt ? cfg->rt->server_ip : 0; uint32_t dst = req.server_ip ? __builtin_bswap32(req.server_ip) : 0xFFFFFFFFu; @@ -100,7 +100,7 @@ static void dhcp_send_renew(uint32_t xid) { static void dhcp_send_rebind(uint32_t xid) { const net_cfg_t *cfg = ipv4_get_cfg(); dhcp_request req = {0}; - memcpy(req.mac, g_local_ep.mac, 6); + memcpy(req.mac, g_local_mac, 6); req.offered_ip = __builtin_bswap32(cfg->ip); req.server_ip = 0; kprintf("[DHCP] rebind xid=%i", xid); @@ -147,9 +147,8 @@ static void dhcp_fsm_once() switch (g_state) { case DHCP_S_INIT: { - const net_l2l3_endpoint *le = network_get_local_endpoint(); - memcpy(g_local_ep.mac, le->mac, 6); - g_local_ep.ip = 0; + const uint8_t *mac = network_get_local_mac(); + memcpy(g_local_mac, mac, 6); xid_seed += 0x1111; dhcp_send_discover(xid_seed); g_state = DHCP_S_SELECTING; @@ -162,7 +161,7 @@ static void dhcp_fsm_once() break; } dhcp_request req = {0}; - memcpy(req.mac, g_local_ep.mac, 6); + memcpy(req.mac, g_local_mac, 6); dhcp_apply_offer(offer, &req, xid_seed); free((void*)sp.ptr, sp.size); @@ -177,7 +176,7 @@ static void dhcp_fsm_once() g_state = DHCP_S_INIT; } else { dhcp_request dummy = {0}; - memcpy(dummy.mac, g_local_ep.mac, 6); + memcpy(dummy.mac, g_local_mac, 6); dhcp_apply_offer(ack, &dummy, xid_seed); free((void*)sp.ptr, sp.size); g_state = DHCP_S_BOUND; @@ -207,7 +206,7 @@ static void dhcp_fsm_once() dhcp_packet *p = NULL; sizedptr sp = {0}; if (dhcp_wait_for_type(DHCPACK, &p, &sp, 2000)) { dhcp_request dummy = {0}; - memcpy(dummy.mac, g_local_ep.mac, 6); + memcpy(dummy.mac, g_local_mac, 6); dhcp_apply_offer(p, &dummy, xid_seed); free((void*)sp.ptr, sp.size); g_state = DHCP_S_BOUND; @@ -222,7 +221,7 @@ static void dhcp_fsm_once() dhcp_packet *p = NULL; sizedptr sp = {0}; if (dhcp_wait_for_type(DHCPACK, &p, &sp, 2000)) { dhcp_request dummy = {0}; - memcpy(dummy.mac, g_local_ep.mac, 6); + memcpy(dummy.mac, g_local_mac, 6); dhcp_apply_offer(p, &dummy, xid_seed); free((void*)sp.ptr, sp.size); g_state = DHCP_S_BOUND; diff --git a/shared/net/internet_layer/icmp.c b/shared/net/internet_layer/icmp.c index 804eacd9..d14ee3d3 100644 --- a/shared/net/internet_layer/icmp.c +++ b/shared/net/internet_layer/icmp.c @@ -1,6 +1,5 @@ #include "icmp.h" #include "net/internet_layer/ipv4.h" -#include "net/network_types.h" #include "net/checksums.h" #include "std/memfunctions.h" #include "console/kio.h" @@ -43,8 +42,6 @@ static void free_slot(int i){ } void create_icmp_packet(uintptr_t p, - const net_l2l3_endpoint *src, - const net_l2l3_endpoint *dst, const icmp_data *d) { icmp_packet *pkt = (icmp_packet*)p; @@ -73,12 +70,13 @@ void icmp_send_echo(uint32_t dst_ip, uintptr_t buf = (uintptr_t)malloc(icmp_len); if(!buf) return; - const net_l2l3_endpoint *local = network_get_local_endpoint(); - create_icmp_packet(buf, local, NULL, &d); + create_icmp_packet(buf, &d); ((icmp_packet*)buf)->checksum = checksum16((uint16_t*)buf, icmp_len); - ipv4_send_segment(local->ip, dst_ip, 1, (sizedptr){ buf, icmp_len }); + const net_cfg_t *cfg = ipv4_get_cfg(); + if (!cfg) { free((void*)buf, icmp_len); return; } + ipv4_send_segment(cfg->ip, dst_ip, 1, (sizedptr){ buf, icmp_len }); free((void*)buf, icmp_len); } @@ -111,11 +109,13 @@ void icmp_input(uintptr_t ptr, uintptr_t buf = (uintptr_t)malloc(reply_len); if(!buf) return; - const net_l2l3_endpoint *local = network_get_local_endpoint(); - create_icmp_packet(buf, local, NULL, &d); + create_icmp_packet(buf, &d); ((icmp_packet*)buf)->checksum = checksum16((uint16_t*)buf, reply_len); - ipv4_send_segment(local->ip, src_ip, 1, (sizedptr){ buf, reply_len }); + const net_cfg_t *cfg = ipv4_get_cfg(); + if (cfg) { + ipv4_send_segment(cfg->ip, src_ip, 1, (sizedptr){ buf, reply_len }); + } free((void*)buf, reply_len); return; } diff --git a/shared/net/internet_layer/icmp.h b/shared/net/internet_layer/icmp.h index 387eb477..31c9ed7d 100644 --- a/shared/net/internet_layer/icmp.h +++ b/shared/net/internet_layer/icmp.h @@ -26,9 +26,7 @@ typedef struct { } icmp_data; void create_icmp_packet(uintptr_t p, - const net_l2l3_endpoint *src, - const net_l2l3_endpoint *dst, - const icmp_data *data); + const icmp_data *d); void icmp_input(uintptr_t ptr, uint32_t len, diff --git a/shared/net/internet_layer/ipv4.c b/shared/net/internet_layer/ipv4.c index 92637d36..ef312df6 100644 --- a/shared/net/internet_layer/ipv4.c +++ b/shared/net/internet_layer/ipv4.c @@ -174,8 +174,8 @@ void ipv4_send_segment(uint32_t src_ip, uintptr_t buf = (uintptr_t)malloc(total); if (!buf) return; - const net_l2l3_endpoint *local = network_get_local_endpoint(); - uintptr_t ptr = create_eth_packet(buf, local->mac, dst_mac, 0x0800); + const uint8_t* src_mac = network_get_local_mac(); + uintptr_t ptr = create_eth_packet(buf, src_mac, dst_mac, 0x0800); ipv4_hdr_t *ip = (ipv4_hdr_t *)ptr; ip->version_ihl = (4 << 4) | (sizeof(*ip)/4); diff --git a/shared/net/link_layer/arp.c b/shared/net/link_layer/arp.c index 8db4c6c4..d78bb8ed 100644 --- a/shared/net/link_layer/arp.c +++ b/shared/net/link_layer/arp.c @@ -100,7 +100,11 @@ bool arp_resolve(uint32_t ip, uint8_t mac_out[6], uint32_t timeout_ms) { } void arp_send_request(uint32_t target_ip) { - const net_l2l3_endpoint *ep = network_get_local_endpoint(); + const uint8_t *local_mac = network_get_local_mac(); + const net_cfg_t *cfg = ipv4_get_cfg(); + + if (!cfg) return; + uint8_t dst_mac[6]; arp_hdr_t hdr; uintptr_t buf; @@ -113,16 +117,16 @@ void arp_send_request(uint32_t target_ip) { hdr.ptype = __builtin_bswap16(0x0800); hdr.hlen = 6; hdr.plen = 4; - hdr.opcode = __builtin_bswap16(1); - memcpy(hdr.sender_mac, ep->mac, 6); - hdr.sender_ip = __builtin_bswap32(ep->ip); + hdr.opcode = __builtin_bswap16(ARP_OPCODE_REQUEST); + memcpy(hdr.sender_mac, local_mac, 6); + hdr.sender_ip = __builtin_bswap32(cfg->ip); hdr.target_ip = __builtin_bswap32(target_ip); len = sizeof(eth_hdr_t) + sizeof(arp_hdr_t); buf = (uintptr_t)malloc(len); if (!buf) return; - uintptr_t ptr = create_eth_packet(buf, ep->mac, dst_mac, 0x0806); + uintptr_t ptr = create_eth_packet(buf, local_mac, dst_mac, 0x0806); memcpy((void*)ptr, &hdr, sizeof(arp_hdr_t)); eth_send_frame(buf, len); @@ -133,9 +137,9 @@ bool arp_should_handle(const arp_hdr_t *arp, uint32_t my_ip) { return __builtin_bswap32(arp->target_ip) == my_ip; } -void arp_populate_response(net_l2l3_endpoint *ep, const arp_hdr_t *arp) { - memcpy(ep->mac, arp->sender_mac, 6); - ep->ip = __builtin_bswap32(arp->sender_ip); +void arp_populate_response(uint8_t out_mac[6], uint32_t *out_ip, const arp_hdr_t *arp) { + if (out_mac) memcpy(out_mac, arp->sender_mac, 6); + if (out_ip) *out_ip = __builtin_bswap32(arp->sender_ip); } bool arp_can_reply() { @@ -160,24 +164,25 @@ int arp_daemon_entry(int argc, char* argv[]){ } } static void arp_send_reply(const arp_hdr_t *in_arp, - const uint8_t in_src_mac[6], - uint32_t frame_len) { - const net_l2l3_endpoint *ep = network_get_local_endpoint(); + const uint8_t in_src_mac[6], + uint32_t frame_len){ + (void)frame_len; + + const uint8_t *local_mac = network_get_local_mac(); + const net_cfg_t *cfg = ipv4_get_cfg(); + if (!cfg) return; uint32_t len = sizeof(eth_hdr_t) + sizeof(arp_hdr_t); uintptr_t buf = (uintptr_t)malloc(len); if (!buf) return; - uintptr_t ptr = create_eth_packet(buf, - ep->mac, - in_src_mac, - 0x0806); + uintptr_t ptr = create_eth_packet(buf, local_mac, in_src_mac, 0x0806); arp_hdr_t reply = *in_arp; memcpy(reply.target_mac, in_arp->sender_mac, 6); - memcpy(reply.sender_mac, ep->mac, 6); + memcpy(reply.sender_mac, local_mac, 6); reply.target_ip = in_arp->sender_ip; - reply.sender_ip = __builtin_bswap32(ep->ip); + reply.sender_ip = __builtin_bswap32(cfg->ip); reply.opcode = __builtin_bswap16(ARP_OPCODE_REPLY); memcpy((void*)ptr, &reply, sizeof(reply)); @@ -189,21 +194,22 @@ static void arp_send_reply(const arp_hdr_t *in_arp, void arp_input(uintptr_t frame_ptr, uint32_t frame_len) { if (frame_len < sizeof(eth_hdr_t) + sizeof(arp_hdr_t)) return; - - if(!init) return; + if (!init) return; arp_hdr_t *hdr = (arp_hdr_t*)(frame_ptr + sizeof(eth_hdr_t)); uint32_t sender_ip = __builtin_bswap32(hdr->sender_ip); arp_table_put(sender_ip, hdr->sender_mac, 180000, false); - const net_l2l3_endpoint *ep = network_get_local_endpoint(); + const net_cfg_t *cfg = ipv4_get_cfg(); + if (!cfg) return; + if (__builtin_bswap16(hdr->opcode) == ARP_OPCODE_REQUEST && - arp_should_handle(hdr, ep->ip) && + arp_should_handle(hdr, cfg->ip) && arp_can_reply()) { - const arp_hdr_t *hdr = (arp_hdr_t*)(frame_ptr + sizeof(eth_hdr_t)); - const uint8_t *src_mac = hdr->sender_mac; - arp_send_reply(hdr, src_mac, frame_len); + const arp_hdr_t *hdr_in = (arp_hdr_t*)(frame_ptr + sizeof(eth_hdr_t)); + const uint8_t *src_mac = hdr_in->sender_mac; + arp_send_reply(hdr_in, src_mac, frame_len); } } \ No newline at end of file diff --git a/shared/net/link_layer/arp.h b/shared/net/link_layer/arp.h index 0543b2fe..efe4ae3e 100644 --- a/shared/net/link_layer/arp.h +++ b/shared/net/link_layer/arp.h @@ -19,7 +19,7 @@ typedef struct __attribute__((packed)) arp_hdr_t { } arp_hdr_t; bool arp_should_handle(const arp_hdr_t *arp, uint32_t my_ip); -void arp_populate_response(net_l2l3_endpoint *ep, const arp_hdr_t *arp); +void arp_populate_response(uint8_t out_mac[6], uint32_t *out_ip, const arp_hdr_t *arp); bool arp_resolve(uint32_t ip, uint8_t mac_out[6], uint32_t timeout_ms); #define ARP_TABLE_MAX 64 diff --git a/shared/net/network_types.h b/shared/net/network_types.h index 57b706f6..d255e4ed 100644 --- a/shared/net/network_types.h +++ b/shared/net/network_types.h @@ -6,19 +6,6 @@ extern "C" { #include "types.h" -typedef enum NetProtocol { - UDP, - DHCP, - ARP, - TCP, - ICMP -} NetProtocol; - -typedef struct net_l2l3_endpoint { - uint8_t mac[6]; - uint32_t ip; //rn ipv4 only -} net_l2l3_endpoint; - typedef struct net_l4_endpoint { uint32_t ip; uint16_t port; From 50f41d0d7f2df71c1a7bb76c4a1dba9465acca4c Mon Sep 17 00:00:00 2001 From: CodeAnarchist Date: Thu, 4 Sep 2025 01:31:59 +0200 Subject: [PATCH 02/23] merge --- run_virt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/run_virt b/run_virt index 3e758080..efeb69e9 100755 --- a/run_virt +++ b/run_virt @@ -31,7 +31,8 @@ elif [ "$OS_TYPE" = "Linux" ]; then NETDEV="-netdev user,id=net0" PRIVILEGE="" DISPLAY_MODE="sdl" - SELECTED_GPU="virtio-gpu-gl$VIRTIO_GPU_VARS" + SELECTED_GPU="virtio-gpu-pci$VIRTIO_GPU_VARS" + GL="off" else echo "Unknown OS: $OS_TYPE" >&2 exit 1 @@ -52,7 +53,7 @@ $PRIVILEGE qemu-system-aarch64 \ -m 512M \ -kernel kernel.elf \ -device $SELECTED_GPU \ - -display $DISPLAY_MODE,gl=$GL \ + -display $DISPLAY_MODE${GL:+,gl=$GL} \ $NETDEV \ -device virtio-net-pci,netdev=net0,mac=52:54:00:12:34:56 \ $DUMP \ From 61a0071ef4dcacd4822056fe9027f364787fd750 Mon Sep 17 00:00:00 2001 From: CodeAnarchist Date: Fri, 5 Sep 2025 13:58:01 +0200 Subject: [PATCH 03/23] net: fix/opt driver and add L2/L3 interfaces header --- kernel/networking/drivers/net_driver.hpp | 2 +- .../drivers/virtio_net_pci/virtio_net_pci.cpp | 92 +++++++---- .../drivers/virtio_net_pci/virtio_net_pci.hpp | 2 +- kernel/networking/interface_manager.h | 145 ++++++++++++++++++ kernel/networking/network_dispatch.cpp | 44 ++++-- 5 files changed, 234 insertions(+), 51 deletions(-) create mode 100644 kernel/networking/interface_manager.h diff --git a/kernel/networking/drivers/net_driver.hpp b/kernel/networking/drivers/net_driver.hpp index 98056631..7f1744b9 100644 --- a/kernel/networking/drivers/net_driver.hpp +++ b/kernel/networking/drivers/net_driver.hpp @@ -9,7 +9,7 @@ class NetDriver { virtual bool init() = 0; virtual sizedptr allocate_packet(size_t size) = 0; - virtual sizedptr handle_receive_packet(void* buffer) = 0; + virtual sizedptr handle_receive_packet() = 0; virtual void handle_sent_packet() = 0; virtual void enable_verbose() = 0; virtual void send_packet(sizedptr packet) = 0; diff --git a/kernel/networking/drivers/virtio_net_pci/virtio_net_pci.cpp b/kernel/networking/drivers/virtio_net_pci/virtio_net_pci.cpp index c67c5464..6ed3cf1d 100644 --- a/kernel/networking/drivers/virtio_net_pci/virtio_net_pci.cpp +++ b/kernel/networking/drivers/virtio_net_pci/virtio_net_pci.cpp @@ -22,7 +22,7 @@ typedef struct __attribute__((packed)) virtio_net_hdr_t { uint16_t hdr_len; uint16_t gso_size; uint16_t csum_start; - uint16_t num_buffers; + uint16_t csum_offset; } virtio_net_hdr_t; typedef struct virtio_net_config { @@ -81,7 +81,8 @@ bool VirtioNetDriver::init(){ select_queue(&vnp_net_dev, RECEIVE_QUEUE); - for (uint16_t i = 0; i < 128; i++){ + uint16_t rx_qsz = vnp_net_dev.common_cfg->queue_size; + for (uint16_t i = 0; i < rx_qsz; i++){ void* buf = kalloc(vnp_net_dev.memory_page, MAX_PACKET_SIZE, ALIGN_64B, MEM_PRIV_KERNEL); virtio_add_buffer(&vnp_net_dev, i, (uintptr_t)buf, MAX_PACKET_SIZE, false); } @@ -119,37 +120,54 @@ sizedptr VirtioNetDriver::allocate_packet(size_t size){ return (sizedptr){(uintptr_t)kalloc(vnp_net_dev.memory_page, size + header_size, ALIGN_64B, MEM_PRIV_KERNEL), size + header_size}; } -sizedptr VirtioNetDriver::handle_receive_packet(void* buffer){ +sizedptr VirtioNetDriver::handle_receive_packet(){ select_queue(&vnp_net_dev, RECEIVE_QUEUE); struct virtq_used* used = (struct virtq_used*)(uintptr_t)vnp_net_dev.common_cfg->queue_device; struct virtq_desc* desc = (struct virtq_desc*)(uintptr_t)vnp_net_dev.common_cfg->queue_desc; struct virtq_avail* avail = (struct virtq_avail*)(uintptr_t)vnp_net_dev.common_cfg->queue_driver; + uint16_t qsz = vnp_net_dev.common_cfg->queue_size; uint16_t new_idx = used->idx; - if (new_idx != last_used_receive_idx) { - uint16_t used_ring_index = last_used_receive_idx % 128; - last_used_receive_idx = new_idx; - struct virtq_used_elem* e = &used->ring[used_ring_index]; - uint32_t desc_index = e->id; - uint32_t len = e->len; - kprintfv("Received network packet %i at index %i (len %i - %i)",used->idx, desc_index, len,sizeof(virtio_net_hdr_t)); - - uintptr_t packet = desc[desc_index].addr; - packet += sizeof(virtio_net_hdr_t); + if (new_idx == last_used_receive_idx) { + return (sizedptr){0,0}; + } - memcpy(buffer, (void*)packet, len); + uint16_t used_ring_index = (uint16_t)(last_used_receive_idx % qsz); + struct virtq_used_elem* e = &used->ring[used_ring_index]; + uint32_t desc_index = e->id; + uint32_t len = e->len; - avail->ring[avail->idx % 128] = desc_index; - avail->idx++; + if (desc_index >= qsz) { + kprintfv("[VIRTIO_NET warn] RX used id %i >= qsz %i", (unsigned)desc_index, (unsigned)qsz); + last_used_receive_idx++; + return (sizedptr){0,0}; + } - *(volatile uint16_t*)(uintptr_t)(vnp_net_dev.notify_cfg + vnp_net_dev.notify_off_multiplier * RECEIVE_QUEUE) = 0; + kprintfv("Received network packet %i at index %i (len %i - hdr %i)", used->idx, desc_index, len, (unsigned)sizeof(virtio_net_hdr_t)); + + uintptr_t packet = desc[desc_index].addr; + uint32_t payload_len = (len > header_size) ? (len - header_size) : 0; + + void* out_buf = 0; + if (payload_len) { + out_buf = kalloc(vnp_net_dev.memory_page, payload_len, ALIGN_64B, MEM_PRIV_KERNEL); + if (!out_buf) { + avail->ring[avail->idx % qsz] = (uint16_t)desc_index; + avail->idx++; + *(volatile uint16_t*)(uintptr_t)(vnp_net_dev.notify_cfg + vnp_net_dev.notify_off_multiplier * RECEIVE_QUEUE) = 0; + last_used_receive_idx++; + return (sizedptr){0,0}; + } + memcpy(out_buf, (void*)(packet + header_size), payload_len); + } - kfree((void*)desc[desc_index].addr, MAX_PACKET_SIZE); + avail->ring[avail->idx % qsz] = (uint16_t)desc_index; + avail->idx++; + *(volatile uint16_t*)(uintptr_t)(vnp_net_dev.notify_cfg + vnp_net_dev.notify_off_multiplier * RECEIVE_QUEUE) = 0; - return (sizedptr){packet,len}; - } + last_used_receive_idx++; - return (sizedptr){0,0}; + return (sizedptr){ (uintptr_t)out_buf, payload_len }; } void VirtioNetDriver::handle_sent_packet(){ @@ -157,29 +175,39 @@ void VirtioNetDriver::handle_sent_packet(){ struct virtq_used* used = (struct virtq_used*)(uintptr_t)vnp_net_dev.common_cfg->queue_device; struct virtq_desc* desc = (struct virtq_desc*)(uintptr_t)vnp_net_dev.common_cfg->queue_desc; + uint16_t qsz = vnp_net_dev.common_cfg->queue_size; - uint16_t new_idx = used->idx; + int cleaned = 0; + while (last_used_sent_idx != used->idx && cleaned < 64) { + uint16_t used_ring_index = (uint16_t)(last_used_sent_idx % qsz); + last_used_sent_idx = (uint16_t)(last_used_sent_idx + 1); - if (new_idx != last_used_sent_idx) { - uint16_t used_ring_index = last_used_sent_idx % 128; - last_used_sent_idx = new_idx; struct virtq_used_elem* e = &used->ring[used_ring_index]; uint32_t desc_index = e->id; - uint32_t len = e->len; - kfree((void*)desc[desc_index].addr, len); - return; + + if (desc_index < qsz) { + kfree((void*)desc[desc_index].addr, desc[desc_index].len); + } else { + kprintfv("[VIRTIO_NET warn] TX used id %i >= qsz %i", (unsigned)desc_index, (unsigned)qsz); + } + cleaned++; } } + void VirtioNetDriver::send_packet(sizedptr packet){ select_queue(&vnp_net_dev, TRANSMIT_QUEUE); - - if (packet.ptr && packet.size) + + if (packet.ptr && packet.size){ + if (header_size <= packet.size) { + memset((void*)packet.ptr, 0, header_size); + } virtio_send_1d(&vnp_net_dev, packet.ptr, packet.size); - + } + kprintfv("Queued new packet"); } void VirtioNetDriver::enable_verbose(){ verbose = true; -} +} \ No newline at end of file diff --git a/kernel/networking/drivers/virtio_net_pci/virtio_net_pci.hpp b/kernel/networking/drivers/virtio_net_pci/virtio_net_pci.hpp index faf7b780..524aecd6 100644 --- a/kernel/networking/drivers/virtio_net_pci/virtio_net_pci.hpp +++ b/kernel/networking/drivers/virtio_net_pci/virtio_net_pci.hpp @@ -14,7 +14,7 @@ class VirtioNetDriver : public NetDriver { sizedptr allocate_packet(size_t size) override; - sizedptr handle_receive_packet(void* buffer) override; + sizedptr handle_receive_packet() override; void handle_sent_packet() override; diff --git a/kernel/networking/interface_manager.h b/kernel/networking/interface_manager.h new file mode 100644 index 00000000..54f213ba --- /dev/null +++ b/kernel/networking/interface_manager.h @@ -0,0 +1,145 @@ +#pragma once + +#include "types.h" +#include "net/network_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define MAX_L2_INTERFACES 16 +#define MAX_IPV4_PER_INTERFACE 4 +#define MAX_IPV6_PER_INTERFACE 4 +#define MAX_IPV4_MCAST_PER_INTERFACE 8 +#define MAX_IPV6_MCAST_PER_INTERFACE 8 + +typedef enum { + NET_MODE_DISABLED = -1, + NET_MODE_DHCP = 0, + NET_MODE_STATIC = 1 +} net_mode_t; + +typedef enum { + IPV6_ADDRK_GLOBAL = 0x01, + IPV6_ADDRK_LINK_LOCAL = 0x02 +} ipv6_addr_kind_t; + +typedef enum { + IPV6_CFG_STATIC = 0x01, + IPV6_CFG_SLAAC = 0x02, + IPV6_CFG_DHCPV6 = 0x04 +} ipv6_cfg_t; + +struct l2_interface; +struct l3_ipv4_interface; +struct l3_ipv6_interface; + +typedef struct l2_interface { + uint8_t ifindex; + char name[16]; + uint8_t mac_addr[6]; + uint16_t mtu; + bool is_up; + void *tx_queue; + void *rx_queue; + void *driver_context; + int (*send_frame)(struct l2_interface *iface, const void *frame, size_t len); + void *arp_table; + void *nd_table; + struct l3_ipv4_interface *l3_v4[MAX_IPV4_PER_INTERFACE]; + struct l3_ipv6_interface *l3_v6[MAX_IPV6_PER_INTERFACE]; + uint8_t ipv4_count; + uint8_t ipv6_count; + uint32_t ipv4_mcast[MAX_IPV4_MCAST_PER_INTERFACE]; + uint8_t ipv4_mcast_count; + uint8_t ipv6_mcast[MAX_IPV6_MCAST_PER_INTERFACE][16]; + uint8_t ipv6_mcast_count; +} l2_interface_t; + +typedef struct l3_ipv4_interface { + uint8_t l3_id; + uint32_t ip; + uint32_t mask; + uint32_t gw; + uint32_t broadcast; + net_mode_t mode; + bool is_localhost; + void *rt_v4; + void *port_manager; + l2_interface_t *l2; +} l3_ipv4_interface_t; + +typedef struct l3_ipv6_interface { + uint8_t l3_id; + uint8_t ip[16]; + uint8_t prefix_len; + uint8_t gateway[16]; + uint8_t kind; + uint8_t cfg; + bool is_localhost; + uint32_t valid_lifetime; + uint32_t preferred_lifetime; + uint32_t timestamp_created; + uint8_t prefix[16]; + uint8_t interface_id[8]; + void *port_manager; + l2_interface_t *l2; +} l3_ipv6_interface_t; + +typedef struct network_dispatcher { + l2_interface_t *l2[MAX_L2_INTERFACES]; + uint8_t l2_count; + l3_ipv4_interface_t *lo_v4; + l3_ipv6_interface_t *lo_v6; + void *rt4; + void *rt6; + int8_t primary_ifindex; +} network_dispatcher_t; + +typedef struct ip_resolution_result { + bool found; + l3_ipv4_interface_t *ipv4; + l3_ipv6_interface_t *ipv6; + l2_interface_t *l2; +} ip_resolution_result_t; + +uint8_t l2_interface_create(const char *name, void *driver_ctx); +bool l2_interface_destroy(uint8_t ifindex); +l2_interface_t *l2_interface_find_by_index(uint8_t ifindex); +bool l2_interface_set_mac(uint8_t ifindex, const uint8_t mac[6]); +bool l2_interface_set_mtu(uint8_t ifindex, uint16_t mtu); +bool l2_interface_set_up(uint8_t ifindex, bool up); +bool l2_ipv4_mcast_join(uint8_t ifindex, uint32_t group); +bool l2_ipv4_mcast_leave(uint8_t ifindex, uint32_t group); +bool l2_ipv6_mcast_join(uint8_t ifindex, const uint8_t group[16]); +bool l2_ipv6_mcast_leave(uint8_t ifindex, const uint8_t group[16]); + +uint8_t l3_ipv4_add_to_interface(uint8_t ifindex, uint32_t ip, uint32_t mask, uint32_t gw, net_mode_t mode); +bool l3_ipv4_remove_from_interface(uint8_t l3_id); +l3_ipv4_interface_t *l3_ipv4_find_by_id(uint8_t l3_id); +l3_ipv4_interface_t *l3_ipv4_find_by_ip(uint32_t ip); + +uint8_t l3_ipv6_add_to_interface(uint8_t ifindex, const uint8_t ip[16], uint8_t prefix_len, const uint8_t gw[16], uint8_t cfg, uint8_t kind); +bool l3_ipv6_remove_from_interface(uint8_t l3_id); +l3_ipv6_interface_t *l3_ipv6_find_by_id(uint8_t l3_id); +l3_ipv6_interface_t *l3_ipv6_find_by_ip(const uint8_t ip[16]); + +void l3_init_localhost_ipv4(void); +void l3_init_localhost_ipv6(void); +//void l3_init_both_localhost(void); + +ip_resolution_result_t resolve_ipv4_to_interface(uint32_t dst_ip); +ip_resolution_result_t resolve_ipv6_to_interface(const uint8_t dst_ip[16]); + +bool check_ipv4_overlap(uint32_t new_ip, uint32_t mask, uint8_t ifindex); +bool check_ipv6_overlap(const uint8_t new_ip[16], uint8_t prefix_len, uint8_t ifindex); + +network_dispatcher_t *get_network_dispatcher(void); +void network_dispatcher_init(void); +bool network_set_primary(uint8_t ifindex); +l2_interface_t *get_primary_interface(void); +l3_ipv4_interface_t *get_primary_ipv4(void); + +#ifdef __cplusplus +} +#endif diff --git a/kernel/networking/network_dispatch.cpp b/kernel/networking/network_dispatch.cpp index 8856de37..6a9721b5 100644 --- a/kernel/networking/network_dispatch.cpp +++ b/kernel/networking/network_dispatch.cpp @@ -11,8 +11,11 @@ extern void sleep(uint64_t ms); extern uintptr_t malloc(uint64_t size); extern void free(void *ptr, uint64_t size); +#define RX_INTR_BATCH_LIMIT 32 +#define TASK_RX_BATCH_LIMIT 32 +#define TASK_TX_BATCH_LIMIT 32 + static uint16_t g_net_pid = 0xFFFF; -static uint8_t recv_buffer[MAX_PACKET_SIZE]; NetworkDispatch::NetworkDispatch() : ports(UINT16_MAX + 1), @@ -37,21 +40,22 @@ bool NetworkDispatch::init() void NetworkDispatch::handle_download_interrupt() { if (!driver) return; - - sizedptr raw = driver->handle_receive_packet(recv_buffer); - if (raw.size < sizeof(eth_hdr_t)) { - return; - } - sizedptr frame{0, raw.size}; - frame.ptr = reinterpret_cast( - kalloc(reinterpret_cast(get_current_heap()), raw.size, ALIGN_16B, get_current_privilege())); - if (!frame.ptr) return; + for (int drained = 0; drained < RX_INTR_BATCH_LIMIT; ++drained) { + sizedptr raw = driver->handle_receive_packet(); + if (raw.size == 0) { + break; + } - memcpy(reinterpret_cast(frame.ptr), recv_buffer, raw.size); + if (raw.size < sizeof(eth_hdr_t)) { + free_frame(raw); + continue; + } - if (!rx_queue.enqueue(frame)) - free_frame(frame); + if (!rx_queue.enqueue(raw)) { + free_frame(raw); + } + } } void NetworkDispatch::handle_upload_interrupt() @@ -82,15 +86,22 @@ int NetworkDispatch::net_task() network_net_set_pid(get_current_proc_pid()); for (;;) { bool did_work = false; - sizedptr pkt{0,0}; - if (!rx_queue.is_empty() && rx_queue.dequeue(pkt)) { + for (int i = 0; i < TASK_RX_BATCH_LIMIT; ++i) { + if (rx_queue.is_empty()) break; + sizedptr pkt{0,0}; + if (!rx_queue.dequeue(pkt)) break; + did_work = true; eth_input(pkt.ptr, pkt.size); free_frame(pkt); } - if (!tx_queue.is_empty() && tx_queue.dequeue(pkt)) { + for (int i = 0; i < TASK_TX_BATCH_LIMIT; ++i) { + if (tx_queue.is_empty()) break; + sizedptr pkt{0,0}; + if (!tx_queue.dequeue(pkt)) break; + did_work = true; driver->send_packet(pkt); } @@ -98,7 +109,6 @@ int NetworkDispatch::net_task() if (!did_work) sleep(10); } - return 0; } bool NetworkDispatch::dequeue_packet_for(uint16_t pid, sizedptr *out) From 52cac458733ecb6a1480cb23b5bee712067a3746 Mon Sep 17 00:00:00 2001 From: CodeAnarchist Date: Fri, 5 Sep 2025 18:41:34 +0200 Subject: [PATCH 04/23] palloc on virtio net driver --- .../drivers/virtio_net_pci/virtio_net_pci.cpp | 27 +++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/kernel/networking/drivers/virtio_net_pci/virtio_net_pci.cpp b/kernel/networking/drivers/virtio_net_pci/virtio_net_pci.cpp index 6ed3cf1d..4018aae7 100644 --- a/kernel/networking/drivers/virtio_net_pci/virtio_net_pci.cpp +++ b/kernel/networking/drivers/virtio_net_pci/virtio_net_pci.cpp @@ -9,6 +9,11 @@ #define RECEIVE_QUEUE 0 #define TRANSMIT_QUEUE 1 +static constexpr uint32_t RX_BUF_SIZE = PAGE_SIZE; + +static void* g_rx_pool = nullptr; +static uint16_t g_rx_qsz = 0; + #define kprintfv(fmt, ...) \ ({ \ if (verbose){\ @@ -82,9 +87,27 @@ bool VirtioNetDriver::init(){ select_queue(&vnp_net_dev, RECEIVE_QUEUE); uint16_t rx_qsz = vnp_net_dev.common_cfg->queue_size; + g_rx_qsz = rx_qsz; + + if (!g_rx_pool) { + g_rx_pool = palloc((uint64_t)rx_qsz * RX_BUF_SIZE, MEM_PRIV_KERNEL, MEM_RW | MEM_DEV, true); + if (!g_rx_pool) { + kprintf("[VIRTIO_NET warn] palloc failed, fallingback to kalloc"); + } + } + for (uint16_t i = 0; i < rx_qsz; i++){ - void* buf = kalloc(vnp_net_dev.memory_page, MAX_PACKET_SIZE, ALIGN_64B, MEM_PRIV_KERNEL); - virtio_add_buffer(&vnp_net_dev, i, (uintptr_t)buf, MAX_PACKET_SIZE, false); + void* buf = nullptr; + if (g_rx_pool) { + buf = (void*)((uintptr_t)g_rx_pool + (uintptr_t)i * RX_BUF_SIZE); + } else { + buf = kalloc(vnp_net_dev.memory_page, RX_BUF_SIZE, ALIGN_64B, MEM_PRIV_KERNEL); + if (!buf) { + kprintf("[VIRTIO_NET error] rx buffer allocation failed at %i", i); + return false; + } + } + virtio_add_buffer(&vnp_net_dev, i, (uintptr_t)buf, RX_BUF_SIZE, false); } vnp_net_dev.common_cfg->queue_msix_vector = 0; From 2ce7be00f4f838735f24811fc5ca644306bef16b Mon Sep 17 00:00:00 2001 From: CodeAnarchist Date: Fri, 5 Sep 2025 21:21:34 +0200 Subject: [PATCH 05/23] removed unnecessary declaration --- kernel/networking/network_dispatch.cpp | 7 ++----- kernel/networking/network_dispatch.hpp | 2 +- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/kernel/networking/network_dispatch.cpp b/kernel/networking/network_dispatch.cpp index 6a9721b5..12f88d91 100644 --- a/kernel/networking/network_dispatch.cpp +++ b/kernel/networking/network_dispatch.cpp @@ -18,13 +18,10 @@ extern void free(void *ptr, uint64_t size); static uint16_t g_net_pid = 0xFFFF; NetworkDispatch::NetworkDispatch() - : ports(UINT16_MAX + 1), - driver(nullptr), + : driver(nullptr), tx_queue(QUEUE_CAPACITY), rx_queue(QUEUE_CAPACITY) { - for (uint32_t i = 0; i <= UINT16_MAX; ++i) - ports[i] = UINT16_MAX; memset(local_mac, 0, sizeof(local_mac)); } @@ -107,7 +104,7 @@ int NetworkDispatch::net_task() } if (!did_work) - sleep(10); + sleep(10); //TODO: manage it with an event } } diff --git a/kernel/networking/network_dispatch.hpp b/kernel/networking/network_dispatch.hpp index 849a85ab..44a4880e 100644 --- a/kernel/networking/network_dispatch.hpp +++ b/kernel/networking/network_dispatch.hpp @@ -31,7 +31,7 @@ class NetworkDispatch { private: static constexpr size_t QUEUE_CAPACITY = 1024; - IndexMap ports; //port pid map + //IndexMap ports; //port pid map NetDriver* driver; uint8_t local_mac[6]; From a99552e370f9c9eb024a9d1df25b93eb3f1147e8 Mon Sep 17 00:00:00 2001 From: CodeAnarchist Date: Sat, 6 Sep 2025 18:15:15 +0200 Subject: [PATCH 06/23] net: add multi-nic support, dynamic init, virtio updates and minor fixes --- kernel/exceptions/irq.c | 20 +- kernel/networking/drivers/net_bus.cpp | 210 +++++++++++++++ kernel/networking/drivers/net_bus.hpp | 12 + kernel/networking/drivers/net_driver.hpp | 15 +- .../drivers/virtio_net_pci/virtio_net_pci.cpp | 207 +++++++-------- .../drivers/virtio_net_pci/virtio_net_pci.hpp | 34 ++- kernel/networking/interface_manager.c | 152 +++++++++++ kernel/networking/interface_manager.h | 21 +- kernel/networking/network.cpp | 75 +++++- kernel/networking/network.h | 13 +- kernel/networking/network_dispatch.cpp | 239 ++++++++++++------ kernel/networking/network_dispatch.hpp | 58 +++-- kernel/networking/processes/net_proc.c | 1 + kernel/pci.c | 102 ++++++-- kernel/pci.h | 10 + kernel/virtio/virtio_pci.c | 32 ++- run_virt | 2 + shared/net/application_layer/dhcp_daemon.c | 4 +- shared/net/application_layer/sntp_daemon.c | 2 +- shared/net/internet_layer/ipv4.c | 4 +- shared/net/internet_layer/ipv4.h | 3 - shared/net/link_layer/arp.c | 4 +- shared/std/allocator.cpp | 12 +- shared/std/allocator.hpp | 12 +- shared/std/string.c | 14 + 25 files changed, 936 insertions(+), 322 deletions(-) create mode 100644 kernel/networking/drivers/net_bus.cpp create mode 100644 kernel/networking/drivers/net_bus.hpp create mode 100644 kernel/networking/interface_manager.c diff --git a/kernel/exceptions/irq.c b/kernel/exceptions/irq.c index 38d875e3..9d757321 100644 --- a/kernel/exceptions/irq.c +++ b/kernel/exceptions/irq.c @@ -9,6 +9,7 @@ #include "networking/network.h" #include "hw/hw.h" #include "audio/audio.h" +#include "networking/interface_manager.h" #define IRQ_TIMER 30 #define SLEEP_TIMER 27 @@ -45,8 +46,11 @@ void irq_init() { gic_enable_irq(IRQ_TIMER, 0x80, 0); gic_enable_irq(MSI_OFFSET + INPUT_IRQ, 0x80, 0); - gic_enable_irq(MSI_OFFSET + NET_IRQ, 0x80, 0); - gic_enable_irq(MSI_OFFSET + NET_IRQ + 1, 0x80, 0); + + for (uint32_t i = 0; i < (uint32_t)MAX_L2_INTERFACES; ++i) { + gic_enable_irq(MSI_OFFSET + NET_IRQ_BASE + (2*i), 0x80, 0); + gic_enable_irq(MSI_OFFSET + NET_IRQ_BASE + (2*i+1), 0x80, 0); + } gic_enable_irq(SLEEP_TIMER, 0x80, 0); gic_enable_irq(MSI_OFFSET + AUDIO_IRQ, 0x80, 0); @@ -91,12 +95,12 @@ void irq_el1_handler() { wake_processes(); if (RPI_BOARD != 3) write32(GICC_BASE + 0x10, irq); process_restore(); - } else if (irq == MSI_OFFSET + NET_IRQ){ - network_handle_download_interrupt(); - if (RPI_BOARD != 3) write32(GICC_BASE + 0x10, irq); - process_restore(); - } else if (irq == MSI_OFFSET + NET_IRQ + 1){ - network_handle_upload_interrupt(); + } else if (irq >= MSI_OFFSET + NET_IRQ_BASE && irq < MSI_OFFSET + NET_IRQ_BASE + (2*MAX_L2_INTERFACES)){ + uint32_t rel = irq - (MSI_OFFSET + NET_IRQ_BASE); + uint16_t nic_id = (uint16_t)(rel >> 1); + uint8_t is_rx = (rel & 1) == 0; + if (is_rx) network_handle_download_interrupt_nic(nic_id); + else network_handle_upload_interrupt_nic(nic_id); if (RPI_BOARD != 3) write32(GICC_BASE + 0x10, irq); process_restore(); } else if (irq == MSI_OFFSET + AUDIO_IRQ){ diff --git a/kernel/networking/drivers/net_bus.cpp b/kernel/networking/drivers/net_bus.cpp new file mode 100644 index 00000000..f2c625fe --- /dev/null +++ b/kernel/networking/drivers/net_bus.cpp @@ -0,0 +1,210 @@ +#include "net_driver.hpp" +#include "virtio_net_pci/virtio_net_pci.hpp" +#include "pci.h" +#include "std/memory.h" +#include "console/kio.h" +#include "types.h" +#include "networking/interface_manager.h" +#include "networking/network.h" + +#define kprintfv(fmt, ...) ({ if (verbose){ kprintf(fmt, ##__VA_ARGS__); } }) + +typedef struct { + NetDriver* drv; + char ifname[16]; + char hw_ifname[32]; + uint8_t mac[6]; + uint16_t mtu; + uint16_t header_size; + uint8_t kind; +} net_nic_desc_t; + +static net_nic_desc_t g_nics[MAX_L2_INTERFACES]; +static size_t g_count = 0; +static int g_eth_next = 0; +static int g_wif_next = 0; +static bool g_lo_added = false; +static bool verbose = true; + +static void memzero(void* p, size_t n){ + memset(p,0,n); +} + +static size_t cpystr(char* dst, size_t cap, const char* src){ + size_t i=0; + if (!dst || !src || cap==0) return 0; + while (i1){ dst[0]='0'; dst[1]=0; return 1; } dst[0]=0; return 0; } + while (v>0 && n<16){ tmp[n++] = (char)('0' + (v%10)); v/=10; } + size_t i=0; + while (i0){ dst[i++] = tmp[--n]; } + dst[i]=0; + return i; +} + +static void make_ifname(char* dst, size_t cap, const char* prefix){ + if (!dst || cap==0) return; + int idx=0; + if (prefix && prefix[0]=='e'){ idx = g_eth_next++; } + else if (prefix && prefix[0]=='w'){ idx = g_wif_next++; } + else { idx = g_eth_next + g_wif_next; g_eth_next++; } + size_t j=0; + if (prefix){ j = cpystr(dst, cap, prefix); } else { dst[0]='n'; dst[1]='i'; dst[2]='c'; dst[3]=0; j=3; } + if (j= MAX_L2_INTERFACES) return; + net_nic_desc_t* d = &g_nics[g_count++]; + d->drv = nullptr; + memzero(d->ifname,sizeof(d->ifname)); + memzero(d->hw_ifname,sizeof(d->hw_ifname)); + d->ifname[0]='l'; d->ifname[1]='o'; d->ifname[2]='0'; d->ifname[3]=0; + d->hw_ifname[0]='l'; d->hw_ifname[1]='o'; d->hw_ifname[2]='o'; d->hw_ifname[3]='p'; d->hw_ifname[4]='b'; d->hw_ifname[5]='a'; d->hw_ifname[6]='c'; d->hw_ifname[7]='k'; d->hw_ifname[8]=0; + memzero(d->mac,6); + d->mtu = 65535; + d->header_size = 0; + d->kind = 2; + g_lo_added = true; + kprintfv("[net-bus] added loopback ifname=%s",d->ifname); +} + +static bool is_virtio_net(uint16_t vendor, uint16_t device, uint8_t class_code, uint8_t subclass){ + if (vendor != 0x1AF4) return false; + if (class_code == 0x02) return true; + if (device == 0x1000) return true; + return false; +} + +int net_bus_init(){ + g_count = 0; + g_eth_next = 0; + g_wif_next = 0; + g_lo_added = false; + + kprintfv("[net-bus] init"); + + pci_device_info infos[64]; + size_t n = pci_enumerate(infos, 64); + kprintfv("[net-bus] pci_enumerate=%u",(unsigned)n); + + int nic_ord = 0; + + for (size_t i=0;i= MAX_L2_INTERFACES){ kprintfv("[net-bus] cap reached"); break; } + + const uint16_t ven = infos[i].vendor; + const uint16_t dev = infos[i].device; + const uint8_t cls = infos[i].class_code; + const uint8_t sub = infos[i].subclass; + + if (cls != 0x02) continue; + + kprintfv("[net-bus] net dev %u ven=%x dev=%x class=%x sub=%x prog=%x addr=%x", + (unsigned)i, ven, dev, cls, sub, infos[i].prog_if, (uintptr_t)infos[i].addr); + + const char* if_prefix = "net"; + uint8_t kind = 1; + if (sub == 0x00){ if_prefix = "eth"; kind = 0; } + else if (sub == 0x80){ if_prefix = "net"; kind = 1; } + + bool matched = false; + + if (is_virtio_net(ven, dev, cls, sub)){ + VirtioNetDriver* d = new VirtioNetDriver(); + if (!d){ kprintf("[net-bus][warn] virtio alloc failed"); continue; } + + uint32_t irq_base = NET_IRQ_BASE + (uint32_t)(2*nic_ord); + if (!d->init_at(infos[i].addr, irq_base)){ + kprintf("[net-bus][warn] virtio init_at failed"); + delete d; + continue; + } + + net_nic_desc_t* e = &g_nics[g_count++]; + e->drv = d; + + uint8_t mac[6]; d->get_mac(mac); + memcpy(e->mac, mac, 6); + e->mtu = d->get_mtu(); + e->header_size = d->get_header_size(); + e->kind = kind; + + make_ifname(e->ifname, sizeof(e->ifname), if_prefix); + + const char* hw = d->hw_ifname(); + if (hw && hw[0]) cpystr(e->hw_ifname, sizeof(e->hw_ifname), hw); + else { e->hw_ifname[0]='v'; e->hw_ifname[1]='n'; e->hw_ifname[2]='e'; e->hw_ifname[3]='t'; e->hw_ifname[4]=0; } + + kprintfv("[net-bus] added if=%s mac=%x:%x:%x:%x:%x:%x mtu=%u hdr=%u hw=%s irq_base=%u", + e->ifname, e->mac[0],e->mac[1],e->mac[2],e->mac[3],e->mac[4],e->mac[5], + e->mtu, e->header_size, e->hw_ifname, (unsigned)irq_base); + + nic_ord += 1; + matched = true; + } + //else if future drivers + + if (!matched){ + kprintf("[net-bus][warn] no driver for ven=%x dev=%x class=%x sub=%x", ven, dev, cls, sub); + } + } + + if (!g_lo_added && g_count < MAX_L2_INTERFACES) add_loopback(); + + kprintfv("[net-bus] total_if=%u",(unsigned)g_count); + return (int)g_count; +} + + +void net_bus_enable_verbose(){ + verbose = true; +} + +int net_bus_count(){ + return (int)g_count; +} + +NetDriver* net_bus_driver(int idx){ + if (idx < 0 || (size_t)idx >= g_count) return nullptr; + return g_nics[idx].drv; +} + +const char* net_bus_ifname(int idx){ + if (idx < 0 || (size_t)idx >= g_count) return nullptr; + return g_nics[idx].ifname; +} + +const char* net_bus_hw_ifname(int idx){ + if (idx < 0 || (size_t)idx >= g_count) return nullptr; + return g_nics[idx].hw_ifname; +} + +void net_bus_get_mac(int idx, uint8_t out_mac[6]){ + if (idx < 0 || (size_t)idx >= g_count) { memzero(out_mac,6); return; } + memcpy(out_mac, g_nics[idx].mac, 6); +} + +uint16_t net_bus_get_mtu(int idx){ + if (idx < 0 || (size_t)idx >= g_count) return 0; + return g_nics[idx].mtu; +} + +uint16_t net_bus_get_header_size(int idx){ + if (idx < 0 || (size_t)idx >= g_count) return 0; + return g_nics[idx].header_size; +} + +uint8_t net_bus_get_kind(int idx){ + if (idx < 0 || (size_t)idx >= g_count) return 0xFF; + return g_nics[idx].kind; +} diff --git a/kernel/networking/drivers/net_bus.hpp b/kernel/networking/drivers/net_bus.hpp new file mode 100644 index 00000000..7dbcc62d --- /dev/null +++ b/kernel/networking/drivers/net_bus.hpp @@ -0,0 +1,12 @@ +#pragma once +#include "net_driver.hpp" + +int net_bus_init(); +int net_bus_count(); +NetDriver* net_bus_driver(int idx); +const char* net_bus_ifname(int idx); +const char* net_bus_hw_ifname(int idx); +void net_bus_get_mac(int idx, uint8_t out_mac[6]); +uint16_t net_bus_get_mtu(int idx); +uint16_t net_bus_get_header_size(int idx); +uint8_t net_bus_get_kind(int idx); \ No newline at end of file diff --git a/kernel/networking/drivers/net_driver.hpp b/kernel/networking/drivers/net_driver.hpp index 7f1744b9..a9449a47 100644 --- a/kernel/networking/drivers/net_driver.hpp +++ b/kernel/networking/drivers/net_driver.hpp @@ -1,21 +1,20 @@ #pragma once - #include "types.h" #include "net/network_types.h" class NetDriver { public: NetDriver() = default; - virtual bool init() = 0; - + virtual ~NetDriver() = default; + virtual bool init_at(uint64_t pci_addr, uint32_t irq_base_vector) = 0; virtual sizedptr allocate_packet(size_t size) = 0; virtual sizedptr handle_receive_packet() = 0; virtual void handle_sent_packet() = 0; virtual void enable_verbose() = 0; virtual void send_packet(sizedptr packet) = 0; - virtual void get_mac(uint8_t out_mac[6]) = 0; - - virtual ~NetDriver() = default; - - uint16_t header_size; + virtual void get_mac(uint8_t out_mac[6]) const = 0; + virtual uint16_t get_mtu() const = 0; + virtual uint16_t get_header_size() const = 0; + virtual const char* if_prefix() const = 0; + virtual const char* hw_ifname() const = 0; }; diff --git a/kernel/networking/drivers/virtio_net_pci/virtio_net_pci.cpp b/kernel/networking/drivers/virtio_net_pci/virtio_net_pci.cpp index 4018aae7..683eb60e 100644 --- a/kernel/networking/drivers/virtio_net_pci/virtio_net_pci.cpp +++ b/kernel/networking/drivers/virtio_net_pci/virtio_net_pci.cpp @@ -1,10 +1,10 @@ #include "virtio_net_pci.hpp" #include "console/kio.h" -#include "networking/network.h" #include "pci.h" #include "syscalls/syscalls.h" #include "memory/page_allocator.h" #include "std/memory.h" +#include "networking/network.h" #define RECEIVE_QUEUE 0 #define TRANSMIT_QUEUE 1 @@ -20,7 +20,6 @@ static uint16_t g_rx_qsz = 0; kprintf(fmt, ##__VA_ARGS__); \ }\ }) - typedef struct __attribute__((packed)) virtio_net_hdr_t { uint8_t flags; uint8_t gso_type; @@ -42,101 +41,127 @@ typedef struct virtio_net_config { uint32_t supported_hash_types; }__attribute__((packed)) virtio_net_config; -VirtioNetDriver* VirtioNetDriver::try_init(){ - VirtioNetDriver* driver = new VirtioNetDriver(); - if (driver->init()) - return driver; - delete driver; - return nullptr; +VirtioNetDriver::VirtioNetDriver() { + verbose = false; + last_used_receive_idx = 0; + last_used_sent_idx = 0; + header_size = sizeof(virtio_net_hdr_t); + mtu = 1500; + hw_name[0] = 0; } -bool VirtioNetDriver::init(){ - uint64_t addr = find_pci_device(VIRTIO_VENDOR, VIRTIO_NET_ID); - if (!addr){ - kprintf("[VIRTIO_NET error] Virtio network device not found"); +VirtioNetDriver::~VirtioNetDriver(){} + +bool VirtioNetDriver::init_at(uint64_t addr, uint32_t irq_base_vector){ + kprintfv("[virtio-net] probing pci_addr=%x",(uintptr_t)addr); + + uint64_t mmio_addr = 0, mmio_size = 0; + virtio_get_capabilities(&vnp_net_dev, addr, &mmio_addr, &mmio_size); + kprintfv("[virtio-net] mmio=%x size=%x",(uintptr_t)mmio_addr,(uintptr_t)mmio_size); + + pci_register(mmio_addr, mmio_size); + + uint8_t interrupts_ok = pci_setup_interrupts(addr, irq_base_vector, 2); + if (!interrupts_ok){ + kprintf("[virtio-net][err] pci_setup_interrupts failed"); return false; } - - uint64_t net_device_address, net_device_size; - - kprintfv("[VIRTIO_NET] Configuring network device"); - - virtio_get_capabilities(&vnp_net_dev, addr, &net_device_address, &net_device_size); - pci_register(net_device_address, net_device_size); - - uint8_t interrupts_ok = pci_setup_interrupts(addr, NET_IRQ, 2); - switch(interrupts_ok){ - case 0: - kprintf("[VIRTIO_NET] Failed to setup interrupts"); - return false; - case 1: - kprintf("[VIRTIO_NET] Interrupts setup with MSI-X %i, %i",NET_IRQ,NET_IRQ+1); - break; - default: - kprintf("[VIRTIO_NET] Interrupts setup with MSI %i,%i",NET_IRQ,NET_IRQ+1); - break; + if (interrupts_ok == 1){ + kprintfv("[virtio-net] interrupts MSI-X base=%u",(unsigned)irq_base_vector); + } else { + kprintfv("[virtio-net] interrupts MSI base=%u",(unsigned)irq_base_vector); } + pci_enable_device(addr); + kprintfv("[virtio-net] device enabled"); - if (!virtio_init_device(&vnp_net_dev)) { - kprintf("[VIRTIO_NET error] Failed network initialization"); + if (!virtio_init_device(&vnp_net_dev)){ + kprintf("[virtio-net][err] virtio_init_device failed"); return false; } - kprintf("[VIRTIO_NET] Device set up at %x",(uintptr_t)vnp_net_dev.device_cfg); + kprintfv("[virtio-net] common_cfg=%x device_cfg=%x", + (uintptr_t)vnp_net_dev.common_cfg,(uintptr_t)vnp_net_dev.device_cfg); select_queue(&vnp_net_dev, RECEIVE_QUEUE); - uint16_t rx_qsz = vnp_net_dev.common_cfg->queue_size; + if (!rx_qsz) return false; g_rx_qsz = rx_qsz; + kprintfv("[virtio-net] RX qsz=%u",rx_qsz); - if (!g_rx_pool) { - g_rx_pool = palloc((uint64_t)rx_qsz * RX_BUF_SIZE, MEM_PRIV_KERNEL, MEM_RW | MEM_DEV, true); - if (!g_rx_pool) { - kprintf("[VIRTIO_NET warn] palloc failed, fallingback to kalloc"); - } + if (!g_rx_pool){ + g_rx_pool = palloc((uint64_t)rx_qsz * RX_BUF_SIZE, MEM_PRIV_KERNEL, MEM_RW, true); + kprintfv("[virtio-net] rx_pool=%x",(uintptr_t)g_rx_pool); + if (!g_rx_pool) return false; } - - for (uint16_t i = 0; i < rx_qsz; i++){ - void* buf = nullptr; - if (g_rx_pool) { - buf = (void*)((uintptr_t)g_rx_pool + (uintptr_t)i * RX_BUF_SIZE); - } else { - buf = kalloc(vnp_net_dev.memory_page, RX_BUF_SIZE, ALIGN_64B, MEM_PRIV_KERNEL); - if (!buf) { - kprintf("[VIRTIO_NET error] rx buffer allocation failed at %i", i); - return false; - } - } + for (uint16_t i=0;iqueue_msix_vector = 0; - if (vnp_net_dev.common_cfg->queue_msix_vector != 0){ - kprintf("[VIRTIO_NET error] failed to set interrupts on receive queue, network will be unable to receive packets"); - return false; - } + kprintfv("[virtio-net] RX vector=%u",vnp_net_dev.common_cfg->queue_msix_vector); + if (vnp_net_dev.common_cfg->queue_msix_vector != 0) return false; select_queue(&vnp_net_dev, TRANSMIT_QUEUE); - vnp_net_dev.common_cfg->queue_msix_vector = 1; - if (vnp_net_dev.common_cfg->queue_msix_vector != 1){ - kprintf("[VIRTIO_NET error] failed to set interrupts on transmit queue, network will be unable to cleanup transmitted packets"); - return false; + kprintfv("[virtio-net] TX vector=%u",vnp_net_dev.common_cfg->queue_msix_vector); + if (vnp_net_dev.common_cfg->queue_msix_vector != 1) return false; + + virtio_net_config* cfg = (virtio_net_config*)vnp_net_dev.device_cfg; + + uint64_t feats = 0; + #ifdef VIRTIO_NEGOTIATED_FEATURES_FIELD + feats = vnp_net_dev.negotiated_features; + #elif defined(VIRTIO_DEVICE_FEATURES_FIELD) + feats = vnp_net_dev.device_features; + #endif + + bool has_mtu_feat = false; + bool has_mrg_rx = false; + #ifdef VIRTIO_NET_F_MTU + has_mtu_feat = (feats & (1ull << VIRTIO_NET_F_MTU)) != 0; + #endif + #ifdef VIRTIO_NET_F_MRG_RXBUF + has_mrg_rx = (feats & (1ull << VIRTIO_NET_F_MRG_RXBUF)) != 0; + #endif + + uint16_t dev_mtu = cfg->mtu; + if (has_mtu_feat && dev_mtu && dev_mtu != 0xFFFF && dev_mtu >= 576){ + mtu = dev_mtu; + } else { + mtu = 1500; } + header_size = has_mrg_rx ? 12 : 10; - header_size = sizeof(virtio_net_hdr_t); + uint8_t mac[6]; get_mac(mac); + kprintfv("[virtio-net] mac=%x:%x:%x:%x:%x:%x mtu=%u hdr=%u", + mac[0],mac[1],mac[2],mac[3],mac[4],mac[5],mtu,header_size); + hw_name[0]='v'; hw_name[1]='i'; hw_name[2]='r'; hw_name[3]='t'; hw_name[4]='i'; hw_name[5]='o'; hw_name[6]=0; return true; } -void VirtioNetDriver::get_mac(uint8_t out_mac[6]){ + +void VirtioNetDriver::get_mac(uint8_t out_mac[6]) const { virtio_net_config* net_config = (virtio_net_config*)vnp_net_dev.device_cfg; - kprintfv("[VIRTIO_NET] %x:%x:%x:%x:%x:%x", net_config->mac[0], net_config->mac[1], net_config->mac[2], net_config->mac[3], net_config->mac[4], net_config->mac[5]); memcpy(out_mac, net_config->mac, 6); - kprintfv("[VIRTIO_NET] %i virtqueue pairs", net_config->max_virtqueue_pairs); - kprintfv("[VIRTIO_NET] %x speed", net_config->speed); - kprintfv("[VIRTIO_NET] status = %x", net_config->status); +} + +uint16_t VirtioNetDriver::get_mtu() const { + return mtu; +} + +uint16_t VirtioNetDriver::get_header_size() const { + return header_size; +} + +const char* VirtioNetDriver::if_prefix() const { + return "eth"; +} + +const char* VirtioNetDriver::hw_ifname() const { + return hw_name; } sizedptr VirtioNetDriver::allocate_packet(size_t size){ @@ -157,39 +182,31 @@ sizedptr VirtioNetDriver::handle_receive_packet(){ uint16_t used_ring_index = (uint16_t)(last_used_receive_idx % qsz); struct virtq_used_elem* e = &used->ring[used_ring_index]; + last_used_receive_idx++; uint32_t desc_index = e->id; uint32_t len = e->len; + if (desc_index >= qsz || len <= header_size) + {avail->ring[avail->idx % qsz] = (uint16_t)desc_index; + avail->idx++; + *(volatile uint16_t*)(uintptr_t)(vnp_net_dev.notify_cfg + vnp_net_dev.notify_off_multiplier * RECEIVE_QUEUE) = 0; + return (sizedptr){0,0};} - if (desc_index >= qsz) { - kprintfv("[VIRTIO_NET warn] RX used id %i >= qsz %i", (unsigned)desc_index, (unsigned)qsz); - last_used_receive_idx++; - return (sizedptr){0,0}; - } - - kprintfv("Received network packet %i at index %i (len %i - hdr %i)", used->idx, desc_index, len, (unsigned)sizeof(virtio_net_hdr_t)); - - uintptr_t packet = desc[desc_index].addr; - uint32_t payload_len = (len > header_size) ? (len - header_size) : 0; + uintptr_t packet_addr = desc[desc_index].addr; + uint32_t payload_len = len - header_size; - void* out_buf = 0; - if (payload_len) { - out_buf = kalloc(vnp_net_dev.memory_page, payload_len, ALIGN_64B, MEM_PRIV_KERNEL); - if (!out_buf) { - avail->ring[avail->idx % qsz] = (uint16_t)desc_index; - avail->idx++; - *(volatile uint16_t*)(uintptr_t)(vnp_net_dev.notify_cfg + vnp_net_dev.notify_off_multiplier * RECEIVE_QUEUE) = 0; - last_used_receive_idx++; - return (sizedptr){0,0}; - } - memcpy(out_buf, (void*)(packet + header_size), payload_len); + void* out_buf = kalloc(vnp_net_dev.memory_page, payload_len, ALIGN_64B, MEM_PRIV_KERNEL); + if (!out_buf){ + avail->ring[avail->idx % qsz] = (uint16_t)desc_index; + avail->idx++; + *(volatile uint16_t*)(uintptr_t)(vnp_net_dev.notify_cfg + vnp_net_dev.notify_off_multiplier * RECEIVE_QUEUE) = 0; + return (sizedptr){0,0}; } + memcpy(out_buf, (void*)(packet_addr + header_size), payload_len); avail->ring[avail->idx % qsz] = (uint16_t)desc_index; avail->idx++; *(volatile uint16_t*)(uintptr_t)(vnp_net_dev.notify_cfg + vnp_net_dev.notify_off_multiplier * RECEIVE_QUEUE) = 0; - last_used_receive_idx++; - return (sizedptr){ (uintptr_t)out_buf, payload_len }; } @@ -204,31 +221,23 @@ void VirtioNetDriver::handle_sent_packet(){ while (last_used_sent_idx != used->idx && cleaned < 64) { uint16_t used_ring_index = (uint16_t)(last_used_sent_idx % qsz); last_used_sent_idx = (uint16_t)(last_used_sent_idx + 1); - struct virtq_used_elem* e = &used->ring[used_ring_index]; uint32_t desc_index = e->id; if (desc_index < qsz) { kfree((void*)desc[desc_index].addr, desc[desc_index].len); - } else { - kprintfv("[VIRTIO_NET warn] TX used id %i >= qsz %i", (unsigned)desc_index, (unsigned)qsz); } cleaned++; } } - void VirtioNetDriver::send_packet(sizedptr packet){ select_queue(&vnp_net_dev, TRANSMIT_QUEUE); - if (packet.ptr && packet.size){ - if (header_size <= packet.size) { - memset((void*)packet.ptr, 0, header_size); - } + if (header_size <= packet.size) memset((void*)packet.ptr, 0, header_size); virtio_send_1d(&vnp_net_dev, packet.ptr, packet.size); + kprintfv("[virtio-net] tx queued len=%u\n",(unsigned)packet.size); } - - kprintfv("Queued new packet"); } void VirtioNetDriver::enable_verbose(){ diff --git a/kernel/networking/drivers/virtio_net_pci/virtio_net_pci.hpp b/kernel/networking/drivers/virtio_net_pci/virtio_net_pci.hpp index 524aecd6..22fc45a0 100644 --- a/kernel/networking/drivers/virtio_net_pci/virtio_net_pci.hpp +++ b/kernel/networking/drivers/virtio_net_pci/virtio_net_pci.hpp @@ -1,34 +1,30 @@ +#pragma once #include "../net_driver.hpp" #include "virtio/virtio_pci.h" #include "net/network_types.h" -#define VIRTIO_NET_ID 0x1000 - class VirtioNetDriver : public NetDriver { public: - static VirtioNetDriver* try_init(); - - VirtioNetDriver(){} - - bool init() override; - + VirtioNetDriver(); + bool init_at(uint64_t pci_addr, uint32_t irq_base_vector) override; sizedptr allocate_packet(size_t size) override; - sizedptr handle_receive_packet() override; - void handle_sent_packet() override; - void enable_verbose() override; - void send_packet(sizedptr packet) override; - - void get_mac(uint8_t out_mac[6]) override; - - ~VirtioNetDriver() = default; + void get_mac(uint8_t out_mac[6]) const override; + uint16_t get_mtu() const override; + uint16_t get_header_size() const override; + const char* if_prefix() const override; + const char* hw_ifname() const override; + ~VirtioNetDriver() override; private: - bool verbose = false; - uint16_t last_used_receive_idx = 0; - uint16_t last_used_sent_idx = 0; + bool verbose; + uint16_t last_used_receive_idx; + uint16_t last_used_sent_idx; virtio_device vnp_net_dev; + uint16_t header_size; + uint16_t mtu; + char hw_name[32]; }; \ No newline at end of file diff --git a/kernel/networking/interface_manager.c b/kernel/networking/interface_manager.c new file mode 100644 index 00000000..4b340e5b --- /dev/null +++ b/kernel/networking/interface_manager.c @@ -0,0 +1,152 @@ +#include "interface_manager.h" +#include "std/memory.h" + +static l2_interface_t g_l2[MAX_L2_INTERFACES]; +static uint8_t g_l2_used[MAX_L2_INTERFACES]; +static uint8_t g_l2_count = 0; + +static void copy_name(char dst[16], const char* src) { + int i = 0; + if (!src) { dst[0] = 0; return; } + while (src[i] && i < 15) { dst[i] = src[i]; i += 1; } + dst[i] = 0; +} + +static int find_free_slot() { + for (int i = 0; i < (int)MAX_L2_INTERFACES; ++i) if (!g_l2_used[i]) return i; + return -1; +} + +uint8_t l2_interface_create(const char *name, void *driver_ctx) { + int slot = find_free_slot(); + if (slot < 0) return 0; + l2_interface_t* itf = &g_l2[slot]; + memset(itf, 0, sizeof(*itf)); + itf->ifindex = (uint8_t)(slot + 1); + copy_name(itf->name, name); + itf->driver_context = driver_ctx; + itf->mtu = 1500; + g_l2_used[slot] = 1; + g_l2_count += 1; + return itf->ifindex; +} + +bool l2_interface_destroy(uint8_t ifindex) { + if (!ifindex) return false; + int slot = (int)ifindex - 1; + if (slot < 0 || slot >= (int)MAX_L2_INTERFACES) return false; + if (!g_l2_used[slot]) return false; + memset(&g_l2[slot], 0, sizeof(l2_interface_t)); + g_l2_used[slot] = 0; + if (g_l2_count) g_l2_count -= 1; + return true; +} + +l2_interface_t* l2_interface_find_by_index(uint8_t ifindex) { + if (!ifindex) return 0; + int slot = (int)ifindex - 1; + if (slot < 0 || slot >= (int)MAX_L2_INTERFACES) return 0; + if (!g_l2_used[slot]) return 0; + return &g_l2[slot]; +} + +uint8_t l2_interface_count(void) { + return g_l2_count; +} + +l2_interface_t* l2_interface_at(uint8_t idx) { + uint8_t seen = 0; + for (int i = 0; i < (int)MAX_L2_INTERFACES; ++i) { + if (!g_l2_used[i]) continue; + if (seen == idx) return &g_l2[i]; + seen += 1; + } + return 0; +} + +bool l2_interface_set_mac(uint8_t ifindex, const uint8_t mac[6]) { + l2_interface_t* itf = l2_interface_find_by_index(ifindex); + if (!itf) return false; + if (!mac) return false; + itf->mac_addr[0]=mac[0]; itf->mac_addr[1]=mac[1]; itf->mac_addr[2]=mac[2]; + itf->mac_addr[3]=mac[3]; itf->mac_addr[4]=mac[4]; itf->mac_addr[5]=mac[5]; + return true; +} + +bool l2_interface_set_mtu(uint8_t ifindex, uint16_t mtu) { + l2_interface_t* itf = l2_interface_find_by_index(ifindex); + if (!itf) return false; + itf->mtu = mtu; + return true; +} + +bool l2_interface_set_up(uint8_t ifindex, bool up) { + l2_interface_t* itf = l2_interface_find_by_index(ifindex); + if (!itf) return false; + itf->is_up = up; + return true; +} + +bool l2_interface_set_send_trampoline(uint8_t ifindex, int (*fn)(struct l2_interface*, const void*, size_t)) { + l2_interface_t* itf = l2_interface_find_by_index(ifindex); + if (!itf) return false; + itf->send_frame = fn; + return true; +} + +static int find_ipv4_group_index(l2_interface_t* itf, uint32_t group) { + for (int i = 0; i < (int)itf->ipv4_mcast_count; ++i) { + if (itf->ipv4_mcast[i] == group) return i; + } + return -1; +} + +bool l2_ipv4_mcast_join(uint8_t ifindex, uint32_t group) { + l2_interface_t* itf = l2_interface_find_by_index(ifindex); + if (!itf) return false; + if (find_ipv4_group_index(itf, group) >= 0) return true; + if (itf->ipv4_mcast_count >= MAX_IPV4_MCAST_PER_INTERFACE) return false; + itf->ipv4_mcast[itf->ipv4_mcast_count++] = group; + return true; +} + +bool l2_ipv4_mcast_leave(uint8_t ifindex, uint32_t group) { + l2_interface_t* itf = l2_interface_find_by_index(ifindex); + if (!itf) return false; + int idx = find_ipv4_group_index(itf, group); + if (idx < 0) return true; + for (int i = idx + 1; i < (int)itf->ipv4_mcast_count; ++i) itf->ipv4_mcast[i-1] = itf->ipv4_mcast[i]; + if (itf->ipv4_mcast_count) itf->ipv4_mcast_count -= 1; + return true; +} + +static int find_ipv6_group_index(l2_interface_t* itf, const uint8_t group[16]) { + for (int i = 0; i < (int)itf->ipv6_mcast_count; ++i) { + int eq = 1; + for (int j = 0; j < 16; ++j) if (itf->ipv6_mcast[i][j] != group[j]) { eq = 0; break; } + if (eq) return i; + } + return -1; +} + +bool l2_ipv6_mcast_join(uint8_t ifindex, const uint8_t group[16]) { + l2_interface_t* itf = l2_interface_find_by_index(ifindex); + if (!itf || !group) return false; + if (find_ipv6_group_index(itf, group) >= 0) return true; + if (itf->ipv6_mcast_count >= MAX_IPV6_MCAST_PER_INTERFACE) return false; + for (int j = 0; j < 16; ++j) itf->ipv6_mcast[itf->ipv6_mcast_count][j] = group[j]; + itf->ipv6_mcast_count += 1; + return true; +} + +bool l2_ipv6_mcast_leave(uint8_t ifindex, const uint8_t group[16]) { + l2_interface_t* itf = l2_interface_find_by_index(ifindex); + if (!itf || !group) return false; + int idx = find_ipv6_group_index(itf, group); + if (idx < 0) return true; + for (int i = idx + 1; i < (int)itf->ipv6_mcast_count; ++i) { + for (int j = 0; j < 16; ++j) itf->ipv6_mcast[i-1][j] = itf->ipv6_mcast[i][j]; + } + if (itf->ipv6_mcast_count) itf->ipv6_mcast_count -= 1; + return true; +} diff --git a/kernel/networking/interface_manager.h b/kernel/networking/interface_manager.h index 54f213ba..6eef3b8d 100644 --- a/kernel/networking/interface_manager.h +++ b/kernel/networking/interface_manager.h @@ -86,16 +86,6 @@ typedef struct l3_ipv6_interface { l2_interface_t *l2; } l3_ipv6_interface_t; -typedef struct network_dispatcher { - l2_interface_t *l2[MAX_L2_INTERFACES]; - uint8_t l2_count; - l3_ipv4_interface_t *lo_v4; - l3_ipv6_interface_t *lo_v6; - void *rt4; - void *rt6; - int8_t primary_ifindex; -} network_dispatcher_t; - typedef struct ip_resolution_result { bool found; l3_ipv4_interface_t *ipv4; @@ -106,9 +96,12 @@ typedef struct ip_resolution_result { uint8_t l2_interface_create(const char *name, void *driver_ctx); bool l2_interface_destroy(uint8_t ifindex); l2_interface_t *l2_interface_find_by_index(uint8_t ifindex); +uint8_t l2_interface_count(void); +l2_interface_t *l2_interface_at(uint8_t idx); bool l2_interface_set_mac(uint8_t ifindex, const uint8_t mac[6]); bool l2_interface_set_mtu(uint8_t ifindex, uint16_t mtu); bool l2_interface_set_up(uint8_t ifindex, bool up); +bool l2_interface_set_send_trampoline(uint8_t ifindex, int (*fn)(struct l2_interface*, const void*, size_t)); bool l2_ipv4_mcast_join(uint8_t ifindex, uint32_t group); bool l2_ipv4_mcast_leave(uint8_t ifindex, uint32_t group); bool l2_ipv6_mcast_join(uint8_t ifindex, const uint8_t group[16]); @@ -134,12 +127,6 @@ ip_resolution_result_t resolve_ipv6_to_interface(const uint8_t dst_ip[16]); bool check_ipv4_overlap(uint32_t new_ip, uint32_t mask, uint8_t ifindex); bool check_ipv6_overlap(const uint8_t new_ip[16], uint8_t prefix_len, uint8_t ifindex); -network_dispatcher_t *get_network_dispatcher(void); -void network_dispatcher_init(void); -bool network_set_primary(uint8_t ifindex); -l2_interface_t *get_primary_interface(void); -l3_ipv4_interface_t *get_primary_ipv4(void); - #ifdef __cplusplus } -#endif +#endif \ No newline at end of file diff --git a/kernel/networking/network.cpp b/kernel/networking/network.cpp index a21efa48..a5697828 100644 --- a/kernel/networking/network.cpp +++ b/kernel/networking/network.cpp @@ -2,19 +2,28 @@ #include "network_dispatch.hpp" #include "process/scheduler.h" -static NetworkDispatch *dispatch = nullptr; +static NetworkDispatch *dispatch = 0; bool network_init() { dispatch = new NetworkDispatch(); - return dispatch && dispatch->init(); + if (!dispatch) return false; + return dispatch->init(); } void network_handle_download_interrupt() { - if (dispatch) dispatch->handle_download_interrupt(); + if (dispatch) dispatch->handle_rx_irq(0); } void network_handle_upload_interrupt() { - if (dispatch) dispatch->handle_upload_interrupt(); + if (dispatch) dispatch->handle_tx_irq(0); +} + +void network_handle_download_interrupt_nic(uint16_t nic_id) { + if (dispatch) dispatch->handle_rx_irq((size_t)nic_id); +} + +void network_handle_upload_interrupt_nic(uint16_t nic_id) { + if (dispatch) dispatch->handle_tx_irq((size_t)nic_id); } int network_net_task_entry(int argc, char* argv[]) { @@ -24,19 +33,61 @@ int network_net_task_entry(int argc, char* argv[]) { int net_tx_frame(uintptr_t frame_ptr, uint32_t frame_len) { if (!dispatch || !frame_ptr || !frame_len) return -1; - return dispatch->enqueue_frame({frame_ptr, frame_len}) ? 0 : -1; + return dispatch->enqueue_frame_on(0, {frame_ptr, frame_len}) ? 0 : -1; } -int net_rx_frame(sizedptr *out_frame) { - extern uint16_t get_current_proc_pid(); - if (!dispatch || !out_frame) return -1; - int sz = dispatch->dequeue_packet_for(get_current_proc_pid(), out_frame) ? (int)out_frame->size : 0; - return sz; +int net_tx_frame_on(uint16_t nic_id, uintptr_t frame_ptr, uint32_t frame_len) { + if (!dispatch || !frame_ptr || !frame_len) return -1; + return dispatch->enqueue_frame_on((size_t)nic_id, {frame_ptr, frame_len}) ? 0 : -1; } +int net_rx_frame(sizedptr* out_frame) { + if (!out_frame) return -1; + out_frame->ptr = 0; + out_frame->size = 0; + return 0; +} const uint8_t* network_get_local_mac() { - static uint8_t dummy[6] = {0}; - return dispatch ? dispatch->get_local_mac() : dummy; + static uint8_t dummy[6] = {0,0,0,0,0,0}; + if (!dispatch) return dummy; + return dispatch->mac(0); +} + +const uint8_t* network_get_mac(uint16_t nic_id) { + static uint8_t dummy[6] = {0,0,0,0,0,0}; + if (!dispatch) return dummy; + const uint8_t* m = dispatch->mac((size_t)nic_id); + return m ? m : dummy; +} + +uint16_t network_get_mtu(uint16_t nic_id) { + if (!dispatch) return 0; + return dispatch->mtu((size_t)nic_id); +} + +uint16_t network_get_header_size(uint16_t nic_id) { + if (!dispatch) return 0; + return dispatch->header_size((size_t)nic_id); +} + +uint8_t network_get_ifindex(uint16_t nic_id) { + if (!dispatch) return 0xFF; + return dispatch->ifindex((size_t)nic_id); +} + +const char* network_get_ifname(uint16_t nic_id) { + if (!dispatch) return 0; + return dispatch->ifname((size_t)nic_id); +} + +const char* network_get_hw_ifname(uint16_t nic_id) { + if (!dispatch) return 0; + return dispatch->hw_ifname((size_t)nic_id); +} + +size_t network_nic_count() { + if (!dispatch) return 0; + return dispatch->nic_count(); } void network_net_set_pid(uint16_t pid) { diff --git a/kernel/networking/network.h b/kernel/networking/network.h index a152f7c0..e0fb6407 100644 --- a/kernel/networking/network.h +++ b/kernel/networking/network.h @@ -8,7 +8,7 @@ extern "C" { #include "net/network_types.h" #include "dev/driver_base.h" -#define NET_IRQ 32 +#define NET_IRQ_BASE 40 //TODO: consider using the system MTU here #define MAX_PACKET_SIZE 0x1000 @@ -18,12 +18,23 @@ uint16_t network_net_get_pid(); bool network_init(); void network_handle_download_interrupt(); void network_handle_upload_interrupt(); +void network_handle_download_interrupt_nic(uint16_t nic_id); +void network_handle_upload_interrupt_nic(uint16_t nic_id); int network_net_task_entry(int argc, char* argv[]); int net_tx_frame(uintptr_t frame_ptr, uint32_t frame_len); +int net_tx_frame_on(uint16_t nic_id, uintptr_t frame_ptr, uint32_t frame_len); int net_rx_frame(sizedptr *out_frame); const uint8_t* network_get_local_mac(void); +const uint8_t* network_get_mac(uint16_t nic_id); +uint16_t network_get_mtu(uint16_t nic_id); +uint16_t network_get_header_size(uint16_t nic_id); +uint8_t network_get_ifindex(uint16_t nic_id); +const char* network_get_ifname(uint16_t nic_id); +const char* network_get_hw_ifname(uint16_t nic_id); +size_t network_nic_count(void); + void network_update_local_ip(uint32_t ip); extern driver_module net_module; diff --git a/kernel/networking/network_dispatch.cpp b/kernel/networking/network_dispatch.cpp index 12f88d91..fc83d1cd 100644 --- a/kernel/networking/network_dispatch.cpp +++ b/kernel/networking/network_dispatch.cpp @@ -1,11 +1,12 @@ #include "network_dispatch.hpp" -#include "network.h" #include "drivers/virtio_net_pci/virtio_net_pci.hpp" +#include "drivers/net_bus.hpp" #include "memory/page_allocator.h" #include "net/link_layer/eth.h" #include "net/network_types.h" #include "port_manager.h" #include "std/memory.h" +#include "std/std.h" extern void sleep(uint64_t ms); extern uintptr_t malloc(uint64_t size); @@ -15,131 +16,149 @@ extern void free(void *ptr, uint64_t size); #define TASK_RX_BATCH_LIMIT 32 #define TASK_TX_BATCH_LIMIT 32 -static uint16_t g_net_pid = 0xFFFF; - NetworkDispatch::NetworkDispatch() - : driver(nullptr), - tx_queue(QUEUE_CAPACITY), - rx_queue(QUEUE_CAPACITY) { - - memset(local_mac, 0, sizeof(local_mac)); + nic_num = 0; + g_net_pid = 0xFFFF; } bool NetworkDispatch::init() { - driver = VirtioNetDriver::try_init(); - if (!driver) return false; - driver->get_mac(local_mac); - return true; + if (net_bus_init() <= 0) return false; + if (!register_all_from_bus()) return false; + return nic_num > 0; } -void NetworkDispatch::handle_download_interrupt() +void NetworkDispatch::handle_rx_irq(size_t nic_id) { + if (nic_id >= nic_num) return; + NetDriver* driver = nics[nic_id].drv; if (!driver) return; - - for (int drained = 0; drained < RX_INTR_BATCH_LIMIT; ++drained) { + for (int i = 0; i < RX_INTR_BATCH_LIMIT; ++i) { sizedptr raw = driver->handle_receive_packet(); - if (raw.size == 0) { - break; - } - - if (raw.size < sizeof(eth_hdr_t)) { - free_frame(raw); - continue; - } - - if (!rx_queue.enqueue(raw)) { - free_frame(raw); - } + if (!raw.ptr || raw.size == 0) break; + if (raw.size < sizeof(eth_hdr_t)) { free_frame(raw); continue; } + if (!nics[nic_id].rx.enqueue(raw)) free_frame(raw); } } -void NetworkDispatch::handle_upload_interrupt() +void NetworkDispatch::handle_tx_irq(size_t nic_id) { - if (driver) - driver->handle_sent_packet(); + if (nic_id >= nic_num) return; + NetDriver* driver = nics[nic_id].drv; + if (!driver) return; + driver->handle_sent_packet(); } -bool NetworkDispatch::enqueue_frame(const sizedptr &frame) +bool NetworkDispatch::enqueue_frame_on(size_t nic_id, const sizedptr& frame) { + if (nic_id >= nic_num) return false; + NetDriver* driver = nics[nic_id].drv; + if (!driver) return false; if (frame.size == 0) return false; - sizedptr pkt = driver->allocate_packet(frame.size); if (!pkt.ptr) return false; - - void* dst = reinterpret_cast(pkt.ptr + driver->header_size); - memcpy(dst, reinterpret_cast(frame.ptr), frame.size); - - if (!tx_queue.enqueue(pkt)) { - free_frame(pkt); - return false; - } + uint16_t hs = nics[nic_id].hdr_sz; + void* dst = (void*)(pkt.ptr + hs); + memcpy(dst, (const void*)frame.ptr, frame.size); + if (!nics[nic_id].tx.enqueue(pkt)) { free_frame(pkt); return false; } return true; } int NetworkDispatch::net_task() { - network_net_set_pid(get_current_proc_pid()); + set_net_pid(get_current_proc_pid()); for (;;) { bool did_work = false; - for (int i = 0; i < TASK_RX_BATCH_LIMIT; ++i) { - if (rx_queue.is_empty()) break; - sizedptr pkt{0,0}; - if (!rx_queue.dequeue(pkt)) break; - - did_work = true; - eth_input(pkt.ptr, pkt.size); - free_frame(pkt); + for (size_t n = 0; n < nic_num; ++n) { + for (int i = 0; i < TASK_RX_BATCH_LIMIT; ++i) { + if (nics[n].rx.is_empty()) break; + sizedptr pkt{0,0}; + if (!nics[n].rx.dequeue(pkt)) break; + did_work = true; + eth_input(pkt.ptr, pkt.size); + free_frame(pkt); + } } - for (int i = 0; i < TASK_TX_BATCH_LIMIT; ++i) { - if (tx_queue.is_empty()) break; - sizedptr pkt{0,0}; - if (!tx_queue.dequeue(pkt)) break; - - did_work = true; - driver->send_packet(pkt); + for (size_t n = 0; n < nic_num; ++n) { + NetDriver* driver = nics[n].drv; + if (!driver) continue; + for (int i = 0; i < TASK_TX_BATCH_LIMIT; ++i) { + if (nics[n].tx.is_empty()) break; + sizedptr pkt{0,0}; + if (!nics[n].tx.dequeue(pkt)) break; + did_work = true; + driver->send_packet(pkt); + } } - if (!did_work) - sleep(10); //TODO: manage it with an event + if (!did_work) sleep(10);//TODO: manage it with an event } } -bool NetworkDispatch::dequeue_packet_for(uint16_t pid, sizedptr *out) +void NetworkDispatch::set_net_pid(uint16_t pid) +{ + g_net_pid = pid; +} + +uint16_t NetworkDispatch::get_net_pid() const +{ + return g_net_pid; +} + +size_t NetworkDispatch::nic_count() const +{ + return nic_num; +} + +const char* NetworkDispatch::ifname(size_t nic_id) const { - process_t *proc = get_proc_by_pid(pid); - if (!proc || !out) return false; + if (nic_id >= nic_num) return 0; + return nics[nic_id].ifname_str; +} - auto &buf = proc->packet_buffer; - if (buf.read_index == buf.write_index) return false; +const char* NetworkDispatch::hw_ifname(size_t nic_id) const +{ + if (nic_id >= nic_num) return 0; + return nics[nic_id].hwname_str; +} - sizedptr stored = buf.entries[buf.read_index]; - buf.read_index = (buf.read_index + 1) % PACKET_BUFFER_CAPACITY; +const uint8_t* NetworkDispatch::mac(size_t nic_id) const +{ + if (nic_id >= nic_num) return 0; + return nics[nic_id].mac_addr; +} - void *dst = kalloc(reinterpret_cast(get_current_heap()), stored.size, ALIGN_16B, get_current_privilege()); - if (!dst) return false; +uint16_t NetworkDispatch::mtu(size_t nic_id) const +{ + if (nic_id >= nic_num) return 0; + return nics[nic_id].mtu_val; +} - memcpy(dst, reinterpret_cast(stored.ptr), stored.size); - out->ptr = reinterpret_cast(dst); - out->size = stored.size; +uint16_t NetworkDispatch::header_size(size_t nic_id) const +{ + if (nic_id >= nic_num) return 0; + return nics[nic_id].hdr_sz; +} - free(reinterpret_cast(stored.ptr), stored.size); - return true; +uint8_t NetworkDispatch::ifindex(size_t nic_id) const +{ + if (nic_id >= nic_num) return 0xFF; + return nics[nic_id].ifindex; } -sizedptr NetworkDispatch::make_copy(const sizedptr &in) +l2_interface_t* NetworkDispatch::l2_at(size_t nic_id) const { - sizedptr out{0, 0}; - void *dst = kalloc(reinterpret_cast(get_current_heap()), in.size, ALIGN_16B, get_current_privilege()); - if (!dst) return out; + if (nic_id >= nic_num) return 0; + return l2_interface_find_by_index(nics[nic_id].ifindex); +} - memcpy(dst, reinterpret_cast(in.ptr), in.size); - out.ptr = reinterpret_cast(dst); - out.size = in.size; - return out; +NetDriver* NetworkDispatch::driver_at(size_t nic_id) const +{ + if (nic_id >= nic_num) return 0; + return nics[nic_id].drv; } void NetworkDispatch::free_frame(const sizedptr &f) @@ -147,5 +166,61 @@ void NetworkDispatch::free_frame(const sizedptr &f) if (f.ptr) free_sized(f); } -void NetworkDispatch::set_net_pid(uint16_t pid) { g_net_pid = pid; } -uint16_t NetworkDispatch::get_net_pid() const { return g_net_pid; } +bool NetworkDispatch::register_all_from_bus() { + int n = net_bus_count(); + if (n <= 0) return false; + + for (int i = 0; i < n && nic_num < MAX_NIC; ++i) { + NetDriver* drv = net_bus_driver(i); + const char* name = net_bus_ifname(i); + const char* hw = net_bus_hw_ifname(i); + uint16_t m = net_bus_get_mtu(i); + uint16_t hs = net_bus_get_header_size(i); + uint8_t macbuf[6]; net_bus_get_mac(i, macbuf); + + if (!name) continue; + + if (!drv) { + bool is_lo0 = (name[0]=='l' && name[1]=='o' && name[2]=='0' && name[3]==0); + if (!is_lo0) continue; + + uint8_t ix = l2_interface_create(name, nullptr); + uint8_t zero_mac[6] = {0,0,0,0,0,0}; + l2_interface_set_mac(ix, zero_mac); + l2_interface_set_mtu(ix, m ? m : 65535); + l2_interface_set_up(ix, true); + continue; + } + + NICCtx* c = &nics[nic_num]; + c->drv = drv; + + new ((void*)&c->tx) Queue(QUEUE_CAPACITY); + new ((void*)&c->rx) Queue(QUEUE_CAPACITY); + + copy_str(c->ifname_str, (int)sizeof(c->ifname_str), name); + copy_str(c->hwname_str, (int)sizeof(c->hwname_str), hw); + memcpy(c->mac_addr, macbuf, 6); + c->mtu_val = m; + c->hdr_sz = hs; + + uint8_t ix = l2_interface_create(c->ifname_str, (void*)drv); + l2_interface_set_mac(ix, c->mac_addr); + l2_interface_set_mtu(ix, c->mtu_val); + l2_interface_set_up(ix, true); + c->ifindex = ix; + + nic_num += 1; + } + return nic_num > 0; +} + + +void NetworkDispatch::copy_str(char* dst, int cap, const char* src) +{ + if (!dst || cap <= 0) return; + if (!src) { dst[0] = 0; return; } + uint32_t n = strlen(src, (uint32_t)(cap - 1)); + memcpy(dst, src, n); + dst[n] = 0; +} diff --git a/kernel/networking/network_dispatch.hpp b/kernel/networking/network_dispatch.hpp index 44a4880e..a7cee82f 100644 --- a/kernel/networking/network_dispatch.hpp +++ b/kernel/networking/network_dispatch.hpp @@ -5,39 +5,51 @@ #include "data_struct/queue.hpp" #include "net/network_types.h" #include "net/internet_layer/ipv4.h" +#include "interface_manager.h" +#include "std/std.h" class NetworkDispatch { public: NetworkDispatch(); - bool init(); - - void handle_download_interrupt(); - void handle_upload_interrupt(); - bool enqueue_frame(const sizedptr&); + void handle_rx_irq(size_t nic_id); + void handle_tx_irq(size_t nic_id); + bool enqueue_frame_on(size_t nic_id, const sizedptr&); int net_task(); - bool dequeue_packet_for(uint16_t, sizedptr*); - void set_net_pid(uint16_t pid); uint16_t get_net_pid() const; - - const uint8_t* get_local_mac() const { return local_mac; } - - - NetDriver* driver_ptr() const { return driver; } - uint16_t header_size() const { return driver ? driver->header_size : 0; } + size_t nic_count() const; + const char* ifname(size_t nic_id) const; + const char* hw_ifname(size_t nic_id) const; + const uint8_t* mac(size_t nic_id) const; + uint16_t mtu(size_t nic_id) const; + uint16_t header_size(size_t nic_id) const; + uint8_t ifindex(size_t nic_id) const; + l2_interface_t* l2_at(size_t nic_id) const; + NetDriver* driver_at(size_t nic_id) const; private: - static constexpr size_t QUEUE_CAPACITY = 1024; - - //IndexMap ports; //port pid map - NetDriver* driver; - uint8_t local_mac[6]; - - Queue tx_queue; - Queue rx_queue; + struct NICCtx { + NetDriver* drv; + uint8_t ifindex; + char ifname_str[16]; + char hwname_str[32]; + uint8_t mac_addr[6]; + uint16_t mtu_val; + uint16_t hdr_sz; + Queue tx; + Queue rx; + }; + + static const size_t MAX_NIC = 16; + static const size_t QUEUE_CAPACITY = 1024; + + NICCtx nics[MAX_NIC]; + size_t nic_num; + uint16_t g_net_pid; - sizedptr make_copy(const sizedptr&); void free_frame(const sizedptr&); -}; + bool register_all_from_bus(); + void copy_str(char* dst, int cap, const char* src); +}; \ No newline at end of file diff --git a/kernel/networking/processes/net_proc.c b/kernel/networking/processes/net_proc.c index b2239362..6a35e442 100644 --- a/kernel/networking/processes/net_proc.c +++ b/kernel/networking/processes/net_proc.c @@ -7,6 +7,7 @@ #include "net/network_types.h" #include "networking/network.h" +#include "networking/interface_manager.h" #include "net/link_layer/arp.h" diff --git a/kernel/pci.c b/kernel/pci.c index 26033470..2104e0ee 100644 --- a/kernel/pci.c +++ b/kernel/pci.c @@ -84,6 +84,9 @@ struct acpi_mcfg_t { #define RSDP_SEARCH_END 0x00100000 bool initialized; +static pci_device_info g_pci_cache[256]; +static size_t g_pci_count = 0; +static bool g_pci_scanned = false; void* find_rsdp() { for (uint64_t addr = RSDP_SEARCH_START; addr < RSDP_SEARCH_END; addr += 16) { @@ -111,20 +114,52 @@ void* find_rsdp() { return 0x0; } +uint64_t pci_make_addr(uint32_t bus, uint32_t slot, uint32_t func, uint32_t offset){ + return PCI_BASE + | (((uint64_t)bus) << 20) + | (((uint64_t)slot) << 15) + | (((uint64_t)func) << 12) + | ((uint64_t)(offset & 0xFFF)); +} + void find_pci(){ if (!initialized){ initialized = true; for (uint64_t addr = PCI_BASE; addr < PCI_BASE + 0x10000000; addr += GRANULE_2MB) register_device_memory_2mb(addr, addr); } -} -uint64_t pci_make_addr(uint32_t bus, uint32_t slot, uint32_t func, uint32_t offset){ - return PCI_BASE - | (((uint64_t)bus) << 20) - | (((uint64_t)slot) << 15) - | (((uint64_t)func) << 12) - | ((uint64_t)(offset & 0xFFF)); + if (!g_pci_scanned){ + g_pci_count = 0; + + for (uint32_t bus = 0; bus < 256 && g_pci_count < (sizeof(g_pci_cache)/sizeof(g_pci_cache[0])); ++bus) { + for (uint32_t slot = 0; slot < 32 && g_pci_count < (sizeof(g_pci_cache)/sizeof(g_pci_cache[0])); ++slot) { + for (uint32_t func = 0; func < 8 && g_pci_count < (sizeof(g_pci_cache)/sizeof(g_pci_cache[0])); ++func) { + uint64_t addr = pci_make_addr(bus, slot, func, 0x00); + uint16_t vendor = read16(addr + 0x00); + if (vendor == 0xFFFF) continue; + + uint16_t device = read16(addr + 0x02); + uint8_t class_code = read8 (addr + 0x0B); + uint8_t subclass = read8 (addr + 0x0A); + uint8_t prog_if = read8 (addr + 0x09); + + g_pci_cache[g_pci_count].addr = addr; + g_pci_cache[g_pci_count].vendor = vendor; + g_pci_cache[g_pci_count].device = device; + g_pci_cache[g_pci_count].class_code = class_code; + g_pci_cache[g_pci_count].subclass = subclass; + g_pci_cache[g_pci_count].prog_if = prog_if; + ++g_pci_count; + + kprintfv("[PCI] device %u: bus=%u slot=%u func=%u ven=%x dev=%x", (unsigned)(g_pci_count-1), bus, slot, func, vendor, device); + } + } + } + + kprintfv("[PCI] devices cached: %u", (unsigned)g_pci_count); + g_pci_scanned = true; + } } uint64_t pci_get_bar_address(uint64_t base, uint8_t offset, uint8_t index){ @@ -240,13 +275,15 @@ void dump_pci_config(uint64_t base) { } void pci_enable_device(uint64_t pci_addr){ - uint32_t cmd = read16(pci_addr + PCI_COMMAND_REGISTER); - cmd |= PCI_COMMAND_MEMORY | PCI_COMMAND_REGISTER; + uint16_t cmd = read16(pci_addr + PCI_COMMAND_REGISTER); + cmd |= (uint16_t)(PCI_COMMAND_MEMORY | PCI_COMMAND_BUS); write16(pci_addr + PCI_COMMAND_REGISTER,cmd); } void pci_register(uint64_t mmio_addr, uint64_t mmio_size){ - for (uint64_t addr = mmio_addr; addr <= mmio_addr + mmio_size; addr += GRANULE_4KB) + uint64_t start = mmio_addr & ~(GRANULE_4KB - 1); + uint64_t end = (mmio_addr + mmio_size + GRANULE_4KB - 1) & ~(GRANULE_4KB - 1); + for (uint64_t addr = start; addr < end; addr += GRANULE_4KB) register_device_memory(addr,addr); } @@ -387,9 +424,9 @@ bool pci_setup_msix(uint64_t pci_addr, msix_irq_line* irq_lines, uint8_t line_si uint8_t cap_id = read8(pci_addr + cap_ptr); if (cap_id == PCI_CAPABILITY_MSIX) { // MSI-X uint16_t msg_ctrl = read16(pci_addr + cap_ptr + 0x2); - msg_ctrl &= ~(1 << 15); // Clear MSI-X Enable bit + msg_ctrl &= (uint16_t)~(1u << 15); // Clear MSI-X Enable bit write16(pci_addr + cap_ptr + 0x2, msg_ctrl); - uint16_t table_size = (msg_ctrl & 0x07FF) +1; // takes the 11 rightmost bits, its value is N-1, so add 1 to it for the full size + uint16_t table_size = (uint16_t)((msg_ctrl & 0x07FF) +1); // takes the 11 rightmost bits, its value is N-1, so add 1 to it for the full size if(line_size > table_size){ kprintf("[PCI] MSI-X only supports %i interrupts, but you tried to add %i interrupts", table_size, line_size); @@ -397,41 +434,41 @@ bool pci_setup_msix(uint64_t pci_addr, msix_irq_line* irq_lines, uint8_t line_si } uint32_t table_offset = read32(pci_addr + cap_ptr + 0x4); - uint8_t bir = table_offset & 0x7; - uint32_t table_addr_offset = table_offset & ~0x7; + uint8_t bir = (uint8_t)(table_offset & 0x7); + uint32_t table_addr_offset = (table_offset & ~0x7); uint64_t table_addr = pci_read_address_bar(pci_addr, bir); if(!table_addr){ - uint64_t bar_size; + uint64_t bar_size = 0; pci_setup_bar(pci_addr, bir, &table_addr, &bar_size); kprintf("Setting up new bar for MSI-X %x + %x",table_addr, table_addr_offset); } else kprintf("Bar %i setup at %x + %x",bir, table_addr, table_addr_offset); - msix_table_entry *msix_start = (msix_table_entry *)(uintptr_t)(table_addr + table_addr_offset); + volatile msix_table_entry *msix_start = (volatile msix_table_entry *)(uintptr_t)(table_addr + table_addr_offset); - for (uint32_t i = 0; i < line_size; i++){ - msix_table_entry *msix_entry = msix_start + i; + for (uint32_t i = 0; i < line_size; ++i){ + volatile msix_table_entry *msix_entry = msix_start + i; msix_irq_line irq_line = irq_lines[i]; uint64_t addr_full = 0x8020040 + irq_line.addr_offset; - msix_entry->msg_addr_low = addr_full & 0xFFFFFFFF; - msix_entry->msg_addr_high = addr_full >> 32; - msix_entry->msg_data = MSI_OFFSET + irq_line.irq_num; + msix_entry->msg_addr_low = (uint32_t)(addr_full & 0xFFFFFFFFu); + msix_entry->msg_addr_high = (uint32_t)(addr_full >> 32); + msix_entry->msg_data = (uint32_t)(MSI_OFFSET + irq_line.irq_num); msix_entry->vector_control = msix_entry->vector_control & ~0x1; // all bits other then the last one are reserved, so don't chnage it, just set the last bit to 0 } - msg_ctrl |= (1 << 15); // MSI-X Enable - msg_ctrl &= ~(1 << 14); // Clear Function Mask + msg_ctrl |= (uint16_t)(1u << 15); // MSI-X Enable + msg_ctrl &= ~(uint16_t)(1u << 14); // Clear Function Mask write16(pci_addr + cap_ptr + 0x2, msg_ctrl); - break; + return true; } cap_ptr = read8(pci_addr + cap_ptr + 1); } - return true; + return false; } uint8_t pci_setup_interrupts(uint64_t pci_addr, uint8_t irq_line, uint8_t amount){ @@ -453,4 +490,17 @@ uint8_t pci_setup_interrupts(uint64_t pci_addr, uint8_t irq_line, uint8_t amount } return 0; -} \ No newline at end of file +} +size_t pci_enumerate(pci_device_info* out, size_t max) { + if (!out || max == 0) return 0; + + if (!initialized || !g_pci_scanned) + find_pci(); + + size_t to_copy = g_pci_count < max ? g_pci_count : max; + for (size_t i = 0; i < to_copy; ++i) + out[i] = g_pci_cache[i]; + + kprintf("[PCI] (enumerate) served %u/ cached %u", (unsigned)to_copy, (unsigned)g_pci_count); + return to_copy; +} diff --git a/kernel/pci.h b/kernel/pci.h index 3c800afc..5b44e6fd 100644 --- a/kernel/pci.h +++ b/kernel/pci.h @@ -11,6 +11,16 @@ typedef struct { uint64_t size; } pci_device_mmio; +typedef struct { + uint64_t addr; + uint16_t vendor; + uint16_t device; + uint8_t class_code; + uint8_t subclass; + uint8_t prog_if; +} pci_device_info; + +size_t pci_enumerate(pci_device_info* out, size_t max); uint64_t find_pci_device(uint32_t vendor_id, uint32_t device_id); uint64_t pci_get_bar_address(uint64_t base, uint8_t offset, uint8_t index); uint64_t pci_setup_bar(uint64_t pci_addr, uint32_t bar_index, uint64_t *mmio_start, uint64_t *mmio_size); diff --git a/kernel/virtio/virtio_pci.c b/kernel/virtio/virtio_pci.c index 780267af..d6685240 100644 --- a/kernel/virtio/virtio_pci.c +++ b/kernel/virtio/virtio_pci.c @@ -123,18 +123,26 @@ bool virtio_init_device(virtio_device *dev) { uint32_t queue_index = 0; uint32_t size; while ((size = select_queue(dev,queue_index))){ - uint64_t base = (uintptr_t)kalloc(dev->memory_page, 16 * size, ALIGN_4KB, MEM_PRIV_KERNEL); - uint64_t avail = (uintptr_t)kalloc(dev->memory_page, 4 + (2 * size), ALIGN_4KB, MEM_PRIV_KERNEL); - uint64_t used = (uintptr_t)kalloc(dev->memory_page, sizeof(uint16_t) * (2 + size), ALIGN_4KB, MEM_PRIV_KERNEL); - - kprintfv("[VIRTIO QUEUE %i] Device base %x",queue_index,base); - kprintfv("[VIRTIO QUEUE %i] Device avail %x",queue_index,avail); - kprintfv("[VIRTIO QUEUE %i] Device used %x",queue_index,used); - - cfg->queue_desc = base; - cfg->queue_driver = avail; - cfg->queue_device = used; - cfg->queue_enable = 1; + uint64_t desc_sz = 16ULL * size; + uint64_t avail_sz = 4ULL + 2ULL * size; + uint64_t used_sz = 4ULL + 8ULL * size; + uint64_t base = (uintptr_t)kalloc(dev->memory_page, desc_sz, ALIGN_4KB, MEM_PRIV_KERNEL); + uint64_t avail = (uintptr_t)kalloc(dev->memory_page, avail_sz, ALIGN_4KB, MEM_PRIV_KERNEL); + uint64_t used = (uintptr_t)kalloc(dev->memory_page, used_sz, ALIGN_4KB, MEM_PRIV_KERNEL); + + dev->common_cfg->queue_desc = base; + dev->common_cfg->queue_driver = avail; + dev->common_cfg->queue_device = used; + + volatile struct virtq_avail* A = (volatile struct virtq_avail*)(uintptr_t)avail; + A->flags = 0; + A->idx = 0; + + volatile struct virtq_used* U = (volatile struct virtq_used*)(uintptr_t)used; + U->flags = 0; + U->idx = 0; + + dev->common_cfg->queue_enable = 1; queue_index++; } diff --git a/run_virt b/run_virt index efeb69e9..43e1a480 100755 --- a/run_virt +++ b/run_virt @@ -66,4 +66,6 @@ $PRIVILEGE qemu-system-aarch64 \ -device virtio-sound-pci,audiodev=sdl_audio \ -audiodev sdl,id=sdl_audio \ -d guest_errors \ + #-netdev tap,id=net1,ifname=tap1,script=no,downscript=no,vnet_hdr=off \ + #-device virtio-net-pci,netdev=net1,mac=52:54:00:12:34:57 $ARGS diff --git a/shared/net/application_layer/dhcp_daemon.c b/shared/net/application_layer/dhcp_daemon.c index 8b6a3d05..d4058cd8 100644 --- a/shared/net/application_layer/dhcp_daemon.c +++ b/shared/net/application_layer/dhcp_daemon.c @@ -228,7 +228,7 @@ static void dhcp_fsm_once() } else { net_cfg_t g_net_cfg; g_net_cfg.ip = 0; - g_net_cfg.mode = NET_MODE_DISABLED; + g_net_cfg.mode = 0; //NET_MODE_DHCP ipv4_set_cfg(&g_net_cfg); g_state = DHCP_S_INIT; } @@ -266,7 +266,7 @@ static void dhcp_apply_offer(dhcp_packet *p, dhcp_request *req, uint32_t xid) { memset(&rt_static, 0, sizeof(rt_static)); cfg_local.rt = &rt_static; cfg_local.rt->xid = (uint16_t)xid; - cfg_local.mode = NET_MODE_DHCP; + cfg_local.mode = 0; //NET_MODE_DHCP uint32_t yi_net = p->yiaddr; cfg_local.ip = __builtin_bswap32(yi_net); diff --git a/shared/net/application_layer/sntp_daemon.c b/shared/net/application_layer/sntp_daemon.c index eacb061d..0e123239 100644 --- a/shared/net/application_layer/sntp_daemon.c +++ b/shared/net/application_layer/sntp_daemon.c @@ -27,7 +27,7 @@ int sntp_daemon_entry(int argc, char* argv[]){ uint32_t attempts = 0; while (attempts < SNTP_BOOTSTRAP_MAX_RETRY){ const net_cfg_t* cfg = ipv4_get_cfg(); - if (!cfg || cfg->mode == NET_MODE_DISABLED || cfg->ip == 0){ + if (!cfg || cfg->mode == -1 || cfg->ip == 0){ //NET_MODE_DISABLED sleep(500); continue; } diff --git a/shared/net/internet_layer/ipv4.c b/shared/net/internet_layer/ipv4.c index 6f56025b..ad600825 100644 --- a/shared/net/internet_layer/ipv4.c +++ b/shared/net/internet_layer/ipv4.c @@ -19,7 +19,7 @@ net_cfg_t g_net_cfg = { .ip = 0, .mask = 0, .gw = 0, - .mode = NET_MODE_DHCP, + .mode = 0,//NET_MODE_DHCP .rt = &g_rt_opts }; @@ -28,7 +28,7 @@ void ipv4_cfg_init() { g_net_cfg.ip = 0; g_net_cfg.mask = 0; g_net_cfg.gw = 0; - g_net_cfg.mode = NET_MODE_DHCP; + g_net_cfg.mode = 0; //NET_MODE_DHCP g_net_cfg.rt = &g_rt_opts; ipv4_rt_init(); } diff --git a/shared/net/internet_layer/ipv4.h b/shared/net/internet_layer/ipv4.h index b005ef9f..e004f03d 100644 --- a/shared/net/internet_layer/ipv4.h +++ b/shared/net/internet_layer/ipv4.h @@ -7,9 +7,6 @@ #ifdef __cplusplus extern "C" { #endif -#define NET_MODE_DISABLED ((int8_t)-1) -#define NET_MODE_DHCP 0 -#define NET_MODE_STATIC 1 typedef struct net_runtime_opts { uint16_t mtu; diff --git a/shared/net/link_layer/arp.c b/shared/net/link_layer/arp.c index 2c7fbc97..64b622ef 100644 --- a/shared/net/link_layer/arp.c +++ b/shared/net/link_layer/arp.c @@ -144,7 +144,7 @@ void arp_populate_response(uint8_t out_mac[6], uint32_t *out_ip, const arp_hdr_t bool arp_can_reply() { const net_cfg_t *cfg = ipv4_get_cfg(); - return (cfg && cfg->ip != 0 && cfg->mode != NET_MODE_DISABLED); + return (cfg && cfg->ip != 0 && cfg->mode != -1); //NET_MODE_DISABLED } @@ -153,7 +153,7 @@ int arp_daemon_entry(int argc, char* argv[]){ arp_set_pid(get_current_proc_pid()); while (1){ const net_cfg_t *cfg = ipv4_get_cfg(); - if(cfg && cfg->ip != 0 && cfg->mode != NET_MODE_DISABLED) break; + if(cfg && cfg->ip != 0 && cfg->mode != -1) break; //NET_MODE_DISABLED sleep(200); } arp_table_init(); diff --git a/shared/std/allocator.cpp b/shared/std/allocator.cpp index 2f5f96c8..d0747869 100644 --- a/shared/std/allocator.cpp +++ b/shared/std/allocator.cpp @@ -10,11 +10,15 @@ void* operator new[](size_t size) { return (void*)malloc(size); } -//TODO: We'll need to implement an unsized version of these, and keep track of size ourselves - +void operator delete(void* ptr) noexcept { + free(ptr, 0); +} +void operator delete[](void* ptr) noexcept { + free(ptr, 0); +} void operator delete(void* ptr, size_t size) noexcept { - free(ptr,size); + free(ptr, size); } void operator delete[](void* ptr, size_t size) noexcept { - free(ptr,size); + free(ptr, size); } \ No newline at end of file diff --git a/shared/std/allocator.hpp b/shared/std/allocator.hpp index 1e5ac82d..49b8bbf3 100644 --- a/shared/std/allocator.hpp +++ b/shared/std/allocator.hpp @@ -4,5 +4,15 @@ void* operator new(size_t size); void* operator new[](size_t size); + +void operator delete(void* ptr) noexcept; +void operator delete[](void* ptr) noexcept; + void operator delete(void* ptr, size_t size) noexcept; -void operator delete[](void* ptr, size_t size) noexcept; \ No newline at end of file +void operator delete[](void* ptr, size_t size) noexcept; + +inline void* operator new(size_t, void* p) noexcept { return p; } +inline void* operator new[](size_t, void* p) noexcept { return p; } + +inline void operator delete(void*, void*) noexcept {} +inline void operator delete[](void*, void*) noexcept {} \ No newline at end of file diff --git a/shared/std/string.c b/shared/std/string.c index a2385115..15afbde3 100644 --- a/shared/std/string.c +++ b/shared/std/string.c @@ -192,6 +192,20 @@ size_t string_format_va_buf(const char *fmt, char *buf, va_list args){ for (int j = temp_len - 1; j >= 0 && len < STRING_MAX_LEN - 1; j--){ buf[len++] = temp[j]; } + + } else if (fmt[i] == 'u') { + uint64_t val = va_arg(args, unsigned int); + char temp[21]; + uint32_t temp_len = 0; + + do { + temp[temp_len++] = '0' + (val % 10); + val /= 10; + } while (val && temp_len < 20); + + for (int j = temp_len - 1; j >= 0 && len < STRING_MAX_LEN - 1; j--) { + buf[len++] = temp[j]; + } } else if (fmt[i] == 'f' || fmt[i] == 'd') { double val = va_arg(args, double); if (val < 0){ From 196d47acf83a139db5e09ee86e31c059705279e5 Mon Sep 17 00:00:00 2001 From: CodeAnarchist Date: Mon, 8 Sep 2025 02:34:20 +0200 Subject: [PATCH 07/23] net: improve l2/l3 separation, eth handles frames and minor fixes --- kernel/networking/interface_manager.h | 4 +-- shared/net/internet_layer/icmp.c | 4 +-- shared/net/internet_layer/ipv4.c | 25 ++++++++---------- shared/net/internet_layer/ipv4.h | 5 +--- shared/net/link_layer/arp.c | 37 ++++++++++++--------------- shared/net/link_layer/eth.c | 31 +++++++++++++++++----- shared/net/link_layer/eth.h | 11 +++----- shared/net/transport_layer/tcp.c | 2 +- shared/net/transport_layer/udp.c | 2 +- 9 files changed, 61 insertions(+), 60 deletions(-) diff --git a/kernel/networking/interface_manager.h b/kernel/networking/interface_manager.h index 6eef3b8d..53fe279e 100644 --- a/kernel/networking/interface_manager.h +++ b/kernel/networking/interface_manager.h @@ -10,8 +10,8 @@ extern "C" { #define MAX_L2_INTERFACES 16 #define MAX_IPV4_PER_INTERFACE 4 #define MAX_IPV6_PER_INTERFACE 4 -#define MAX_IPV4_MCAST_PER_INTERFACE 8 -#define MAX_IPV6_MCAST_PER_INTERFACE 8 +#define MAX_IPV4_MCAST_PER_INTERFACE 12 +#define MAX_IPV6_MCAST_PER_INTERFACE 12 typedef enum { NET_MODE_DISABLED = -1, diff --git a/shared/net/internet_layer/icmp.c b/shared/net/internet_layer/icmp.c index d692c589..5522b842 100644 --- a/shared/net/internet_layer/icmp.c +++ b/shared/net/internet_layer/icmp.c @@ -76,7 +76,7 @@ void icmp_send_echo(uint32_t dst_ip, const net_cfg_t *cfg = ipv4_get_cfg(); if (!cfg) { free((void*)buf, icmp_len); return; } - ipv4_send_segment(cfg->ip, dst_ip, 1, (sizedptr){ buf, icmp_len }); + ipv4_send_packet(cfg->ip, dst_ip, 1, (sizedptr){ buf, icmp_len }); free((void*)buf, icmp_len); } @@ -114,7 +114,7 @@ void icmp_input(uintptr_t ptr, const net_cfg_t *cfg = ipv4_get_cfg(); if (cfg) { - ipv4_send_segment(cfg->ip, src_ip, 1, (sizedptr){ buf, reply_len }); + ipv4_send_packet(cfg->ip, src_ip, 1, (sizedptr){ buf, reply_len }); } free((void*)buf, reply_len); return; diff --git a/shared/net/internet_layer/ipv4.c b/shared/net/internet_layer/ipv4.c index ad600825..fb801c67 100644 --- a/shared/net/internet_layer/ipv4.c +++ b/shared/net/internet_layer/ipv4.c @@ -147,7 +147,7 @@ void ip_input(uintptr_t ip_ptr, } } -void ipv4_send_segment(uint32_t src_ip, +void ipv4_send_packet(uint32_t src_ip, uint32_t dst_ip, uint8_t proto, sizedptr segment) @@ -168,19 +168,14 @@ void ipv4_send_segment(uint32_t src_ip, memset(dst_mac, 0xFF, sizeof(dst_mac)); } - uint32_t total = sizeof(eth_hdr_t) - + sizeof(ipv4_hdr_t) - + segment.size; - uintptr_t buf = (uintptr_t)malloc(total); - if (!buf) return; + uint32_t ip_len = sizeof(ipv4_hdr_t) + segment.size; + uintptr_t ip_buf = (uintptr_t)malloc(ip_len); + if (!ip_buf) return; - const uint8_t* src_mac = network_get_local_mac(); - uintptr_t ptr = create_eth_packet(buf, src_mac, dst_mac, 0x0800); - - ipv4_hdr_t *ip = (ipv4_hdr_t *)ptr; + ipv4_hdr_t *ip = (ipv4_hdr_t *)ip_buf; ip->version_ihl = (4 << 4) | (sizeof(*ip)/4); ip->dscp_ecn = 0; - ip->total_length = __builtin_bswap16(sizeof(*ip) + segment.size); + ip->total_length = __builtin_bswap16(ip_len); ip->identification = 0; ip->flags_frag_offset = __builtin_bswap16(0x4000); ip->ttl = 64; @@ -190,13 +185,13 @@ void ipv4_send_segment(uint32_t src_ip, ip->header_checksum = 0; ip->header_checksum = ipv4_checksum(ip, sizeof(*ip)); - ptr += sizeof(*ip); if (segment.size) { - memcpy((void*)ptr, (void*)segment.ptr, segment.size); + memcpy((void*)(ip_buf + sizeof(*ip)), (void*)segment.ptr, segment.size); } - eth_send_frame(buf, total); + sizedptr payload = { ip_buf, ip_len }; + eth_send_frame(0x0800, dst_mac, payload); - free((void*)buf, total); + free((void*)ip_buf, ip_len); } diff --git a/shared/net/internet_layer/ipv4.h b/shared/net/internet_layer/ipv4.h index e004f03d..5da6d4e7 100644 --- a/shared/net/internet_layer/ipv4.h +++ b/shared/net/internet_layer/ipv4.h @@ -46,7 +46,7 @@ const net_cfg_t* ipv4_get_cfg(); void ipv4_to_string(uint32_t ip, char* buf); -void ipv4_send_segment(uint32_t src_ip, +void ipv4_send_packet(uint32_t src_ip, uint32_t dst_ip, uint8_t proto, sizedptr segment); @@ -60,9 +60,6 @@ static inline uint32_t ipv4_broadcast(uint32_t ip, uint32_t mask){ return (ip & static inline uint32_t ipv4_first_host(uint32_t ip, uint32_t mask){ return (ip & mask) + 1; } static inline uint32_t ipv4_last_host(uint32_t ip, uint32_t mask){ return ((ip & mask) | ~mask) - 1; } -void ipv4_cfg_init(); -void ipv4_set_cfg(const net_cfg_t *src); -const net_cfg_t* ipv4_get_cfg(); #ifdef __cplusplus } #endif diff --git a/shared/net/link_layer/arp.c b/shared/net/link_layer/arp.c index 64b622ef..726d1da6 100644 --- a/shared/net/link_layer/arp.c +++ b/shared/net/link_layer/arp.c @@ -105,14 +105,10 @@ void arp_send_request(uint32_t target_ip) { if (!cfg) return; - uint8_t dst_mac[6]; + uint8_t dst_mac[6] = {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}; arp_hdr_t hdr; - uintptr_t buf; - uint32_t len; - memset(dst_mac, 0xFF, sizeof(dst_mac)); memset(hdr.target_mac, 0x00, sizeof(hdr.target_mac)); - hdr.htype = __builtin_bswap16(1); hdr.ptype = __builtin_bswap16(0x0800); hdr.hlen = 6; @@ -122,15 +118,15 @@ void arp_send_request(uint32_t target_ip) { hdr.sender_ip = __builtin_bswap32(cfg->ip); hdr.target_ip = __builtin_bswap32(target_ip); - len = sizeof(eth_hdr_t) + sizeof(arp_hdr_t); - buf = (uintptr_t)malloc(len); + sizedptr payload = { (uintptr_t)&hdr, sizeof(hdr) }; + uintptr_t buf = (uintptr_t)malloc(sizeof(hdr)); if (!buf) return; + memcpy((void*)buf, &hdr, sizeof(hdr)); + payload.ptr = buf; - uintptr_t ptr = create_eth_packet(buf, local_mac, dst_mac, 0x0806); - memcpy((void*)ptr, &hdr, sizeof(arp_hdr_t)); + eth_send_frame(0x0806, dst_mac, payload); - eth_send_frame(buf, len); - free((void*)buf, len); + free((void*)buf, sizeof(hdr)); } bool arp_should_handle(const arp_hdr_t *arp, uint32_t my_ip) { @@ -163,6 +159,7 @@ int arp_daemon_entry(int argc, char* argv[]){ sleep(1000); } } + static void arp_send_reply(const arp_hdr_t *in_arp, const uint8_t in_src_mac[6], uint32_t frame_len){ @@ -172,12 +169,6 @@ static void arp_send_reply(const arp_hdr_t *in_arp, const net_cfg_t *cfg = ipv4_get_cfg(); if (!cfg) return; - uint32_t len = sizeof(eth_hdr_t) + sizeof(arp_hdr_t); - uintptr_t buf = (uintptr_t)malloc(len); - if (!buf) return; - - uintptr_t ptr = create_eth_packet(buf, local_mac, in_src_mac, 0x0806); - arp_hdr_t reply = *in_arp; memcpy(reply.target_mac, in_arp->sender_mac, 6); memcpy(reply.sender_mac, local_mac, 6); @@ -185,12 +176,16 @@ static void arp_send_reply(const arp_hdr_t *in_arp, reply.sender_ip = __builtin_bswap32(cfg->ip); reply.opcode = __builtin_bswap16(ARP_OPCODE_REPLY); - memcpy((void*)ptr, &reply, sizeof(reply)); + sizedptr payload = {(uintptr_t)&reply, sizeof(reply)}; - eth_send_frame(buf, len); - free((void*)buf, len); -} + uintptr_t buf = (uintptr_t)malloc(sizeof(reply)); + if (!buf) return; + memcpy((void*)buf, &reply, sizeof(reply)); + payload.ptr = buf; + eth_send_frame(0x0806, in_src_mac, payload); + free((void*)buf, sizeof(reply)); +} void arp_input(uintptr_t frame_ptr, uint32_t frame_len) { if (frame_len < sizeof(eth_hdr_t) + sizeof(arp_hdr_t)) return; diff --git a/shared/net/link_layer/eth.c b/shared/net/link_layer/eth.c index a2fcc7f4..48e11662 100644 --- a/shared/net/link_layer/eth.c +++ b/shared/net/link_layer/eth.c @@ -2,7 +2,11 @@ #include "arp.h" #include "std/memory.h" #include "net/internet_layer/ipv4.h" +#include "networking/network.h" + extern int net_tx_frame(uintptr_t frame_ptr, uint32_t frame_len); +extern uintptr_t malloc(uint64_t size); +extern void free(void *ptr, uint64_t size); uintptr_t create_eth_packet(uintptr_t p, const uint8_t src_mac[6], @@ -21,24 +25,37 @@ uint16_t eth_parse_packet_type(uintptr_t ptr) { return __builtin_bswap16(eth->ethertype); } -const uint8_t* eth_get_source_mac(uintptr_t ptr) { - const eth_hdr_t* eth = (const eth_hdr_t*)ptr; - return eth->src_mac; -} const uint8_t* eth_get_source(uintptr_t ptr){ const eth_hdr_t* eth = (const eth_hdr_t*)ptr; return eth->src_mac; } -bool eth_send_frame(uintptr_t frame_ptr, uint32_t frame_len){ - return net_tx_frame(frame_ptr, frame_len); +bool eth_send_frame(uint16_t ethertype, + const uint8_t dst_mac[6], + sizedptr payload) +{ + const uint8_t* src_mac = network_get_local_mac(); + + uint32_t total = (uint32_t)sizeof(eth_hdr_t) + (uint32_t)payload.size; + uintptr_t buf = (uintptr_t)malloc(total); + if (!buf) return false; + + uintptr_t ptr = create_eth_packet(buf, src_mac, dst_mac, ethertype); + if (payload.size) { + memcpy((void*)ptr, (void*)payload.ptr, payload.size); + } + + bool ok = net_tx_frame(buf, total); + + free((void*)buf, total); + return ok; } void eth_input(uintptr_t frame_ptr, uint32_t frame_len) { if (frame_len < sizeof(eth_hdr_t)) return; uint16_t type = eth_parse_packet_type(frame_ptr); - const uint8_t* src_mac = eth_get_source_mac(frame_ptr); + const uint8_t* src_mac = eth_get_source(frame_ptr); uintptr_t payload_ptr = frame_ptr + sizeof(eth_hdr_t); uint32_t payload_len = frame_len - sizeof(eth_hdr_t); diff --git a/shared/net/link_layer/eth.h b/shared/net/link_layer/eth.h index c3eacb8c..f83ed3d6 100644 --- a/shared/net/link_layer/eth.h +++ b/shared/net/link_layer/eth.h @@ -12,16 +12,13 @@ typedef struct __attribute__((packed)) eth_hdr_t { uint16_t ethertype; } eth_hdr_t; -uintptr_t create_eth_packet(uintptr_t ptr, - const uint8_t src_mac[6], - const uint8_t dst_mac[6], - uint16_t type); - uint16_t eth_parse_packet_type(uintptr_t ptr); - const uint8_t* eth_get_source(uintptr_t ptr); -bool eth_send_frame(uintptr_t frame_ptr, uint32_t frame_len); +bool eth_send_frame(uint16_t ethertype, + const uint8_t dst_mac[6], + sizedptr payload); + void eth_input(uintptr_t frame_ptr, uint32_t frame_len); #ifdef __cplusplus diff --git a/shared/net/transport_layer/tcp.c b/shared/net/transport_layer/tcp.c index 0389ff1a..ff42fa1e 100644 --- a/shared/net/transport_layer/tcp.c +++ b/shared/net/transport_layer/tcp.c @@ -155,7 +155,7 @@ static bool send_tcp_segment(uint32_t src_ip, uint32_t dst_ip, tcp_hdr_t *hdr, c hdr_on_buf->checksum = 0; uint16_t csum = tcp_compute_checksum(segment, tcp_len, src_ip, dst_ip); hdr_on_buf->checksum = csum; - ipv4_send_segment(src_ip, dst_ip, 6, (sizedptr){ .ptr = (uintptr_t)segment, .size = tcp_len }); + ipv4_send_packet(src_ip, dst_ip, 6, (sizedptr){ .ptr = (uintptr_t)segment, .size = tcp_len }); free(segment, tcp_len); return true; } diff --git a/shared/net/transport_layer/udp.c b/shared/net/transport_layer/udp.c index beb8860c..f817bbda 100644 --- a/shared/net/transport_layer/udp.c +++ b/shared/net/transport_layer/udp.c @@ -62,7 +62,7 @@ void udp_send_segment(const net_l4_endpoint *src, uintptr_t udp_buf = buf + sizeof(eth_hdr_t) + sizeof(ipv4_hdr_t); size_t udp_len = create_udp_segment(udp_buf, src, dst, payload); - ipv4_send_segment(src->ip, dst->ip, 0x11,(sizedptr){ udp_buf, (uint32_t)udp_len }); + ipv4_send_packet(src->ip, dst->ip, 0x11,(sizedptr){ udp_buf, (uint32_t)udp_len }); free((void*)buf, eth_total); } From 7bf0862907504d367f29b4b7c7de16c8ff3f4e15 Mon Sep 17 00:00:00 2001 From: CodeAnarchist Date: Mon, 8 Sep 2025 17:11:35 +0200 Subject: [PATCH 08/23] net: add O1 ifindex--nic_id map, keep nic_id kernel-internal --- kernel/networking/network.cpp | 42 +++++++------- kernel/networking/network.h | 13 ++--- kernel/networking/network_dispatch.cpp | 80 +++++++++++++++----------- kernel/networking/network_dispatch.hpp | 28 +++++---- 4 files changed, 92 insertions(+), 71 deletions(-) diff --git a/kernel/networking/network.cpp b/kernel/networking/network.cpp index a5697828..f95916a9 100644 --- a/kernel/networking/network.cpp +++ b/kernel/networking/network.cpp @@ -11,11 +11,11 @@ bool network_init() { } void network_handle_download_interrupt() { - if (dispatch) dispatch->handle_rx_irq(0); + if (dispatch) dispatch->handle_rx_irq(0);//legacy } void network_handle_upload_interrupt() { - if (dispatch) dispatch->handle_tx_irq(0); + if (dispatch) dispatch->handle_tx_irq(0); //legacy } void network_handle_download_interrupt_nic(uint16_t nic_id) { @@ -33,12 +33,14 @@ int network_net_task_entry(int argc, char* argv[]) { int net_tx_frame(uintptr_t frame_ptr, uint32_t frame_len) { if (!dispatch || !frame_ptr || !frame_len) return -1; - return dispatch->enqueue_frame_on(0, {frame_ptr, frame_len}) ? 0 : -1; + uint8_t ix = 1; //legacy + if (ix == 0xFF) return -1; + return dispatch->enqueue_frame(ix, {frame_ptr, frame_len}) ? 0 : -1; } -int net_tx_frame_on(uint16_t nic_id, uintptr_t frame_ptr, uint32_t frame_len) { +int net_tx_frame_on(uint16_t ifindex, uintptr_t frame_ptr, uint32_t frame_len) { if (!dispatch || !frame_ptr || !frame_len) return -1; - return dispatch->enqueue_frame_on((size_t)nic_id, {frame_ptr, frame_len}) ? 0 : -1; + return dispatch->enqueue_frame(ifindex, {frame_ptr, frame_len}) ? 0 : -1; } int net_rx_frame(sizedptr* out_frame) { @@ -47,42 +49,40 @@ int net_rx_frame(sizedptr* out_frame) { out_frame->size = 0; return 0; } + const uint8_t* network_get_local_mac() { static uint8_t dummy[6] = {0,0,0,0,0,0}; if (!dispatch) return dummy; - return dispatch->mac(0); + if (1 == 0xFF) return dummy; + const uint8_t* m = dispatch->mac(1); //kegacy + return m ? m : dummy; } -const uint8_t* network_get_mac(uint16_t nic_id) { +const uint8_t* network_get_mac(uint16_t ifindex) { static uint8_t dummy[6] = {0,0,0,0,0,0}; if (!dispatch) return dummy; - const uint8_t* m = dispatch->mac((size_t)nic_id); + const uint8_t* m = dispatch->mac(ifindex); return m ? m : dummy; } -uint16_t network_get_mtu(uint16_t nic_id) { +uint16_t network_get_mtu(uint16_t ifindex) { if (!dispatch) return 0; - return dispatch->mtu((size_t)nic_id); + return dispatch->mtu(ifindex); } -uint16_t network_get_header_size(uint16_t nic_id) { +uint16_t network_get_header_size(uint16_t ifindex) { if (!dispatch) return 0; - return dispatch->header_size((size_t)nic_id); -} - -uint8_t network_get_ifindex(uint16_t nic_id) { - if (!dispatch) return 0xFF; - return dispatch->ifindex((size_t)nic_id); + return dispatch->header_size(ifindex); } -const char* network_get_ifname(uint16_t nic_id) { +const char* network_get_ifname(uint16_t ifindex) { if (!dispatch) return 0; - return dispatch->ifname((size_t)nic_id); + return dispatch->ifname(ifindex); } -const char* network_get_hw_ifname(uint16_t nic_id) { +const char* network_get_hw_ifname(uint16_t ifindex) { if (!dispatch) return 0; - return dispatch->hw_ifname((size_t)nic_id); + return dispatch->hw_ifname(ifindex); } size_t network_nic_count() { diff --git a/kernel/networking/network.h b/kernel/networking/network.h index e0fb6407..83196eba 100644 --- a/kernel/networking/network.h +++ b/kernel/networking/network.h @@ -23,16 +23,15 @@ void network_handle_upload_interrupt_nic(uint16_t nic_id); int network_net_task_entry(int argc, char* argv[]); int net_tx_frame(uintptr_t frame_ptr, uint32_t frame_len); -int net_tx_frame_on(uint16_t nic_id, uintptr_t frame_ptr, uint32_t frame_len); +int net_tx_frame_on(uint16_t ifindex, uintptr_t frame_ptr, uint32_t frame_len); int net_rx_frame(sizedptr *out_frame); const uint8_t* network_get_local_mac(void); -const uint8_t* network_get_mac(uint16_t nic_id); -uint16_t network_get_mtu(uint16_t nic_id); -uint16_t network_get_header_size(uint16_t nic_id); -uint8_t network_get_ifindex(uint16_t nic_id); -const char* network_get_ifname(uint16_t nic_id); -const char* network_get_hw_ifname(uint16_t nic_id); +const uint8_t* network_get_mac(uint16_t ifindex); +uint16_t network_get_mtu(uint16_t ifindex); +uint16_t network_get_header_size(uint16_t ifindex); +const char* network_get_ifname(uint16_t ifindex); +const char* network_get_hw_ifname(uint16_t ifindex); size_t network_nic_count(void); void network_update_local_ip(uint32_t ip); diff --git a/kernel/networking/network_dispatch.cpp b/kernel/networking/network_dispatch.cpp index fc83d1cd..9331a678 100644 --- a/kernel/networking/network_dispatch.cpp +++ b/kernel/networking/network_dispatch.cpp @@ -7,6 +7,7 @@ #include "port_manager.h" #include "std/memory.h" #include "std/std.h" +#include "console/kio.h" extern void sleep(uint64_t ms); extern uintptr_t malloc(uint64_t size); @@ -20,12 +21,20 @@ NetworkDispatch::NetworkDispatch() { nic_num = 0; g_net_pid = 0xFFFF; + for (int i = 0; i <= (int)MAX_L2_INTERFACES; ++i) ifindex_to_nicid[i] = 0xFF; } bool NetworkDispatch::init() { if (net_bus_init() <= 0) return false; if (!register_all_from_bus()) return false; + for (int ix=1; ix <= (int)MAX_L2_INTERFACES; ++ix) { + int nid = nic_for_ifindex((uint8_t)ix); + if (nid >= 0) { + const char* nm = nics[nid].ifname_str; + kprintf("[net] ifindex=%i -> nic_id=%i (%s)", ix, nid, nm ); + } + } return nic_num > 0; } @@ -50,17 +59,21 @@ void NetworkDispatch::handle_tx_irq(size_t nic_id) driver->handle_sent_packet(); } -bool NetworkDispatch::enqueue_frame_on(size_t nic_id, const sizedptr& frame) +bool NetworkDispatch::enqueue_frame(uint8_t ifindex, const sizedptr& frame) { - if (nic_id >= nic_num) return false; + int nic_id = nic_for_ifindex(ifindex); + if (nic_id < 0) return false; NetDriver* driver = nics[nic_id].drv; if (!driver) return false; if (frame.size == 0) return false; + sizedptr pkt = driver->allocate_packet(frame.size); if (!pkt.ptr) return false; + uint16_t hs = nics[nic_id].hdr_sz; void* dst = (void*)(pkt.ptr + hs); memcpy(dst, (const void*)frame.ptr, frame.size); + if (!nics[nic_id].tx.enqueue(pkt)) { free_frame(pkt); return false; } return true; } @@ -113,52 +126,45 @@ size_t NetworkDispatch::nic_count() const return nic_num; } -const char* NetworkDispatch::ifname(size_t nic_id) const -{ - if (nic_id >= nic_num) return 0; - return nics[nic_id].ifname_str; -} - -const char* NetworkDispatch::hw_ifname(size_t nic_id) const +const char* NetworkDispatch::ifname(uint8_t ifindex) const { - if (nic_id >= nic_num) return 0; - return nics[nic_id].hwname_str; + int nic_id = nic_for_ifindex(ifindex); + return nic_id < 0 ? nullptr : nics[nic_id].ifname_str; } -const uint8_t* NetworkDispatch::mac(size_t nic_id) const +const char* NetworkDispatch::hw_ifname(uint8_t ifindex) const { - if (nic_id >= nic_num) return 0; - return nics[nic_id].mac_addr; + int nic_id = nic_for_ifindex(ifindex); + return nic_id < 0 ? nullptr : nics[nic_id].hwname_str; } -uint16_t NetworkDispatch::mtu(size_t nic_id) const +const uint8_t* NetworkDispatch::mac(uint8_t ifindex) const { - if (nic_id >= nic_num) return 0; - return nics[nic_id].mtu_val; + int nic_id = nic_for_ifindex(ifindex); + return nic_id < 0 ? nullptr : nics[nic_id].mac_addr; } -uint16_t NetworkDispatch::header_size(size_t nic_id) const +uint16_t NetworkDispatch::mtu(uint8_t ifindex) const { - if (nic_id >= nic_num) return 0; - return nics[nic_id].hdr_sz; + int nic_id = nic_for_ifindex(ifindex); + return nic_id < 0 ? 0 : nics[nic_id].mtu_val; } -uint8_t NetworkDispatch::ifindex(size_t nic_id) const +uint16_t NetworkDispatch::header_size(uint8_t ifindex) const { - if (nic_id >= nic_num) return 0xFF; - return nics[nic_id].ifindex; + int nic_id = nic_for_ifindex(ifindex); + return nic_id < 0 ? 0 : nics[nic_id].hdr_sz; } -l2_interface_t* NetworkDispatch::l2_at(size_t nic_id) const +l2_interface_t* NetworkDispatch::l2_at(uint8_t ifindex) const { - if (nic_id >= nic_num) return 0; - return l2_interface_find_by_index(nics[nic_id].ifindex); + return l2_interface_find_by_index(ifindex); } -NetDriver* NetworkDispatch::driver_at(size_t nic_id) const +NetDriver* NetworkDispatch::driver_at(uint8_t ifindex) const { - if (nic_id >= nic_num) return 0; - return nics[nic_id].drv; + int nic_id = nic_for_ifindex(ifindex); + return nic_id < 0 ? nullptr : nics[nic_id].drv; } void NetworkDispatch::free_frame(const sizedptr &f) @@ -189,6 +195,7 @@ bool NetworkDispatch::register_all_from_bus() { l2_interface_set_mac(ix, zero_mac); l2_interface_set_mtu(ix, m ? m : 65535); l2_interface_set_up(ix, true); + continue; } @@ -210,17 +217,26 @@ bool NetworkDispatch::register_all_from_bus() { l2_interface_set_up(ix, true); c->ifindex = ix; + if (ix <= MAX_L2_INTERFACES) ifindex_to_nicid[ix] = (uint8_t)nic_num; + nic_num += 1; } return nic_num > 0; } - -void NetworkDispatch::copy_str(char* dst, int cap, const char* src) -{ +void NetworkDispatch::copy_str(char* dst, int cap, const char* src) { if (!dst || cap <= 0) return; if (!src) { dst[0] = 0; return; } uint32_t n = strlen(src, (uint32_t)(cap - 1)); memcpy(dst, src, n); dst[n] = 0; } + +int NetworkDispatch::nic_for_ifindex(uint8_t ifindex) const { + if (!ifindex) return -1; + if (ifindex > MAX_L2_INTERFACES) return -1; + uint8_t nic_id = ifindex_to_nicid[ifindex]; + if (nic_id == 0xFF) return -1; + if (nic_id >= nic_num) return -1; + return (int)nic_id; +} diff --git a/kernel/networking/network_dispatch.hpp b/kernel/networking/network_dispatch.hpp index a7cee82f..99a5aabd 100644 --- a/kernel/networking/network_dispatch.hpp +++ b/kernel/networking/network_dispatch.hpp @@ -6,28 +6,30 @@ #include "net/network_types.h" #include "net/internet_layer/ipv4.h" #include "interface_manager.h" -#include "std/std.h" class NetworkDispatch { public: NetworkDispatch(); bool init(); + void handle_rx_irq(size_t nic_id); void handle_tx_irq(size_t nic_id); - bool enqueue_frame_on(size_t nic_id, const sizedptr&); + + bool enqueue_frame(uint8_t ifindex, const sizedptr&); + int net_task(); void set_net_pid(uint16_t pid); uint16_t get_net_pid() const; size_t nic_count() const; - const char* ifname(size_t nic_id) const; - const char* hw_ifname(size_t nic_id) const; - const uint8_t* mac(size_t nic_id) const; - uint16_t mtu(size_t nic_id) const; - uint16_t header_size(size_t nic_id) const; - uint8_t ifindex(size_t nic_id) const; - l2_interface_t* l2_at(size_t nic_id) const; - NetDriver* driver_at(size_t nic_id) const; + + const char* ifname(uint8_t ifindex) const; + const char* hw_ifname(uint8_t ifindex) const; + const uint8_t* mac(uint8_t ifindex) const; + uint16_t mtu(uint8_t ifindex) const; + uint16_t header_size(uint8_t ifindex) const; + l2_interface_t* l2_at(uint8_t ifindex) const; + NetDriver* driver_at(uint8_t ifindex) const; private: struct NICCtx { @@ -49,7 +51,11 @@ class NetworkDispatch { size_t nic_num; uint16_t g_net_pid; + uint8_t ifindex_to_nicid[MAX_L2_INTERFACES + 1]; + void free_frame(const sizedptr&); bool register_all_from_bus(); void copy_str(char* dst, int cap, const char* src); -}; \ No newline at end of file + + int nic_for_ifindex(uint8_t ifindex) const; +}; From 4bc877c4f2a89544b79deb260f0b91d23dc077e5 Mon Sep 17 00:00:00 2001 From: CodeAnarchist Date: Thu, 11 Sep 2025 00:55:11 +0200 Subject: [PATCH 09/23] net: added logical interface init --- kernel/networking/interface_manager.c | 656 ++++++++++++++++++++++--- kernel/networking/interface_manager.h | 42 +- kernel/networking/network_dispatch.cpp | 104 +++- kernel/networking/network_dispatch.hpp | 3 +- kernel/networking/processes/net_proc.c | 10 +- shared/net/internet_layer/ipv4.h | 12 +- 6 files changed, 728 insertions(+), 99 deletions(-) diff --git a/kernel/networking/interface_manager.c b/kernel/networking/interface_manager.c index 4b340e5b..3599193f 100644 --- a/kernel/networking/interface_manager.c +++ b/kernel/networking/interface_manager.c @@ -1,9 +1,9 @@ #include "interface_manager.h" #include "std/memory.h" -static l2_interface_t g_l2[MAX_L2_INTERFACES]; -static uint8_t g_l2_used[MAX_L2_INTERFACES]; -static uint8_t g_l2_count = 0; +//TODO: add network settings +static inline void mem_zero(void *p, size_t n){ if (p) memset(p,0,n); } +static inline void mem_copy(void *d, const void *s, size_t n){ if (d && s && n) memcpy(d,s,n); } static void copy_name(char dst[16], const char* src) { int i = 0; @@ -12,74 +12,137 @@ static void copy_name(char dst[16], const char* src) { dst[i] = 0; } -static int find_free_slot() { - for (int i = 0; i < (int)MAX_L2_INTERFACES; ++i) if (!g_l2_used[i]) return i; +static inline bool is_power2_mask_contiguous(uint32_t mask){ + if (mask == 0) return true; + uint32_t inv = ~mask; + return ((inv & (inv + 1u)) == 0); +} + +static inline uint32_t ipv4_net(uint32_t ip, uint32_t mask){ return ip & mask; } +static inline uint32_t ipv4_broadcast_calc(uint32_t ip, uint32_t mask){ return (mask==0)?0:((ip & mask) | ~mask); } + +static inline bool ipv4_is_unspecified(uint32_t ip){ return ip == 0; } +static inline bool ipv4_is_loopback(uint32_t ip){ return ((ip & 0xFF000000u) == 0x7F000000u); } +static inline bool ipv4_is_multicast(uint32_t ip){ return ((ip & 0xF0000000u) == 0xE0000000u); } +static inline bool ipv4_is_network_address(uint32_t ip, uint32_t mask){ if (mask==0 || mask==0xFFFFFFFFu) return false; return ((ip & mask) == ip); } +static inline bool ipv4_is_broadcast_address(uint32_t ip, uint32_t mask){ if (mask==0 || mask==0xFFFFFFFFu) return false; return (ip == ((ip & mask) | ~mask)); } +static inline bool ipv4_is_reserved_special(uint32_t ip){ + if ((ip & 0xFF000000u) == 0x00000000u) return true; + if ((ip & 0xFFFF0000u) == 0xA9FE0000u) return true; + if ((ip & 0xF0000000u) == 0xF0000000u) return true; + return false; +} + +static inline int prefix_match(const uint8_t a[16], const uint8_t b[16]){ + int bits = 0; + for (int i=0;i<16;i++){ + uint8_t x = (uint8_t)(a[i] ^ b[i]); + if (x==0){ bits += 8; continue; } + for (int bpos=7; bpos>=0; --bpos){ + if (x & (1u<=(int)MAX_L2_INTERFACES) return -1; + if (!g_l2_used[s]) return -1; + return s; +} +static inline uint8_t make_l3_id(uint8_t ifindex, uint8_t local_slot){ return (uint8_t)((ifindex<<4) | (local_slot & 0x0F)); } +static inline uint8_t l3_ifindex_from_id(uint8_t l3_id){ return (uint8_t)((l3_id >> 4) & 0x0F); } +static inline uint8_t l3_local_slot_from_id(uint8_t l3_id){ return (uint8_t)(l3_id & 0x0F); } uint8_t l2_interface_create(const char *name, void *driver_ctx) { - int slot = find_free_slot(); + int slot = find_free_l2_slot(); if (slot < 0) return 0; l2_interface_t* itf = &g_l2[slot]; - memset(itf, 0, sizeof(*itf)); + mem_zero(itf, sizeof(*itf)); itf->ifindex = (uint8_t)(slot + 1); copy_name(itf->name, name); itf->driver_context = driver_ctx; - itf->mtu = 1500; + itf->arp_table = NULL; + itf->nd_table = NULL; g_l2_used[slot] = 1; g_l2_count += 1; return itf->ifindex; } bool l2_interface_destroy(uint8_t ifindex) { - if (!ifindex) return false; - int slot = (int)ifindex - 1; - if (slot < 0 || slot >= (int)MAX_L2_INTERFACES) return false; - if (!g_l2_used[slot]) return false; - memset(&g_l2[slot], 0, sizeof(l2_interface_t)); + int slot = l2_slot_from_ifindex(ifindex); + if (slot < 0) return false; + l2_interface_t* itf = &g_l2[slot]; + if (itf->ipv4_count || itf->ipv6_count) return false; + mem_zero(&g_l2[slot], sizeof(l2_interface_t)); g_l2_used[slot] = 0; if (g_l2_count) g_l2_count -= 1; return true; } l2_interface_t* l2_interface_find_by_index(uint8_t ifindex) { - if (!ifindex) return 0; - int slot = (int)ifindex - 1; - if (slot < 0 || slot >= (int)MAX_L2_INTERFACES) return 0; - if (!g_l2_used[slot]) return 0; + int slot = l2_slot_from_ifindex(ifindex); + if (slot < 0) return 0; return &g_l2[slot]; } -uint8_t l2_interface_count(void) { - return g_l2_count; -} +uint8_t l2_interface_count(void) { return g_l2_count; } l2_interface_t* l2_interface_at(uint8_t idx) { uint8_t seen = 0; - for (int i = 0; i < (int)MAX_L2_INTERFACES; ++i) { + for (int i=0;i<(int)MAX_L2_INTERFACES;i++){ if (!g_l2_used[i]) continue; if (seen == idx) return &g_l2[i]; - seen += 1; + seen++; } return 0; } -bool l2_interface_set_mac(uint8_t ifindex, const uint8_t mac[6]) { - l2_interface_t* itf = l2_interface_find_by_index(ifindex); - if (!itf) return false; - if (!mac) return false; - itf->mac_addr[0]=mac[0]; itf->mac_addr[1]=mac[1]; itf->mac_addr[2]=mac[2]; - itf->mac_addr[3]=mac[3]; itf->mac_addr[4]=mac[4]; itf->mac_addr[5]=mac[5]; - return true; -} - -bool l2_interface_set_mtu(uint8_t ifindex, uint16_t mtu) { - l2_interface_t* itf = l2_interface_find_by_index(ifindex); - if (!itf) return false; - itf->mtu = mtu; - return true; -} - bool l2_interface_set_up(uint8_t ifindex, bool up) { l2_interface_t* itf = l2_interface_find_by_index(ifindex); if (!itf) return false; @@ -87,23 +150,15 @@ bool l2_interface_set_up(uint8_t ifindex, bool up) { return true; } -bool l2_interface_set_send_trampoline(uint8_t ifindex, int (*fn)(struct l2_interface*, const void*, size_t)) { - l2_interface_t* itf = l2_interface_find_by_index(ifindex); - if (!itf) return false; - itf->send_frame = fn; - return true; -} - static int find_ipv4_group_index(l2_interface_t* itf, uint32_t group) { - for (int i = 0; i < (int)itf->ipv4_mcast_count; ++i) { - if (itf->ipv4_mcast[i] == group) return i; - } + for (int i = 0; i < (int)itf->ipv4_mcast_count; ++i) if (itf->ipv4_mcast[i] == group) return i; return -1; } bool l2_ipv4_mcast_join(uint8_t ifindex, uint32_t group) { l2_interface_t* itf = l2_interface_find_by_index(ifindex); if (!itf) return false; + if (!ipv4_is_multicast(group)) return false; if (find_ipv4_group_index(itf, group) >= 0) return true; if (itf->ipv4_mcast_count >= MAX_IPV4_MCAST_PER_INTERFACE) return false; itf->ipv4_mcast[itf->ipv4_mcast_count++] = group; @@ -121,32 +176,515 @@ bool l2_ipv4_mcast_leave(uint8_t ifindex, uint32_t group) { } static int find_ipv6_group_index(l2_interface_t* itf, const uint8_t group[16]) { - for (int i = 0; i < (int)itf->ipv6_mcast_count; ++i) { - int eq = 1; - for (int j = 0; j < 16; ++j) if (itf->ipv6_mcast[i][j] != group[j]) { eq = 0; break; } - if (eq) return i; - } + for (int i = 0; i < (int)itf->ipv6_mcast_count; ++i) if (cmp16(itf->ipv6_mcast[i], group) == 0) return i; return -1; } - bool l2_ipv6_mcast_join(uint8_t ifindex, const uint8_t group[16]) { l2_interface_t* itf = l2_interface_find_by_index(ifindex); if (!itf || !group) return false; + if (!ipv6_is_multicast(group)) return false; if (find_ipv6_group_index(itf, group) >= 0) return true; if (itf->ipv6_mcast_count >= MAX_IPV6_MCAST_PER_INTERFACE) return false; - for (int j = 0; j < 16; ++j) itf->ipv6_mcast[itf->ipv6_mcast_count][j] = group[j]; + cp16(itf->ipv6_mcast[itf->ipv6_mcast_count], group); itf->ipv6_mcast_count += 1; return true; } - bool l2_ipv6_mcast_leave(uint8_t ifindex, const uint8_t group[16]) { l2_interface_t* itf = l2_interface_find_by_index(ifindex); if (!itf || !group) return false; int idx = find_ipv6_group_index(itf, group); if (idx < 0) return true; - for (int i = idx + 1; i < (int)itf->ipv6_mcast_count; ++i) { - for (int j = 0; j < 16; ++j) itf->ipv6_mcast[i-1][j] = itf->ipv6_mcast[i][j]; - } + for (int i = idx + 1; i < (int)itf->ipv6_mcast_count; ++i) cp16(itf->ipv6_mcast[i-1], itf->ipv6_mcast[i]); if (itf->ipv6_mcast_count) itf->ipv6_mcast_count -= 1; return true; } + +static bool v4_ip_exists_anywhere(uint32_t ip){ + for (int i=0;il2 || x->l2->ifindex != ifindex) continue; + if (x->mode == IPV4_CFG_DISABLED) continue; + uint32_t m = (x->mask==0)?mask:((mask==0)?x->mask:((x->mask < mask)?x->mask:mask)); + if (ipv4_net(ip, m) == ipv4_net(x->ip, m)) return true; + (void)n1; + } + return false; +} + +static bool v6_ip_exists_anywhere(const uint8_t ip[16]){ + if (ipv6_is_unspecified(ip)) return false; + for (int i=0;il2 || x->l2->ifindex != ifindex) continue; + if (x->cfg == IPV6_CFG_DISABLE) continue; + if (ipv6_is_unspecified(x->ip)) continue; + uint8_t minp = (x->prefix_len < prefix_len) ? x->prefix_len : prefix_len; + int eq = 1; + int fb = minp/8, rb = minp%8; + for (int b=0;bip[b]) {eq=0;break;} } + if (eq && rb){ + uint8_t m=(uint8_t)(0xFF<<(8-rb)); + if ( (ip[fb]&m) != (x->ip[fb]&m) ) eq=0; + } + if (eq) return true; + } + return false; +} + +static int alloc_local_slot_v4(l2_interface_t *l2){ + if (!l2) return -1; + for (int s=0; sl3_v4[s] == NULL) return s; + return -1; +} + +static int alloc_local_slot_v6(l2_interface_t *l2){ + if (!l2) return -1; + for (int s=0; sl3_v6[s] == NULL) return s; + return -1; +} + +static int alloc_global_v4_slot(void){ for (int i=0;iname[0]=='l' && l2->name[1]=='o')) return 0; + if (ipv4_is_multicast(ip)) return 0; + if (ipv4_is_reserved_special(ip)) return 0; + if (ipv4_is_network_address(ip, mask)) return 0; + if (ipv4_is_broadcast_address(ip, mask)) return 0; + if (v4_ip_exists_anywhere(ip)) return 0; + if (v4_overlap_intra_l2(ifindex, ip, mask)) return 0; + } + if (l2->ipv4_count >= MAX_IPV4_PER_INTERFACE) return 0; + int loc = alloc_local_slot_v4(l2); + int g = alloc_global_v4_slot(); + if (loc < 0 || g < 0) return 0; + g_v4[g].used = true; + g_v4[g].slot_in_l2 = (uint8_t)loc; + l3_ipv4_interface_t *n = &g_v4[g].node; + mem_zero(n, sizeof(*n)); + n->l2 = l2; + n->mode = mode; + n->ip = (mode==IPV4_CFG_STATIC) ? ip : 0; + n->mask = (mode==IPV4_CFG_STATIC) ? mask : 0; + n->gw = (mode==IPV4_CFG_STATIC) ? gw : 0; + n->broadcast = (mode==IPV4_CFG_STATIC) ? ipv4_broadcast_calc(ip, mask) : 0; + n->rt_v4 = rt; + n->is_localhost = (l2->name[0]=='l' && l2->name[1]=='o'); + n->l3_id = make_l3_id(l2->ifindex, (uint8_t)loc); + l2->l3_v4[loc] = n; + l2->ipv4_count++; + return n->l3_id; +} + +bool l3_ipv4_update(uint8_t l3_id, uint32_t ip, uint32_t mask, uint32_t gw, ipv4_cfg_t mode, net_runtime_opts_t *rt){ + l3_ipv4_interface_t *n = l3_ipv4_find_by_id(l3_id); + if (!n) return false; + l2_interface_t *l2 = n->l2; + if (!l2) return false; + if (mode == IPV4_CFG_STATIC){ + if (ipv4_is_unspecified(ip)) return false; + if (!is_power2_mask_contiguous(mask)) return false; + if (ipv4_is_loopback(ip) && !(l2->name[0]=='l' && l2->name[1]=='o')) return false; + if (ipv4_is_multicast(ip)) return false; + if (ipv4_is_reserved_special(ip)) return false; + if (ipv4_is_network_address(ip, mask)) return false; + if (ipv4_is_broadcast_address(ip, mask)) return false; + if (ip != n->ip && v4_ip_exists_anywhere(ip)) return false; + for (int i=0;il2 || x->l2->ifindex != l2->ifindex) continue; + if (x->mode == IPV4_CFG_DISABLED) continue; + uint32_t m = (x->mask < mask) ? x->mask : mask; + if (ipv4_net(ip, m) == ipv4_net(x->ip, m)) return false; + } + } + n->mode = mode; + n->rt_v4 = rt; + if (mode == IPV4_CFG_STATIC){ + n->ip = ip; n->mask = mask; n->gw = gw; + n->broadcast = ipv4_broadcast_calc(ip, mask); + } else { + n->ip = 0; n->mask = 0; n->gw = 0; n->broadcast = 0; + } + return true; +} + +bool l3_ipv4_remove_from_interface(uint8_t l3_id){ + l3_ipv4_interface_t *n = l3_ipv4_find_by_id(l3_id); + if (!n) return false; + l2_interface_t *l2 = n->l2; + if (!l2) return false; + if (l2->ipv4_count <= 1) return false; + uint8_t slot = l3_local_slot_from_id(l3_id); + if (slot < MAX_IPV4_PER_INTERFACE && l2->l3_v4[slot] == n){ + l2->l3_v4[slot] = NULL; + if (l2->ipv4_count) l2->ipv4_count--; + } + for (int i=0;i= MAX_IPV4_PER_INTERFACE) return NULL; + return l2->l3_v4[loc]; +} +l3_ipv4_interface_t* l3_ipv4_find_by_ip(uint32_t ip){ + for (int i=0;i 128) return 0; + + int i_; + int placeholder_ll = 0; + if (ip[0]==0xFE && ip[1]==0x80){ placeholder_ll = 1; for(i_=2;i_<16;i_++){ if (ip[i_]!=0){ placeholder_ll=0; break; } } } + int placeholder_gua = 0; + if (ip[0]==0x20 && ip[1]==0x00){ placeholder_gua = 1; for(i_=2;i_<16;i_++){ if (ip[i_]!=0){ placeholder_gua=0; break; } } } + + if (kind & IPV6_ADDRK_LINK_LOCAL){ + if (!(cfg & (IPV6_CFG_SLAAC | IPV6_CFG_DHCPV6))){ + if (!ipv6_is_linklocal(ip)) return 0; + } + if (!ipv6_is_unspecified(ip) && !placeholder_ll && v6_ip_exists_anywhere(ip)) return 0; + for (int i=0;iifindex != ifindex) continue; + if (ipv6_is_linklocal(g_v6[i].node.ip) && g_v6[i].node.cfg != IPV6_CFG_DISABLE) return 0; + } + } else if (kind & IPV6_ADDRK_GLOBAL){ + int is_loop = ipv6_is_loopback(ip); + + if (!(cfg & (IPV6_CFG_SLAAC | IPV6_CFG_DHCPV6))){ + if (ipv6_is_unspecified(ip)) return 0; + } + if (!ipv6_is_unspecified(ip)){ + if (ipv6_is_multicast(ip)) return 0; + if (is_loop && !(l2->name[0]=='l' && l2->name[1]=='o')) return 0; + if (!is_loop){ + if (ipv6_is_ula(ip)) return 0; + if (!placeholder_gua){ + if (v6_ip_exists_anywhere(ip)) return 0; + if (v6_overlap_intra_l2(ifindex, ip, prefix_len)) return 0; + } + } + } + if (!is_loop){ + bool has_lla=false; + for (int i=0;il2 || x->l2->ifindex != ifindex) continue; + if (ipv6_is_linklocal(x->ip) && x->cfg != IPV6_CFG_DISABLE){ has_lla=true; break; } + } + if (!has_lla) return 0; + } + } else { + return 0; + } + + if (l2->ipv6_count >= MAX_IPV6_PER_INTERFACE) return 0; + int loc = alloc_local_slot_v6(l2); + int g = alloc_global_v6_slot(); + if (loc < 0 || g < 0) return 0; + + g_v6[g].used = true; + g_v6[g].slot_in_l2 = (uint8_t)loc; + l3_ipv6_interface_t *n = &g_v6[g].node; + mem_zero(n, sizeof(*n)); + n->l2 = l2; + n->cfg = cfg; + n->kind = kind; + cp16(n->ip, ip); + n->prefix_len = prefix_len; + cp16(n->gateway, gw); + n->is_localhost = (l2->name[0]=='l' && l2->name[1]=='o'); + n->l3_id = make_l3_id(l2->ifindex, (uint8_t)loc); + l2->l3_v6[loc] = n; + l2->ipv6_count++; + return n->l3_id; +} + +bool l3_ipv6_update(uint8_t l3_id, const uint8_t ip[16], uint8_t prefix_len, const uint8_t gw[16], uint8_t cfg, uint8_t kind){ + l3_ipv6_interface_t *n = l3_ipv6_find_by_id(l3_id); + if (!n) return false; + l2_interface_t *l2 = n->l2; + if (!l2) return false; + if (prefix_len > 128) return false; + + if ((n->kind & IPV6_ADDRK_LINK_LOCAL) && cfg == IPV6_CFG_DISABLE){ + for (int i=0;il2 || x->l2->ifindex != l2->ifindex) continue; + if ((x->kind & IPV6_ADDRK_GLOBAL) && x->cfg != IPV6_CFG_DISABLE) return false; + } + } + + if (kind & IPV6_ADDRK_LINK_LOCAL){ + if (!(cfg & (IPV6_CFG_SLAAC | IPV6_CFG_DHCPV6))){ + if (!ipv6_is_linklocal(ip)) return false; + } + if (!ipv6_is_unspecified(ip) && cmp16(ip, n->ip)!=0 && v6_ip_exists_anywhere(ip)) return false; + for (int i=0;il2 || x->l2->ifindex != l2->ifindex) continue; + if (ipv6_is_linklocal(x->ip) && x->cfg != IPV6_CFG_DISABLE) return false; + } + } else if (kind & IPV6_ADDRK_GLOBAL){ + if (!(cfg & (IPV6_CFG_SLAAC | IPV6_CFG_DHCPV6))){ + if (ipv6_is_unspecified(ip)) return false; + } + if (!ipv6_is_unspecified(ip)){ + if (ipv6_is_multicast(ip) || ipv6_is_loopback(ip) || ipv6_is_ula(ip)) return false; + if (cmp16(ip,n->ip)!=0 && v6_ip_exists_anywhere(ip)) return false; + if (v6_overlap_intra_l2(l2->ifindex, ip, prefix_len)){ + for (int i=0;il2 || x->l2->ifindex != l2->ifindex) continue; + if (ipv6_is_unspecified(x->ip)) continue; + uint8_t minp = (x->prefix_len < prefix_len) ? x->prefix_len : prefix_len; + int eq = 1; + int fb=minp/8, rb=minp%8; + for (int b=0;bip[b]) {eq=0;break;} } + if (eq && rb){ + uint8_t m=(uint8_t)(0xFF<<(8-rb)); + if ( (ip[fb]&m) != (x->ip[fb]&m) ) eq=0; + } + if (eq) return false; + } + } + } + } else { + return false; + } + + n->cfg = cfg; + n->kind = kind; + cp16(n->ip, ip); + n->prefix_len = prefix_len; + cp16(n->gateway, gw); + return true; +} + +bool l3_ipv6_remove_from_interface(uint8_t l3_id){ + l3_ipv6_interface_t *n = l3_ipv6_find_by_id(l3_id); + if (!n) return false; + l2_interface_t *l2 = n->l2; + if (!l2) return false; + if ((n->kind & IPV6_ADDRK_LINK_LOCAL)){ + for (int i=0;il2 || x->l2->ifindex != l2->ifindex) continue; + if ((x->kind & IPV6_ADDRK_GLOBAL) && x->cfg != IPV6_CFG_DISABLE) return false; + } + } + if (l2->ipv6_count <= 1) return false; + uint8_t slot = l3_local_slot_from_id(l3_id); + if (slot < MAX_IPV6_PER_INTERFACE && l2->l3_v6[slot] == n){ + l2->l3_v6[slot] = NULL; + if (l2->ipv6_count) l2->ipv6_count--; + } + for (int i=0;icfg == IPV6_CFG_DISABLE) n->cfg = IPV6_CFG_STATIC; + return true; + } else { + if ((n->kind & IPV6_ADDRK_LINK_LOCAL)){ + l2_interface_t *l2 = n->l2; + for (int i=0;il2 || x->l2->ifindex != l2->ifindex) continue; + if ((x->kind & IPV6_ADDRK_GLOBAL) && x->cfg != IPV6_CFG_DISABLE) return false; + } + } + n->cfg = IPV6_CFG_DISABLE; + return true; + } +} + +l3_ipv6_interface_t* l3_ipv6_find_by_id(uint8_t l3_id){ + uint8_t ifx = l3_ifindex_from_id(l3_id); + uint8_t loc = l3_local_slot_from_id(l3_id); + l2_interface_t *l2 = l2_interface_find_by_index(ifx); + if (!l2) return NULL; + if (loc >= MAX_IPV6_PER_INTERFACE) return NULL; + return l2->l3_v6[loc]; +} +l3_ipv6_interface_t* l3_ipv6_find_by_ip(const uint8_t ip[16]){ + for (int i=0;iifindex, 0x7F000001u, 0xFF000000u, 0, IPV4_CFG_STATIC, NULL); +} + +void l3_init_localhost_ipv6(void){ + l2_interface_t *lo = NULL; + for (int i=0;i<(int)MAX_L2_INTERFACES;i++){ + if (!g_l2_used[i]) continue; + if (g_l2[i].name[0]=='l' && g_l2[i].name[1]=='o' && g_l2[i].name[2]=='0' && g_l2[i].name[3]==0) { lo = &g_l2[i]; break; } + } + if (!lo) return; + uint8_t loop6[16]={0}; loop6[15]=1; + for (int i=0;iifindex, loop6, 128, zero16, IPV6_CFG_STATIC, IPV6_ADDRK_GLOBAL); +} + +void ifmgr_autoconfig_l2(uint8_t ifindex){ + l2_interface_t *l2 = l2_interface_find_by_index(ifindex); + if (!l2) return; + + if (l2->name[0]=='l' && l2->name[1]=='o' && l2->name[2]=='0' && l2->name[3]==0){ + return; + } + + if (l2->ipv4_count == 0){ + (void)l3_ipv4_add_to_interface(ifindex, 0, 0, 0, IPV4_CFG_DHCP, NULL); + } + + bool has_lla=false; + for (int i=0;il2 || x->l2->ifindex != ifindex) continue; + if (ipv6_is_linklocal(x->ip) && x->cfg != IPV6_CFG_DISABLE){ has_lla=true; break; } + } + if (!has_lla){ + uint8_t fe80_0[16]={0}; fe80_0[0]=0xFE; fe80_0[1]=0x80; + uint8_t zero16[16]={0}; + (void)l3_ipv6_add_to_interface(ifindex, fe80_0, 64, zero16, IPV6_CFG_SLAAC, IPV6_ADDRK_LINK_LOCAL); + } + + bool has_gua=false; + for (int i=0;il2 || x->l2->ifindex != ifindex) continue; + if (!ipv6_is_linklocal(x->ip) && x->cfg != IPV6_CFG_DISABLE){ has_gua=true; break; } + } + if (!has_gua){ + uint8_t g2000_0[16]={0}; g2000_0[0]=0x20; g2000_0[1]=0x00; + uint8_t zero16[16]={0}; + (void)l3_ipv6_add_to_interface(ifindex, g2000_0, 64, zero16, IPV6_CFG_SLAAC, IPV6_ADDRK_GLOBAL); + } + + //TODO: add autoconfig settings/policy +} + +void ifmgr_autoconfig_all_l2(void){ + for (int i=0;i<(int)MAX_L2_INTERFACES;i++){ + if (!g_l2_used[i]) continue; + ifmgr_autoconfig_l2(g_l2[i].ifindex); + } +} + +ip_resolution_result_t resolve_ipv4_to_interface(uint32_t dst_ip){ + ip_resolution_result_t r; r.found=false; r.ipv4=NULL; r.ipv6=NULL; r.l2=NULL; + int best_plen = -1; + for (int i=0;il2) continue; + if (x->mode == IPV4_CFG_DISABLED) continue; + uint32_t m = x->mask; + if (m==0){ + if (x->ip == dst_ip && best_plen < 32){ best_plen = 32; r.found=true; r.ipv4=x; r.l2=x->l2; } + continue; + } + if (ipv4_net(dst_ip, m) == ipv4_net(x->ip, m)){ + int plen=0; uint32_t tmp=m; + while (tmp){ plen += (tmp & 1u); tmp >>= 1; } + if (plen > best_plen){ best_plen = plen; r.found=true; r.ipv4=x; r.l2=x->l2; } + } + } + return r; +} + +ip_resolution_result_t resolve_ipv6_to_interface(const uint8_t dst_ip[16]){ + ip_resolution_result_t r; r.found=false; r.ipv4=NULL; r.ipv6=NULL; r.l2=NULL; + int best = -1; + for (int i=0;il2) continue; + if (x->cfg == IPV6_CFG_DISABLE) continue; + if (ipv6_is_unspecified(x->ip)) continue; + int match = prefix_match(dst_ip, x->ip); + if (match >= x->prefix_len && match > best){ best = match; r.found=true; r.ipv6=x; r.l2=x->l2; } + } + return r; +} + +bool check_ipv4_overlap(uint32_t new_ip, uint32_t mask, uint8_t ifindex){ return v4_overlap_intra_l2(ifindex, new_ip, mask); } +bool check_ipv6_overlap(const uint8_t new_ip[16], uint8_t prefix_len, uint8_t ifindex){ return v6_overlap_intra_l2(ifindex, new_ip, prefix_len); } diff --git a/kernel/networking/interface_manager.h b/kernel/networking/interface_manager.h index 53fe279e..ca84a8e3 100644 --- a/kernel/networking/interface_manager.h +++ b/kernel/networking/interface_manager.h @@ -1,7 +1,6 @@ #pragma once #include "types.h" -#include "net/network_types.h" #ifdef __cplusplus extern "C" { @@ -14,10 +13,10 @@ extern "C" { #define MAX_IPV6_MCAST_PER_INTERFACE 12 typedef enum { - NET_MODE_DISABLED = -1, - NET_MODE_DHCP = 0, - NET_MODE_STATIC = 1 -} net_mode_t; + IPV4_CFG_DISABLED = -1, + IPV4_CFG_DHCP = 0, + IPV4_CFG_STATIC = 1 +} ipv4_cfg_t; typedef enum { IPV6_ADDRK_GLOBAL = 0x01, @@ -25,6 +24,7 @@ typedef enum { } ipv6_addr_kind_t; typedef enum { + IPV6_CFG_DISABLE = -1, IPV6_CFG_STATIC = 0x01, IPV6_CFG_SLAAC = 0x02, IPV6_CFG_DHCPV6 = 0x04 @@ -37,13 +37,8 @@ struct l3_ipv6_interface; typedef struct l2_interface { uint8_t ifindex; char name[16]; - uint8_t mac_addr[6]; - uint16_t mtu; bool is_up; - void *tx_queue; - void *rx_queue; void *driver_context; - int (*send_frame)(struct l2_interface *iface, const void *frame, size_t len); void *arp_table; void *nd_table; struct l3_ipv4_interface *l3_v4[MAX_IPV4_PER_INTERFACE]; @@ -62,13 +57,25 @@ typedef struct l3_ipv4_interface { uint32_t mask; uint32_t gw; uint32_t broadcast; - net_mode_t mode; + ipv4_cfg_t mode; bool is_localhost; void *rt_v4; void *port_manager; l2_interface_t *l2; } l3_ipv4_interface_t; +typedef struct net_runtime_opts { + uint16_t mtu; + uint32_t t1; + uint32_t t2; + uint32_t dns[2]; + uint32_t ntp[2]; + uint16_t xid; + uint32_t server_ip; + uint32_t lease; + uint32_t lease_start_time; +} net_runtime_opts_t; + typedef struct l3_ipv6_interface { uint8_t l3_id; uint8_t ip[16]; @@ -98,28 +105,31 @@ bool l2_interface_destroy(uint8_t ifindex); l2_interface_t *l2_interface_find_by_index(uint8_t ifindex); uint8_t l2_interface_count(void); l2_interface_t *l2_interface_at(uint8_t idx); -bool l2_interface_set_mac(uint8_t ifindex, const uint8_t mac[6]); -bool l2_interface_set_mtu(uint8_t ifindex, uint16_t mtu); bool l2_interface_set_up(uint8_t ifindex, bool up); -bool l2_interface_set_send_trampoline(uint8_t ifindex, int (*fn)(struct l2_interface*, const void*, size_t)); + bool l2_ipv4_mcast_join(uint8_t ifindex, uint32_t group); bool l2_ipv4_mcast_leave(uint8_t ifindex, uint32_t group); bool l2_ipv6_mcast_join(uint8_t ifindex, const uint8_t group[16]); bool l2_ipv6_mcast_leave(uint8_t ifindex, const uint8_t group[16]); -uint8_t l3_ipv4_add_to_interface(uint8_t ifindex, uint32_t ip, uint32_t mask, uint32_t gw, net_mode_t mode); +uint8_t l3_ipv4_add_to_interface(uint8_t ifindex, uint32_t ip, uint32_t mask, uint32_t gw, ipv4_cfg_t mode, net_runtime_opts_t *rt); +bool l3_ipv4_update(uint8_t l3_id, uint32_t ip, uint32_t mask, uint32_t gw, ipv4_cfg_t mode, net_runtime_opts_t *rt); bool l3_ipv4_remove_from_interface(uint8_t l3_id); l3_ipv4_interface_t *l3_ipv4_find_by_id(uint8_t l3_id); l3_ipv4_interface_t *l3_ipv4_find_by_ip(uint32_t ip); uint8_t l3_ipv6_add_to_interface(uint8_t ifindex, const uint8_t ip[16], uint8_t prefix_len, const uint8_t gw[16], uint8_t cfg, uint8_t kind); +bool l3_ipv6_update(uint8_t l3_id, const uint8_t ip[16], uint8_t prefix_len, const uint8_t gw[16], uint8_t cfg, uint8_t kind); bool l3_ipv6_remove_from_interface(uint8_t l3_id); +bool l3_ipv6_set_enabled(uint8_t l3_id, bool enable); l3_ipv6_interface_t *l3_ipv6_find_by_id(uint8_t l3_id); l3_ipv6_interface_t *l3_ipv6_find_by_ip(const uint8_t ip[16]); void l3_init_localhost_ipv4(void); void l3_init_localhost_ipv6(void); -//void l3_init_both_localhost(void); + +void ifmgr_autoconfig_all_l2(void); +void ifmgr_autoconfig_l2(uint8_t ifindex); ip_resolution_result_t resolve_ipv4_to_interface(uint32_t dst_ip); ip_resolution_result_t resolve_ipv6_to_interface(const uint8_t dst_ip[16]); diff --git a/kernel/networking/network_dispatch.cpp b/kernel/networking/network_dispatch.cpp index 9331a678..5d5051e0 100644 --- a/kernel/networking/network_dispatch.cpp +++ b/kernel/networking/network_dispatch.cpp @@ -8,6 +8,7 @@ #include "std/memory.h" #include "std/std.h" #include "console/kio.h" +#include "networking/interface_manager.h" extern void sleep(uint64_t ms); extern uintptr_t malloc(uint64_t size); @@ -28,7 +29,14 @@ bool NetworkDispatch::init() { if (net_bus_init() <= 0) return false; if (!register_all_from_bus()) return false; - for (int ix=1; ix <= (int)MAX_L2_INTERFACES; ++ix) { + + l3_init_localhost_ipv4(); + l3_init_localhost_ipv6(); + ifmgr_autoconfig_all_l2(); + + dump_interfaces(); + + for (int ix = 1; ix <= (int)MAX_L2_INTERFACES; ++ix){ int nid = nic_for_ifindex((uint8_t)ix); if (nid >= 0) { const char* nm = nics[nid].ifname_str; @@ -191,11 +199,7 @@ bool NetworkDispatch::register_all_from_bus() { if (!is_lo0) continue; uint8_t ix = l2_interface_create(name, nullptr); - uint8_t zero_mac[6] = {0,0,0,0,0,0}; - l2_interface_set_mac(ix, zero_mac); - l2_interface_set_mtu(ix, m ? m : 65535); l2_interface_set_up(ix, true); - continue; } @@ -212,8 +216,6 @@ bool NetworkDispatch::register_all_from_bus() { c->hdr_sz = hs; uint8_t ix = l2_interface_create(c->ifname_str, (void*)drv); - l2_interface_set_mac(ix, c->mac_addr); - l2_interface_set_mtu(ix, c->mtu_val); l2_interface_set_up(ix, true); c->ifindex = ix; @@ -240,3 +242,91 @@ int NetworkDispatch::nic_for_ifindex(uint8_t ifindex) const { if (nic_id >= nic_num) return -1; return (int)nic_id; } + +void NetworkDispatch::dump_interfaces() +{ + kprintf("[net]interface dump start"); + + auto ipv6_to_str = [&](const uint8_t ip[16], char out[41]){ //TODO: move this to ipv6 file + static const char HEX[] = "0123456789abcdef"; + int p = 0; + for (int g = 0; g < 8; ++g) { + uint16_t w = (uint16_t(ip[g*2]) << 8) | uint16_t(ip[g*2 + 1]); + out[p++] = HEX[(w >> 12) & 0xF]; + out[p++] = HEX[(w >> 8) & 0xF]; + out[p++] = HEX[(w >> 4) & 0xF]; + out[p++] = HEX[w & 0xF]; + if (g != 7) out[p++] = ':'; + } + out[p] = 0; + }; + + for (uint8_t ifx = 1; ifx <= (uint8_t)MAX_L2_INTERFACES; ++ifx){ + l2_interface_t* l2 = l2_interface_find_by_index(ifx); + if (!l2) continue; + + int nid = nic_for_ifindex(ifx); + kprintf("int l2 %u: name=%s up=%u ipv4_count=%u ipv6_count=%u arp=%x nd=%x mcast4=%u mcast6=%u", + (unsigned)ifx, l2->name, l2->is_up?1:0, + (unsigned)l2->ipv4_count, (unsigned)l2->ipv6_count, + (uint64_t)(uintptr_t)l2->arp_table, (uint64_t)(uintptr_t)l2->nd_table, + (unsigned)l2->ipv4_mcast_count, (unsigned)l2->ipv6_mcast_count); + + if (nid >= 0){ + char macs[18]; + { + static const char HEX[] = "0123456789abcdef"; + int p = 0; + for (int i = 0; i < 6; ++i) { + uint8_t b = nics[nid].mac_addr[i]; + macs[p++] = HEX[b >> 4]; + macs[p++] = HEX[b & 0x0F]; + if (i != 5) macs[p++] = ':'; + } + macs[p] = 0; + } + + kprintf(" driver: nic_id=%u ifname=%s hw=%s mtu=%u hdr=%u mac=%s drv=%x", + (unsigned)nid, + nics[nid].ifname_str ? nics[nid].ifname_str : (char*)"(null)", + nics[nid].hwname_str ? nics[nid].hwname_str : (char*)"(null)", + (unsigned)nics[nid].mtu_val, (unsigned)nics[nid].hdr_sz, macs, + (uint64_t)(uintptr_t)nics[nid].drv); + } else { + kprintf(" driver: none"); + } + + kprintf(" int ipv4:"); + for (int s = 0; s < (int)MAX_IPV4_PER_INTERFACE; ++s){ + l3_ipv4_interface_t* v4 = l2->l3_v4[s]; + if (!v4) continue; + char ip[16], mask[16], gw[16], bc[16]; + ipv4_to_string(v4->ip, ip); + ipv4_to_string(v4->mask, mask); + ipv4_to_string(v4->gw, gw); + ipv4_to_string(v4->broadcast, bc); + kprintf(" - slot=%u l3_id=%u mode=%i ip=%s mask=%s gw=%s bcast=%s rt=%x localhost=%u", + (unsigned)s, (unsigned)v4->l3_id, (int)v4->mode, ip, mask, gw, bc, + (uint64_t)(uintptr_t)v4->rt_v4, v4->is_localhost?1:0); + } + + kprintf(" int ipv6:"); + for (int s = 0; s < (int)MAX_IPV6_PER_INTERFACE; ++s){ + l3_ipv6_interface_t* v6 = l2->l3_v6[s]; + if (!v6) continue; + char ip6[41], gw6[41]; + ipv6_to_str(v6->ip, ip6); + ipv6_to_str(v6->gateway, gw6); + uint32_t llc = (v6->kind & IPV6_ADDRK_LINK_LOCAL) ? 1u : 0u; + uint32_t gua = (v6->kind & IPV6_ADDRK_GLOBAL) ? 1u : 0u; + uint32_t en = (v6->cfg != IPV6_CFG_DISABLE) ? 1u : 0u; + kprintf(" - slot=%u l3_id=%u kind=%u cfg=%i llc=%u gua=%u en=%u ip=%s/%u gw=%s vlft=%u plft=%u tsc=%u localhost=%u", + (unsigned)s, (unsigned)v6->l3_id, (unsigned)v6->kind, (int)v6->cfg, llc, gua, en, + ip6, (unsigned)v6->prefix_len, gw6, + (unsigned)v6->valid_lifetime, (unsigned)v6->preferred_lifetime, (unsigned)v6->timestamp_created, + v6->is_localhost?1:0); + } + } + + kprintf("[net]interface dump end"); +} \ No newline at end of file diff --git a/kernel/networking/network_dispatch.hpp b/kernel/networking/network_dispatch.hpp index 99a5aabd..05728a6e 100644 --- a/kernel/networking/network_dispatch.hpp +++ b/kernel/networking/network_dispatch.hpp @@ -56,6 +56,7 @@ class NetworkDispatch { void free_frame(const sizedptr&); bool register_all_from_bus(); void copy_str(char* dst, int cap, const char* src); - + void dump_interfaces(); + int nic_for_ifindex(uint8_t ifindex) const; }; diff --git a/kernel/networking/processes/net_proc.c b/kernel/networking/processes/net_proc.c index 6a35e442..7dd506b7 100644 --- a/kernel/networking/processes/net_proc.c +++ b/kernel/networking/processes/net_proc.c @@ -29,7 +29,7 @@ extern void sleep(uint64_t ms); static uint32_t pick_probe_ip() { const net_cfg_t *cfg = ipv4_get_cfg(); - if (!cfg || cfg->mode == NET_MODE_DISABLED || cfg->ip == 0) + if (!cfg || cfg->mode == IPV4_CFG_DISABLED || cfg->ip == 0) return 0; if (cfg->gw) return cfg->gw; @@ -235,7 +235,7 @@ static void print_info() { while (!timer_is_synchronised()); const net_cfg_t *cfg = ipv4_get_cfg(); - if (cfg && cfg->mode != NET_MODE_DISABLED && cfg->ip != 0) { + if (cfg && cfg->mode != IPV4_CFG_DISABLED && cfg->ip != 0) { char ip_str[16], mask_str[16], gw_str[16]; ipv4_to_string(cfg->ip, ip_str); ipv4_to_string(cfg->mask, mask_str); @@ -271,7 +271,7 @@ static void test_net() { const net_cfg_t *cfg = ipv4_get_cfg(); net_l4_endpoint srv = {0}; - if (cfg && cfg->mode != NET_MODE_DISABLED && cfg->ip != 0) { + if (cfg && cfg->mode != IPV4_CFG_DISABLED && cfg->ip != 0) { print_info(); uint32_t bcast = ipv4_broadcast(cfg->ip, cfg->mask); @@ -308,7 +308,7 @@ static int ip_waiter_entry(int argc, char* argv[]) { (void)argc; (void)argv; for (;;) { const net_cfg_t *cfg = ipv4_get_cfg(); - if (cfg && cfg->mode != NET_MODE_DISABLED && cfg->ip != 0) { + if (cfg && cfg->mode != IPV4_CFG_DISABLED && cfg->ip != 0) { create_kernel_process("net_test", net_test_entry, 0, 0); break; } @@ -325,7 +325,7 @@ process_t* launch_net_process() { create_kernel_process("dhcp_daemon", dhcp_daemon_entry, 0, 0); create_kernel_process("dns_daemon", dns_deamon_entry, 0, 0); - if (cfg && cfg->mode != NET_MODE_DISABLED && cfg->ip != 0) { + if (cfg && cfg->mode != IPV4_CFG_DISABLED && cfg->ip != 0) { create_kernel_process("net_test", net_test_entry, 0, 0); return NULL; } diff --git a/shared/net/internet_layer/ipv4.h b/shared/net/internet_layer/ipv4.h index 5da6d4e7..7c71d16f 100644 --- a/shared/net/internet_layer/ipv4.h +++ b/shared/net/internet_layer/ipv4.h @@ -4,21 +4,11 @@ #include "net/link_layer/eth.h" #include "net/network_types.h" #include "net/checksums.h" +#include "networking/interface_manager.h" #ifdef __cplusplus extern "C" { #endif -typedef struct net_runtime_opts { - uint16_t mtu; - uint32_t t1; - uint32_t t2; - uint32_t dns[2]; - uint32_t ntp[2]; - uint16_t xid; - uint32_t server_ip; - uint32_t lease; -} net_runtime_opts_t; - typedef struct net_cfg { uint32_t ip; uint32_t mask; From 33b70422f347d1bf52c6ba84355919fbceed6c57 Mon Sep 17 00:00:00 2001 From: CodeAnarchist Date: Thu, 11 Sep 2025 02:00:55 +0200 Subject: [PATCH 10/23] net: minor fixes and warning cleanup --- kernel/networking/drivers/net_bus.cpp | 22 +++++++--------------- kernel/networking/interface_manager.c | 4 ++-- kernel/networking/interface_manager.h | 6 +++--- kernel/networking/network_dispatch.cpp | 4 ++-- shared/std/string.c | 8 ++++++++ shared/std/string.h | 1 + 6 files changed, 23 insertions(+), 22 deletions(-) diff --git a/kernel/networking/drivers/net_bus.cpp b/kernel/networking/drivers/net_bus.cpp index f2c625fe..b55e0c2f 100644 --- a/kernel/networking/drivers/net_bus.cpp +++ b/kernel/networking/drivers/net_bus.cpp @@ -1,7 +1,7 @@ #include "net_driver.hpp" #include "virtio_net_pci/virtio_net_pci.hpp" #include "pci.h" -#include "std/memory.h" +#include "std/std.h" #include "console/kio.h" #include "types.h" #include "networking/interface_manager.h" @@ -23,6 +23,7 @@ static net_nic_desc_t g_nics[MAX_L2_INTERFACES]; static size_t g_count = 0; static int g_eth_next = 0; static int g_wif_next = 0; +static int g_net_next = 0; static bool g_lo_added = false; static bool verbose = true; @@ -30,14 +31,6 @@ static void memzero(void* p, size_t n){ memset(p,0,n); } -static size_t cpystr(char* dst, size_t cap, const char* src){ - size_t i=0; - if (!dst || !src || cap==0) return 0; - while (idrv = d; - uint8_t mac[6]; d->get_mac(mac); - memcpy(e->mac, mac, 6); + d->get_mac(e->mac); e->mtu = d->get_mtu(); e->header_size = d->get_header_size(); e->kind = kind; @@ -142,8 +135,7 @@ int net_bus_init(){ make_ifname(e->ifname, sizeof(e->ifname), if_prefix); const char* hw = d->hw_ifname(); - if (hw && hw[0]) cpystr(e->hw_ifname, sizeof(e->hw_ifname), hw); - else { e->hw_ifname[0]='v'; e->hw_ifname[1]='n'; e->hw_ifname[2]='e'; e->hw_ifname[3]='t'; e->hw_ifname[4]=0; } + strcpy(e->hw_ifname, sizeof(e->hw_ifname), (hw && hw[0]) ? hw : "vnet"); kprintfv("[net-bus] added if=%s mac=%x:%x:%x:%x:%x:%x mtu=%u hdr=%u hw=%s irq_base=%u", e->ifname, e->mac[0],e->mac[1],e->mac[2],e->mac[3],e->mac[4],e->mac[5], diff --git a/kernel/networking/interface_manager.c b/kernel/networking/interface_manager.c index 3599193f..5a6563e3 100644 --- a/kernel/networking/interface_manager.c +++ b/kernel/networking/interface_manager.c @@ -366,7 +366,7 @@ l3_ipv4_interface_t* l3_ipv4_find_by_ip(uint32_t ip){ return NULL; } -uint8_t l3_ipv6_add_to_interface(uint8_t ifindex, const uint8_t ip[16], uint8_t prefix_len, const uint8_t gw[16], uint8_t cfg, uint8_t kind){ +uint8_t l3_ipv6_add_to_interface(uint8_t ifindex, const uint8_t ip[16], uint8_t prefix_len, const uint8_t gw[16], ipv6_cfg_t cfg, uint8_t kind){ l2_interface_t *l2 = l2_interface_find_by_index(ifindex); if (!l2) return 0; if (prefix_len > 128) return 0; @@ -440,7 +440,7 @@ uint8_t l3_ipv6_add_to_interface(uint8_t ifindex, const uint8_t ip[16], uint8_t return n->l3_id; } -bool l3_ipv6_update(uint8_t l3_id, const uint8_t ip[16], uint8_t prefix_len, const uint8_t gw[16], uint8_t cfg, uint8_t kind){ +bool l3_ipv6_update(uint8_t l3_id, const uint8_t ip[16], uint8_t prefix_len, const uint8_t gw[16], ipv6_cfg_t cfg, uint8_t kind){ l3_ipv6_interface_t *n = l3_ipv6_find_by_id(l3_id); if (!n) return false; l2_interface_t *l2 = n->l2; diff --git a/kernel/networking/interface_manager.h b/kernel/networking/interface_manager.h index ca84a8e3..55dba680 100644 --- a/kernel/networking/interface_manager.h +++ b/kernel/networking/interface_manager.h @@ -82,7 +82,7 @@ typedef struct l3_ipv6_interface { uint8_t prefix_len; uint8_t gateway[16]; uint8_t kind; - uint8_t cfg; + ipv6_cfg_t cfg; bool is_localhost; uint32_t valid_lifetime; uint32_t preferred_lifetime; @@ -118,8 +118,8 @@ bool l3_ipv4_remove_from_interface(uint8_t l3_id); l3_ipv4_interface_t *l3_ipv4_find_by_id(uint8_t l3_id); l3_ipv4_interface_t *l3_ipv4_find_by_ip(uint32_t ip); -uint8_t l3_ipv6_add_to_interface(uint8_t ifindex, const uint8_t ip[16], uint8_t prefix_len, const uint8_t gw[16], uint8_t cfg, uint8_t kind); -bool l3_ipv6_update(uint8_t l3_id, const uint8_t ip[16], uint8_t prefix_len, const uint8_t gw[16], uint8_t cfg, uint8_t kind); +uint8_t l3_ipv6_add_to_interface(uint8_t ifindex, const uint8_t ip[16], uint8_t prefix_len, const uint8_t gw[16], ipv6_cfg_t cfg, uint8_t kind); +bool l3_ipv6_update(uint8_t l3_id, const uint8_t ip[16], uint8_t prefix_len, const uint8_t gw[16], ipv6_cfg_t cfg, uint8_t kind); bool l3_ipv6_remove_from_interface(uint8_t l3_id); bool l3_ipv6_set_enabled(uint8_t l3_id, bool enable); l3_ipv6_interface_t *l3_ipv6_find_by_id(uint8_t l3_id); diff --git a/kernel/networking/network_dispatch.cpp b/kernel/networking/network_dispatch.cpp index 5d5051e0..0f069ff2 100644 --- a/kernel/networking/network_dispatch.cpp +++ b/kernel/networking/network_dispatch.cpp @@ -288,8 +288,8 @@ void NetworkDispatch::dump_interfaces() kprintf(" driver: nic_id=%u ifname=%s hw=%s mtu=%u hdr=%u mac=%s drv=%x", (unsigned)nid, - nics[nid].ifname_str ? nics[nid].ifname_str : (char*)"(null)", - nics[nid].hwname_str ? nics[nid].hwname_str : (char*)"(null)", + nics[nid].ifname_str[0] ? nics[nid].ifname_str : "(null)", + nics[nid].hwname_str[0] ? nics[nid].hwname_str : "(null)", (unsigned)nics[nid].mtu_val, (unsigned)nics[nid].hdr_sz, macs, (uint64_t)(uintptr_t)nics[nid].drv); } else { diff --git a/shared/std/string.c b/shared/std/string.c index 15afbde3..fff2a8a4 100644 --- a/shared/std/string.c +++ b/shared/std/string.c @@ -429,4 +429,12 @@ const char* seek_to(const char *string, char character){ string++; string++; return string; +} + +size_t strcpy(char* dst, size_t cap, const char* src){ + size_t i=0; + if (!dst || !src || cap==0) return 0; + while (i Date: Thu, 11 Sep 2025 02:38:41 +0200 Subject: [PATCH 11/23] net: fixed crash caused by network, minor bug fixes --- .../drivers/virtio_net_pci/virtio_net_pci.cpp | 5 +++- shared/net/application_layer/dhcp.c | 2 +- shared/net/application_layer/dhcp_daemon.c | 28 +++++++++---------- shared/net/internet_layer/icmp.c | 8 +++--- shared/net/internet_layer/ipv4.c | 14 +++++----- shared/net/link_layer/arp.c | 22 +++++++-------- shared/net/link_layer/eth.c | 4 +-- 7 files changed, 43 insertions(+), 40 deletions(-) diff --git a/kernel/networking/drivers/virtio_net_pci/virtio_net_pci.cpp b/kernel/networking/drivers/virtio_net_pci/virtio_net_pci.cpp index 683eb60e..1f70f145 100644 --- a/kernel/networking/drivers/virtio_net_pci/virtio_net_pci.cpp +++ b/kernel/networking/drivers/virtio_net_pci/virtio_net_pci.cpp @@ -59,7 +59,10 @@ bool VirtioNetDriver::init_at(uint64_t addr, uint32_t irq_base_vector){ virtio_get_capabilities(&vnp_net_dev, addr, &mmio_addr, &mmio_size); kprintfv("[virtio-net] mmio=%x size=%x",(uintptr_t)mmio_addr,(uintptr_t)mmio_size); - pci_register(mmio_addr, mmio_size); + if (vnp_net_dev.common_cfg) pci_register(((uintptr_t)vnp_net_dev.common_cfg) & ~(uintptr_t)(PAGE_SIZE-1), PAGE_SIZE); + if (vnp_net_dev.device_cfg) pci_register(((uintptr_t)vnp_net_dev.device_cfg) & ~(uintptr_t)(PAGE_SIZE-1), PAGE_SIZE); + if (vnp_net_dev.notify_cfg) pci_register(((uintptr_t)vnp_net_dev.notify_cfg) & ~(uintptr_t)(PAGE_SIZE-1), PAGE_SIZE); + if (vnp_net_dev.isr_cfg) pci_register(((uintptr_t)vnp_net_dev.isr_cfg) & ~(uintptr_t)(PAGE_SIZE-1), PAGE_SIZE); uint8_t interrupts_ok = pci_setup_interrupts(addr, irq_base_vector, 2); if (!interrupts_ok){ diff --git a/shared/net/application_layer/dhcp.c b/shared/net/application_layer/dhcp.c index d19cfa84..b5c7e475 100644 --- a/shared/net/application_layer/dhcp.c +++ b/shared/net/application_layer/dhcp.c @@ -18,7 +18,7 @@ sizedptr dhcp_build_packet(const dhcp_request *req, p.op = 1; p.htype = 1; p.hlen = 6; p.hops = 0; p.xid = xid; p.secs = 0; - p.flags = __builtin_bswap16(0x8000); + p.flags = bswap16(0x8000); p.ciaddr = 0; p.yiaddr = 0; p.siaddr = 0; p.giaddr = 0; memcpy(p.chaddr, req->mac, 6); diff --git a/shared/net/application_layer/dhcp_daemon.c b/shared/net/application_layer/dhcp_daemon.c index d4058cd8..e2c9f485 100644 --- a/shared/net/application_layer/dhcp_daemon.c +++ b/shared/net/application_layer/dhcp_daemon.c @@ -81,7 +81,7 @@ static void dhcp_send_request(const dhcp_request *req, uint32_t xid, bool broadcast) { - uint32_t dst = broadcast ? 0xFFFFFFFFu : __builtin_bswap32(req->server_ip); + uint32_t dst = broadcast ? 0xFFFFFFFFu : bswap32(req->server_ip); //kprintf("[DHCP] request xid=%i dst=%x\n", (uint64_t)xid, (uint64_t)dst); dhcp_tx_packet(req, DHCPREQUEST, xid, dst); } @@ -90,9 +90,9 @@ static void dhcp_send_renew(uint32_t xid) { const net_cfg_t *cfg = ipv4_get_cfg(); dhcp_request req = {0}; memcpy(req.mac, g_local_mac, 6); - req.offered_ip = __builtin_bswap32(cfg->ip); + req.offered_ip = bswap32(cfg->ip); req.server_ip = cfg->rt ? cfg->rt->server_ip : 0; - uint32_t dst = req.server_ip ? __builtin_bswap32(req.server_ip) : 0xFFFFFFFFu; + uint32_t dst = req.server_ip ? bswap32(req.server_ip) : 0xFFFFFFFFu; kprintf("[DHCP] renew xid=%i dst=%x", xid, dst); dhcp_tx_packet(&req, DHCPREQUEST, xid, dst); } @@ -101,7 +101,7 @@ static void dhcp_send_rebind(uint32_t xid) { const net_cfg_t *cfg = ipv4_get_cfg(); dhcp_request req = {0}; memcpy(req.mac, g_local_mac, 6); - req.offered_ip = __builtin_bswap32(cfg->ip); + req.offered_ip = bswap32(cfg->ip); req.server_ip = 0; kprintf("[DHCP] rebind xid=%i", xid); dhcp_tx_packet(&req, DHCPREQUEST, xid, 0xFFFFFFFFu); @@ -269,7 +269,7 @@ static void dhcp_apply_offer(dhcp_packet *p, dhcp_request *req, uint32_t xid) { cfg_local.mode = 0; //NET_MODE_DHCP uint32_t yi_net = p->yiaddr; - cfg_local.ip = __builtin_bswap32(yi_net); + cfg_local.ip = bswap32(yi_net); req->offered_ip = yi_net; uint16_t idx; @@ -279,14 +279,14 @@ static void dhcp_apply_offer(dhcp_packet *p, dhcp_request *req, uint32_t xid) { if (idx != UINT16_MAX && (len = p->options[idx+1]) >= 4) { uint32_t mask_net; memcpy(&mask_net, &p->options[idx+2], 4); - cfg_local.mask = __builtin_bswap32(mask_net); + cfg_local.mask = bswap32(mask_net); } idx = dhcp_parse_option(p, 3); if (idx != UINT16_MAX && (len = p->options[idx+1]) >= 4) { uint32_t gw_net; memcpy(&gw_net, &p->options[idx+2], 4); - cfg_local.gw = __builtin_bswap32(gw_net); + cfg_local.gw = bswap32(gw_net); } idx = dhcp_parse_option(p, 6); @@ -295,7 +295,7 @@ static void dhcp_apply_offer(dhcp_packet *p, dhcp_request *req, uint32_t xid) { for (int i = 0; i < 2 && (i*4 + 4) <= len; ++i) { uint32_t dns_net; memcpy(&dns_net, &p->options[idx+2 + i*4], 4); - cfg_local.rt->dns[i] = __builtin_bswap32(dns_net); + cfg_local.rt->dns[i] = bswap32(dns_net); } } @@ -305,7 +305,7 @@ static void dhcp_apply_offer(dhcp_packet *p, dhcp_request *req, uint32_t xid) { for (int i = 0; i < 2 && (i*4 + 4) <= len; ++i) { uint32_t ntp_net; memcpy(&ntp_net, &p->options[idx+2 + i*4], 4); - cfg_local.rt->ntp[i] = __builtin_bswap32(ntp_net); + cfg_local.rt->ntp[i] = bswap32(ntp_net); } } @@ -313,21 +313,21 @@ static void dhcp_apply_offer(dhcp_packet *p, dhcp_request *req, uint32_t xid) { if (idx != UINT16_MAX && p->options[idx+1] == 2) { uint16_t mtu_net; memcpy(&mtu_net, &p->options[idx+2], 2); - cfg_local.rt->mtu = __builtin_bswap16(mtu_net); + cfg_local.rt->mtu = bswap16(mtu_net); } idx = dhcp_parse_option(p, 51); if (idx != UINT16_MAX && p->options[idx+1] >= 4) { uint32_t lease_net; memcpy(&lease_net, &p->options[idx+2], 4); - cfg_local.rt->lease = __builtin_bswap32(lease_net); + cfg_local.rt->lease = bswap32(lease_net); } idx = dhcp_parse_option(p, 58); if (idx != UINT16_MAX && p->options[idx+1] >= 4) { uint32_t t1_net; memcpy(&t1_net, &p->options[idx+2], 4); - cfg_local.rt->t1 = __builtin_bswap32(t1_net); + cfg_local.rt->t1 = bswap32(t1_net); }else { cfg_local.rt->t1 = cfg_local.rt->lease / 2; } @@ -336,7 +336,7 @@ static void dhcp_apply_offer(dhcp_packet *p, dhcp_request *req, uint32_t xid) { if (idx != UINT16_MAX && p->options[idx+1] >= 4) { uint32_t t2_net; memcpy(&t2_net, &p->options[idx+2], 4); - cfg_local.rt->t2 = __builtin_bswap32(t2_net); + cfg_local.rt->t2 = bswap32(t2_net); } else { cfg_local.rt->t2 = (cfg_local.rt->lease / 8) * 7; } @@ -345,7 +345,7 @@ static void dhcp_apply_offer(dhcp_packet *p, dhcp_request *req, uint32_t xid) { if (idx != UINT16_MAX && p->options[idx+1] >= 4) { uint32_t srv_net; memcpy(&srv_net, &p->options[idx+2], 4); - cfg_local.rt->server_ip = __builtin_bswap32(srv_net); + cfg_local.rt->server_ip = bswap32(srv_net); req->server_ip = srv_net; } diff --git a/shared/net/internet_layer/icmp.c b/shared/net/internet_layer/icmp.c index 5522b842..c67c1d2c 100644 --- a/shared/net/internet_layer/icmp.c +++ b/shared/net/internet_layer/icmp.c @@ -47,8 +47,8 @@ void create_icmp_packet(uintptr_t p, icmp_packet *pkt = (icmp_packet*)p; pkt->type = d->response ? ICMP_ECHO_REPLY : ICMP_ECHO_REQUEST; pkt->code = 0; - pkt->id = __builtin_bswap16(d->id); - pkt->seq = __builtin_bswap16(d->seq); + pkt->id = bswap16(d->id); + pkt->seq = bswap16(d->seq); memset(pkt->payload, 0, sizeof(pkt->payload)); memcpy(pkt->payload, d->payload, sizeof(pkt->payload)); @@ -95,8 +95,8 @@ void icmp_input(uintptr_t ptr, pkt->checksum = recv_ck; uint8_t type = pkt->type; - uint16_t id = __builtin_bswap16(pkt->id); - uint16_t sq = __builtin_bswap16(pkt->seq); + uint16_t id = bswap16(pkt->id); + uint16_t sq = bswap16(pkt->seq); uint32_t pay = len - 8; if(pay > 56) pay = 56; diff --git a/shared/net/internet_layer/ipv4.c b/shared/net/internet_layer/ipv4.c index fb801c67..3f7b2cc7 100644 --- a/shared/net/internet_layer/ipv4.c +++ b/shared/net/internet_layer/ipv4.c @@ -123,14 +123,14 @@ void ip_input(uintptr_t ip_ptr, hdr->header_checksum = recv_ck; } - uint32_t sip = __builtin_bswap32(hdr->src_ip); + uint32_t sip = bswap32(hdr->src_ip); arp_table_put(sip, src_mac, 60000, false); - uint32_t dip = __builtin_bswap32(hdr->dst_ip); + uint32_t dip = bswap32(hdr->dst_ip); //TODO manage special ip uintptr_t payload_ptr = ip_ptr + header_bytes; - uint32_t payload_len = __builtin_bswap16(hdr->total_length) - header_bytes; + uint32_t payload_len = bswap16(hdr->total_length) - header_bytes; switch (hdr->protocol) { case 1://icmp icmp_input(payload_ptr, payload_len, sip, dip); @@ -175,13 +175,13 @@ void ipv4_send_packet(uint32_t src_ip, ipv4_hdr_t *ip = (ipv4_hdr_t *)ip_buf; ip->version_ihl = (4 << 4) | (sizeof(*ip)/4); ip->dscp_ecn = 0; - ip->total_length = __builtin_bswap16(ip_len); + ip->total_length = bswap16(ip_len); ip->identification = 0; - ip->flags_frag_offset = __builtin_bswap16(0x4000); + ip->flags_frag_offset = bswap16(0x4000); ip->ttl = 64; ip->protocol = proto; - ip->src_ip = __builtin_bswap32(src_ip); - ip->dst_ip = __builtin_bswap32(dst_ip); + ip->src_ip = bswap32(src_ip); + ip->dst_ip = bswap32(dst_ip); ip->header_checksum = 0; ip->header_checksum = ipv4_checksum(ip, sizeof(*ip)); diff --git a/shared/net/link_layer/arp.c b/shared/net/link_layer/arp.c index 726d1da6..7589be54 100644 --- a/shared/net/link_layer/arp.c +++ b/shared/net/link_layer/arp.c @@ -109,14 +109,14 @@ void arp_send_request(uint32_t target_ip) { arp_hdr_t hdr; memset(hdr.target_mac, 0x00, sizeof(hdr.target_mac)); - hdr.htype = __builtin_bswap16(1); - hdr.ptype = __builtin_bswap16(0x0800); + hdr.htype = bswap16(1); + hdr.ptype = bswap16(0x0800); hdr.hlen = 6; hdr.plen = 4; - hdr.opcode = __builtin_bswap16(ARP_OPCODE_REQUEST); + hdr.opcode = bswap16(ARP_OPCODE_REQUEST); memcpy(hdr.sender_mac, local_mac, 6); - hdr.sender_ip = __builtin_bswap32(cfg->ip); - hdr.target_ip = __builtin_bswap32(target_ip); + hdr.sender_ip = bswap32(cfg->ip); + hdr.target_ip = bswap32(target_ip); sizedptr payload = { (uintptr_t)&hdr, sizeof(hdr) }; uintptr_t buf = (uintptr_t)malloc(sizeof(hdr)); @@ -130,12 +130,12 @@ void arp_send_request(uint32_t target_ip) { } bool arp_should_handle(const arp_hdr_t *arp, uint32_t my_ip) { - return __builtin_bswap32(arp->target_ip) == my_ip; + return bswap32(arp->target_ip) == my_ip; } void arp_populate_response(uint8_t out_mac[6], uint32_t *out_ip, const arp_hdr_t *arp) { if (out_mac) memcpy(out_mac, arp->sender_mac, 6); - if (out_ip) *out_ip = __builtin_bswap32(arp->sender_ip); + if (out_ip) *out_ip = bswap32(arp->sender_ip); } bool arp_can_reply() { @@ -173,8 +173,8 @@ static void arp_send_reply(const arp_hdr_t *in_arp, memcpy(reply.target_mac, in_arp->sender_mac, 6); memcpy(reply.sender_mac, local_mac, 6); reply.target_ip = in_arp->sender_ip; - reply.sender_ip = __builtin_bswap32(cfg->ip); - reply.opcode = __builtin_bswap16(ARP_OPCODE_REPLY); + reply.sender_ip = bswap32(cfg->ip); + reply.opcode = bswap16(ARP_OPCODE_REPLY); sizedptr payload = {(uintptr_t)&reply, sizeof(reply)}; @@ -192,14 +192,14 @@ void arp_input(uintptr_t frame_ptr, uint32_t frame_len) { if (!init) return; arp_hdr_t *hdr = (arp_hdr_t*)(frame_ptr + sizeof(eth_hdr_t)); - uint32_t sender_ip = __builtin_bswap32(hdr->sender_ip); + uint32_t sender_ip = bswap32(hdr->sender_ip); arp_table_put(sender_ip, hdr->sender_mac, 180000, false); const net_cfg_t *cfg = ipv4_get_cfg(); if (!cfg) return; - if (__builtin_bswap16(hdr->opcode) == ARP_OPCODE_REQUEST && + if (bswap16(hdr->opcode) == ARP_OPCODE_REQUEST && arp_should_handle(hdr, cfg->ip) && arp_can_reply()) { diff --git a/shared/net/link_layer/eth.c b/shared/net/link_layer/eth.c index 48e11662..ec87ad9c 100644 --- a/shared/net/link_layer/eth.c +++ b/shared/net/link_layer/eth.c @@ -16,13 +16,13 @@ uintptr_t create_eth_packet(uintptr_t p, eth_hdr_t* eth =(eth_hdr_t*)p; memcpy(eth->src_mac, src_mac, 6); memcpy(eth->dst_mac, dst_mac, 6); - eth->ethertype = __builtin_bswap16(type); + eth->ethertype = bswap16(type); return p + sizeof(eth_hdr_t); } uint16_t eth_parse_packet_type(uintptr_t ptr) { const eth_hdr_t* eth = (const eth_hdr_t*)ptr; - return __builtin_bswap16(eth->ethertype); + return bswap16(eth->ethertype); } const uint8_t* eth_get_source(uintptr_t ptr){ From 570ac5018f2e4c4695ce4b0a2822af93f7eb0dff Mon Sep 17 00:00:00 2001 From: CodeAnarchist Date: Fri, 12 Sep 2025 00:23:38 +0200 Subject: [PATCH 12/23] net: dhcp interface management --- kernel/networking/interface_manager.c | 46 ++++++++++++++++++++++++--- 1 file changed, 42 insertions(+), 4 deletions(-) diff --git a/kernel/networking/interface_manager.c b/kernel/networking/interface_manager.c index 5a6563e3..2151401d 100644 --- a/kernel/networking/interface_manager.c +++ b/kernel/networking/interface_manager.c @@ -99,6 +99,17 @@ static inline uint8_t make_l3_id(uint8_t ifindex, uint8_t local_slot){ return (u static inline uint8_t l3_ifindex_from_id(uint8_t l3_id){ return (uint8_t)((l3_id >> 4) & 0x0F); } static inline uint8_t l3_local_slot_from_id(uint8_t l3_id){ return (uint8_t)(l3_id & 0x0F); } +static bool v4_has_dhcp_on_l2(uint8_t ifindex){ + for (int i = 0; i < V4_POOL_SIZE; i++){ + if (!g_v4[i].used) continue; + l3_ipv4_interface_t *x = &g_v4[i].node; + if (!x->l2) continue; + if (x->l2->ifindex != ifindex) continue; + if (x->mode == IPV4_CFG_DHCP) return true; + } + return false; +} + uint8_t l2_interface_create(const char *name, void *driver_ctx) { int slot = find_free_l2_slot(); if (slot < 0) return 0; @@ -264,6 +275,13 @@ static int alloc_global_v6_slot(void){ for (int i=0;iipv4_count >= MAX_IPV4_PER_INTERFACE) return 0; int loc = alloc_local_slot_v4(l2); int g = alloc_global_v4_slot(); @@ -300,8 +319,16 @@ uint8_t l3_ipv4_add_to_interface(uint8_t ifindex, uint32_t ip, uint32_t mask, ui bool l3_ipv4_update(uint8_t l3_id, uint32_t ip, uint32_t mask, uint32_t gw, ipv4_cfg_t mode, net_runtime_opts_t *rt){ l3_ipv4_interface_t *n = l3_ipv4_find_by_id(l3_id); if (!n) return false; + l2_interface_t *l2 = n->l2; if (!l2) return false; + + if (mode == IPV4_CFG_DHCP && n->mode != IPV4_CFG_DHCP) { + if (v4_has_dhcp_on_l2(l2->ifindex)) { + return false; + } + } + if (mode == IPV4_CFG_STATIC){ if (ipv4_is_unspecified(ip)) return false; if (!is_power2_mask_contiguous(mask)) return false; @@ -311,27 +338,38 @@ bool l3_ipv4_update(uint8_t l3_id, uint32_t ip, uint32_t mask, uint32_t gw, ipv4 if (ipv4_is_network_address(ip, mask)) return false; if (ipv4_is_broadcast_address(ip, mask)) return false; if (ip != n->ip && v4_ip_exists_anywhere(ip)) return false; - for (int i=0;il2 || x->l2->ifindex != l2->ifindex) continue; if (x->mode == IPV4_CFG_DISABLED) continue; + uint32_t m = (x->mask < mask) ? x->mask : mask; if (ipv4_net(ip, m) == ipv4_net(x->ip, m)) return false; } } + n->mode = mode; n->rt_v4 = rt; - if (mode == IPV4_CFG_STATIC){ - n->ip = ip; n->mask = mask; n->gw = gw; + + if (mode == IPV4_CFG_STATIC) { + n->ip = ip; + n->mask = mask; + n->gw = gw; n->broadcast = ipv4_broadcast_calc(ip, mask); } else { - n->ip = 0; n->mask = 0; n->gw = 0; n->broadcast = 0; + n->ip = 0; + n->mask = 0; + n->gw = 0; + n->broadcast = 0; } + return true; } + bool l3_ipv4_remove_from_interface(uint8_t l3_id){ l3_ipv4_interface_t *n = l3_ipv4_find_by_id(l3_id); if (!n) return false; From 333b049d16d694a211d27892d803642a9a06e764 Mon Sep 17 00:00:00 2001 From: CodeAnarchist Date: Wed, 17 Sep 2025 00:49:02 +0200 Subject: [PATCH 13/23] net: refactor link-layer and internet-layer --- kernel/networking/drivers/net_bus.cpp | 31 +- kernel/networking/drivers/net_bus.hpp | 12 +- kernel/networking/drivers/net_driver.hpp | 3 +- .../drivers/virtio_net_pci/virtio_net_pci.cpp | 101 ++-- .../drivers/virtio_net_pci/virtio_net_pci.hpp | 66 ++- kernel/networking/interface_manager.c | 47 +- kernel/networking/interface_manager.h | 9 +- kernel/networking/network_dispatch.cpp | 77 ++- kernel/networking/network_dispatch.hpp | 7 + kernel/networking/processes/net_proc.c | 9 +- run_virt | 2 +- shared/net/application_layer/dhcp_daemon.c | 4 +- shared/net/internet_layer/icmp.c | 38 +- shared/net/internet_layer/ipv4.c | 535 +++++++++++++----- shared/net/internet_layer/ipv4.h | 51 +- shared/net/internet_layer/ipv4_route.c | 125 ++-- shared/net/internet_layer/ipv4_route.h | 28 +- shared/net/link_layer/arp.c | 293 +++++----- shared/net/link_layer/arp.h | 39 +- shared/net/link_layer/eth.c | 65 ++- shared/net/link_layer/eth.h | 17 +- shared/net/transport_layer/tcp.c | 2 +- shared/net/transport_layer/udp.c | 3 +- 23 files changed, 1030 insertions(+), 534 deletions(-) diff --git a/kernel/networking/drivers/net_bus.cpp b/kernel/networking/drivers/net_bus.cpp index b55e0c2f..bc6ffb35 100644 --- a/kernel/networking/drivers/net_bus.cpp +++ b/kernel/networking/drivers/net_bus.cpp @@ -1,3 +1,4 @@ +#include "net_bus.hpp" #include "net_driver.hpp" #include "virtio_net_pci/virtio_net_pci.hpp" #include "pci.h" @@ -17,6 +18,8 @@ typedef struct { uint16_t mtu; uint16_t header_size; uint8_t kind; + uint32_t speed_mbps; + uint8_t duplex; } net_nic_desc_t; static net_nic_desc_t g_nics[MAX_L2_INTERFACES]; @@ -66,7 +69,9 @@ static void add_loopback(){ memzero(d->mac,6); d->mtu = 65535; d->header_size = 0; - d->kind = 2; + d->kind = NET_IFK_LOCALHOST; + d->speed_mbps = 0xFFFFFFFFu; + d->duplex = NET_IFK_LOCALHOST; g_lo_added = true; kprintfv("[net-bus] added loopback ifname=%s",d->ifname); } @@ -107,9 +112,8 @@ int net_bus_init(){ (unsigned)i, ven, dev, cls, sub, infos[i].prog_if, (uintptr_t)infos[i].addr); const char* if_prefix = "net"; - uint8_t kind = 1; - if (sub == 0x00){ if_prefix = "eth"; kind = 0; } - else if (sub == 0x80){ if_prefix = "net"; kind = 1; } + uint8_t kind = NET_IFK_OTHER; + if (sub == 0x00){ if_prefix = "eth"; kind = NET_IFK_ETH; } bool matched = false; @@ -131,15 +135,18 @@ int net_bus_init(){ e->mtu = d->get_mtu(); e->header_size = d->get_header_size(); e->kind = kind; + e->speed_mbps = d->get_speed_mbps(); + e->duplex = d->get_duplex(); make_ifname(e->ifname, sizeof(e->ifname), if_prefix); const char* hw = d->hw_ifname(); strcpy(e->hw_ifname, sizeof(e->hw_ifname), (hw && hw[0]) ? hw : "vnet"); - kprintfv("[net-bus] added if=%s mac=%x:%x:%x:%x:%x:%x mtu=%u hdr=%u hw=%s irq_base=%u", + kprintfv("[net-bus] added if=%s mac=%x:%x:%x:%x:%x:%x mtu=%u hdr=%u hw=%s irq_base=%u spd=%u dup=%u", e->ifname, e->mac[0],e->mac[1],e->mac[2],e->mac[3],e->mac[4],e->mac[5], - e->mtu, e->header_size, e->hw_ifname, (unsigned)irq_base); + e->mtu, e->header_size, e->hw_ifname, (unsigned)irq_base, + (unsigned)e->speed_mbps, (unsigned)e->duplex); nic_ord += 1; matched = true; @@ -197,6 +204,16 @@ uint16_t net_bus_get_header_size(int idx){ } uint8_t net_bus_get_kind(int idx){ - if (idx < 0 || (size_t)idx >= g_count) return 0xFF; + if (idx < 0 || (size_t)idx >= g_count) return NET_IFK_UNKNOWN; return g_nics[idx].kind; } + +uint32_t net_bus_get_speed_mbps(int idx){ + if (idx < 0 || (size_t)idx >= g_count) return 0xFFFFFFFFu; + return g_nics[idx].speed_mbps; +} + +uint8_t net_bus_get_duplex(int idx){ + if (idx < 0 || (size_t)idx >= g_count) return 0xFFu; + return g_nics[idx].duplex; +} diff --git a/kernel/networking/drivers/net_bus.hpp b/kernel/networking/drivers/net_bus.hpp index 7dbcc62d..4d27bfe2 100644 --- a/kernel/networking/drivers/net_bus.hpp +++ b/kernel/networking/drivers/net_bus.hpp @@ -1,6 +1,14 @@ #pragma once #include "net_driver.hpp" +enum NetIfKind : uint8_t { + NET_IFK_ETH = 0x00, + NET_IFK_WIFI = 0x01, + NET_IFK_OTHER = 0x02, + NET_IFK_LOCALHOST = 0xFE, + NET_IFK_UNKNOWN = 0xFF +}; + int net_bus_init(); int net_bus_count(); NetDriver* net_bus_driver(int idx); @@ -9,4 +17,6 @@ const char* net_bus_hw_ifname(int idx); void net_bus_get_mac(int idx, uint8_t out_mac[6]); uint16_t net_bus_get_mtu(int idx); uint16_t net_bus_get_header_size(int idx); -uint8_t net_bus_get_kind(int idx); \ No newline at end of file +uint8_t net_bus_get_kind(int idx); +uint32_t net_bus_get_speed_mbps(int idx); +uint8_t net_bus_get_duplex(int idx); \ No newline at end of file diff --git a/kernel/networking/drivers/net_driver.hpp b/kernel/networking/drivers/net_driver.hpp index a9449a47..0b62a375 100644 --- a/kernel/networking/drivers/net_driver.hpp +++ b/kernel/networking/drivers/net_driver.hpp @@ -15,6 +15,7 @@ class NetDriver { virtual void get_mac(uint8_t out_mac[6]) const = 0; virtual uint16_t get_mtu() const = 0; virtual uint16_t get_header_size() const = 0; - virtual const char* if_prefix() const = 0; virtual const char* hw_ifname() const = 0; + virtual uint32_t get_speed_mbps() const = 0; + virtual uint8_t get_duplex() const = 0; }; diff --git a/kernel/networking/drivers/virtio_net_pci/virtio_net_pci.cpp b/kernel/networking/drivers/virtio_net_pci/virtio_net_pci.cpp index 1f70f145..888154a3 100644 --- a/kernel/networking/drivers/virtio_net_pci/virtio_net_pci.cpp +++ b/kernel/networking/drivers/virtio_net_pci/virtio_net_pci.cpp @@ -20,33 +20,14 @@ static uint16_t g_rx_qsz = 0; kprintf(fmt, ##__VA_ARGS__); \ }\ }) -typedef struct __attribute__((packed)) virtio_net_hdr_t { - uint8_t flags; - uint8_t gso_type; - uint16_t hdr_len; - uint16_t gso_size; - uint16_t csum_start; - uint16_t csum_offset; -} virtio_net_hdr_t; - -typedef struct virtio_net_config { - uint8_t mac[6]; - uint16_t status; - uint16_t max_virtqueue_pairs; - uint16_t mtu; - uint32_t speed; - uint8_t duplex; - uint8_t rss_max_key_size; - uint16_t rss_max_indirection_table_length; - uint32_t supported_hash_types; -}__attribute__((packed)) virtio_net_config; - VirtioNetDriver::VirtioNetDriver() { verbose = false; - last_used_receive_idx = 0; - last_used_sent_idx = 0; header_size = sizeof(virtio_net_hdr_t); mtu = 1500; + speed_mbps = 0xFFFFFFFFu; + duplex = LinkDuplex::Unknown; + last_used_receive_idx = 0; + last_used_sent_idx = 0; hw_name[0] = 0; } @@ -112,35 +93,34 @@ bool VirtioNetDriver::init_at(uint64_t addr, uint32_t irq_base_vector){ virtio_net_config* cfg = (virtio_net_config*)vnp_net_dev.device_cfg; - uint64_t feats = 0; - #ifdef VIRTIO_NEGOTIATED_FEATURES_FIELD - feats = vnp_net_dev.negotiated_features; - #elif defined(VIRTIO_DEVICE_FEATURES_FIELD) - feats = vnp_net_dev.device_features; - #endif - - bool has_mtu_feat = false; - bool has_mrg_rx = false; - #ifdef VIRTIO_NET_F_MTU - has_mtu_feat = (feats & (1ull << VIRTIO_NET_F_MTU)) != 0; - #endif - #ifdef VIRTIO_NET_F_MRG_RXBUF - has_mrg_rx = (feats & (1ull << VIRTIO_NET_F_MRG_RXBUF)) != 0; - #endif + uint8_t mac[6]; get_mac(mac); + uint16_t dev_mtu = cfg->mtu; - if (has_mtu_feat && dev_mtu && dev_mtu != 0xFFFF && dev_mtu >= 576){ - mtu = dev_mtu; - } else { - mtu = 1500; + if (dev_mtu != 0 && dev_mtu != 0xFFFF && dev_mtu >= 576) mtu = dev_mtu; else mtu = 1500; + + header_size = sizeof(virtio_net_hdr_t); + + speed_mbps = cfg->speed; + switch (cfg->duplex) { + case 0: duplex = LinkDuplex::Half; break; + case 1: duplex = LinkDuplex::Full; break; + default: duplex = LinkDuplex::Unknown; break; } - header_size = has_mrg_rx ? 12 : 10; - uint8_t mac[6]; get_mac(mac); - kprintfv("[virtio-net] mac=%x:%x:%x:%x:%x:%x mtu=%u hdr=%u", - mac[0],mac[1],mac[2],mac[3],mac[4],mac[5],mtu,header_size); + hw_name[0] = 'v'; hw_name[1] = 'i'; hw_name[2] = 'r'; hw_name[3] = 't'; hw_name[4] = 'i'; hw_name[5] = 'o'; hw_name[6] = 0; + + const char* dpx_str = (duplex == LinkDuplex::Full) ? "full" : (duplex == LinkDuplex::Half) ? "half" : "unknown"; + if (speed_mbps != 0xFFFFFFFF) { + kprintfv("[virtio-net] mac=%x:%x:%x:%x:%x:%x mtu=%u hdr=%u speed=%uMbps duplex=%s", + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5], + (unsigned)mtu, (unsigned)header_size, (unsigned)speed_mbps, dpx_str); + } else { + kprintfv("[virtio-net] mac=%x:%x:%x:%x:%x:%x mtu=%u hdr=%u speed=unknown duplex=%s", + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5], + (unsigned)mtu, (unsigned)header_size, dpx_str); + } - hw_name[0]='v'; hw_name[1]='i'; hw_name[2]='r'; hw_name[3]='t'; hw_name[4]='i'; hw_name[5]='o'; hw_name[6]=0; return true; } @@ -159,14 +139,20 @@ uint16_t VirtioNetDriver::get_header_size() const { return header_size; } -const char* VirtioNetDriver::if_prefix() const { - return "eth"; -} - const char* VirtioNetDriver::hw_ifname() const { return hw_name; } +uint32_t VirtioNetDriver::get_speed_mbps() const { return speed_mbps; } + +uint8_t VirtioNetDriver::get_duplex() const { + switch (duplex) { + case LinkDuplex::Half: return 0; + case LinkDuplex::Full: return 1; + default: return 0xFF; + } +} + sizedptr VirtioNetDriver::allocate_packet(size_t size){ return (sizedptr){(uintptr_t)kalloc(vnp_net_dev.memory_page, size + header_size, ALIGN_64B, MEM_PRIV_KERNEL), size + header_size}; } @@ -186,13 +172,16 @@ sizedptr VirtioNetDriver::handle_receive_packet(){ uint16_t used_ring_index = (uint16_t)(last_used_receive_idx % qsz); struct virtq_used_elem* e = &used->ring[used_ring_index]; last_used_receive_idx++; + uint32_t desc_index = e->id; uint32_t len = e->len; if (desc_index >= qsz || len <= header_size) - {avail->ring[avail->idx % qsz] = (uint16_t)desc_index; - avail->idx++; - *(volatile uint16_t*)(uintptr_t)(vnp_net_dev.notify_cfg + vnp_net_dev.notify_off_multiplier * RECEIVE_QUEUE) = 0; - return (sizedptr){0,0};} + { + avail->ring[avail->idx % qsz] = (uint16_t)desc_index; + avail->idx++; + *(volatile uint16_t*)(uintptr_t)(vnp_net_dev.notify_cfg + vnp_net_dev.notify_off_multiplier * RECEIVE_QUEUE) = 0; + return (sizedptr){0,0}; + } uintptr_t packet_addr = desc[desc_index].addr; uint32_t payload_len = len - header_size; @@ -239,7 +228,7 @@ void VirtioNetDriver::send_packet(sizedptr packet){ if (packet.ptr && packet.size){ if (header_size <= packet.size) memset((void*)packet.ptr, 0, header_size); virtio_send_1d(&vnp_net_dev, packet.ptr, packet.size); - kprintfv("[virtio-net] tx queued len=%u\n",(unsigned)packet.size); + kprintfv("[virtio-net] tx queued len=%u",(unsigned)packet.size); } } diff --git a/kernel/networking/drivers/virtio_net_pci/virtio_net_pci.hpp b/kernel/networking/drivers/virtio_net_pci/virtio_net_pci.hpp index 22fc45a0..b683c084 100644 --- a/kernel/networking/drivers/virtio_net_pci/virtio_net_pci.hpp +++ b/kernel/networking/drivers/virtio_net_pci/virtio_net_pci.hpp @@ -1,30 +1,66 @@ #pragma once -#include "../net_driver.hpp" +#include "types.h" +#include "networking/drivers/net_driver.hpp" #include "virtio/virtio_pci.h" -#include "net/network_types.h" +#include "std/memory.h" + +typedef struct __attribute__((packed)) virtio_net_hdr_t { + uint8_t flags; + uint8_t gso_type; + uint16_t hdr_len; + uint16_t gso_size; + uint16_t csum_start; + uint16_t csum_offset; +} virtio_net_hdr_t; + +typedef struct __attribute__((packed)) virtio_net_config { + uint8_t mac[6]; + uint16_t status; + uint16_t max_virtqueue_pairs; + uint16_t mtu; + uint32_t speed; + uint8_t duplex; + uint8_t rss_max_key_size; + uint16_t rss_max_indirection_table_length; + uint32_t supported_hash_types; +} virtio_net_config; + +enum class LinkDuplex : uint8_t { + Unknown = 0xFF, + Half = 0, + Full = 1 +}; class VirtioNetDriver : public NetDriver { public: VirtioNetDriver(); - bool init_at(uint64_t pci_addr, uint32_t irq_base_vector) override; - sizedptr allocate_packet(size_t size) override; - sizedptr handle_receive_packet() override; - void handle_sent_packet() override; - void enable_verbose() override; - void send_packet(sizedptr packet) override; + ~VirtioNetDriver(); + + bool init_at(uint64_t pci_addr, uint32_t irq_base_vector); void get_mac(uint8_t out_mac[6]) const override; uint16_t get_mtu() const override; uint16_t get_header_size() const override; - const char* if_prefix() const override; const char* hw_ifname() const override; - ~VirtioNetDriver() override; + void enable_verbose() override; + + uint32_t get_speed_mbps() const override; + uint8_t get_duplex() const override; + + sizedptr allocate_packet(size_t size) override; + sizedptr handle_receive_packet() override; + void handle_sent_packet() override; + void send_packet(sizedptr packet) override; private: - bool verbose; - uint16_t last_used_receive_idx; - uint16_t last_used_sent_idx; virtio_device vnp_net_dev; + + bool verbose; uint16_t header_size; uint16_t mtu; - char hw_name[32]; -}; \ No newline at end of file + uint32_t speed_mbps; + LinkDuplex duplex; + char hw_name[8]; + + uint16_t last_used_receive_idx; + uint16_t last_used_sent_idx; +}; diff --git a/kernel/networking/interface_manager.c b/kernel/networking/interface_manager.c index 2151401d..31e7e274 100644 --- a/kernel/networking/interface_manager.c +++ b/kernel/networking/interface_manager.c @@ -1,5 +1,7 @@ #include "interface_manager.h" #include "std/memory.h" +#include "net/link_layer/arp.h" +#include "net/internet_layer/ipv4_route.h" //TODO: add network settings static inline void mem_zero(void *p, size_t n){ if (p) memset(p,0,n); } @@ -13,14 +15,11 @@ static void copy_name(char dst[16], const char* src) { } static inline bool is_power2_mask_contiguous(uint32_t mask){ - if (mask == 0) return true; + if (mask == 0) return false; uint32_t inv = ~mask; return ((inv & (inv + 1u)) == 0); } -static inline uint32_t ipv4_net(uint32_t ip, uint32_t mask){ return ip & mask; } -static inline uint32_t ipv4_broadcast_calc(uint32_t ip, uint32_t mask){ return (mask==0)?0:((ip & mask) | ~mask); } - static inline bool ipv4_is_unspecified(uint32_t ip){ return ip == 0; } static inline bool ipv4_is_loopback(uint32_t ip){ return ((ip & 0xFF000000u) == 0x7F000000u); } static inline bool ipv4_is_multicast(uint32_t ip){ return ((ip & 0xF0000000u) == 0xE0000000u); } @@ -110,7 +109,7 @@ static bool v4_has_dhcp_on_l2(uint8_t ifindex){ return false; } -uint8_t l2_interface_create(const char *name, void *driver_ctx) { +uint8_t l2_interface_create(const char *name, void *driver_ctx, uint16_t base_metric){ int slot = find_free_l2_slot(); if (slot < 0) return 0; l2_interface_t* itf = &g_l2[slot]; @@ -118,18 +117,25 @@ uint8_t l2_interface_create(const char *name, void *driver_ctx) { itf->ifindex = (uint8_t)(slot + 1); copy_name(itf->name, name); itf->driver_context = driver_ctx; - itf->arp_table = NULL; + itf->base_metric = base_metric; + + + itf->arp_table = arp_table_create(); itf->nd_table = NULL; + g_l2_used[slot] = 1; g_l2_count += 1; return itf->ifindex; } -bool l2_interface_destroy(uint8_t ifindex) { +bool l2_interface_destroy(uint8_t ifindex){ int slot = l2_slot_from_ifindex(ifindex); if (slot < 0) return false; l2_interface_t* itf = &g_l2[slot]; if (itf->ipv4_count || itf->ipv6_count) return false; + + if (itf->arp_table) { arp_table_destroy((arp_table_t*)itf->arp_table); itf->arp_table = NULL; } + mem_zero(&g_l2[slot], sizeof(l2_interface_t)); g_l2_used[slot] = 0; if (g_l2_count) g_l2_count -= 1; @@ -272,16 +278,14 @@ static int alloc_local_slot_v6(l2_interface_t *l2){ static int alloc_global_v4_slot(void){ for (int i=0;iipv4_count >= MAX_IPV4_PER_INTERFACE) return 0; int loc = alloc_local_slot_v4(l2); int g = alloc_global_v4_slot(); @@ -308,7 +311,9 @@ uint8_t l3_ipv4_add_to_interface(uint8_t ifindex, uint32_t ip, uint32_t mask, ui n->mask = (mode==IPV4_CFG_STATIC) ? mask : 0; n->gw = (mode==IPV4_CFG_STATIC) ? gw : 0; n->broadcast = (mode==IPV4_CFG_STATIC) ? ipv4_broadcast_calc(ip, mask) : 0; - n->rt_v4 = rt; + n->runtime_opts_v4 = runtime_opts; + n->routing_table = ipv4_rt_create(); + ipv4_rt_ensure_basics((ipv4_rt_table_t*)n->routing_table, n->ip, n->mask, n->gw, l2->base_metric); n->is_localhost = (l2->name[0]=='l' && l2->name[1]=='o'); n->l3_id = make_l3_id(l2->ifindex, (uint8_t)loc); l2->l3_v4[loc] = n; @@ -316,19 +321,16 @@ uint8_t l3_ipv4_add_to_interface(uint8_t ifindex, uint32_t ip, uint32_t mask, ui return n->l3_id; } -bool l3_ipv4_update(uint8_t l3_id, uint32_t ip, uint32_t mask, uint32_t gw, ipv4_cfg_t mode, net_runtime_opts_t *rt){ +bool l3_ipv4_update(uint8_t l3_id, uint32_t ip, uint32_t mask, uint32_t gw, ipv4_cfg_t mode, net_runtime_opts_t *runtime_opts){ l3_ipv4_interface_t *n = l3_ipv4_find_by_id(l3_id); if (!n) return false; - l2_interface_t *l2 = n->l2; if (!l2) return false; - if (mode == IPV4_CFG_DHCP && n->mode != IPV4_CFG_DHCP) { if (v4_has_dhcp_on_l2(l2->ifindex)) { return false; } } - if (mode == IPV4_CFG_STATIC){ if (ipv4_is_unspecified(ip)) return false; if (!is_power2_mask_contiguous(mask)) return false; @@ -338,23 +340,19 @@ bool l3_ipv4_update(uint8_t l3_id, uint32_t ip, uint32_t mask, uint32_t gw, ipv4 if (ipv4_is_network_address(ip, mask)) return false; if (ipv4_is_broadcast_address(ip, mask)) return false; if (ip != n->ip && v4_ip_exists_anywhere(ip)) return false; - for (int i = 0; i < V4_POOL_SIZE; i++){ if (!g_v4[i].used) continue; l3_ipv4_interface_t *x = &g_v4[i].node; if (x==n) continue; if (!x->l2 || x->l2->ifindex != l2->ifindex) continue; if (x->mode == IPV4_CFG_DISABLED) continue; - uint32_t m = (x->mask < mask) ? x->mask : mask; if (ipv4_net(ip, m) == ipv4_net(x->ip, m)) return false; } } - n->mode = mode; - n->rt_v4 = rt; - - if (mode == IPV4_CFG_STATIC) { + n->runtime_opts_v4 = runtime_opts; + if (mode == IPV4_CFG_STATIC || mode == IPV4_CFG_DHCP) { n->ip = ip; n->mask = mask; n->gw = gw; @@ -365,11 +363,11 @@ bool l3_ipv4_update(uint8_t l3_id, uint32_t ip, uint32_t mask, uint32_t gw, ipv4 n->gw = 0; n->broadcast = 0; } - + if (!n->routing_table) n->routing_table = ipv4_rt_create(); + ipv4_rt_sync_basics((ipv4_rt_table_t*)n->routing_table, n->ip, n->mask, n->gw, l2->base_metric); return true; } - bool l3_ipv4_remove_from_interface(uint8_t l3_id){ l3_ipv4_interface_t *n = l3_ipv4_find_by_id(l3_id); if (!n) return false; @@ -381,6 +379,7 @@ bool l3_ipv4_remove_from_interface(uint8_t l3_id){ l2->l3_v4[slot] = NULL; if (l2->ipv4_count) l2->ipv4_count--; } + if (n->routing_table) { ipv4_rt_destroy((ipv4_rt_table_t*)n->routing_table); n->routing_table = 0; } for (int i=0;i= 40000u) ? 0 : + (sp >= 10000u) ? 2 : + (sp >= 1000u) ? 5 : + (sp >= 100u) ? 15 : 40; + + uint16_t duplex_cost = + (dp == 1) ? 0 : + (dp == 0) ? 20 : 5; + + uint16_t mtu_cost = + (m >= 9000u) ? 0 : + (m >= 2000u) ? 3 : + (m >= 1500u) ? 5 : + (m >= 576u) ? 15 : 100; + + uint16_t base_metric = (kd == NET_IFK_LOCALHOST) ? 0 : (uint16_t)(type_cost + speed_cost + duplex_cost + mtu_cost); + NICCtx* c = &nics[nic_num]; c->drv = drv; new ((void*)&c->tx) Queue(QUEUE_CAPACITY); new ((void*)&c->rx) Queue(QUEUE_CAPACITY); - copy_str(c->ifname_str, (int)sizeof(c->ifname_str), name); - copy_str(c->hwname_str, (int)sizeof(c->hwname_str), hw); + strcpy(c->ifname_str, (int)sizeof(c->ifname_str), name); + strcpy(c->hwname_str, (int)sizeof(c->hwname_str), hw); memcpy(c->mac_addr, macbuf, 6); c->mtu_val = m; c->hdr_sz = hs; + c->speed_mbps = sp; + c->duplex_mode = dp; + c->kind_val = kd; - uint8_t ix = l2_interface_create(c->ifname_str, (void*)drv); + uint8_t ix = l2_interface_create(c->ifname_str, (void*)drv, base_metric); l2_interface_set_up(ix, true); c->ifindex = ix; @@ -226,14 +273,6 @@ bool NetworkDispatch::register_all_from_bus() { return nic_num > 0; } -void NetworkDispatch::copy_str(char* dst, int cap, const char* src) { - if (!dst || cap <= 0) return; - if (!src) { dst[0] = 0; return; } - uint32_t n = strlen(src, (uint32_t)(cap - 1)); - memcpy(dst, src, n); - dst[n] = 0; -} - int NetworkDispatch::nic_for_ifindex(uint8_t ifindex) const { if (!ifindex) return -1; if (ifindex > MAX_L2_INTERFACES) return -1; @@ -286,12 +325,16 @@ void NetworkDispatch::dump_interfaces() macs[p] = 0; } - kprintf(" driver: nic_id=%u ifname=%s hw=%s mtu=%u hdr=%u mac=%s drv=%x", + const char* dpx = (nics[nid].duplex_mode == 0) ? "half" : + (nics[nid].duplex_mode == 1) ? "full" : "unknown"; + + kprintf(" driver: nic_id=%u ifname=%s hw=%s mtu=%u hdr=%u mac=%s drv=%x spd=%u dup=%s kind=%u", (unsigned)nid, nics[nid].ifname_str[0] ? nics[nid].ifname_str : "(null)", nics[nid].hwname_str[0] ? nics[nid].hwname_str : "(null)", (unsigned)nics[nid].mtu_val, (unsigned)nics[nid].hdr_sz, macs, - (uint64_t)(uintptr_t)nics[nid].drv); + (uint64_t)(uintptr_t)nics[nid].drv, + (unsigned)nics[nid].speed_mbps, dpx, (unsigned)nics[nid].kind_val); } else { kprintf(" driver: none"); } @@ -307,7 +350,7 @@ void NetworkDispatch::dump_interfaces() ipv4_to_string(v4->broadcast, bc); kprintf(" - slot=%u l3_id=%u mode=%i ip=%s mask=%s gw=%s bcast=%s rt=%x localhost=%u", (unsigned)s, (unsigned)v4->l3_id, (int)v4->mode, ip, mask, gw, bc, - (uint64_t)(uintptr_t)v4->rt_v4, v4->is_localhost?1:0); + (uint64_t)(uintptr_t)v4->runtime_opts_v4, v4->is_localhost?1:0); } kprintf(" int ipv6:"); diff --git a/kernel/networking/network_dispatch.hpp b/kernel/networking/network_dispatch.hpp index 05728a6e..c273f7d4 100644 --- a/kernel/networking/network_dispatch.hpp +++ b/kernel/networking/network_dispatch.hpp @@ -31,6 +31,10 @@ class NetworkDispatch { l2_interface_t* l2_at(uint8_t ifindex) const; NetDriver* driver_at(uint8_t ifindex) const; + uint32_t speed(uint8_t ifindex) const; + uint8_t duplex(uint8_t ifindex) const; + uint8_t kind(uint8_t ifindex) const; + private: struct NICCtx { NetDriver* drv; @@ -40,6 +44,9 @@ class NetworkDispatch { uint8_t mac_addr[6]; uint16_t mtu_val; uint16_t hdr_sz; + uint32_t speed_mbps; + uint8_t duplex_mode; + uint8_t kind_val; Queue tx; Queue rx; }; diff --git a/kernel/networking/processes/net_proc.c b/kernel/networking/processes/net_proc.c index 7dd506b7..6bc4e933 100644 --- a/kernel/networking/processes/net_proc.c +++ b/kernel/networking/processes/net_proc.c @@ -33,10 +33,8 @@ static uint32_t pick_probe_ip() { return 0; if (cfg->gw) return cfg->gw; - uint32_t bcast = ipv4_broadcast(cfg->ip, cfg->mask); - if (bcast) - return bcast; - return ipv4_first_host(cfg->ip, cfg->mask); + uint32_t bcast = ipv4_broadcast_calc(cfg->ip, cfg->mask); + return bcast; } static int udp_probe_server(uint32_t probe_ip, uint16_t probe_port, net_l4_endpoint *out_l4) { @@ -274,7 +272,7 @@ static void test_net() { if (cfg && cfg->mode != IPV4_CFG_DISABLED && cfg->ip != 0) { print_info(); - uint32_t bcast = ipv4_broadcast(cfg->ip, cfg->mask); + uint32_t bcast = ipv4_broadcast_calc(cfg->ip, cfg->mask); char bcast_str[16]; ipv4_to_string(bcast, bcast_str); @@ -323,6 +321,7 @@ process_t* launch_net_process() { create_kernel_process("net_net", network_net_task_entry, 0, 0); create_kernel_process("arp_daemon", arp_daemon_entry, 0, 0); create_kernel_process("dhcp_daemon", dhcp_daemon_entry, 0, 0); + return NULL; create_kernel_process("dns_daemon", dns_deamon_entry, 0, 0); if (cfg && cfg->mode != IPV4_CFG_DISABLED && cfg->ip != 0) { diff --git a/run_virt b/run_virt index 43e1a480..98c9ee24 100755 --- a/run_virt +++ b/run_virt @@ -55,7 +55,7 @@ $PRIVILEGE qemu-system-aarch64 \ -device $SELECTED_GPU \ -display $DISPLAY_MODE${GL:+,gl=$GL} \ $NETDEV \ - -device virtio-net-pci,netdev=net0,mac=52:54:00:12:34:56 \ + -device virtio-net-pci,netdev=net0,mac=52:54:00:12:34:56,speed=10000,duplex=full \ $DUMP \ -serial mon:stdio \ -drive file=disk.img,if=none,format=raw,id=hd0 \ diff --git a/shared/net/application_layer/dhcp_daemon.c b/shared/net/application_layer/dhcp_daemon.c index e2c9f485..bd955c0d 100644 --- a/shared/net/application_layer/dhcp_daemon.c +++ b/shared/net/application_layer/dhcp_daemon.c @@ -353,9 +353,9 @@ static void dhcp_apply_offer(dhcp_packet *p, dhcp_request *req, uint32_t xid) { cfg_local.rt->dns[0] = cfg_local.gw; } - uint32_t bcast = ipv4_broadcast(cfg_local.ip, cfg_local.mask); + uint32_t bcast = ipv4_broadcast_calc(cfg_local.ip, cfg_local.mask); static const uint8_t bmac[6] = {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}; - arp_table_put(bcast, bmac, 0, true); + arp_table_put_for_l2(1, bcast, bmac, 0, true); ipv4_set_cfg(&cfg_local); diff --git a/shared/net/internet_layer/icmp.c b/shared/net/internet_layer/icmp.c index c67c1d2c..c5d61af1 100644 --- a/shared/net/internet_layer/icmp.c +++ b/shared/net/internet_layer/icmp.c @@ -1,10 +1,9 @@ #include "icmp.h" -#include "net/internet_layer/ipv4.h" #include "net/checksums.h" #include "std/memory.h" -#include "console/kio.h" -#include "ipv4.h" -#include "networking/network.h" +#include "networking/interface_manager.h" +#include "net/internet_layer/ipv4.h" +#include "net/internet_layer/ipv4_route.h" extern uintptr_t malloc(uint64_t size); extern void free(void *ptr, uint64_t size); @@ -74,9 +73,7 @@ void icmp_send_echo(uint32_t dst_ip, ((icmp_packet*)buf)->checksum = checksum16((uint16_t*)buf, icmp_len); - const net_cfg_t *cfg = ipv4_get_cfg(); - if (!cfg) { free((void*)buf, icmp_len); return; } - ipv4_send_packet(cfg->ip, dst_ip, 1, (sizedptr){ buf, icmp_len }); + ipv4_send_packet(dst_ip, 1, (sizedptr){ buf, icmp_len}, NULL); free((void*)buf, icmp_len); } @@ -86,22 +83,22 @@ void icmp_input(uintptr_t ptr, uint32_t src_ip, uint32_t dst_ip) { - if(len < 8) return; + if (len < 8) return; icmp_packet *pkt = (icmp_packet*)ptr; uint16_t recv_ck = pkt->checksum; pkt->checksum = 0; - if(checksum16((uint16_t*)pkt, len) != recv_ck) return; + if (checksum16((uint16_t*)pkt, len) != recv_ck) return; pkt->checksum = recv_ck; uint8_t type = pkt->type; uint16_t id = bswap16(pkt->id); uint16_t sq = bswap16(pkt->seq); uint32_t pay = len - 8; - if(pay > 56) pay = 56; + if (pay > 56) pay = 56; - if(type == ICMP_ECHO_REQUEST){ - icmp_data d = { .response=true, .id=id, .seq=sq }; + if (type == ICMP_ECHO_REQUEST) { + icmp_data d = { .response = true, .id = id, .seq = sq }; memcpy(d.payload, pkt->payload, pay); memset(d.payload + pay, 0, 56 - pay); @@ -112,18 +109,27 @@ void icmp_input(uintptr_t ptr, create_icmp_packet(buf, &d); ((icmp_packet*)buf)->checksum = checksum16((uint16_t*)buf, reply_len); - const net_cfg_t *cfg = ipv4_get_cfg(); - if (cfg) { - ipv4_send_packet(cfg->ip, src_ip, 1, (sizedptr){ buf, reply_len }); + l3_ipv4_interface_t *l3 = l3_ipv4_find_by_ip(dst_ip); // nostro IP + if (l3 && l3->l2) { + ipv4_tx_opts_t o = { .index = l3->l3_id, .int_type = 1 }; + + char sbuf[16], dbuf[16]; + ipv4_to_string(src_ip, sbuf); + ipv4_to_string(dst_ip, dbuf); + + ipv4_send_packet(src_ip, 1, (sizedptr){ buf, reply_len }, &o); } + free((void*)buf, reply_len); return; } - if(type == ICMP_ECHO_REPLY) + if(type == ICMP_ECHO_REPLY) { mark_received(id, sq); + } } + bool icmp_ping(uint32_t dst_ip, uint16_t id, uint16_t seq, diff --git a/shared/net/internet_layer/ipv4.c b/shared/net/internet_layer/ipv4.c index 3f7b2cc7..0ceb398a 100644 --- a/shared/net/internet_layer/ipv4.c +++ b/shared/net/internet_layer/ipv4.c @@ -1,64 +1,105 @@ #include "ipv4.h" -#include "console/kio.h" -#include "std/memory.h" -#include "networking/network.h" +#include "ipv4_route.h" #include "net/link_layer/arp.h" -#include "net/transport_layer/udp.h" -#include "net/transport_layer/tcp.h" -#include "icmp.h" +#include "net/internet_layer/icmp.h" +#include "std/memory.h" #include "std/string.h" -#include "types.h" -#include "ipv4_route.h" - +#include "net/transport_layer/tcp.h" +#include "net/transport_layer/udp.h" +#include "console/kio.h" extern uintptr_t malloc(uint64_t size); extern void free(void *ptr, uint64_t size); extern void sleep(uint64_t ms); -static net_runtime_opts_t g_rt_opts; -net_cfg_t g_net_cfg = { - .ip = 0, - .mask = 0, - .gw = 0, - .mode = 0,//NET_MODE_DHCP - .rt = &g_rt_opts -}; - -void ipv4_cfg_init() { - memset(&g_rt_opts, 0, sizeof(g_rt_opts)); - g_net_cfg.ip = 0; - g_net_cfg.mask = 0; - g_net_cfg.gw = 0; - g_net_cfg.mode = 0; //NET_MODE_DHCP - g_net_cfg.rt = &g_rt_opts; - ipv4_rt_init(); -} - -void ipv4_set_cfg(const net_cfg_t *src) { - if (!src) return; - g_net_cfg.ip = src->ip; - g_net_cfg.mask = src->mask; - g_net_cfg.gw = src->gw; - g_net_cfg.mode = src->mode; - if (src->rt) { - g_rt_opts = *src->rt; - } else { - memset(&g_rt_opts, 0, sizeof(g_rt_opts)); +static net_cfg_t g_ipv4_compat_cfg; +static bool g_ipv4_compat_valid; + +static l3_ipv4_interface_t* first_ipv4_if(void) { + uint8_t n = l2_interface_count(); + for (uint8_t i = 0; i < n; i++) { + l2_interface_t* l2 = l2_interface_at(i); + if (!l2) continue; + for (int s = 0; s < MAX_IPV4_PER_INTERFACE; s++) { + l3_ipv4_interface_t* v4 = l2->l3_v4[s]; + if (!v4) continue; + if (v4->mode == IPV4_CFG_DISABLED) continue; + return v4; + } + } + return NULL; +} + +static void ipv4_compat_refresh(void) { + l3_ipv4_interface_t* v4 = first_ipv4_if(); + if (!v4) { + memset(&g_ipv4_compat_cfg, 0, sizeof(g_ipv4_compat_cfg)); + g_ipv4_compat_valid = false; + return; } - if(g_net_cfg.ip != 0){ - uint8_t bmac[6] = {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}; - arp_table_put(ipv4_broadcast(g_net_cfg.ip, g_net_cfg.mask), bmac, 0, true); + g_ipv4_compat_cfg.ip = v4->ip; + g_ipv4_compat_cfg.mask = v4->mask; + g_ipv4_compat_cfg.gw = v4->gw; + g_ipv4_compat_cfg.mode = (int8_t)v4->mode; + g_ipv4_compat_cfg.rt = (net_runtime_opts_t*)v4->runtime_opts_v4; + g_ipv4_compat_valid = true; +} + + + + + +// LEGACY +void ipv4_cfg_init(void) { + memset(&g_ipv4_compat_cfg, 0, sizeof(g_ipv4_compat_cfg)); + g_ipv4_compat_valid = false; +} + +void ipv4_set_cfg(const net_cfg_t* src) { + if (!src) { + g_ipv4_compat_valid = false; + memset(&g_ipv4_compat_cfg, 0, sizeof(g_ipv4_compat_cfg)); + l2_interface_t* l2 = l2_interface_find_by_index(1); + if (l2) { + for (int s = 0; s < MAX_IPV4_PER_INTERFACE; ++s) { + if (l2->l3_v4[s]) { + l3_ipv4_remove_from_interface(l2->l3_v4[s]->l3_id); + } + } + } + return; } - g_net_cfg.rt = &g_rt_opts; - ipv4_rt_init(); - if (g_net_cfg.gw) { - ipv4_rt_add(0, 0, g_net_cfg.gw); + + g_ipv4_compat_cfg = *src; + g_ipv4_compat_valid = true; + + l2_interface_t* l2 = l2_interface_find_by_index(1); + if (!l2) return; + + l3_ipv4_interface_t* v4 = NULL; + for (int s = 0; s < MAX_IPV4_PER_INTERFACE; ++s) { + if (l2->l3_v4[s]) { v4 = l2->l3_v4[s]; break; } + } + + ipv4_cfg_t mode = (src->mode == 0) ? IPV4_CFG_DHCP : IPV4_CFG_STATIC; + char buf[16]; + ipv4_to_string(src->ip, buf); + if (v4) { + kprintf("update ip=%s", buf); + l3_ipv4_update(v4->l3_id, src->ip, src->mask, src->gw, mode, (net_runtime_opts_t*)src->rt); } + + if (!l2->is_up) l2_interface_set_up(1, true); } -const net_cfg_t* ipv4_get_cfg() { - return &g_net_cfg; + +const net_cfg_t* ipv4_get_cfg(void) { + ipv4_compat_refresh(); + return g_ipv4_compat_valid ? &g_ipv4_compat_cfg : NULL; } + + + static char* u8_to_str(uint8_t val, char* out) { if (val >= 100) { *out++ = '0' + (val / 100); @@ -74,124 +115,348 @@ static char* u8_to_str(uint8_t val, char* out) { return out; } -void ipv4_to_string(uint32_t ip, char* buf) { - uint8_t a = (ip >> 24) & 0xFF; - uint8_t b = (ip >> 16) & 0xFF; - uint8_t c = (ip >> 8) & 0xFF; - uint8_t d = ip & 0xFF; +#define IP_IHL_NOOPTS 5 +#define IP_VERSION_4 4 +#define IP_TTL_DEFAULT 64 - char* p = buf; - p = u8_to_str(a, p); *p++ = '.'; - p = u8_to_str(b, p); *p++ = '.'; - p = u8_to_str(c, p); *p++ = '.'; - p = u8_to_str(d, p); - *p = '\0'; +static uint16_t g_ip_ident = 1; + +static int mask_prefix_len(uint32_t m) { + int n = 0; + while (m & 0x80000000u) { n++; m <<= 1; } + return n; } -static uint16_t ipv4_checksum(const void *buf, size_t len) { - const uint16_t *data = buf; - uint32_t sum = 0; - for (; len > 1; len -= 2) { - sum += *data++; +static inline bool is_lbcast(uint32_t ip) { return ip == 0xFFFFFFFFu; } + +static l3_ipv4_interface_t* best_v4_on_l2_for_dst(l2_interface_t* l2, uint32_t dst) { + l3_ipv4_interface_t* best = NULL; + int best_pl = -1; + for (int s = 0; s < MAX_IPV4_PER_INTERFACE; s++) { + l3_ipv4_interface_t* v4 = l2->l3_v4[s]; + if (!v4) continue; + if (v4->mode == IPV4_CFG_DISABLED) continue; + if (!v4->ip) continue; + uint32_t m = v4->mask; + if (m && ((dst & m) == (v4->ip & m))) { + int pl = mask_prefix_len(m); + if (pl > best_pl) { best_pl = pl; best = v4; } + } else if (!best) { + best = v4; + } } - if (len) { - sum += *(const uint8_t*)data; + return best; +} + +static bool lookup_route_in_tables(uint32_t dst, uint32_t* out_nh, uint8_t* out_ifx, uint32_t* out_src) { + int best_pl = -1; + int best_metric = 0x7FFF; + uint32_t best_nh = 0; + uint8_t best_ifx = 0; + uint32_t best_src = 0; + + uint8_t cnt = l2_interface_count(); + for (uint8_t i = 0; i < cnt; i++) { + l2_interface_t* l2 = l2_interface_at(i); + if (!l2) continue; + for (int s = 0; s < MAX_IPV4_PER_INTERFACE; s++) { + l3_ipv4_interface_t* v4 = l2->l3_v4[s]; + if (!v4) continue; + if (v4->mode == IPV4_CFG_DISABLED) continue; + if (!v4->routing_table) continue; + + uint32_t nh = 0; int pl = -1; int metric = 0; + if (ipv4_rt_lookup_in(v4->routing_table, dst, &nh, &pl, &metric)) { + if (pl > best_pl || (pl == best_pl && metric < best_metric)) { + best_pl = pl; + best_metric = metric; + best_nh = nh ? nh : dst; + best_ifx = l2->ifindex; + best_src = v4->ip; + } + } + } } - while (sum >> 16) { - sum = (sum & 0xFFFF) + (sum >> 16); + + if (best_pl >= 0) { + if (out_nh) *out_nh = best_nh; + if (out_ifx) *out_ifx = best_ifx; + if (out_src) *out_src = best_src; + return true; } - return (uint16_t)~sum; + return false; } -void ip_input(uintptr_t ip_ptr, - uint32_t ip_len, - const uint8_t src_mac[6]) -{ - if (ip_len < sizeof(ipv4_hdr_t)) return; - ipv4_hdr_t *hdr = (ipv4_hdr_t*)ip_ptr; - uint8_t version = hdr->version_ihl >> 4; - uint8_t ihl = hdr->version_ihl & 0x0F; - if (version != 4 || ihl < 5) return; +static bool pick_broadcast_bound_l3(uint8_t l3_id, uint8_t* out_ifx, uint32_t* out_src, uint32_t* out_nh) { + l3_ipv4_interface_t* v4 = l3_ipv4_find_by_id(l3_id); + if (!v4 || !v4->l2) return false; + if (v4->mode == IPV4_CFG_DISABLED) return false; + + if (out_ifx) *out_ifx = v4->l2->ifindex; + if (out_src) *out_src = v4->ip; + if (!v4->ip && v4->mode == IPV4_CFG_DHCP && out_src) *out_src = 0; + if (out_nh) *out_nh = 0xFFFFFFFFu; + return true; +} - uint32_t header_bytes = ihl * 4; - if (ip_len < header_bytes) return; +static bool pick_broadcast_bound_l2(uint8_t ifindex, uint8_t* out_ifx, uint32_t* out_src, uint32_t* out_nh) { + l2_interface_t* l2 = l2_interface_find_by_index(ifindex); + if (!l2) return false; - if (hdr->header_checksum != 0) { - uint16_t recv_ck = hdr->header_checksum; - hdr->header_checksum = 0; - if (ipv4_checksum(hdr, header_bytes) != recv_ck) return; - hdr->header_checksum = recv_ck; + l3_ipv4_interface_t* chosen = NULL; + l3_ipv4_interface_t* dhcp = NULL; + for (int s = 0; s < MAX_IPV4_PER_INTERFACE; s++) { + l3_ipv4_interface_t* v4 = l2->l3_v4[s]; + if (!v4) continue; + if (v4->mode == IPV4_CFG_DISABLED) continue; + if (v4->ip) { chosen = v4; break; } + if (!v4->ip && v4->mode == IPV4_CFG_DHCP && !dhcp) dhcp = v4; } + if (!chosen) chosen = dhcp; - uint32_t sip = bswap32(hdr->src_ip); - arp_table_put(sip, src_mac, 60000, false); + if (out_ifx) *out_ifx = l2->ifindex; + if (out_src) *out_src = (chosen && chosen->ip) ? chosen->ip : 0; + if (out_nh) *out_nh = 0xFFFFFFFFu; + return true; +} - uint32_t dip = bswap32(hdr->dst_ip); - //TODO manage special ip +static bool pick_broadcast_global(uint8_t* out_ifx, uint32_t* out_src, uint32_t* out_nh) { + l3_ipv4_interface_t* static_cand = NULL; + l3_ipv4_interface_t* dhcp_cand = NULL; + l2_interface_t* l2_s = NULL; + l2_interface_t* l2_d = NULL; - uintptr_t payload_ptr = ip_ptr + header_bytes; - uint32_t payload_len = bswap16(hdr->total_length) - header_bytes; - switch (hdr->protocol) { - case 1://icmp - icmp_input(payload_ptr, payload_len, sip, dip); - break; - case 6://tcp - tcp_input(payload_ptr, payload_len, sip, dip); - break; - case 17://udp - udp_input(payload_ptr, payload_len, sip, dip); - break; - default: - //everything else - break; + uint8_t n = l2_interface_count(); + for (uint8_t i = 0; i < n; i++) { + l2_interface_t* l2 = l2_interface_at(i); + if (!l2) continue; + for (int s = 0; s < MAX_IPV4_PER_INTERFACE; s++) { + l3_ipv4_interface_t* v4 = l2->l3_v4[s]; + if (!v4) continue; + if (v4->mode == IPV4_CFG_DISABLED) continue; + if (v4->ip && !static_cand) { static_cand = v4; l2_s = l2; } + if (!v4->ip && v4->mode == IPV4_CFG_DHCP && !dhcp_cand) { dhcp_cand = v4; l2_d = l2; } + } } + + l3_ipv4_interface_t* pick = static_cand ? static_cand : dhcp_cand; + l2_interface_t* l2 = static_cand ? l2_s : l2_d; + if (!l2) return false; + + if (out_ifx) *out_ifx = l2->ifindex; + if (out_src) *out_src = (pick && pick->ip) ? pick->ip : 0; + if (out_nh) *out_nh = 0xFFFFFFFFu; + return true; } -void ipv4_send_packet(uint32_t src_ip, - uint32_t dst_ip, - uint8_t proto, - sizedptr segment) -{ - uint32_t nh_ip; - if (!ipv4_rt_lookup(dst_ip, &nh_ip)) { - const net_cfg_t *cfg = ipv4_get_cfg(); - if (cfg && ((dst_ip & cfg->mask) == (cfg->ip & cfg->mask))) { - nh_ip = dst_ip; - } else { - nh_ip = cfg ? cfg->gw : dst_ip; +static bool pick_route_global(uint32_t dst, uint8_t* out_ifx, uint32_t* out_src, uint32_t* out_nh) { + if (is_lbcast(dst)) return pick_broadcast_global(out_ifx, out_src, out_nh); + + ip_resolution_result_t r = resolve_ipv4_to_interface(dst); + if (r.found && r.ipv4 && r.l2) { + uint32_t m = r.ipv4->mask; + if (m && ((dst & m) == (r.ipv4->ip & m))) { + if (out_ifx) *out_ifx = r.l2->ifindex; + if (out_src) *out_src = r.ipv4->ip; + if (out_nh) *out_nh = dst; + return true; + } + if (r.ipv4->gw) { + if (out_ifx) *out_ifx = r.l2->ifindex; + if (out_src) *out_src = r.ipv4->ip; + if (out_nh) *out_nh = r.ipv4->gw; + return true; + } + if (r.ipv4->routing_table) { + uint32_t nh = 0; int pl = -1; int metric = 0; + if (ipv4_rt_lookup_in(r.ipv4->routing_table, dst, &nh, &pl, &metric)) { + if (out_ifx) *out_ifx = r.l2->ifindex; + if (out_src) *out_src = r.ipv4->ip; + if (out_nh) *out_nh = nh ? nh : dst; + return true; + } } } + return lookup_route_in_tables(dst, out_nh, out_ifx, out_src); +} - uint8_t dst_mac[6]; - bool ok = arp_resolve(nh_ip, dst_mac, 200); - if (!ok) { - memset(dst_mac, 0xFF, sizeof(dst_mac)); +static bool pick_route_bound_l3(uint8_t l3_id, uint32_t dst, uint8_t* out_ifx, uint32_t* out_src, uint32_t* out_nh) { + if (is_lbcast(dst)) return pick_broadcast_bound_l3(l3_id, out_ifx, out_src, out_nh); + + l3_ipv4_interface_t* v4 = l3_ipv4_find_by_id(l3_id); + if (!v4 || !v4->l2) return false; + if (v4->mode == IPV4_CFG_DISABLED) return false; + if (!v4->ip) return false; + + uint32_t m = v4->mask; + if (m && ((dst & m) == (v4->ip & m))) { + if (out_ifx) *out_ifx = v4->l2->ifindex; + if (out_src) *out_src = v4->ip; + if (out_nh) *out_nh = dst; + return true; + } + if (v4->gw) { + if (out_ifx) *out_ifx = v4->l2->ifindex; + if (out_src) *out_src = v4->ip; + if (out_nh) *out_nh = v4->gw; + return true; + } + if (v4->routing_table) { + uint32_t nh = 0; int pl = -1; int metric = 0; + if (ipv4_rt_lookup_in(v4->routing_table, dst, &nh, &pl, &metric)) { + if (out_ifx) *out_ifx = v4->l2->ifindex; + if (out_src) *out_src = v4->ip; + if (out_nh) *out_nh = nh ? nh : dst; + return true; + } } + return false; +} + +static bool pick_route_bound_l2(uint8_t ifindex, uint32_t dst, uint8_t* out_ifx, uint32_t* out_src, uint32_t* out_nh) { + if (is_lbcast(dst)) return pick_broadcast_bound_l2(ifindex, out_ifx, out_src, out_nh); + + l2_interface_t* l2 = l2_interface_find_by_index(ifindex); + if (!l2) return false; + + l3_ipv4_interface_t* v4 = best_v4_on_l2_for_dst(l2, dst); + if (!v4) return false; + if (v4->mode == IPV4_CFG_DISABLED) return false; + + uint32_t m = v4->mask; + if (m && ((dst & m) == (v4->ip & m))) { + if (out_ifx) *out_ifx = l2->ifindex; + if (out_src) *out_src = v4->ip; + if (out_nh) *out_nh = dst; + return true; + } + if (v4->gw) { + if (out_ifx) *out_ifx = l2->ifindex; + if (out_src) *out_src = v4->ip; + if (out_nh) *out_nh = v4->gw; + return true; + } + if (v4->routing_table) { + uint32_t nh = 0; int pl = -1; int metric = 0; + if (ipv4_rt_lookup_in(v4->routing_table, dst, &nh, &pl, &metric)) { + if (out_ifx) *out_ifx = l2->ifindex; + if (out_src) *out_src = v4->ip; + if (out_nh) *out_nh = nh ? nh : dst; + return true; + } + } + return false; +} + +static bool pick_route(uint32_t dst, const ipv4_tx_opts_t* opts, uint8_t* out_ifx, uint32_t* out_src, uint32_t* out_nh) { + if (opts) { + return opts->int_type + ? pick_route_bound_l3(opts->index, dst, out_ifx, out_src, out_nh) + : pick_route_bound_l2(opts->index, dst, out_ifx, out_src, out_nh); + } + return pick_route_global(dst, out_ifx, out_src, out_nh); +} + +void ipv4_to_string(uint32_t ip, char* buf) { + uint8_t a = (ip >> 24) & 0xFF; + uint8_t b = (ip >> 16) & 0xFF; + uint8_t c = (ip >> 8) & 0xFF; + uint8_t d = ip & 0xFF; + + char* p = buf; + p = u8_to_str(a, p); *p++ = '.'; + p = u8_to_str(b, p); *p++ = '.'; + p = u8_to_str(c, p); *p++ = '.'; + p = u8_to_str(d, p); + *p = '\0'; +} + +void ipv4_send_packet(uint32_t dst_ip, uint8_t proto, sizedptr segment, const ipv4_tx_opts_t* opts) { + if (!segment.ptr || !segment.size) return; - uint32_t ip_len = sizeof(ipv4_hdr_t) + segment.size; - uintptr_t ip_buf = (uintptr_t)malloc(ip_len); - if (!ip_buf) return; + uint8_t ifx = 0; + uint32_t src_ip = 0; + uint32_t nh = 0; + if (!pick_route(dst_ip, opts, &ifx, &src_ip, &nh)) return; + + uint8_t dst_mac[6]; + if (!arp_resolve_on(ifx, nh, dst_mac, 200)) return; - ipv4_hdr_t *ip = (ipv4_hdr_t *)ip_buf; - ip->version_ihl = (4 << 4) | (sizeof(*ip)/4); + uint32_t hdr_len = IP_IHL_NOOPTS * 4; + uint32_t total = hdr_len + (uint32_t)segment.size; + + uintptr_t buf = (uintptr_t)malloc(total); + if (!buf) return; + + ipv4_hdr_t* ip = (ipv4_hdr_t*)buf; + ip->version_ihl = (uint8_t)((IP_VERSION_4 << 4) | IP_IHL_NOOPTS); ip->dscp_ecn = 0; - ip->total_length = bswap16(ip_len); - ip->identification = 0; - ip->flags_frag_offset = bswap16(0x4000); - ip->ttl = 64; + ip->total_length = bswap16((uint16_t)total); + ip->identification = bswap16(g_ip_ident++); + ip->flags_frag_offset = bswap16(0); + ip->ttl = IP_TTL_DEFAULT; ip->protocol = proto; + ip->header_checksum = 0; ip->src_ip = bswap32(src_ip); ip->dst_ip = bswap32(dst_ip); + + memcpy((void*)(buf + hdr_len), (const void*)segment.ptr, segment.size); + ip->header_checksum = checksum16((const uint16_t*)ip, hdr_len / 2); + + sizedptr payload = { buf, total }; + eth_send_frame_on(ifx, ETHERTYPE_IPV4, dst_mac, payload); + + free((void*)buf, total); +} + +void ipv4_input(uint16_t ifindex, uintptr_t ip_ptr, uint32_t ip_len, const uint8_t src_mac[6]) { + if (ip_len < sizeof(ipv4_hdr_t)) return; + + ipv4_hdr_t* ip = (ipv4_hdr_t*)ip_ptr; + uint8_t ver = (uint8_t)(ip->version_ihl >> 4); + uint8_t ihl = (uint8_t)(ip->version_ihl & 0x0F); + if (ver != IP_VERSION_4) return; + if (ihl < IP_IHL_NOOPTS) return; + + uint32_t hdr_len = (uint32_t)ihl * 4; + if (ip_len < hdr_len) return; + + uint16_t saved = ip->header_checksum; ip->header_checksum = 0; - ip->header_checksum = ipv4_checksum(ip, sizeof(*ip)); + if (checksum16((const uint16_t*)ip, hdr_len / 2) != saved) { + ip->header_checksum = saved; + return; + } + ip->header_checksum = saved; + uint32_t src = bswap32(ip->src_ip); + uint32_t dst = bswap32(ip->dst_ip); - if (segment.size) { - memcpy((void*)(ip_buf + sizeof(*ip)), (void*)segment.ptr, segment.size); + if (ifindex && src) { + uint8_t mac_old[6]; + bool had = arp_table_get_for_l2((uint8_t)ifindex, src, mac_old); + if (!had || memcmp(mac_old, src_mac, 6) != 0) { + arp_table_put_for_l2((uint8_t)ifindex, src, src_mac, 180000, false); + } else { + arp_table_put_for_l2((uint8_t)ifindex, src, mac_old, 180000, false); + } } - sizedptr payload = { ip_buf, ip_len }; - eth_send_frame(0x0800, dst_mac, payload); + uint8_t proto = ip->protocol; + uintptr_t l4 = ip_ptr + hdr_len; + uint32_t l4_len = ip_len - hdr_len; - free((void*)ip_buf, ip_len); -} + switch (proto) { + case 1://icmp + icmp_input(l4, l4_len, src, dst); + break; + case 6: //tcp + tcp_input(l4, l4_len, src, dst); + break; + case 17://udp + udp_input(l4, l4_len, src, dst); + break; + default: + break; + } +} \ No newline at end of file diff --git a/shared/net/internet_layer/ipv4.h b/shared/net/internet_layer/ipv4.h index 7c71d16f..50f5c369 100644 --- a/shared/net/internet_layer/ipv4.h +++ b/shared/net/internet_layer/ipv4.h @@ -5,18 +5,11 @@ #include "net/network_types.h" #include "net/checksums.h" #include "networking/interface_manager.h" + #ifdef __cplusplus extern "C" { #endif -typedef struct net_cfg { - uint32_t ip; - uint32_t mask; - uint32_t gw; - int8_t mode; - net_runtime_opts_t *rt; -} net_cfg_t; - typedef struct __attribute__((packed)) ipv4_hdr_t { uint8_t version_ihl; uint8_t dscp_ecn; @@ -30,25 +23,39 @@ typedef struct __attribute__((packed)) ipv4_hdr_t { uint32_t dst_ip; } ipv4_hdr_t; -void ipv4_cfg_init(); -void ipv4_set_cfg(const net_cfg_t *src); -const net_cfg_t* ipv4_get_cfg(); +typedef struct { + uint8_t index; + bool int_type; //0 = l2 index, 1= l3 index +} ipv4_tx_opts_t; void ipv4_to_string(uint32_t ip, char* buf); -void ipv4_send_packet(uint32_t src_ip, - uint32_t dst_ip, - uint8_t proto, - sizedptr segment); +void ipv4_send_packet(uint32_t dst_ip, + uint8_t proto, + sizedptr segment, + const ipv4_tx_opts_t* opts); + +void ipv4_input(uint16_t ifindex, uintptr_t ip_ptr, + uint32_t ip_len, + const uint8_t src_mac[6]); + + -void ip_input(uintptr_t ip_ptr, - uint32_t ip_len, - const uint8_t src_mac[6]); -static inline uint32_t ipv4_network(uint32_t ip, uint32_t mask){ return ip & mask; } -static inline uint32_t ipv4_broadcast(uint32_t ip, uint32_t mask){ return (ip & mask) | ~mask; } -static inline uint32_t ipv4_first_host(uint32_t ip, uint32_t mask){ return (ip & mask) + 1; } -static inline uint32_t ipv4_last_host(uint32_t ip, uint32_t mask){ return ((ip & mask) | ~mask) - 1; } + + +//LEGACY + +typedef struct net_cfg { + uint32_t ip; + uint32_t mask; + uint32_t gw; + int8_t mode; + net_runtime_opts_t *rt; +} net_cfg_t; +void ipv4_cfg_init(void); +void ipv4_set_cfg(const net_cfg_t *src); +const net_cfg_t* ipv4_get_cfg(void); #ifdef __cplusplus } diff --git a/shared/net/internet_layer/ipv4_route.c b/shared/net/internet_layer/ipv4_route.c index 68ac553e..cc99dabe 100644 --- a/shared/net/internet_layer/ipv4_route.c +++ b/shared/net/internet_layer/ipv4_route.c @@ -1,66 +1,111 @@ #include "ipv4_route.h" #include "std/memory.h" -static ipv4_rt_entry_t g_rt[IPV4_RT_MAX]; -static int g_rt_len = 0; +extern uintptr_t malloc(uint64_t size); +extern void free(void* ptr, uint64_t size); -void ipv4_rt_init() { - g_rt_len = 0; - memset(g_rt, 0, sizeof(g_rt)); +struct ipv4_rt_table { + ipv4_rt_entry_t e[IPV4_RT_PER_IF_MAX]; + int len; +}; + +static int prefix_len(uint32_t m) { + int n = 0; + while (m & 0x80000000u) { n++; m <<= 1; } + return n; } -bool ipv4_rt_add(uint32_t network, uint32_t mask, uint32_t gateway) -{ - if (g_rt_len >= IPV4_RT_MAX) return false; +ipv4_rt_table_t* ipv4_rt_create(void) { + ipv4_rt_table_t* t = (ipv4_rt_table_t*)malloc(sizeof(ipv4_rt_table_t)); + if (!t) return 0; + memset(t, 0, sizeof(*t)); + return t; +} - for (int i = 0; i < g_rt_len; ++i) { - if (g_rt[i].network == network && g_rt[i].mask == mask) { - g_rt[i].gateway = gateway; +void ipv4_rt_destroy(ipv4_rt_table_t* t) { + if (!t) return; + free(t, sizeof(*t)); +} + +void ipv4_rt_clear(ipv4_rt_table_t* t) { + if (!t) return; + t->len = 0; + memset(t->e, 0, sizeof(t->e)); +} + +bool ipv4_rt_add_in(ipv4_rt_table_t* t, uint32_t network, uint32_t mask, uint32_t gateway, uint16_t metric) { + if (!t) return false; + for (int i = 0; i < t->len; i++) { + if (t->e[i].network == network && t->e[i].mask == mask) { + t->e[i].gateway = gateway; + t->e[i].metric = metric; return true; } } - g_rt[g_rt_len++] = (ipv4_rt_entry_t){ network, mask, gateway }; + if (t->len >= IPV4_RT_PER_IF_MAX) return false; + t->e[t->len++] = (ipv4_rt_entry_t){ network, mask, gateway, metric }; return true; } -bool ipv4_rt_del(uint32_t network, uint32_t mask) -{ - for (int i = 0; i < g_rt_len; ++i) { - if (g_rt[i].network == network && g_rt[i].mask == mask) { - g_rt[i] = g_rt[--g_rt_len]; - memset(&g_rt[g_rt_len], 0, sizeof(g_rt[0])); +bool ipv4_rt_del_in(ipv4_rt_table_t* t, uint32_t network, uint32_t mask) { + if (!t) return false; + for (int i = 0; i < t->len; i++) { + if (t->e[i].network == network && t->e[i].mask == mask) { + t->e[i] = t->e[--t->len]; + memset(&t->e[t->len], 0, sizeof(t->e[0])); return true; } } return false; } -static inline int prefix_len(uint32_t mask) -{ - int len = 0; - while (mask & 0x80000000U) { ++len; mask <<= 1; } - return len; -} - -bool ipv4_rt_lookup(uint32_t dst, uint32_t *next_hop) -{ - int best_len = -1; +bool ipv4_rt_lookup_in(const ipv4_rt_table_t* t, uint32_t dst, uint32_t* next_hop, int* out_prefix_len, int* out_metric) { + if (!t) return false; + int best_pl = -1; + int best_metric = 0x7FFF; uint32_t best_nh = 0; - for (int i = 0; i < g_rt_len; ++i) { - uint32_t net = g_rt[i].network; - uint32_t mask = g_rt[i].mask; - if (mask && (dst & mask) == net) { - int l = prefix_len(mask); - if (l > best_len) { - best_len = l; - best_nh = g_rt[i].gateway ? g_rt[i].gateway : dst; + for (int i = 0; i < t->len; i++) { + uint32_t net = t->e[i].network; + uint32_t mask = t->e[i].mask; + if (mask == 0 || ((dst & mask) == net)) { + int pl = prefix_len(mask); + int met = t->e[i].metric; + if (pl > best_pl || (pl == best_pl && met < best_metric)) { + best_pl = pl; + best_metric = met; + best_nh = t->e[i].gateway ? t->e[i].gateway : dst; } } } - if (best_len >= 0) { - if (next_hop) *next_hop = best_nh; - return true; + + if (best_pl < 0) return false; + if (next_hop) *next_hop = best_nh; + if (out_prefix_len) *out_prefix_len = best_pl; + if (out_metric) *out_metric = best_metric; + return true; +} + +void ipv4_rt_ensure_basics(ipv4_rt_table_t* t, uint32_t ip, uint32_t mask, uint32_t gw, uint16_t base_metric) { + if (!t) return; + if (ip && mask) { + uint32_t net = ip & mask; + (void)ipv4_rt_add_in(t, net, mask, 0, base_metric); + } + if (gw) { + (void)ipv4_rt_add_in(t, 0, 0, gw, (uint16_t)(base_metric + 1)); + } +} + +void ipv4_rt_sync_basics(ipv4_rt_table_t* t, uint32_t ip, uint32_t mask, uint32_t gw, uint16_t base_metric) { + if (!t) return; + if (gw) { + (void)ipv4_rt_add_in(t, 0, 0, gw, (uint16_t)(base_metric + 1)); + } else { + (void)ipv4_rt_del_in(t, 0, 0); + } + if (ip && mask) { + uint32_t net = ip & mask; + (void)ipv4_rt_add_in(t, net, mask, 0, base_metric); } - return false; } diff --git a/shared/net/internet_layer/ipv4_route.h b/shared/net/internet_layer/ipv4_route.h index e030427b..30b6cd11 100644 --- a/shared/net/internet_layer/ipv4_route.h +++ b/shared/net/internet_layer/ipv4_route.h @@ -1,15 +1,33 @@ #pragma once #include "types.h" -#define IPV4_RT_MAX 8 +#ifdef __cplusplus +extern "C" { +#endif + +#define IPV4_RT_PER_IF_MAX 32 typedef struct { uint32_t network; uint32_t mask; uint32_t gateway; + uint16_t metric; } ipv4_rt_entry_t; -void ipv4_rt_init(); -bool ipv4_rt_add(uint32_t network, uint32_t mask, uint32_t gateway); -bool ipv4_rt_del(uint32_t network, uint32_t mask); -bool ipv4_rt_lookup(uint32_t dst, uint32_t *next_hop); +typedef struct ipv4_rt_table ipv4_rt_table_t; + +ipv4_rt_table_t* ipv4_rt_create(void); +void ipv4_rt_destroy(ipv4_rt_table_t* t); +void ipv4_rt_clear(ipv4_rt_table_t* t); + +bool ipv4_rt_add_in(ipv4_rt_table_t* t, uint32_t network, uint32_t mask, uint32_t gateway, uint16_t metric); +bool ipv4_rt_del_in(ipv4_rt_table_t* t, uint32_t network, uint32_t mask); + +bool ipv4_rt_lookup_in(const ipv4_rt_table_t* t, uint32_t dst, uint32_t *next_hop, int* out_prefix_len, int* out_metric); + +void ipv4_rt_ensure_basics(ipv4_rt_table_t* t, uint32_t ip, uint32_t mask, uint32_t gw, uint16_t base_metric); +void ipv4_rt_sync_basics(ipv4_rt_table_t* t, uint32_t ip, uint32_t mask, uint32_t gw, uint16_t base_metric); + +#ifdef __cplusplus +} +#endif diff --git a/shared/net/link_layer/arp.c b/shared/net/link_layer/arp.c index 7589be54..fd5b6019 100644 --- a/shared/net/link_layer/arp.c +++ b/shared/net/link_layer/arp.c @@ -1,210 +1,241 @@ #include "arp.h" #include "eth.h" -#include "console/kio.h" #include "std/memory.h" -#include "net/internet_layer/ipv4.h" -#include "networking/network.h" -#include "process/scheduler.h" -#include "types.h" #include "std/string.h" #include "networking/network.h" - - -#define ARP_OPCODE_REQUEST 1 -#define ARP_OPCODE_REPLY 2 - +#include "process/scheduler.h" +#include "console/kio.h" +#include "net/internet_layer/ipv4.h" extern void sleep(uint64_t ms); extern uintptr_t malloc(uint64_t size); extern void free(void *ptr, uint64_t size); +typedef struct arp_table { + arp_entry_t entries[ARP_TABLE_MAX]; + uint8_t init; +} arp_table_t; + static uint16_t g_arp_pid = 0xFFFF; -static arp_entry_t g_arp_table[ARP_TABLE_MAX]; -static bool init = false; -void arp_set_pid(uint16_t pid) { g_arp_pid = pid; } -uint16_t arp_get_pid() { return g_arp_pid; } +static inline arp_table_t* l2_arp(uint8_t ifindex){ + l2_interface_t* l2 = l2_interface_find_by_index(ifindex); + return l2 ? (arp_table_t*)l2->arp_table : 0; +} + +arp_table_t* arp_table_create(void){ + arp_table_t* t = (arp_table_t*)malloc(sizeof(arp_table_t)); + if (!t) return 0; + memset(t, 0, sizeof(*t)); + t->init = 1; + arp_table_init_static_defaults(t); + return t; +} -void arp_table_init() { - memset(g_arp_table, 0, sizeof(g_arp_table)); - init = true; - arp_table_init_static_defaults(); +void arp_table_destroy(arp_table_t* t){ + if (t) free(t, sizeof(*t)); } -void arp_table_init_static_defaults() { - uint8_t bmac[6] = {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}; - arp_table_put(0xFFFFFFFF, bmac, 0, true); +void arp_table_init_static_defaults(arp_table_t* t){ + if (!t) return; + t->entries[0].ip = 0xFFFFFFFFu; + t->entries[0].mac[0] = 0xFF; + t->entries[0].mac[1] = 0xFF; + t->entries[0].mac[2] = 0xFF; + t->entries[0].mac[3] = 0xFF; + t->entries[0].mac[4] = 0xFF; + t->entries[0].mac[5] = 0xFF; + t->entries[0].ttl_ms = 0; + t->entries[0].static_entry = 1; } -static int arp_table_find_slot(uint32_t ip) { - for (int i = 0; i < ARP_TABLE_MAX; i++) { - if (g_arp_table[i].ip == ip) return i; - } +static int arp_find_slot(arp_table_t* t, uint32_t ip){ + if (!t) return -1; + for (int i=0;ientries[i].ip == ip) return i; return -1; } -static int arp_table_find_free() { - for (int i = 0; i < ARP_TABLE_MAX; i++) { - if (g_arp_table[i].ip == 0) return i; - } +static int arp_find_free(arp_table_t* t){ + if (!t) return -1; + for (int i=0;ientries[i].ip == 0) return i; return -1; } -void arp_table_put(uint32_t ip, const uint8_t mac[6], uint32_t ttl_ms, bool is_static) { - int idx = arp_table_find_slot(ip); - if (idx < 0) idx = arp_table_find_free(); +void arp_table_put_for_l2(uint8_t ifindex, uint32_t ip, const uint8_t mac[6], uint32_t ttl_ms, bool is_static){ + arp_table_t* t = l2_arp(ifindex); + if (!t) return; + int idx = arp_find_slot(t, ip); + if (idx < 0) idx = arp_find_free(t); if (idx < 0) idx = 0; - - g_arp_table[idx].ip = ip; - memcpy(g_arp_table[idx].mac, mac, 6); - g_arp_table[idx].ttl_ms = is_static ? 0 : ttl_ms; - g_arp_table[idx].static_entry = is_static ? 1 : 0; + t->entries[idx].ip = ip; + memcpy(t->entries[idx].mac, mac, 6); + t->entries[idx].ttl_ms = is_static ? 0 : ttl_ms; + t->entries[idx].static_entry = is_static ? 1 : 0; } -bool arp_table_get(uint32_t ip, uint8_t mac_out[6]) { - int idx = arp_table_find_slot(ip); - if (idx < 0) return false; - memcpy(mac_out, g_arp_table[idx].mac, 6); - return true; +bool arp_table_get_for_l2(uint8_t ifindex, uint32_t ip, uint8_t mac_out[6]){ + arp_table_t* t = l2_arp(ifindex); + if (!t) return false; + for (int i=0;ientries[i].ip == ip){ + memcpy(mac_out, t->entries[i].mac, 6); + return true; + } + } + return false; } -void arp_table_tick(uint32_t ms) { - for (int i = 0; i < ARP_TABLE_MAX; i++) { - if (g_arp_table[i].ip == 0 || g_arp_table[i].static_entry) - continue; - if (g_arp_table[i].ttl_ms <= ms) { - memset(&g_arp_table[i], 0, sizeof(arp_entry_t)); +void arp_table_tick_for_l2(uint8_t ifindex, uint32_t ms){ + arp_table_t* t = l2_arp(ifindex); + if (!t) return; + for (int i=0;ientries[i].ip == 0 || t->entries[i].static_entry) continue; + if (t->entries[i].ttl_ms <= ms){ + memset(&t->entries[i], 0, sizeof(arp_entry_t)); } else { - g_arp_table[i].ttl_ms -= ms; + t->entries[i].ttl_ms -= ms; + } + } +} + +void arp_tick_all(uint32_t ms){ + for (uint8_t i=1;i<=MAX_L2_INTERFACES;i++){ + l2_interface_t* l2 = l2_interface_find_by_index(i); + if (!l2) continue; + if (!l2->arp_table) continue; + arp_table_tick_for_l2(i, ms); + } +} + +static uint32_t pick_spa_for_l2(uint8_t ifindex, uint32_t target_ip){ + l2_interface_t* l2 = l2_interface_find_by_index(ifindex); + if (!l2) return 0; + for (int s=0;sl3_v4[s]; + if (!v4) continue; + if (v4->mode == IPV4_CFG_DISABLED) continue; + if (v4->ip && v4->mask){ + uint32_t a = v4->ip & v4->mask; + uint32_t b = target_ip & v4->mask; + if (a == b) return v4->ip; } } + for (int s=0;sl3_v4[s]; + if (!v4) continue; + if (v4->mode == IPV4_CFG_DISABLED) continue; + if (v4->ip) return v4->ip; + } + return 0; } -bool arp_resolve(uint32_t ip, uint8_t mac_out[6], uint32_t timeout_ms) { - - if (arp_table_get(ip, mac_out)) return true; - if (ip == 0xFFFFFFFF) { +bool arp_resolve_on(uint8_t ifindex, uint32_t ip, uint8_t mac_out[6], uint32_t timeout_ms){ + if (ip == 0xFFFFFFFFu){ memset(mac_out, 0xFF, 6); return true; } - arp_send_request(ip); - + if (arp_table_get_for_l2(ifindex, ip, mac_out)) return true; + arp_send_request_on(ifindex, ip); uint32_t waited = 0; const uint32_t POLL_MS = 100; while (waited < timeout_ms) { - arp_table_tick(POLL_MS); - if (arp_table_get(ip, mac_out)) return true; + arp_table_tick_for_l2(ifindex, POLL_MS); + if (arp_table_get_for_l2(ifindex, ip, mac_out)) return true; sleep(POLL_MS); waited += POLL_MS; } return false; } -void arp_send_request(uint32_t target_ip) { - const uint8_t *local_mac = network_get_local_mac(); - const net_cfg_t *cfg = ipv4_get_cfg(); - - if (!cfg) return; - +void arp_send_request_on(uint8_t ifindex, uint32_t target_ip){ + const uint8_t* local_mac = network_get_mac(ifindex); + if (!local_mac) return; + uint32_t spa = pick_spa_for_l2(ifindex, target_ip); uint8_t dst_mac[6] = {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}; arp_hdr_t hdr; - - memset(hdr.target_mac, 0x00, sizeof(hdr.target_mac)); + memset(&hdr, 0, sizeof(hdr)); hdr.htype = bswap16(1); - hdr.ptype = bswap16(0x0800); + hdr.ptype = bswap16(ETHERTYPE_IPV4); hdr.hlen = 6; hdr.plen = 4; hdr.opcode = bswap16(ARP_OPCODE_REQUEST); memcpy(hdr.sender_mac, local_mac, 6); - hdr.sender_ip = bswap32(cfg->ip); + hdr.sender_ip = bswap32(spa); hdr.target_ip = bswap32(target_ip); - - sizedptr payload = { (uintptr_t)&hdr, sizeof(hdr) }; uintptr_t buf = (uintptr_t)malloc(sizeof(hdr)); if (!buf) return; memcpy((void*)buf, &hdr, sizeof(hdr)); - payload.ptr = buf; - - eth_send_frame(0x0806, dst_mac, payload); - + sizedptr payload = { buf, sizeof(hdr) }; + (void)eth_send_frame_on(ifindex, ETHERTYPE_ARP, dst_mac, payload); free((void*)buf, sizeof(hdr)); } -bool arp_should_handle(const arp_hdr_t *arp, uint32_t my_ip) { - return bswap32(arp->target_ip) == my_ip; -} - -void arp_populate_response(uint8_t out_mac[6], uint32_t *out_ip, const arp_hdr_t *arp) { - if (out_mac) memcpy(out_mac, arp->sender_mac, 6); - if (out_ip) *out_ip = bswap32(arp->sender_ip); -} - -bool arp_can_reply() { - const net_cfg_t *cfg = ipv4_get_cfg(); - return (cfg && cfg->ip != 0 && cfg->mode != -1); //NET_MODE_DISABLED -} - - -int arp_daemon_entry(int argc, char* argv[]){ - (void)argc; (void)argv; - arp_set_pid(get_current_proc_pid()); - while (1){ - const net_cfg_t *cfg = ipv4_get_cfg(); - if(cfg && cfg->ip != 0 && cfg->mode != -1) break; //NET_MODE_DISABLED - sleep(200); - } - arp_table_init(); - - while (1) { - arp_table_tick(1000); - sleep(1000); +static bool l2_has_ip(uint8_t ifindex, uint32_t ip){ + l2_interface_t* l2 = l2_interface_find_by_index(ifindex); + if (!l2) return false; + for (int s=0;sl3_v4[s]; + if (!v4) continue; + if (v4->mode == IPV4_CFG_DISABLED) continue; + if (v4->ip == ip) return true; } + return false; } -static void arp_send_reply(const arp_hdr_t *in_arp, - const uint8_t in_src_mac[6], - uint32_t frame_len){ - (void)frame_len; - - const uint8_t *local_mac = network_get_local_mac(); - const net_cfg_t *cfg = ipv4_get_cfg(); - if (!cfg) return; - +static void arp_send_reply_on(uint8_t ifindex, const arp_hdr_t* in_arp, const uint8_t in_src_mac[6]){ + const uint8_t* local_mac = network_get_mac(ifindex); + if (!local_mac) return; + uint32_t spa = pick_spa_for_l2(ifindex, bswap32(in_arp->sender_ip)); + if (!spa) return; arp_hdr_t reply = *in_arp; memcpy(reply.target_mac, in_arp->sender_mac, 6); - memcpy(reply.sender_mac, local_mac, 6); + memcpy(reply.sender_mac, local_mac, 6); reply.target_ip = in_arp->sender_ip; - reply.sender_ip = bswap32(cfg->ip); + reply.sender_ip = bswap32(spa); reply.opcode = bswap16(ARP_OPCODE_REPLY); - - sizedptr payload = {(uintptr_t)&reply, sizeof(reply)}; - uintptr_t buf = (uintptr_t)malloc(sizeof(reply)); if (!buf) return; memcpy((void*)buf, &reply, sizeof(reply)); - payload.ptr = buf; - - eth_send_frame(0x0806, in_src_mac, payload); + sizedptr payload = { buf, sizeof(reply) }; + (void)eth_send_frame_on(ifindex, ETHERTYPE_ARP, in_src_mac, payload); free((void*)buf, sizeof(reply)); } -void arp_input(uintptr_t frame_ptr, uint32_t frame_len) { +void arp_input(uint16_t ifindex, uintptr_t frame_ptr, uint32_t frame_len){ if (frame_len < sizeof(eth_hdr_t) + sizeof(arp_hdr_t)) return; - if (!init) return; - arp_hdr_t *hdr = (arp_hdr_t*)(frame_ptr + sizeof(eth_hdr_t)); + const eth_hdr_t* eth = (const eth_hdr_t*)frame_ptr; + const uint8_t* src_mac = eth->src_mac; + const arp_hdr_t* hdr = (const arp_hdr_t*)(frame_ptr + sizeof(eth_hdr_t)); + uint16_t op = bswap16(hdr->opcode); uint32_t sender_ip = bswap32(hdr->sender_ip); + uint32_t target_ip = bswap32(hdr->target_ip); + + arp_table_put_for_l2((uint8_t)ifindex, sender_ip, hdr->sender_mac, 180000, false); + + if (op == ARP_OPCODE_REQUEST) { + char tbuf[16], abuf[16]; + ipv4_to_string(target_ip, tbuf); + + bool has = l2_has_ip((uint8_t)ifindex, target_ip); + + uint32_t spa_guess = pick_spa_for_l2((uint8_t)ifindex, sender_ip); + ipv4_to_string(spa_guess, abuf); + if (has || (spa_guess == target_ip)) { + arp_send_reply_on((uint8_t)ifindex, hdr, src_mac); + } + } +} - arp_table_put(sender_ip, hdr->sender_mac, 180000, false); - const net_cfg_t *cfg = ipv4_get_cfg(); - if (!cfg) return; +void arp_set_pid(uint16_t pid){ g_arp_pid = pid; } +uint16_t arp_get_pid(void){ return g_arp_pid; } - if (bswap16(hdr->opcode) == ARP_OPCODE_REQUEST && - arp_should_handle(hdr, cfg->ip) && - arp_can_reply()) - { - const arp_hdr_t *hdr_in = (arp_hdr_t*)(frame_ptr + sizeof(eth_hdr_t)); - const uint8_t *src_mac = hdr_in->sender_mac; - arp_send_reply(hdr_in, src_mac, frame_len); +int arp_daemon_entry(int argc, char* argv[]){ + (void)argc; (void)argv; + arp_set_pid(get_current_proc_pid()); + const uint32_t tick_ms = 10000; + while (1){ + arp_tick_all(tick_ms); + sleep(tick_ms); } } \ No newline at end of file diff --git a/shared/net/link_layer/arp.h b/shared/net/link_layer/arp.h index efe4ae3e..0f3e11ba 100644 --- a/shared/net/link_layer/arp.h +++ b/shared/net/link_layer/arp.h @@ -1,11 +1,15 @@ #pragma once #include "types.h" -#include "net/network_types.h" +#include "networking/interface_manager.h" #ifdef __cplusplus extern "C" { #endif +#define ARP_TABLE_MAX 64 +#define ARP_OPCODE_REQUEST 1 +#define ARP_OPCODE_REPLY 2 + typedef struct __attribute__((packed)) arp_hdr_t { uint16_t htype; uint16_t ptype; @@ -18,12 +22,6 @@ typedef struct __attribute__((packed)) arp_hdr_t { uint32_t target_ip; } arp_hdr_t; -bool arp_should_handle(const arp_hdr_t *arp, uint32_t my_ip); -void arp_populate_response(uint8_t out_mac[6], uint32_t *out_ip, const arp_hdr_t *arp); -bool arp_resolve(uint32_t ip, uint8_t mac_out[6], uint32_t timeout_ms); - -#define ARP_TABLE_MAX 64 - typedef struct arp_entry { uint32_t ip; uint8_t mac[6]; @@ -31,23 +29,26 @@ typedef struct arp_entry { uint8_t static_entry;//1 static, 0 dynamic } arp_entry_t; -void arp_table_init(); - -void arp_table_put(uint32_t ip, const uint8_t mac[6], uint32_t ttl_ms, bool is_static); +typedef struct arp_table arp_table_t; -bool arp_table_get(uint32_t ip, uint8_t mac_out[6]); +arp_table_t* arp_table_create(void); +void arp_table_destroy(arp_table_t* t); +void arp_table_init_static_defaults(arp_table_t* t); -void arp_table_tick(uint32_t ms); +void arp_table_put_for_l2(uint8_t ifindex, uint32_t ip, const uint8_t mac[6], uint32_t ttl_ms, bool is_static); +bool arp_table_get_for_l2(uint8_t ifindex, uint32_t ip, uint8_t mac_out[6]); +void arp_table_tick_for_l2(uint8_t ifindex, uint32_t ms); +void arp_tick_all(uint32_t ms); -void arp_table_init_static_defaults(); +bool arp_resolve_on(uint8_t ifindex, uint32_t ip, uint8_t mac_out[6], uint32_t timeout_ms); +void arp_send_request_on(uint8_t ifindex, uint32_t target_ip); -void arp_send_request(uint32_t target_ip); +void arp_input(uint16_t ifindex, uintptr_t frame_ptr, uint32_t frame_len); -int arp_daemon_entry(int argc, char* argv[]); -bool arp_can_reply(); void arp_set_pid(uint16_t pid); -uint16_t arp_get_pid(); -void arp_input(uintptr_t frame_ptr, uint32_t frame_len); +uint16_t arp_get_pid(void); +int arp_daemon_entry(int argc, char* argv[]); + #ifdef __cplusplus } -#endif +#endif \ No newline at end of file diff --git a/shared/net/link_layer/eth.c b/shared/net/link_layer/eth.c index ec87ad9c..33a787b3 100644 --- a/shared/net/link_layer/eth.c +++ b/shared/net/link_layer/eth.c @@ -1,10 +1,12 @@ #include "eth.h" -#include "arp.h" #include "std/memory.h" +#include "networking/network.h" +#include "arp.h" #include "net/internet_layer/ipv4.h" #include "networking/network.h" +//#include "net/internet_layer/ipv6.h" +#include "console/kio.h" -extern int net_tx_frame(uintptr_t frame_ptr, uint32_t frame_len); extern uintptr_t malloc(uint64_t size); extern void free(void *ptr, uint64_t size); @@ -14,59 +16,68 @@ uintptr_t create_eth_packet(uintptr_t p, uint16_t type) { eth_hdr_t* eth =(eth_hdr_t*)p; - memcpy(eth->src_mac, src_mac, 6); + memcpy(eth->dst_mac, dst_mac, 6); + memcpy(eth->src_mac, src_mac, 6); eth->ethertype = bswap16(type); + return p + sizeof(eth_hdr_t); } -uint16_t eth_parse_packet_type(uintptr_t ptr) { +uint16_t eth_parse_type(uintptr_t ptr){ const eth_hdr_t* eth = (const eth_hdr_t*)ptr; return bswap16(eth->ethertype); } -const uint8_t* eth_get_source(uintptr_t ptr){ +const uint8_t* eth_src(uintptr_t ptr){ const eth_hdr_t* eth = (const eth_hdr_t*)ptr; return eth->src_mac; } -bool eth_send_frame(uint16_t ethertype, - const uint8_t dst_mac[6], - sizedptr payload) -{ - const uint8_t* src_mac = network_get_local_mac(); +const uint8_t* eth_dst(uintptr_t ptr){ + const eth_hdr_t* eth = (const eth_hdr_t*)ptr; + return eth->dst_mac; +} + +bool eth_send_frame_on(uint16_t ifindex, uint16_t ethertype, const uint8_t dst_mac[6], sizedptr payload){ + const uint8_t* src_mac = network_get_mac(ifindex); + if (!src_mac || !dst_mac) return false; uint32_t total = (uint32_t)sizeof(eth_hdr_t) + (uint32_t)payload.size; uintptr_t buf = (uintptr_t)malloc(total); if (!buf) return false; uintptr_t ptr = create_eth_packet(buf, src_mac, dst_mac, ethertype); - if (payload.size) { - memcpy((void*)ptr, (void*)payload.ptr, payload.size); - } - bool ok = net_tx_frame(buf, total); + if (payload.size) memcpy((void*)ptr, (const void*)payload.ptr, payload.size); + bool ok = (net_tx_frame_on(ifindex, buf, total) == 0); free((void*)buf, total); return ok; } -void eth_input(uintptr_t frame_ptr, uint32_t frame_len) { +void eth_input(uint16_t ifindex, uintptr_t frame_ptr, uint32_t frame_len){ + if (frame_len < sizeof(eth_hdr_t)) return; - uint16_t type = eth_parse_packet_type(frame_ptr); - const uint8_t* src_mac = eth_get_source(frame_ptr); + uint16_t type = eth_parse_type(frame_ptr); + const uint8_t* src_mac = eth_src(frame_ptr); uintptr_t payload_ptr = frame_ptr + sizeof(eth_hdr_t); - uint32_t payload_len = frame_len - sizeof(eth_hdr_t); - + uint32_t payload_len = frame_len - (uint32_t)sizeof(eth_hdr_t); switch (type) { - case 0x0806: - arp_input(frame_ptr, frame_len); - break; - case 0x0800: - ip_input(payload_ptr, payload_len, src_mac); - break; - default: - break; + case ETHERTYPE_ARP: + arp_input(ifindex, frame_ptr, frame_len); + break; + case ETHERTYPE_IPV4: + ipv4_input(ifindex, payload_ptr, payload_len, src_mac); + break; + case ETHERTYPE_IPV6: //TODO IPV6 + break; + case ETHERTYPE_VLAN1Q: //TODO vlan + break; + case ETHERTYPE_VLAN1AD: //TODO vlan + break; + default: + break; } } diff --git a/shared/net/link_layer/eth.h b/shared/net/link_layer/eth.h index f83ed3d6..2ffdedd4 100644 --- a/shared/net/link_layer/eth.h +++ b/shared/net/link_layer/eth.h @@ -6,20 +6,25 @@ extern "C" { #endif +#define ETHERTYPE_IPV4 0x0800 +#define ETHERTYPE_ARP 0x0806 +#define ETHERTYPE_VLAN1Q 0x8100 +#define ETHERTYPE_VLAN1AD 0x88A8 +#define ETHERTYPE_IPV6 0x86DD + typedef struct __attribute__((packed)) eth_hdr_t { uint8_t dst_mac[6]; uint8_t src_mac[6]; uint16_t ethertype; } eth_hdr_t; -uint16_t eth_parse_packet_type(uintptr_t ptr); -const uint8_t* eth_get_source(uintptr_t ptr); +uint16_t eth_parse_type(uintptr_t frame_ptr); +const uint8_t* eth_src(uintptr_t frame_ptr); +const uint8_t* eth_dst(uintptr_t frame_ptr); -bool eth_send_frame(uint16_t ethertype, - const uint8_t dst_mac[6], - sizedptr payload); +bool eth_send_frame_on(uint16_t ifindex, uint16_t ethertype, const uint8_t dst_mac[6], sizedptr payload); -void eth_input(uintptr_t frame_ptr, uint32_t frame_len); +void eth_input(uint16_t ifindex, uintptr_t frame_ptr, uint32_t frame_len); #ifdef __cplusplus } diff --git a/shared/net/transport_layer/tcp.c b/shared/net/transport_layer/tcp.c index ff42fa1e..ab64737e 100644 --- a/shared/net/transport_layer/tcp.c +++ b/shared/net/transport_layer/tcp.c @@ -155,7 +155,7 @@ static bool send_tcp_segment(uint32_t src_ip, uint32_t dst_ip, tcp_hdr_t *hdr, c hdr_on_buf->checksum = 0; uint16_t csum = tcp_compute_checksum(segment, tcp_len, src_ip, dst_ip); hdr_on_buf->checksum = csum; - ipv4_send_packet(src_ip, dst_ip, 6, (sizedptr){ .ptr = (uintptr_t)segment, .size = tcp_len }); + ipv4_send_packet(dst_ip, 6, (sizedptr){ .ptr = (uintptr_t)segment, .size = tcp_len }, NULL); free(segment, tcp_len); return true; } diff --git a/shared/net/transport_layer/udp.c b/shared/net/transport_layer/udp.c index f817bbda..4f295c85 100644 --- a/shared/net/transport_layer/udp.c +++ b/shared/net/transport_layer/udp.c @@ -62,7 +62,8 @@ void udp_send_segment(const net_l4_endpoint *src, uintptr_t udp_buf = buf + sizeof(eth_hdr_t) + sizeof(ipv4_hdr_t); size_t udp_len = create_udp_segment(udp_buf, src, dst, payload); - ipv4_send_packet(src->ip, dst->ip, 0x11,(sizedptr){ udp_buf, (uint32_t)udp_len }); + ipv4_tx_opts_t o = { .index = 1, .int_type = 0 }; + ipv4_send_packet(0xFFFFFFFFu, 0x11,(sizedptr){ udp_buf, (uint32_t)udp_len }, &o); free((void*)buf, eth_total); } From 1ef8e68415b462676b94401eab1f2f909f07a438 Mon Sep 17 00:00:00 2001 From: CodeAnarchist Date: Sat, 27 Sep 2025 15:05:33 +0200 Subject: [PATCH 14/23] net: update l4 and upper layers for multi-int support --- kernel/networking/interface_manager.c | 108 ++- kernel/networking/interface_manager.h | 41 +- kernel/networking/network.cpp | 4 + kernel/networking/network.h | 2 + kernel/networking/network_dispatch.cpp | 29 +- kernel/networking/network_dispatch.hpp | 3 +- kernel/networking/port_manager.c | 71 +- kernel/networking/port_manager.h | 43 +- kernel/networking/processes/net_proc.c | 288 ++++--- kernel/process/syscall.c | 27 +- .../application_layer/csocket_http_client.cpp | 22 +- .../application_layer/csocket_http_client.h | 11 +- .../application_layer/csocket_http_server.cpp | 27 +- .../application_layer/csocket_http_server.h | 16 +- shared/net/application_layer/dhcp.c | 92 ++- shared/net/application_layer/dhcp.h | 20 +- shared/net/application_layer/dhcp_daemon.c | 728 ++++++++++++------ shared/net/application_layer/dns.c | 170 +++- shared/net/application_layer/dns.h | 6 +- shared/net/application_layer/dns_daemon.c | 4 +- shared/net/application_layer/http.c | 4 +- shared/net/application_layer/sntp.c | 128 +-- shared/net/application_layer/sntp_daemon.c | 31 +- .../application_layer/socket_http_client.hpp | 198 +++-- .../application_layer/socket_http_server.hpp | 3 +- shared/net/internet_layer/icmp.c | 8 +- shared/net/internet_layer/ipv4.c | 239 +++--- shared/net/internet_layer/ipv4.h | 25 +- shared/net/internet_layer/ipv4_route.c | 44 +- shared/net/internet_layer/ipv4_route.h | 2 + shared/net/link_layer/arp.c | 4 +- shared/net/link_layer/eth.c | 4 +- shared/net/network_types.h | 9 +- shared/net/transport_layer/csocket_tcp.cpp | 45 +- shared/net/transport_layer/csocket_tcp.h | 10 +- shared/net/transport_layer/csocket_udp.cpp | 34 +- shared/net/transport_layer/csocket_udp.h | 26 +- shared/net/transport_layer/socket.hpp | 66 +- shared/net/transport_layer/socket_tcp.hpp | 462 +++++++---- shared/net/transport_layer/socket_types.h | 31 + shared/net/transport_layer/socket_udp.hpp | 493 +++++++++--- shared/net/transport_layer/tcp.c | 678 ++++++++-------- shared/net/transport_layer/tcp.h | 36 +- shared/net/transport_layer/udp.c | 158 ++-- shared/net/transport_layer/udp.h | 29 +- shared/std/memory.c | 47 +- 46 files changed, 2886 insertions(+), 1640 deletions(-) create mode 100644 shared/net/transport_layer/socket_types.h diff --git a/kernel/networking/interface_manager.c b/kernel/networking/interface_manager.c index 31e7e274..0eac062e 100644 --- a/kernel/networking/interface_manager.c +++ b/kernel/networking/interface_manager.c @@ -2,6 +2,11 @@ #include "std/memory.h" #include "net/link_layer/arp.h" #include "net/internet_layer/ipv4_route.h" +#include "networking/port_manager.h" +#include "process/scheduler.h" +#include "memory/page_allocator.h" + +static void* g_kmem_page = NULL; //TODO: add network settings static inline void mem_zero(void *p, size_t n){ if (p) memset(p,0,n); } @@ -298,11 +303,14 @@ uint8_t l3_ipv4_add_to_interface(uint8_t ifindex, uint32_t ip, uint32_t mask, ui if (v4_overlap_intra_l2(ifindex, ip, mask)) return 0; } if (l2->ipv4_count >= MAX_IPV4_PER_INTERFACE) return 0; + int loc = alloc_local_slot_v4(l2); int g = alloc_global_v4_slot(); if (loc < 0 || g < 0) return 0; + g_v4[g].used = true; g_v4[g].slot_in_l2 = (uint8_t)loc; + l3_ipv4_interface_t *n = &g_v4[g].node; mem_zero(n, sizeof(*n)); n->l2 = l2; @@ -311,13 +319,38 @@ uint8_t l3_ipv4_add_to_interface(uint8_t ifindex, uint32_t ip, uint32_t mask, ui n->mask = (mode==IPV4_CFG_STATIC) ? mask : 0; n->gw = (mode==IPV4_CFG_STATIC) ? gw : 0; n->broadcast = (mode==IPV4_CFG_STATIC) ? ipv4_broadcast_calc(ip, mask) : 0; - n->runtime_opts_v4 = runtime_opts; + + mem_zero(&n->runtime_opts_v4, sizeof(n->runtime_opts_v4)); + if (runtime_opts) { + n->runtime_opts_v4 = *runtime_opts; + } + n->routing_table = ipv4_rt_create(); + if (!n->routing_table) { + g_v4[g].used = false; + mem_zero(&g_v4[g], sizeof(g_v4[g])); + return 0; + } ipv4_rt_ensure_basics((ipv4_rt_table_t*)n->routing_table, n->ip, n->mask, n->gw, l2->base_metric); + n->is_localhost = (l2->name[0]=='l' && l2->name[1]=='o'); n->l3_id = make_l3_id(l2->ifindex, (uint8_t)loc); l2->l3_v4[loc] = n; l2->ipv4_count++; + + if (!g_kmem_page) g_kmem_page = palloc(PAGE_SIZE, MEM_PRIV_KERNEL, MEM_RW | MEM_NORM, false); + n->port_manager = (port_manager_t*)kalloc(g_kmem_page, sizeof(port_manager_t), ALIGN_16B, MEM_PRIV_KERNEL); + if (!n->port_manager) { + l2->l3_v4[loc] = NULL; + if (l2->ipv4_count) l2->ipv4_count--; + ipv4_rt_destroy((ipv4_rt_table_t*)n->routing_table); + n->routing_table = NULL; + g_v4[g].used = false; + mem_zero(&g_v4[g], sizeof(g_v4[g])); + return 0; + } + port_manager_init(n->port_manager); + return n->l3_id; } @@ -327,9 +360,7 @@ bool l3_ipv4_update(uint8_t l3_id, uint32_t ip, uint32_t mask, uint32_t gw, ipv4 l2_interface_t *l2 = n->l2; if (!l2) return false; if (mode == IPV4_CFG_DHCP && n->mode != IPV4_CFG_DHCP) { - if (v4_has_dhcp_on_l2(l2->ifindex)) { - return false; - } + if (v4_has_dhcp_on_l2(l2->ifindex)) return false; } if (mode == IPV4_CFG_STATIC){ if (ipv4_is_unspecified(ip)) return false; @@ -350,8 +381,13 @@ bool l3_ipv4_update(uint8_t l3_id, uint32_t ip, uint32_t mask, uint32_t gw, ipv4 if (ipv4_net(ip, m) == ipv4_net(x->ip, m)) return false; } } + n->mode = mode; - n->runtime_opts_v4 = runtime_opts; + + if (runtime_opts) { + n->runtime_opts_v4 = *runtime_opts; + } + if (mode == IPV4_CFG_STATIC || mode == IPV4_CFG_DHCP) { n->ip = ip; n->mask = mask; @@ -363,6 +399,7 @@ bool l3_ipv4_update(uint8_t l3_id, uint32_t ip, uint32_t mask, uint32_t gw, ipv4 n->gw = 0; n->broadcast = 0; } + if (!n->routing_table) n->routing_table = ipv4_rt_create(); ipv4_rt_sync_basics((ipv4_rt_table_t*)n->routing_table, n->ip, n->mask, n->gw, l2->base_metric); return true; @@ -374,19 +411,31 @@ bool l3_ipv4_remove_from_interface(uint8_t l3_id){ l2_interface_t *l2 = n->l2; if (!l2) return false; if (l2->ipv4_count <= 1) return false; + + int g = -1; + for (int i=0;iport_manager) { + kfree(n->port_manager, sizeof(port_manager_t)); + n->port_manager = NULL; + } + uint8_t slot = l3_local_slot_from_id(l3_id); if (slot < MAX_IPV4_PER_INTERFACE && l2->l3_v4[slot] == n){ l2->l3_v4[slot] = NULL; if (l2->ipv4_count) l2->ipv4_count--; } - if (n->routing_table) { ipv4_rt_destroy((ipv4_rt_table_t*)n->routing_table); n->routing_table = 0; } - for (int i=0;irouting_table) { + ipv4_rt_destroy((ipv4_rt_table_t*)n->routing_table); + n->routing_table = 0; } + + g_v4[g].used = false; + mem_zero(&g_v4[g], sizeof(g_v4[g])); return true; } @@ -462,6 +511,7 @@ uint8_t l3_ipv6_add_to_interface(uint8_t ifindex, const uint8_t ip[16], uint8_t g_v6[g].used = true; g_v6[g].slot_in_l2 = (uint8_t)loc; + l3_ipv6_interface_t *n = &g_v6[g].node; mem_zero(n, sizeof(*n)); n->l2 = l2; @@ -474,6 +524,18 @@ uint8_t l3_ipv6_add_to_interface(uint8_t ifindex, const uint8_t ip[16], uint8_t n->l3_id = make_l3_id(l2->ifindex, (uint8_t)loc); l2->l3_v6[loc] = n; l2->ipv6_count++; + + if (!g_kmem_page) g_kmem_page = palloc(PAGE_SIZE, MEM_PRIV_KERNEL, MEM_RW | MEM_NORM, false); + n->port_manager = (port_manager_t*)kalloc(g_kmem_page, sizeof(port_manager_t), ALIGN_16B, MEM_PRIV_KERNEL); + if (!n->port_manager){ + l2->l3_v6[loc] = NULL; + if (l2->ipv6_count) l2->ipv6_count--; + g_v6[g].used = false; + mem_zero(&g_v6[g], sizeof(g_v6[g])); + return 0; + } + port_manager_init(n->port_manager); + return n->l3_id; } @@ -557,18 +619,26 @@ bool l3_ipv6_remove_from_interface(uint8_t l3_id){ } } if (l2->ipv6_count <= 1) return false; + + int g = -1; + for (int i=0;iport_manager) { + kfree(n->port_manager, sizeof(port_manager_t)); + n->port_manager = NULL; + } + uint8_t slot = l3_local_slot_from_id(l3_id); if (slot < MAX_IPV6_PER_INTERFACE && l2->l3_v6[slot] == n){ l2->l3_v6[slot] = NULL; if (l2->ipv6_count) l2->ipv6_count--; } - for (int i=0;iport_manager : NULL; +} +static inline port_manager_t* ifmgr_pm_v6(uint8_t l3_id){ + l3_ipv6_interface_t* n = l3_ipv6_find_by_id(l3_id); + return n ? n->port_manager : NULL; +} + #ifdef __cplusplus } #endif \ No newline at end of file diff --git a/kernel/networking/network.cpp b/kernel/networking/network.cpp index f95916a9..04946089 100644 --- a/kernel/networking/network.cpp +++ b/kernel/networking/network.cpp @@ -98,6 +98,10 @@ uint16_t network_net_get_pid() { return dispatch ? dispatch->get_net_pid() : UINT16_MAX; } +void network_dump_interfaces() { + if (dispatch) dispatch->dump_interfaces(); +} + driver_module net_module = (driver_module){ .name = "net", .mount = "/net", diff --git a/kernel/networking/network.h b/kernel/networking/network.h index 83196eba..8fc5fb62 100644 --- a/kernel/networking/network.h +++ b/kernel/networking/network.h @@ -36,6 +36,8 @@ size_t network_nic_count(void); void network_update_local_ip(uint32_t ip); +void network_dump_interfaces(void); + extern driver_module net_module; #ifdef __cplusplus diff --git a/kernel/networking/network_dispatch.cpp b/kernel/networking/network_dispatch.cpp index b4af4142..b2040c4b 100644 --- a/kernel/networking/network_dispatch.cpp +++ b/kernel/networking/network_dispatch.cpp @@ -9,10 +9,7 @@ #include "std/std.h" #include "console/kio.h" #include "networking/interface_manager.h" - -extern void sleep(uint64_t ms); -extern uintptr_t malloc(uint64_t size); -extern void free(void *ptr, uint64_t size); +#include "syscalls/syscalls.h" #define RX_INTR_BATCH_LIMIT 32 #define TASK_RX_BATCH_LIMIT 32 @@ -343,16 +340,34 @@ void NetworkDispatch::dump_interfaces() for (int s = 0; s < (int)MAX_IPV4_PER_INTERFACE; ++s){ l3_ipv4_interface_t* v4 = l2->l3_v4[s]; if (!v4) continue; + char ip[16], mask[16], gw[16], bc[16]; ipv4_to_string(v4->ip, ip); ipv4_to_string(v4->mask, mask); ipv4_to_string(v4->gw, gw); ipv4_to_string(v4->broadcast, bc); - kprintf(" - slot=%u l3_id=%u mode=%i ip=%s mask=%s gw=%s bcast=%s rt=%x localhost=%u", - (unsigned)s, (unsigned)v4->l3_id, (int)v4->mode, ip, mask, gw, bc, - (uint64_t)(uintptr_t)v4->runtime_opts_v4, v4->is_localhost?1:0); + + char dns0[16], dns1[16], ntp0[16], ntp1[16]; + if (v4->runtime_opts_v4.dns[0]) ipv4_to_string(v4->runtime_opts_v4.dns[0], dns0); else { dns0[0]='-'; dns0[1]=0; } + if (v4->runtime_opts_v4.dns[1]) ipv4_to_string(v4->runtime_opts_v4.dns[1], dns1); else { dns1[0]='-'; dns1[1]=0; } + if (v4->runtime_opts_v4.ntp[0]) ipv4_to_string(v4->runtime_opts_v4.ntp[0], ntp0); else { ntp0[0]='-'; ntp0[1]=0; } + if (v4->runtime_opts_v4.ntp[1]) ipv4_to_string(v4->runtime_opts_v4.ntp[1], ntp1); else { ntp1[0]='-'; ntp1[1]=0; } + + kprintf(" - slot=%u l3_id=%u mode=%i ip=%s mask=%s gw=%s bcast=%s " + "mtu=%u dns=[%s,%s] ntp=[%s,%s] xid=%u lease=%us t1=%us t2=%us localhost=%u", + (unsigned)s, (unsigned)v4->l3_id, (int)v4->mode, + ip, mask, gw, bc, + (unsigned)v4->runtime_opts_v4.mtu, + dns0, dns1, + ntp0, ntp1, + (unsigned)v4->runtime_opts_v4.xid, + (unsigned)v4->runtime_opts_v4.lease, + (unsigned)v4->runtime_opts_v4.t1, + (unsigned)v4->runtime_opts_v4.t2, + v4->is_localhost ? 1u : 0u); } + kprintf(" int ipv6:"); for (int s = 0; s < (int)MAX_IPV6_PER_INTERFACE; ++s){ l3_ipv6_interface_t* v6 = l2->l3_v6[s]; diff --git a/kernel/networking/network_dispatch.hpp b/kernel/networking/network_dispatch.hpp index c273f7d4..4aaa0ee1 100644 --- a/kernel/networking/network_dispatch.hpp +++ b/kernel/networking/network_dispatch.hpp @@ -34,6 +34,8 @@ class NetworkDispatch { uint32_t speed(uint8_t ifindex) const; uint8_t duplex(uint8_t ifindex) const; uint8_t kind(uint8_t ifindex) const; + + void dump_interfaces(); private: struct NICCtx { @@ -63,7 +65,6 @@ class NetworkDispatch { void free_frame(const sizedptr&); bool register_all_from_bus(); void copy_str(char* dst, int cap, const char* src); - void dump_interfaces(); int nic_for_ifindex(uint8_t ifindex) const; }; diff --git a/kernel/networking/port_manager.c b/kernel/networking/port_manager.c index 8cda0ed2..2e8e5df7 100644 --- a/kernel/networking/port_manager.c +++ b/kernel/networking/port_manager.c @@ -1,43 +1,42 @@ -#include "port_manager.h" -#include "types.h" #include "networking/port_manager.h" -#include "net/internet_layer/ipv4.h" +#include "types.h" #include "math/rng.h" - -static port_entry_t g_port_table[PROTO_COUNT][MAX_PORTS];//tab proto/port +#include "net/network_types.h" static inline bool proto_valid(protocol_t proto) { return (uint32_t)proto < PROTO_COUNT; } -void port_manager_init(void) { +void port_manager_init(port_manager_t* pm) { + if (!pm) return; for (uint32_t pr = 0; pr < PROTO_COUNT; ++pr) { for (uint32_t p = 0; p < MAX_PORTS; ++p) { - g_port_table[pr][p].used = false; - g_port_table[pr][p].pid = PORT_FREE_OWNER; - g_port_table[pr][p].handler = NULL; + pm->tab[pr][p].used = false; + pm->tab[pr][p].pid = PORT_FREE_OWNER; + pm->tab[pr][p].handler = NULL; } } } -int port_alloc_ephemeral(protocol_t proto, +int port_alloc_ephemeral(port_manager_t* pm, + protocol_t proto, uint16_t pid, port_recv_handler_t handler) { - if (!proto_valid(proto)) return -1; + if (!pm || !proto_valid(proto)) return -1; rng_t rng; rng_init_random(&rng); uint32_t seed = rng_next32(&rng); - uint32_t minp = (uint32_t)PORT_MIN_EPHEMERAL; - uint32_t maxp = (uint32_t)PORT_MAX_EPHEMERAL; - uint32_t range = maxp - minp + 1u; - uint32_t first = minp + (seed % range); + const uint32_t minp = (uint32_t)PORT_MIN_EPHEMERAL; + const uint32_t maxp = (uint32_t)PORT_MAX_EPHEMERAL; + const uint32_t range = maxp - minp + 1u; + const uint32_t first = minp + (seed % range); for (uint32_t i = 0; i < range; ++i) { uint32_t p = minp + ((first - minp + i) % range); - port_entry_t *e = &g_port_table[proto][p]; + port_entry_t *e = &pm->tab[proto][p]; if (!e->used) { e->used = true; e->pid = pid; @@ -48,13 +47,14 @@ int port_alloc_ephemeral(protocol_t proto, return -1; } -bool port_bind_manual(protocol_t proto, +bool port_bind_manual(port_manager_t* pm, + protocol_t proto, uint16_t port, uint16_t pid, port_recv_handler_t handler) { - if (!proto_valid(proto)) return false; - port_entry_t *e = &g_port_table[proto][port]; + if (!pm || !proto_valid(proto)) return false; + port_entry_t *e = &pm->tab[proto][port]; if (e->used) return false; e->used = true; e->pid = pid; @@ -62,12 +62,13 @@ bool port_bind_manual(protocol_t proto, return true; } -bool port_unbind(protocol_t proto, +bool port_unbind(port_manager_t* pm, + protocol_t proto, uint16_t port, uint16_t pid) { - if (!proto_valid(proto)) return false; - port_entry_t *e = &g_port_table[proto][port]; + if (!pm || !proto_valid(proto)) return false; + port_entry_t *e = &pm->tab[proto][port]; if (!e->used || e->pid != pid) return false; e->used = false; e->pid = PORT_FREE_OWNER; @@ -75,10 +76,11 @@ bool port_unbind(protocol_t proto, return true; } -void port_unbind_all(uint16_t pid) { +void port_unbind_all(port_manager_t* pm, uint16_t pid) { + if (!pm) return; for (uint32_t pr = 0; pr < PROTO_COUNT; ++pr) { for (uint32_t p = 1; p < MAX_PORTS; ++p) { - port_entry_t *e = &g_port_table[pr][p]; + port_entry_t *e = &pm->tab[pr][p]; if (e->used && e->pid == pid) { e->used = false; e->pid = PORT_FREE_OWNER; @@ -88,19 +90,18 @@ void port_unbind_all(uint16_t pid) { } } -bool port_is_bound(protocol_t proto, uint16_t port) { - if (!proto_valid(proto)) return false; - return g_port_table[proto][port].used; +bool port_is_bound(const port_manager_t* pm, protocol_t proto, uint16_t port) { + if (!pm || !proto_valid(proto)) return false; + return pm->tab[proto][port].used; } -uint16_t port_owner_of(protocol_t proto, uint16_t port) { - if (!proto_valid(proto)) return PORT_FREE_OWNER; - return g_port_table[proto][port].pid; +uint16_t port_owner_of(const port_manager_t* pm, protocol_t proto, uint16_t port) { + if (!pm || !proto_valid(proto)) return PORT_FREE_OWNER; + return pm->tab[proto][port].pid; } -port_recv_handler_t port_get_handler(protocol_t proto, uint16_t port) { - if (!proto_valid(proto)) return NULL; - return g_port_table[proto][port].used - ? g_port_table[proto][port].handler - : NULL; +port_recv_handler_t port_get_handler(const port_manager_t* pm, protocol_t proto, uint16_t port) { + if (!pm || !proto_valid(proto)) return NULL; + const port_entry_t* e = &pm->tab[proto][port]; + return e->used ? e->handler : NULL; } diff --git a/kernel/networking/port_manager.h b/kernel/networking/port_manager.h index b623d909..4c29207a 100644 --- a/kernel/networking/port_manager.h +++ b/kernel/networking/port_manager.h @@ -1,5 +1,6 @@ #pragma once #include "types.h" +#include "net/network_types.h" #ifdef __cplusplus extern "C" { @@ -18,9 +19,12 @@ typedef enum { #define PROTO_COUNT 2 typedef void (*port_recv_handler_t)( + uint8_t ifindex, + ip_version_t ipver, + const void* src_ip_addr, + const void* dst_ip_addr, uintptr_t frame_ptr, uint32_t frame_len, - uint32_t src_ip, uint16_t src_port, uint16_t dst_port); @@ -30,28 +34,33 @@ typedef struct { bool used; } port_entry_t; -void port_manager_init(); - -int port_alloc_ephemeral(protocol_t proto, - uint16_t pid, - port_recv_handler_t handler); +typedef struct { + port_entry_t tab[PROTO_COUNT][MAX_PORTS]; +} port_manager_t; -bool port_bind_manual(protocol_t proto, - uint16_t port, - uint16_t pid, - port_recv_handler_t handler); +void port_manager_init(port_manager_t* pm); -bool port_unbind(protocol_t proto, - uint16_t port, - uint16_t pid); +int port_alloc_ephemeral(port_manager_t* pm, + protocol_t proto, + uint16_t pid, + port_recv_handler_t handler); -void port_unbind_all(uint16_t pid); +bool port_bind_manual(port_manager_t* pm, + protocol_t proto, + uint16_t port, + uint16_t pid, + port_recv_handler_t handler); -bool port_is_bound(protocol_t proto, uint16_t port); +bool port_unbind(port_manager_t* pm, + protocol_t proto, + uint16_t port, + uint16_t pid); -uint16_t port_owner_of(protocol_t proto, uint16_t port); +void port_unbind_all(port_manager_t* pm, uint16_t pid); -port_recv_handler_t port_get_handler(protocol_t proto, uint16_t port); +bool port_is_bound(const port_manager_t* pm, protocol_t proto, uint16_t port); +uint16_t port_owner_of(const port_manager_t* pm, protocol_t proto, uint16_t port); +port_recv_handler_t port_get_handler(const port_manager_t* pm, protocol_t proto, uint16_t port); #ifdef __cplusplus } diff --git a/kernel/networking/processes/net_proc.c b/kernel/networking/processes/net_proc.c index 6bc4e933..6fa009bb 100644 --- a/kernel/networking/processes/net_proc.c +++ b/kernel/networking/processes/net_proc.c @@ -23,27 +23,30 @@ #include "net/application_layer/sntp_daemon.h" #include "exceptions/timer.h" -extern uintptr_t malloc(uint64_t size); -extern void free(void *ptr, uint64_t size); -extern void sleep(uint64_t ms); +#include "syscalls/syscalls.h" -static uint32_t pick_probe_ip() { - const net_cfg_t *cfg = ipv4_get_cfg(); - if (!cfg || cfg->mode == IPV4_CFG_DISABLED || cfg->ip == 0) - return 0; - if (cfg->gw) - return cfg->gw; - uint32_t bcast = ipv4_broadcast_calc(cfg->ip, cfg->mask); - return bcast; +static inline int ipv4_is_loopback_u32(uint32_t ip) { + return ((ip & 0xFF000000u) == 0x7F000000u); +} + +static uint32_t pick_probe_ip_v4(const l3_ipv4_interface_t *ifv4) { + if (ifv4->ip && ifv4->mask) return ipv4_broadcast_calc(ifv4->ip, ifv4->mask); + return 0; } static int udp_probe_server(uint32_t probe_ip, uint16_t probe_port, net_l4_endpoint *out_l4) { - socket_handle_t sock = udp_socket_create(0, 0); + socket_handle_t sock = udp_socket_create(SOCK_ROLE_CLIENT, (uint16_t)get_current_proc_pid()); if (!sock) return 0; - const char greeting[] = "hello"; - if (socket_sendto_udp(sock, probe_ip, probe_port, greeting, sizeof(greeting)) < 0) { + net_l4_endpoint dst = (net_l4_endpoint){0}; + dst.ver = IP_VER4; + memcpy(dst.ip, &probe_ip, 4); + dst.port = probe_port; + + static const char greeting[] = "hello"; + if (socket_sendto_udp_ex(sock, DST_ENDPOINT, &dst, 0, greeting, sizeof(greeting)) < 0) { + socket_close_udp(sock); socket_destroy_udp(sock); return 0; } @@ -53,60 +56,51 @@ static int udp_probe_server(uint32_t probe_ip, uint16_t probe_port, net_l4_endpo const uint32_t TIMEOUT_MS = 2000; const uint32_t INTERVAL_MS = 50; int64_t recvd = 0; - uint32_t resp_ip = 0; - uint16_t resp_port = 0; + net_l4_endpoint src = (net_l4_endpoint){0}; while (waited < TIMEOUT_MS) { - recvd = socket_recvfrom_udp(sock, recv_buf, sizeof(recv_buf), &resp_ip, &resp_port); + recvd = socket_recvfrom_udp_ex(sock, recv_buf, sizeof(recv_buf), &src); if (recvd > 0) break; sleep(INTERVAL_MS); waited += INTERVAL_MS; } - if (recvd <= 0) { - socket_close_udp(sock); - socket_destroy_udp(sock); - return 0; - } - socket_close_udp(sock); socket_destroy_udp(sock); - out_l4->ip = resp_ip; - out_l4->port = resp_port; - - return resp_ip; + if (recvd <= 0) return 0; + if (out_l4) *out_l4 = src; + return 1; } static void free_request(HTTPRequestMsg *req) { if (req->path.mem_length) free(req->path.data, req->path.mem_length); - - for (uint32_t i = 0; i < req->extra_header_count; ++i) { + for (uint32_t i = 0; i < req->extra_header_count; i++) { HTTPHeader *h = &req->extra_headers[i]; if (h->key.mem_length) free(h->key.data, h->key.mem_length); if (h->value.mem_length) free(h->value.data, h->value.mem_length); } - if (req->extra_headers) free(req->extra_headers, req->extra_header_count * sizeof(HTTPHeader)); - if (req->body.ptr && req->body.size) free((void*)req->body.ptr, req->body.size); } static void run_http_server() { + kprintf("[HTTP] server bootstrap"); uint16_t pid = get_current_proc_pid(); http_server_handle_t srv = http_server_create(pid); if (!srv) { stop_current_process(1); return; } - - if (http_server_bind(srv, 80) < 0) { + struct SockBindSpec spec = {0}; + spec.kind = BIND_ANY; + if (http_server_bind_ex(srv, &spec, 80) < 0) { http_server_destroy(srv); stop_current_process(2); return; @@ -138,9 +132,7 @@ static void run_http_server() { http_connection_handle_t conn = http_server_accept(srv); if (!conn) continue; - HTTPRequestMsg req = http_server_recv_request(srv, conn); - if (req.path.length) { char tmp[128] = {0}; uint32_t n = req.path.length < sizeof(tmp) - 1 ? req.path.length : sizeof(tmp) - 1; @@ -148,7 +140,7 @@ static void run_http_server() { kprintf("[HTTP] GET %s", tmp); } - HTTPResponseMsg res = {0}; + HTTPResponseMsg res = (HTTPResponseMsg){0}; if (req.path.length == 1 && req.path.data[0] == '/') { res.status_code = HTTP_OK; @@ -174,29 +166,50 @@ static void run_http_server() { } } -static void test_http(uint32_t ip) { - char ip_str[16]; - ipv4_to_string(ip, ip_str); +static void test_http(const net_l4_endpoint* ep) { + if (ep->ver == IP_VER4) { + uint32_t ip_u32; + memcpy(&ip_u32, ep->ip, 4); + char ip_str[16]; + ipv4_to_string(ip_u32, ip_str); + + kprintf("[HTTP] GET %s:80", ip_str); + } - kprintf("[HTTP] GET %s:80\n", ip_str); uint16_t pid = get_current_proc_pid(); http_client_handle_t cli = http_client_create(pid); - if (!cli) - return; + if (!cli) { + kprintf("[HTTP] http_client_create FAIL"); + return; + } - if (http_client_connect(cli, ip, 80) < 0) { + net_l4_endpoint e = {0}; + e.ver = IP_VER4; + memcpy(e.ip, ep->ip, 4); + e.port = 80; + + int rc = http_client_connect_ex(cli, DST_ENDPOINT, &e, 0); + if (rc < 0) { http_client_destroy(cli); return; } - HTTPRequestMsg req = {0}; + HTTPRequestMsg req = (HTTPRequestMsg){0}; req.method = HTTP_METHOD_GET; req.path = string_from_const("/"); req.headers_common.connection = string_from_const("close"); HTTPResponseMsg resp = http_client_send_request(cli, &req); - free(req.path.data, req.path.mem_length); - free(req.headers_common.connection.data, req.headers_common.connection.mem_length); + + //free(req.path.data, req.path.mem_length); + //free(req.headers_common.connection.data, req.headers_common.connection.mem_length); + + if ((int)resp.status_code < 0) { + kprintf("[HTTP] request FAIL status=%i", (int)resp.status_code); + http_client_close(cli); + http_client_destroy(cli); + return; + } if (resp.body.ptr && resp.body.size > 0) { char *body_str = (char*)malloc(resp.body.size + 1); @@ -227,73 +240,130 @@ static void test_http(uint32_t ip) { free(resp.extra_headers, resp.extra_header_count * sizeof(HTTPHeader)); } -static void print_info() { - if (!sntp_is_running()) { - create_kernel_process("sntpd", sntp_daemon_entry, 0, 0); - while (!timer_is_synchronised()); - - const net_cfg_t *cfg = ipv4_get_cfg(); - if (cfg && cfg->mode != IPV4_CFG_DISABLED && cfg->ip != 0) { - char ip_str[16], mask_str[16], gw_str[16]; - ipv4_to_string(cfg->ip, ip_str); - ipv4_to_string(cfg->mask, mask_str); - ipv4_to_string(cfg->gw, gw_str); - kprintf("[NET] IP: %s MASK: %s GW: %s", ip_str, mask_str, gw_str); - } - kprintf("[NET] PIDs -- NET: %i ARP: %i DHCP: %i DNS: %i SNTP: %i", - network_net_get_pid(), - arp_get_pid(), - dhcp_get_pid(), - dns_get_pid(), - sntp_get_pid()); +static void print_info_for_ifv4(const l3_ipv4_interface_t* ifv4) { + if (!ifv4 || !ifv4->ip) return; + if (ifv4->is_localhost) return; + if (ipv4_is_loopback_u32(ifv4->ip)) return; + char ip_str[16]; + char mask_str[16]; + char gw_str[16]; + ipv4_to_string(ifv4->ip, ip_str); + ipv4_to_string(ifv4->mask, mask_str); + ipv4_to_string(ifv4->gw, gw_str); + kprintf("[NET] IF l3_id=%u IP: %s MASK: %s GW: %s", (unsigned)ifv4->l3_id, ip_str, mask_str, gw_str); +} - timer_set_timezone_minutes(120); - kprintf("[TIME]timezone offset %i minutes", (int32_t)timer_get_timezone_minutes()); +static int ifv4_is_ready_nonlocal(const l3_ipv4_interface_t* ifv4) { + if (!ifv4) return 0; + if (ifv4->mode == IPV4_CFG_DISABLED) return 0; + if (!ifv4->ip) return 0; + if (ifv4->is_localhost) return 0; + if (ipv4_is_loopback_u32(ifv4->ip)) return 0; + return 1; +} - DateTime now_dt_utc, now_dt_loc; - if (timer_now_datetime(&now_dt_utc, 0)) { - char s[20]; - timer_datetime_to_string(&now_dt_utc, s, sizeof s); - kprintf("[TIME] UTC: %s", s); - } - if (timer_now_datetime(&now_dt_loc, 1)) { - char s[20]; - timer_datetime_to_string(&now_dt_loc, s, sizeof s); - kprintf("[TIME] LOCAL: %s (TZ %i min)", s, (int32_t)timer_get_timezone_minutes()); +static int any_ipv4_ready(void) { + uint8_t n_if = l2_interface_count(); + for (uint8_t i = 0; i < n_if; i++) { + l2_interface_t* l2 = l2_interface_at(i); + if (!l2 || !l2->is_up) continue; + for (uint8_t j = 0; j < MAX_IPV4_PER_INTERFACE; j++) { + l3_ipv4_interface_t* ifv4 = l2->l3_v4[j]; + if (ifv4_is_ready_nonlocal(ifv4)) return 1; } } + return 0; } -static void test_net() { - const net_cfg_t *cfg = ipv4_get_cfg(); - net_l4_endpoint srv = {0}; - - if (cfg && cfg->mode != IPV4_CFG_DISABLED && cfg->ip != 0) { - print_info(); - - uint32_t bcast = ipv4_broadcast_calc(cfg->ip, cfg->mask); - char bcast_str[16]; - ipv4_to_string(bcast, bcast_str); +static void print_info() { + network_dump_interfaces(); + uint8_t n_if = l2_interface_count(); + for (uint8_t i = 0; i < n_if; i++) { + l2_interface_t* l2 = l2_interface_at(i); + if (!l2 || !l2->is_up) continue; + for (uint8_t j = 0; j < MAX_IPV4_PER_INTERFACE; j++) { + l3_ipv4_interface_t* ifv4 = l2->l3_v4[j]; + if (!ifv4_is_ready_nonlocal(ifv4)) continue; + print_info_for_ifv4(ifv4); + } + } + if (!sntp_is_running()) { + kprintf("[TIME] starting SNTP..."); + create_kernel_process("sntpd", sntp_daemon_entry, 0, 0); + uint32_t waited = 0; + const uint32_t step = 200; + const uint32_t timeout = 10000; + while (!timer_is_synchronised() && waited < timeout) { + if ((waited % 1000) == 0) kprintf("[TIME] waiting SNTP sync..."); + sleep(step); + waited += step; - kprintf("[NET] probing broadcast %s", bcast_str); + } + if (!timer_is_synchronised()) kprintf("[TIME] SNTP sync timeout, continuing"); + } + kprintf("[NET] PIDs -- NET: %i ARP: %i DHCP: %i DNS: %i SNTP: %i", + network_net_get_pid(), + arp_get_pid(), + dhcp_get_pid(), + dns_get_pid(), + sntp_get_pid()); - if (udp_probe_server(bcast, 8080, &srv)) - test_http(srv.ip); + timer_set_timezone_minutes(120); + kprintf("[TIME]timezone offset %i minutes", (int32_t)timer_get_timezone_minutes()); - sleep(2000); - run_http_server(); - return; + DateTime now_dt_utc, now_dt_loc; + if (timer_now_datetime(&now_dt_utc, 0)) { + char s[20]; + timer_datetime_to_string(&now_dt_utc, s, sizeof s); + kprintf("[TIME] UTC: %s", s); } + if (timer_now_datetime(&now_dt_loc, 1)) { + char s[20]; + timer_datetime_to_string(&now_dt_loc, s, sizeof s); + kprintf("[TIME] LOCAL: %s (TZ %i min)", s, (int32_t)timer_get_timezone_minutes()); + } +} - uint32_t fallback = pick_probe_ip(); - if (!fallback) - fallback = (192<<24)|(168<<16)|(1<<8)|255; +static void test_net_for_interface(l3_ipv4_interface_t* ifv4) { + if (!ifv4_is_ready_nonlocal(ifv4)) return; + print_info_for_ifv4(ifv4); + uint32_t probe_ip = pick_probe_ip_v4(ifv4); + if (!probe_ip) return; + char probe_str[16]; + ipv4_to_string(probe_ip, probe_str); + kprintf("[NET] probing %s (l3_id=%u)", probe_str, (unsigned)ifv4->l3_id); + net_l4_endpoint srv = (net_l4_endpoint){0}; + if (udp_probe_server(probe_ip, 8080, &srv)) { + test_http(&srv); + } else { + kprintf("[NET] no UDP responder at %s:8080 (l3_id=%u)", probe_str, (unsigned)ifv4->l3_id); + } +} - if (udp_probe_server(fallback, 8080, &srv)) - test_http(srv.ip); - else - kprintf("[NET] could not find update server\n"); +static void test_net() { + print_info(); + uint8_t n_if = l2_interface_count(); + int tested_any = 0; + for (uint8_t i = 0; i < n_if; i++) { + l2_interface_t* l2 = l2_interface_at(i); + if (!l2 || !l2->is_up) continue; + for (uint8_t j = 0; j < MAX_IPV4_PER_INTERFACE; j++) { + l3_ipv4_interface_t* ifv4 = l2->l3_v4[j]; + if (!ifv4_is_ready_nonlocal(ifv4)) continue; + test_net_for_interface(ifv4); + tested_any = 1; + } + } + run_http_server(); + if (!tested_any) { + net_l4_endpoint srv = (net_l4_endpoint){0}; + uint32_t fallback = (192<<24)|(168<<16)|(1<<8)|255; + if (udp_probe_server(fallback, 8080, &srv)) + test_http(&srv); + else + kprintf("[NET] could not find update server"); + } } static int net_test_entry(int argc, char* argv[]) { @@ -304,27 +374,25 @@ static int net_test_entry(int argc, char* argv[]) { static int ip_waiter_entry(int argc, char* argv[]) { (void)argc; (void)argv; - for (;;) { - const net_cfg_t *cfg = ipv4_get_cfg(); - if (cfg && cfg->mode != IPV4_CFG_DISABLED && cfg->ip != 0) { - create_kernel_process("net_test", net_test_entry, 0, 0); - break; - } + uint32_t waited = 0; + while (!any_ipv4_ready()) { + if ((waited % 1000) == 0) kprintf("[NET] ip_waiter: waiting for ipv4..."); sleep(200); + waited += 200; } + create_kernel_process("net_test", net_test_entry, 0, 0); return 0; } process_t* launch_net_process() { - const net_cfg_t *cfg = ipv4_get_cfg(); - create_kernel_process("net_net", network_net_task_entry, 0, 0); create_kernel_process("arp_daemon", arp_daemon_entry, 0, 0); create_kernel_process("dhcp_daemon", dhcp_daemon_entry, 0, 0); - return NULL; + create_kernel_process("dns_daemon", dns_deamon_entry, 0, 0); - if (cfg && cfg->mode != IPV4_CFG_DISABLED && cfg->ip != 0) { + if (any_ipv4_ready()) { + kprintf("[NET] ipv4 ready, starting net_test"); create_kernel_process("net_test", net_test_entry, 0, 0); return NULL; } diff --git a/kernel/process/syscall.c b/kernel/process/syscall.c index 928f83e3..0970b58e 100644 --- a/kernel/process/syscall.c +++ b/kernel/process/syscall.c @@ -18,6 +18,7 @@ #include "graph/tres.h" #include "memory/mmu.h" #include "loading/process_loader.h" +#include "networking/interface_manager.h" int syscall_depth = 0; @@ -89,18 +90,30 @@ uint64_t syscall_get_time(process_t *ctx){ } uint64_t syscall_bind_port(process_t *ctx){ - uint16_t port = (uint16_t)ctx->PROC_X0; - port_recv_handler_t handler = (port_recv_handler_t)ctx->PROC_X1; - protocol_t proto = (protocol_t)ctx->PROC_X2; + ip_version_t ipver= (ip_version_t)ctx->PROC_X0; + uint8_t l3_id = (uint8_t)ctx->PROC_X1; + uint16_t port = (uint16_t)ctx->PROC_X2; + port_recv_handler_t handler = (port_recv_handler_t)ctx->PROC_X3; + protocol_t proto = (protocol_t)ctx->PROC_X4; uint16_t pid = get_current_proc_pid(); - return port_bind_manual(port, pid, proto, handler); + + port_manager_t* pm = (ipver == IP_VER6) ? ifmgr_pm_v6(l3_id) : ifmgr_pm_v4(l3_id); + if (!pm) return 0; + + return port_bind_manual(pm, proto, port, pid, handler); } uint64_t syscall_unbind_port(process_t *ctx){ - uint16_t port = (uint16_t)ctx->PROC_X0; - protocol_t proto = (protocol_t)ctx->PROC_X2; + ip_version_t ipver = (ip_version_t)ctx->PROC_X0; + uint8_t l3_id = (uint8_t)ctx->PROC_X1; + uint16_t port = (uint16_t)ctx->PROC_X2; + protocol_t proto = (protocol_t)ctx->PROC_X3; uint16_t pid = get_current_proc_pid(); - return port_unbind(port, proto, pid); + + port_manager_t* pm = (ipver == IP_VER6) ? ifmgr_pm_v6(l3_id) : ifmgr_pm_v4(l3_id); + if (!pm) return 0; + + return port_unbind(pm, proto, port, pid); } uint64_t syscall_send_packet(process_t *ctx){ diff --git a/shared/net/application_layer/csocket_http_client.cpp b/shared/net/application_layer/csocket_http_client.cpp index a33c03b2..484fcee3 100644 --- a/shared/net/application_layer/csocket_http_client.cpp +++ b/shared/net/application_layer/csocket_http_client.cpp @@ -1,12 +1,7 @@ #include "csocket_http_client.h" #include "socket_http_client.hpp" #include "net/transport_layer/socket_tcp.hpp" - -extern "C" { - extern uintptr_t malloc(uint64_t size); - extern void free(void *ptr, uint64_t size); - extern void sleep(uint64_t ms); -} +#include "net/transport_layer/socket.hpp" extern "C" { @@ -22,19 +17,14 @@ void http_client_destroy(http_client_handle_t h) { delete cli; } -int32_t http_client_connect(http_client_handle_t h, - uint32_t ip, - uint16_t port) -{ - if (!h) return (int32_t)SOCK_ERR_INVAL; +int32_t http_client_connect_ex(http_client_handle_t h, uint8_t dst_kind, const void* dst, uint16_t port) { + if (!h || !dst) return (int32_t)SOCK_ERR_INVAL; HTTPClient *cli = reinterpret_cast(h); - return cli->connect(ip, port); + return cli->connect(static_cast(dst_kind), dst, port); } -HTTPResponseMsg http_client_send_request(http_client_handle_t h, - const HTTPRequestMsg *req) -{ - HTTPResponseMsg empty; +HTTPResponseMsg http_client_send_request(http_client_handle_t h, const HTTPRequestMsg *req) { + HTTPResponseMsg empty{}; if (!h || !req) { empty.status_code = (HttpError)SOCK_ERR_INVAL; return empty; diff --git a/shared/net/application_layer/csocket_http_client.h b/shared/net/application_layer/csocket_http_client.h index 93919f21..8c7357c8 100644 --- a/shared/net/application_layer/csocket_http_client.h +++ b/shared/net/application_layer/csocket_http_client.h @@ -1,8 +1,6 @@ #pragma once - #include "http.h" -#include "std/string.h" -#include "std/memory.h" +#include "net/transport_layer/socket_types.h" #ifdef __cplusplus extern "C" { @@ -13,12 +11,9 @@ typedef void* http_client_handle_t; http_client_handle_t http_client_create(uint16_t pid); void http_client_destroy(http_client_handle_t h); -int32_t http_client_connect(http_client_handle_t h, - uint32_t ip, - uint16_t port); +int32_t http_client_connect_ex(http_client_handle_t h, uint8_t dst_kind, const void *dst, uint16_t port); -HTTPResponseMsg http_client_send_request(http_client_handle_t h, - const HTTPRequestMsg *req); +HTTPResponseMsg http_client_send_request(http_client_handle_t h, const HTTPRequestMsg *req); int32_t http_client_close(http_client_handle_t h); diff --git a/shared/net/application_layer/csocket_http_server.cpp b/shared/net/application_layer/csocket_http_server.cpp index 607ca4b0..de860296 100644 --- a/shared/net/application_layer/csocket_http_server.cpp +++ b/shared/net/application_layer/csocket_http_server.cpp @@ -1,11 +1,7 @@ #include "csocket_http_server.h" #include "socket_http_server.hpp" - -extern "C" { - extern uintptr_t malloc(uint64_t size); - extern void free(void *ptr, uint64_t size); - extern void sleep(uint64_t ms); -} +#include "net/transport_layer/socket_tcp.hpp" +#include "net/transport_layer/socket.hpp" extern "C" { @@ -21,10 +17,10 @@ void http_server_destroy(http_server_handle_t h) { delete srv; } -int32_t http_server_bind(http_server_handle_t h, uint16_t port) { - if (!h) return (int32_t)SOCK_ERR_INVAL; +int32_t http_server_bind_ex(http_server_handle_t h, const SockBindSpec *spec, uint16_t port) { + if (!h || !spec) return (int32_t)SOCK_ERR_INVAL; HTTPServer* srv = reinterpret_cast(h); - return srv->bind(port); + return srv->bind(*spec, port); } int32_t http_server_listen(http_server_handle_t h, int backlog) { @@ -40,22 +36,15 @@ http_connection_handle_t http_server_accept(http_server_handle_t h) { return reinterpret_cast(cli); } -HTTPRequestMsg http_server_recv_request(http_server_handle_t h, - http_connection_handle_t c) -{ +HTTPRequestMsg http_server_recv_request(http_server_handle_t h, http_connection_handle_t c) { HTTPRequestMsg empty{}; - if (!h || !c) { - return empty; - } + if (!h || !c) return empty; HTTPServer* srv = reinterpret_cast(h); TCPSocket* conn = reinterpret_cast(c); return srv->recv_request(conn); } -int32_t http_server_send_response(http_server_handle_t h, - http_connection_handle_t c, - const HTTPResponseMsg* res) -{ +int32_t http_server_send_response(http_server_handle_t h, http_connection_handle_t c, const HTTPResponseMsg *res) { if (!h || !c || !res) return (int32_t)SOCK_ERR_INVAL; HTTPServer* srv = reinterpret_cast(h); TCPSocket* conn = reinterpret_cast(c); diff --git a/shared/net/application_layer/csocket_http_server.h b/shared/net/application_layer/csocket_http_server.h index e46d221e..6d1beb6a 100644 --- a/shared/net/application_layer/csocket_http_server.h +++ b/shared/net/application_layer/csocket_http_server.h @@ -1,6 +1,7 @@ #pragma once #include "types.h" #include "http.h" +#include "net/transport_layer/socket_types.h" #ifdef __cplusplus extern "C" { @@ -10,26 +11,19 @@ typedef void* http_server_handle_t; typedef void* http_connection_handle_t; http_server_handle_t http_server_create(uint16_t pid); - void http_server_destroy(http_server_handle_t srv); -int32_t http_server_bind(http_server_handle_t srv, - uint16_t port); +int32_t http_server_bind_ex(http_server_handle_t srv, const struct SockBindSpec *spec, uint16_t port); -int32_t http_server_listen(http_server_handle_t srv, - int backlog); +int32_t http_server_listen(http_server_handle_t srv, int backlog); http_connection_handle_t http_server_accept(http_server_handle_t srv); -HTTPRequestMsg http_server_recv_request(http_server_handle_t srv, - http_connection_handle_t conn); +HTTPRequestMsg http_server_recv_request(http_server_handle_t srv, http_connection_handle_t conn); -int32_t http_server_send_response(http_server_handle_t srv, - http_connection_handle_t conn, - const HTTPResponseMsg* res); +int32_t http_server_send_response(http_server_handle_t srv, http_connection_handle_t conn, const HTTPResponseMsg* res); int32_t http_connection_close(http_connection_handle_t conn); - int32_t http_server_close(http_server_handle_t srv); #ifdef __cplusplus diff --git a/shared/net/application_layer/dhcp.c b/shared/net/application_layer/dhcp.c index b5c7e475..2f5752d6 100644 --- a/shared/net/application_layer/dhcp.c +++ b/shared/net/application_layer/dhcp.c @@ -3,47 +3,68 @@ #include "net/transport_layer/udp.h" #include "net/internet_layer/ipv4.h" #include "types.h" -#include "net/transport_layer/csocket_udp.h" +#include "syscalls/syscalls.h" -extern uintptr_t malloc(uint64_t size); -extern void free(void *ptr, uint64_t size); -extern void sleep(uint64_t ms); -sizedptr dhcp_build_packet(const dhcp_request *req, - uint8_t msg_type, - uint32_t xid) -{ +static size_t dhcp_options_write_param_req_list(uint8_t *opt, size_t idx) { + static const uint8_t prl[] = { 1, 3, 6, 15, 42, 26, 51, 58, 59, 119 }; + size_t n = sizeof(prl); + if (idx + 2 + n >= 312) return idx; + opt[idx++] = 55; + opt[idx++] = (uint8_t)n; + for (size_t i = 0; i < n; i++) opt[idx++] = prl[i]; + return idx; +} + +sizedptr dhcp_build_packet(const dhcp_request *req, uint8_t msg_type, uint32_t xid, dhcp_req_kind kind, bool broadcast) { dhcp_packet p; memset(&p, 0, sizeof(p)); size_t idx = 0; - p.op = 1; p.htype = 1; p.hlen = 6; p.hops = 0; - p.xid = xid; p.secs = 0; - p.flags = bswap16(0x8000); - p.ciaddr = 0; p.yiaddr = 0; p.siaddr = 0; p.giaddr = 0; + p.op = 1; + p.htype = 1; + p.hlen = 6; + p.hops = 0; + p.xid = xid; + p.secs = 0; + p.flags = broadcast ? bswap16(0x8000) : 0; + p.ciaddr = 0; + p.yiaddr = 0; + p.siaddr = 0; + p.giaddr = 0; memcpy(p.chaddr, req->mac, 6); - p.options[idx++] = 0x63; p.options[idx++] = 0x82; - p.options[idx++] = 0x53; p.options[idx++] = 0x63; + if (msg_type == DHCPINFORM) p.ciaddr = req->offered_ip; + if (msg_type == DHCPREQUEST && (kind == DHCPK_RENEW || kind == DHCPK_REBIND)) p.ciaddr = req->offered_ip; + + p.options[idx++] = DHCP_MAGIC_COOKIE_0; + p.options[idx++] = DHCP_MAGIC_COOKIE_1; + p.options[idx++] = DHCP_MAGIC_COOKIE_2; + p.options[idx++] = DHCP_MAGIC_COOKIE_3; - p.options[idx++] = 53; p.options[idx++] = 1; + p.options[idx++] = 53; + p.options[idx++] = 1; p.options[idx++] = msg_type; - if (msg_type == DHCPREQUEST) { - p.options[idx++] = 50; p.options[idx++] = 4; - memcpy(&p.options[idx], &req->offered_ip, 4); idx += 4; + if (msg_type == DHCPREQUEST && kind == DHCPK_SELECT) { + p.options[idx++] = 50; + p.options[idx++] = 4; + memcpy(&p.options[idx], &req->offered_ip, 4); + idx += 4; if (req->server_ip) { - p.options[idx++] = 54; p.options[idx++] = 4; - memcpy(&p.options[idx], &req->server_ip, 4); idx += 4; + p.options[idx++] = 54; + p.options[idx++] = 4; + memcpy(&p.options[idx], &req->server_ip, 4); + idx += 4; } } + idx = dhcp_options_write_param_req_list(p.options, idx); + p.options[idx++] = 255; size_t dhcp_len = sizeof(dhcp_packet) - (sizeof(p.options) - idx); - uintptr_t buf = malloc(dhcp_len); memcpy((void*)buf, &p, dhcp_len); - return (sizedptr){ .ptr = buf, .size = (uint32_t)dhcp_len }; } @@ -51,18 +72,29 @@ dhcp_packet* dhcp_parse_frame_payload(uintptr_t frame_ptr) { return (dhcp_packet*)frame_ptr; } -uint16_t dhcp_parse_option(const dhcp_packet *p, uint16_t wanted) { +bool dhcp_has_valid_cookie(const dhcp_packet *p) { + return p->options[0] == DHCP_MAGIC_COOKIE_0 && + p->options[1] == DHCP_MAGIC_COOKIE_1 && + p->options[2] == DHCP_MAGIC_COOKIE_2 && + p->options[3] == DHCP_MAGIC_COOKIE_3; +} + +uint16_t dhcp_parse_option_bounded(const dhcp_packet *p, uint32_t payload_len, uint8_t wanted) { + if (payload_len < sizeof(dhcp_packet) - sizeof(p->options)) return UINT16_MAX; + uint32_t header_sz = sizeof(dhcp_packet) - sizeof(p->options); + if (payload_len < header_sz + 4) return UINT16_MAX; const uint8_t *opt = p->options; - size_t i= 4; - while (i < sizeof(p->options)) { + uint32_t i= 4; + uint32_t max = payload_len - header_sz; + while (i < max) { uint8_t code = opt[i++]; if (code == 0) continue; if (code == 255) break; - if (i >= sizeof(p->options)) break; + if (i >= max) break; uint8_t len = opt[i++]; - if (code == wanted) { + if ((uint32_t)i + len > max) break; + if (code == wanted) return (uint16_t)(i - 2); - } i += len; } return UINT16_MAX; @@ -70,8 +102,6 @@ uint16_t dhcp_parse_option(const dhcp_packet *p, uint16_t wanted) { uint8_t dhcp_option_len(const dhcp_packet *p, uint16_t idx) { size_t opt_size = sizeof(p->options); - if (idx == 0 || (size_t)idx + 1 >= opt_size) return 0; return p->options[idx + 1]; -} - +} \ No newline at end of file diff --git a/shared/net/application_layer/dhcp.h b/shared/net/application_layer/dhcp.h index 90c29697..caf12228 100644 --- a/shared/net/application_layer/dhcp.h +++ b/shared/net/application_layer/dhcp.h @@ -22,6 +22,10 @@ enum { }; #define DHCP_FRAME_MAX ( sizeof(eth_hdr_t) + sizeof(ipv4_hdr_t) + sizeof(udp_hdr_t) + sizeof(dhcp_packet) ) +#define DHCP_MAGIC_COOKIE_0 0x63 +#define DHCP_MAGIC_COOKIE_1 0x82 +#define DHCP_MAGIC_COOKIE_2 0x53 +#define DHCP_MAGIC_COOKIE_3 0x63 typedef struct __attribute__((packed)) { uint8_t op; @@ -47,13 +51,21 @@ typedef struct { uint32_t offered_ip; } dhcp_request; -sizedptr dhcp_build_packet(const dhcp_request *req, - uint8_t msg_type, - uint32_t xid); +typedef enum { + DHCPK_SELECT = 0, + DHCPK_RENEW = 1, + DHCPK_REBIND = 2, + DHCPK_INFORM = 3, + DHCPK_DISCOVER = 4 +} dhcp_req_kind; + +sizedptr dhcp_build_packet(const dhcp_request *req, uint8_t msg_type, uint32_t xid, dhcp_req_kind kind, bool broadcast); dhcp_packet* dhcp_parse_frame_payload(uintptr_t frame_ptr); -uint16_t dhcp_parse_option(const dhcp_packet *p, uint16_t wanted); +bool dhcp_has_valid_cookie(const dhcp_packet *p); + +uint16_t dhcp_parse_option_bounded(const dhcp_packet *p, uint32_t payload_len, uint8_t wanted); uint8_t dhcp_option_len(const dhcp_packet *p, uint16_t idx); diff --git a/shared/net/application_layer/dhcp_daemon.c b/shared/net/application_layer/dhcp_daemon.c index bd955c0d..5ea135c1 100644 --- a/shared/net/application_layer/dhcp_daemon.c +++ b/shared/net/application_layer/dhcp_daemon.c @@ -3,33 +3,21 @@ #include "console/kio.h" #include "std/memory.h" #include "process/scheduler.h" -#include "math/math.h" #include "math/rng.h" -#include "networking/network.h" #include "net/application_layer/dhcp.h" #include "net/internet_layer/ipv4.h" #include "net/network_types.h" #include "net/link_layer/arp.h" +#include "net/transport_layer/udp.h" #include "net/transport_layer/csocket_udp.h" -extern void sleep(uint64_t ms); -extern uintptr_t malloc(uint64_t size); -extern void free(void *ptr, uint64_t size); - -#ifndef SOCK_ROLE_SERVER -#define SOCK_ROLE_SERVER 1 -#endif - -#define DHCPDISCOVER 1 -#define DHCPOFFER 2 -#define DHCPREQUEST 3 -#define DHCPDECLINE 4 -#define DHCPACK 5 -#define DHCPNAK 6 -#define DHCPRELEASE 7 -#define DHCPINFORM 8 +#include "types.h" +#include "networking/interface_manager.h" +#include "networking/network.h" +#include "net/internet_layer/ipv4_route.h" +#include "syscalls/syscalls.h" typedef enum { DHCP_S_INIT = 0, @@ -40,325 +28,569 @@ typedef enum { DHCP_S_REBINDING } dhcp_state_t; -static dhcp_state_t g_state = DHCP_S_INIT; -static uint8_t g_local_mac[6] = {0}; +typedef struct { + uint8_t ifindex; + uint8_t l3_id; + dhcp_state_t state; + uint32_t t1_left_ms; + uint32_t t2_left_ms; + uint32_t lease_left_ms; + uint32_t last_xid; + uint32_t trans_xid; + uint32_t server_ip_net; + uint8_t mac[6]; + bool mac_ok; + bool needs_inform; + socket_handle_t sock; + uint32_t retry_left_ms; + uint32_t backoff_ms; +} dhcp_if_state_t; + static volatile bool g_force_renew = false; -static uint32_t g_t1_left_ms = 0; -static uint32_t g_t2_left_ms = 0; static uint16_t g_pid_dhcpd = 0xFFFF; - -static socket_handle_t g_sock = 0; +static dhcp_if_state_t g_if[MAX_L2_INTERFACES * MAX_IPV4_PER_INTERFACE]; +static int g_if_count = 0; uint16_t dhcp_get_pid() { return g_pid_dhcpd; } bool dhcp_is_running() { return g_pid_dhcpd != 0xFFFF; } void dhcp_set_pid(uint16_t p){ g_pid_dhcpd = p; } void dhcp_force_renew() { g_force_renew = true; } -static void log_state_change(dhcp_state_t old, dhcp_state_t now){ - kprintf("[DHCP] state %i -> %i", old, now); +static uint32_t dhcp_next_backoff_ms(dhcp_if_state_t* st) { + if (st->backoff_ms == 0) st->backoff_ms = 4000; + else { + uint64_t v = (uint64_t)st->backoff_ms * 2u; + if (v > 64000u) v = 64000u; + st->backoff_ms = (uint32_t)v; + } + rng_t rng; + rng_init_random(&rng); + uint32_t jitter = (uint32_t)(rng_next32(&rng) % 2000u); + int32_t signed_jitter = (int32_t)jitter - 1000; + int64_t val = (int64_t)st->backoff_ms + signed_jitter; + if (val < 1000) val = 1000; + return (uint32_t)val; } -static void dhcp_apply_offer(dhcp_packet *p, dhcp_request *req, uint32_t xid); - -static void dhcp_tx_packet(const dhcp_request *req, - uint8_t msg_type, - uint32_t xid, - uint32_t dst_ip) -{ - sizedptr pkt = dhcp_build_packet(req, msg_type, xid); - socket_sendto_udp(g_sock, dst_ip, 67, (const void*)pkt.ptr, pkt.size); - free((void*)pkt.ptr, pkt.size); +static void dhcp_reset_backoff(dhcp_if_state_t* st) { + st->backoff_ms = 0; + st->retry_left_ms = 0; } -static void dhcp_send_discover(uint32_t xid){ - kprintf("[DHCP] discover xid=%i", xid); - dhcp_request req = {0}; - memcpy(req.mac, g_local_mac, 6); - dhcp_tx_packet(&req, DHCPDISCOVER, xid, 0xFFFFFFFFu); +static bool find_state(uint8_t l3_id, int* idx) { + for (int i = 0; i < g_if_count; i++) if (g_if[i].l3_id == l3_id) { *idx = i; return true; } + return false; } -static void dhcp_send_request(const dhcp_request *req, - uint32_t xid, - bool broadcast) -{ - uint32_t dst = broadcast ? 0xFFFFFFFFu : bswap32(req->server_ip); - //kprintf("[DHCP] request xid=%i dst=%x\n", (uint64_t)xid, (uint64_t)dst); - dhcp_tx_packet(req, DHCPREQUEST, xid, dst); +static void remove_state_at(int i) { + if (g_if[i].sock) { + socket_close_udp(g_if[i].sock); + socket_destroy_udp(g_if[i].sock); + g_if[i].sock = 0; + } + if (i < g_if_count - 1) g_if[i] = g_if[g_if_count - 1]; + g_if_count--; } -static void dhcp_send_renew(uint32_t xid) { - const net_cfg_t *cfg = ipv4_get_cfg(); - dhcp_request req = {0}; - memcpy(req.mac, g_local_mac, 6); - req.offered_ip = bswap32(cfg->ip); - req.server_ip = cfg->rt ? cfg->rt->server_ip : 0; - uint32_t dst = req.server_ip ? bswap32(req.server_ip) : 0xFFFFFFFFu; - kprintf("[DHCP] renew xid=%i dst=%x", xid, dst); - dhcp_tx_packet(&req, DHCPREQUEST, xid, dst); +static void ensure_inventory() { + for (int i = 0; i < g_if_count;) { + uint8_t l3id = g_if[i].l3_id; + l3_ipv4_interface_t* v4 = l3_ipv4_find_by_id(l3id); + if (!v4 || v4->mode == IPV4_CFG_DISABLED || !v4->l2 || !v4->l2->is_up) { remove_state_at(i); continue; } + i++; + } + uint8_t n = l2_interface_count(); + for (uint8_t ix = 0; ix < n; ix++) { + l2_interface_t* l2 = l2_interface_at(ix); + if (!l2 || !l2->is_up) continue; + for (int s = 0; s < MAX_IPV4_PER_INTERFACE; s++) { + l3_ipv4_interface_t* v4 = l2->l3_v4[s]; + if (!v4) continue; + if (v4->mode == IPV4_CFG_DISABLED) continue; + int idx; + if (find_state(v4->l3_id, &idx)) continue; + dhcp_if_state_t st; + memset(&st, 0, sizeof(st)); + st.ifindex = l2->ifindex; + st.l3_id = v4->l3_id; + st.state = DHCP_S_INIT; + st.t1_left_ms = 0; + st.t2_left_ms = 0; + st.lease_left_ms = 0; + st.last_xid = 0; + st.trans_xid = 0; + st.server_ip_net = 0; + const uint8_t* m = network_get_mac(st.ifindex); + if (m) { memcpy(st.mac, m, 6); st.mac_ok = true; } + st.needs_inform = (v4->mode == IPV4_CFG_STATIC && v4->ip != 0); + st.sock = udp_socket_create(SOCK_ROLE_SERVER, g_pid_dhcpd); + SockBindSpec spec; + memset(&spec, 0, sizeof(spec)); + spec.kind = BIND_L3; + spec.l3_id = st.l3_id; + if (socket_bind_udp_ex(st.sock, &spec, 68) != SOCK_OK) { + socket_destroy_udp(st.sock); + continue; + } + st.retry_left_ms = 0; + st.backoff_ms = 0; + g_if[g_if_count++] = st; + } + } } -static void dhcp_send_rebind(uint32_t xid) { - const net_cfg_t *cfg = ipv4_get_cfg(); - dhcp_request req = {0}; - memcpy(req.mac, g_local_mac, 6); - req.offered_ip = bswap32(cfg->ip); - req.server_ip = 0; - kprintf("[DHCP] rebind xid=%i", xid); - dhcp_tx_packet(&req, DHCPREQUEST, xid, 0xFFFFFFFFu); +static bool packet_mac_matches(const dhcp_packet *p, const uint8_t mac[6]) { + if (!mac) return true; + for (int i = 0; i < 6; i++) if (p->chaddr[i] != mac[i]) return false; + return true; } -static bool dhcp_wait_for_type(uint8_t wanted, - dhcp_packet **outp, - sizedptr *outsp, - uint32_t timeout_ms) -{ +static bool udp_wait_for_type_on(socket_handle_t sock, uint8_t wanted, uint32_t expect_xid, const uint8_t mac[6], dhcp_packet **outp, sizedptr *outsp, uint32_t timeout_ms) { uint32_t waited = 0; while(waited < timeout_ms){ uint8_t buf[1024]; - uint32_t sip; uint16_t sport; - int64_t r = socket_recvfrom_udp(g_sock, buf, sizeof(buf), &sip, &sport); - if(r > 0){ + net_l4_endpoint src; + memset(&src, 0, sizeof(src)); + int64_t r = socket_recvfrom_udp_ex(sock, buf, sizeof(buf), &src); + if (r > 0) { + if (src.port != 67) { continue; } + if ((size_t)r < sizeof(dhcp_packet) - sizeof(((dhcp_packet*)0)->options) + 4) { continue; } dhcp_packet *p = (dhcp_packet*)buf; - uint16_t idx= dhcp_parse_option(p, 53); - if (idx != UINT16_MAX && p->options[idx + 2] == wanted){ - uintptr_t copy = malloc((uint32_t)r); - memcpy((void*)copy, buf, (size_t)r); - if (outp) *outp= (dhcp_packet*)copy; - if (outsp) *outsp = (sizedptr){ copy, (uint32_t)r }; - return true; - } + if (p->htype != 1) { continue; } + if (p->hlen != 6) { continue; } + if (!dhcp_has_valid_cookie(p)) { continue; } + if (expect_xid && p->xid != expect_xid) { continue; } + if (mac && !packet_mac_matches(p, mac)) { continue; } + uint16_t idx = dhcp_parse_option_bounded(p, (uint32_t)r, 53); + if (idx == UINT16_MAX) { continue; } + uint8_t len = p->options[idx+1]; + if (len < 1) { continue; } + if (p->options[idx+2] != wanted) { continue; } + uintptr_t copy = malloc((uint32_t)r); + memcpy((void*)copy, buf, (size_t)r); + if (outp) *outp= (dhcp_packet*)copy; + if (outsp) *outsp = (sizedptr){ copy, (uint32_t)r }; + return true; } else { sleep(50); waited += 50; } } - kprintf("[DHCP] wait timeout type=%i", wanted); return false; } -static void dhcp_fsm_once() -{ - //TODO: use a syscall for the rng - rng_t rng; - rng_init_random(&rng); - uint32_t xid_seed = rng_next32(&rng); - dhcp_state_t old = g_state; - - switch (g_state) { - - case DHCP_S_INIT: { - const uint8_t *mac = network_get_local_mac(); - memcpy(g_local_mac, mac, 6); - xid_seed += 0x1111; - dhcp_send_discover(xid_seed); - g_state = DHCP_S_SELECTING; - } break; - - case DHCP_S_SELECTING: { - dhcp_packet *offer = NULL; sizedptr sp = {0}; - if (!dhcp_wait_for_type(DHCPOFFER, &offer, &sp, 5000)) { - g_state = DHCP_S_INIT; - break; - } - dhcp_request req = {0}; - memcpy(req.mac, g_local_mac, 6); - dhcp_apply_offer(offer, &req, xid_seed); - free((void*)sp.ptr, sp.size); - - xid_seed += 0x0101; - dhcp_send_request(&req, xid_seed, true); - g_state = DHCP_S_REQUESTING; - } break; - - case DHCP_S_REQUESTING: { - dhcp_packet *ack = NULL; sizedptr sp = {0}; - if (!dhcp_wait_for_type(DHCPACK, &ack, &sp, 5000)) { - g_state = DHCP_S_INIT; - } else { - dhcp_request dummy = {0}; - memcpy(dummy.mac, g_local_mac, 6); - dhcp_apply_offer(ack, &dummy, xid_seed); - free((void*)sp.ptr, sp.size); - g_state = DHCP_S_BOUND; - } - } break; - - case DHCP_S_BOUND: { - if (g_force_renew) { - g_force_renew = false; - xid_seed += 0x2222; - dhcp_send_renew(xid_seed); - g_state = DHCP_S_RENEWING; - - } else if (g_t2_left_ms == 0) { - xid_seed += 0x3333; - dhcp_send_rebind(xid_seed); - g_state = DHCP_S_REBINDING; - - } else if (g_t1_left_ms == 0) { - xid_seed += 0x2222; - dhcp_send_renew(xid_seed); - g_state = DHCP_S_RENEWING; - } - } break; - - case DHCP_S_RENEWING: { - dhcp_packet *p = NULL; sizedptr sp = {0}; - if (dhcp_wait_for_type(DHCPACK, &p, &sp, 2000)) { - dhcp_request dummy = {0}; - memcpy(dummy.mac, g_local_mac, 6); - dhcp_apply_offer(p, &dummy, xid_seed); - free((void*)sp.ptr, sp.size); - g_state = DHCP_S_BOUND; - } else { - xid_seed += 0x3333; - dhcp_send_rebind(xid_seed); - g_state = DHCP_S_REBINDING; - } - } break; - - case DHCP_S_REBINDING: { - dhcp_packet *p = NULL; sizedptr sp = {0}; - if (dhcp_wait_for_type(DHCPACK, &p, &sp, 2000)) { - dhcp_request dummy = {0}; - memcpy(dummy.mac, g_local_mac, 6); - dhcp_apply_offer(p, &dummy, xid_seed); - free((void*)sp.ptr, sp.size); - g_state = DHCP_S_BOUND; +static bool udp_wait_for_ack_or_nak(socket_handle_t sock, uint32_t expect_xid, const uint8_t mac[6], dhcp_packet **outp, sizedptr *outsp, uint32_t timeout_ms, uint8_t *out_msg_type) { + uint32_t waited = 0; + while (waited < timeout_ms) { + uint8_t buf[1024]; + net_l4_endpoint src; + memset(&src, 0, sizeof(src)); + int64_t r = socket_recvfrom_udp_ex(sock, buf, sizeof(buf), &src); + if (r > 0) { + if (src.port != 67) { continue; } + if ((size_t)r < sizeof(dhcp_packet) - sizeof(((dhcp_packet*)0)->options) + 4) { continue; } + dhcp_packet* p = (dhcp_packet*)buf; + if (p->htype != 1 || p->hlen != 6) { continue; } + if (!dhcp_has_valid_cookie(p)) { continue; } + if (expect_xid && p->xid != expect_xid) { continue; } + if (mac && !packet_mac_matches(p, mac)) { continue; } + uint16_t idx = dhcp_parse_option_bounded(p, (uint32_t)r, 53); + if (idx == UINT16_MAX || p->options[idx+1] < 1) { continue; } + uint8_t mtype = p->options[idx+2]; + if (mtype != DHCPACK && mtype != DHCPNAK) { continue; } + uintptr_t copy = malloc((uint32_t)r); + memcpy((void*)copy, buf, (size_t)r); + if (outp) *outp = (dhcp_packet*)copy; + if (outsp) *outsp = (sizedptr){ copy, (uint32_t)r }; + if (out_msg_type) *out_msg_type = mtype; + return true; } else { - net_cfg_t g_net_cfg; - g_net_cfg.ip = 0; - g_net_cfg.mode = 0; //NET_MODE_DHCP - ipv4_set_cfg(&g_net_cfg); - g_state = DHCP_S_INIT; - } - } break; - } - - if (old != g_state) log_state_change(old, g_state); -} - -int dhcp_daemon_entry(int argc, char* argv[]){ - (void)argc; (void)argv; - g_pid_dhcpd = (uint16_t)get_current_proc_pid(); - dhcp_set_pid(g_pid_dhcpd); - g_sock = udp_socket_create(SOCK_ROLE_SERVER, g_pid_dhcpd); - if(socket_bind_udp(g_sock, 68) != 0){ - kprint("[DHCP] bind failed"); - return 1; - } - - for(;;){ - dhcp_fsm_once(); - sleep(100); - - if(g_state == DHCP_S_BOUND){ - if(g_t1_left_ms > 100) g_t1_left_ms -= 100; else g_t1_left_ms = 0; - if(g_t2_left_ms > 100) g_t2_left_ms -= 100; else g_t2_left_ms = 0; + sleep(50); + waited += 50; } } + return false; } -static void dhcp_apply_offer(dhcp_packet *p, dhcp_request *req, uint32_t xid) { - const net_cfg_t *current = ipv4_get_cfg(); - net_cfg_t cfg_local = *current; - static net_runtime_opts_t rt_static; - memset(&rt_static, 0, sizeof(rt_static)); - cfg_local.rt = &rt_static; - cfg_local.rt->xid = (uint16_t)xid; - cfg_local.mode = 0; //NET_MODE_DHCP - +static void apply_offer_to_l3(uint8_t ifindex, uint8_t l3_id, dhcp_packet *p, sizedptr sp, uint32_t xid, dhcp_if_state_t* st) { + l3_ipv4_interface_t* v4 = l3_ipv4_find_by_id(l3_id); + if (!v4) return; + net_runtime_opts_t rt_local; + memset(&rt_local, 0, sizeof(rt_local)); uint32_t yi_net = p->yiaddr; - cfg_local.ip = bswap32(yi_net); - req->offered_ip = yi_net; - + uint32_t ip_host = bswap32(yi_net); uint16_t idx; uint8_t len; - - idx = dhcp_parse_option(p, 1); + uint32_t mask_host = 0; + + idx = dhcp_parse_option_bounded(p, sp.size, 1); if (idx != UINT16_MAX && (len = p->options[idx+1]) >= 4) { uint32_t mask_net; memcpy(&mask_net, &p->options[idx+2], 4); - cfg_local.mask = bswap32(mask_net); + mask_host = bswap32(mask_net); } - idx = dhcp_parse_option(p, 3); + uint32_t gw_host = 0; + idx = dhcp_parse_option_bounded(p, sp.size, 3); if (idx != UINT16_MAX && (len = p->options[idx+1]) >= 4) { uint32_t gw_net; memcpy(&gw_net, &p->options[idx+2], 4); - cfg_local.gw = bswap32(gw_net); + gw_host = bswap32(gw_net); } - idx = dhcp_parse_option(p, 6); + idx = dhcp_parse_option_bounded(p, sp.size, 6); if (idx != UINT16_MAX) { len = p->options[idx+1]; - for (int i = 0; i < 2 && (i*4 + 4) <= len; ++i) { + for (int i = 0; i < 2 && (i*4 + 4) <= len; i++) { uint32_t dns_net; memcpy(&dns_net, &p->options[idx+2 + i*4], 4); - cfg_local.rt->dns[i] = bswap32(dns_net); + rt_local.dns[i] = bswap32(dns_net); } } - idx = dhcp_parse_option(p, 42); + idx = dhcp_parse_option_bounded(p, sp.size, 42); if (idx != UINT16_MAX) { len = p->options[idx+1]; - for (int i = 0; i < 2 && (i*4 + 4) <= len; ++i) { + for (int i = 0; i < 2 && (i*4 + 4) <= len; i++) { uint32_t ntp_net; memcpy(&ntp_net, &p->options[idx+2 + i*4], 4); - cfg_local.rt->ntp[i] = bswap32(ntp_net); + rt_local.ntp[i] = bswap32(ntp_net); } } - idx = dhcp_parse_option(p, 26); + idx = dhcp_parse_option_bounded(p, sp.size, 26); if (idx != UINT16_MAX && p->options[idx+1] == 2) { uint16_t mtu_net; memcpy(&mtu_net, &p->options[idx+2], 2); - cfg_local.rt->mtu = bswap16(mtu_net); + rt_local.mtu = bswap16(mtu_net); } - idx = dhcp_parse_option(p, 51); + uint32_t lease_s = 0; + idx = dhcp_parse_option_bounded(p, sp.size, 51); if (idx != UINT16_MAX && p->options[idx+1] >= 4) { uint32_t lease_net; memcpy(&lease_net, &p->options[idx+2], 4); - cfg_local.rt->lease = bswap32(lease_net); + lease_s = bswap32(lease_net); + rt_local.lease = lease_s; } - idx = dhcp_parse_option(p, 58); + uint32_t t1_s = 0; + idx = dhcp_parse_option_bounded(p, sp.size, 58); if (idx != UINT16_MAX && p->options[idx+1] >= 4) { uint32_t t1_net; memcpy(&t1_net, &p->options[idx+2], 4); - cfg_local.rt->t1 = bswap32(t1_net); - }else { - cfg_local.rt->t1 = cfg_local.rt->lease / 2; + t1_s = bswap32(t1_net); + } else { + if (lease_s) t1_s = lease_s / 2; } - - idx = dhcp_parse_option(p, 59); + rt_local.t1 = t1_s; + + uint32_t t2_s = 0; + idx = dhcp_parse_option_bounded(p, sp.size, 59); if (idx != UINT16_MAX && p->options[idx+1] >= 4) { uint32_t t2_net; memcpy(&t2_net, &p->options[idx+2], 4); - cfg_local.rt->t2 = bswap32(t2_net); + t2_s = bswap32(t2_net); } else { - cfg_local.rt->t2 = (cfg_local.rt->lease / 8) * 7; + if (lease_s) t2_s = (lease_s / 8) * 7; } + rt_local.t2 = t2_s; - idx = dhcp_parse_option(p, 54); + idx = dhcp_parse_option_bounded(p, sp.size, 54); if (idx != UINT16_MAX && p->options[idx+1] >= 4) { - uint32_t srv_net; - memcpy(&srv_net, &p->options[idx+2], 4); - cfg_local.rt->server_ip = bswap32(srv_net); - req->server_ip = srv_net; + memcpy(&st->server_ip_net, &p->options[idx+2], 4); } - if (cfg_local.rt->dns[0] == 0 && cfg_local.gw != 0) { - cfg_local.rt->dns[0] = cfg_local.gw; + if (rt_local.dns[0] == 0 && gw_host != 0) rt_local.dns[0] = gw_host; + rt_local.xid = (uint16_t)xid; + + l3_ipv4_update(l3_id, ip_host, mask_host, gw_host, IPV4_CFG_DHCP, &rt_local); + + l3_ipv4_interface_t* v4u = l3_ipv4_find_by_id(l3_id); + if (v4u) { + if (!v4u->routing_table) { + v4u->routing_table = ipv4_rt_create(); + } else { + ipv4_rt_clear(v4u->routing_table); + } + if (v4u->routing_table) { + if (ip_host && mask_host) { + uint32_t net = ip_host & mask_host; + ipv4_rt_add_in(v4u->routing_table, net, mask_host, 0, 10); + } + if (gw_host) { + ipv4_rt_add_in(v4u->routing_table, 0, 0, gw_host, 11); + } + } } - uint32_t bcast = ipv4_broadcast_calc(cfg_local.ip, cfg_local.mask); - static const uint8_t bmac[6] = {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}; - arp_table_put_for_l2(1, bcast, bmac, 0, true); + st->t1_left_ms = t1_s * 1000; + st->t2_left_ms = t2_s * 1000; + st->lease_left_ms = lease_s * 1000; +} - ipv4_set_cfg(&cfg_local); +static void dhcp_send_discover_for(dhcp_if_state_t* st) { + rng_t rng; + rng_init_random(&rng); + uint32_t xid = rng_next32(&rng); + st->trans_xid = xid; + dhcp_request req; + memset(&req, 0, sizeof(req)); + if (st->mac_ok) memcpy(req.mac, st->mac, 6); + sizedptr pkt = dhcp_build_packet(&req, DHCPDISCOVER, xid, DHCPK_DISCOVER, true); + net_l4_endpoint dst; + memset(&dst, 0, sizeof(dst)); + dst.ver = IP_VER4; + uint32_t bcast = 0xFFFFFFFFu; + memcpy(dst.ip, &bcast, 4); + dst.port = 67; + socket_sendto_udp_ex(st->sock, 0, &dst, 0, (const void*)pkt.ptr, pkt.size); + free((void*)pkt.ptr, pkt.size); +} - g_t1_left_ms = cfg_local.rt->t1 * 1000; - g_t2_left_ms = cfg_local.rt->t2 * 1000; +static void dhcp_send_request_select_for(dhcp_if_state_t* st, const dhcp_request* base) { + sizedptr pkt = dhcp_build_packet(base, DHCPREQUEST, st->trans_xid, DHCPK_SELECT, true); + net_l4_endpoint dst; + memset(&dst, 0, sizeof(dst)); + dst.ver = IP_VER4; + uint32_t dip = 0xFFFFFFFFu; + memcpy(dst.ip, &dip, 4); + dst.port = 67; + socket_sendto_udp_ex(st->sock, 0, &dst, 0, (const void*)pkt.ptr, pkt.size); + free((void*)pkt.ptr, pkt.size); +} + +static void dhcp_send_renew_for(dhcp_if_state_t* st) { + l3_ipv4_interface_t* v4 = l3_ipv4_find_by_id(st->l3_id); + if (!v4) return; + dhcp_request req; + memset(&req, 0, sizeof(req)); + if (st->mac_ok) memcpy(req.mac, st->mac, 6); + uint32_t ip_net = bswap32(v4->ip); + req.offered_ip = ip_net; + req.server_ip = st->server_ip_net; + rng_t rng; + rng_init_random(&rng); + st->trans_xid = rng_next32(&rng); + sizedptr pkt = dhcp_build_packet(&req, DHCPREQUEST, st->trans_xid, DHCPK_RENEW, st->server_ip_net == 0); + net_l4_endpoint dst; + memset(&dst, 0, sizeof(dst)); + dst.ver = IP_VER4; + uint32_t dip = st->server_ip_net ? st->server_ip_net : 0xFFFFFFFFu; + memcpy(dst.ip, &dip, 4); + dst.port = 67; + socket_sendto_udp_ex(st->sock, 0, &dst, 0, (const void*)pkt.ptr, pkt.size); + free((void*)pkt.ptr, pkt.size); +} + +static void dhcp_send_rebind_for(dhcp_if_state_t* st) { + l3_ipv4_interface_t* v4 = l3_ipv4_find_by_id(st->l3_id); + if (!v4) return; + dhcp_request req; + memset(&req, 0, sizeof(req)); + if (st->mac_ok) memcpy(req.mac, st->mac, 6); + uint32_t ip_net = bswap32(v4->ip); + req.offered_ip = ip_net; + req.server_ip = 0; + rng_t rng; + rng_init_random(&rng); + st->trans_xid = rng_next32(&rng); + sizedptr pkt = dhcp_build_packet(&req, DHCPREQUEST, st->trans_xid, DHCPK_REBIND, true); + net_l4_endpoint dst; + memset(&dst, 0, sizeof(dst)); + dst.ver = IP_VER4; + uint32_t dip = 0xFFFFFFFFu; + memcpy(dst.ip, &dip, 4); + dst.port = 67; + socket_sendto_udp_ex(st->sock, 0, &dst, 0, (const void*)pkt.ptr, pkt.size); + free((void*)pkt.ptr, pkt.size); +} + +static void dhcp_send_inform_for(dhcp_if_state_t* st) { + l3_ipv4_interface_t* v4 = l3_ipv4_find_by_id(st->l3_id); + if (!v4 || !v4->ip) return; + dhcp_request req; + memset(&req, 0, sizeof(req)); + if (st->mac_ok) memcpy(req.mac, st->mac, 6); + uint32_t ip_net = bswap32(v4->ip); + req.offered_ip = ip_net; + req.server_ip = 0; + rng_t rng; + rng_init_random(&rng); + uint32_t xid = rng_next32(&rng); + sizedptr pkt = dhcp_build_packet(&req, DHCPINFORM, xid, DHCPK_INFORM, true); + net_l4_endpoint dst; + memset(&dst, 0, sizeof(dst)); + dst.ver = IP_VER4; + uint32_t dip = 0xFFFFFFFFu; + memcpy(dst.ip, &dip, 4); + dst.port = 67; + socket_sendto_udp_ex(st->sock, 0, &dst, 0, (const void*)pkt.ptr, pkt.size); + free((void*)pkt.ptr, pkt.size); +} + +static void schedule_retry(dhcp_if_state_t* st) { + st->retry_left_ms = dhcp_next_backoff_ms(st); +} + +static void fsm_once_for(dhcp_if_state_t* st) { + dhcp_state_t old = st->state; + switch (st->state) { + case DHCP_S_INIT: { + if (st->retry_left_ms != 0) break; + dhcp_send_discover_for(st); + st->last_xid = st->trans_xid; + st->state = DHCP_S_SELECTING; + } break; + case DHCP_S_SELECTING: { + dhcp_packet* offer = NULL; sizedptr sp = (sizedptr){0,0}; + if (!udp_wait_for_type_on(st->sock, DHCPOFFER, st->last_xid, st->mac_ok ? st->mac : NULL, &offer, &sp, 5000)) { + st->state = DHCP_S_INIT; + schedule_retry(st); + break; + } + dhcp_request req; + memset(&req, 0, sizeof(req)); + if (st->mac_ok) memcpy(req.mac, st->mac, 6); + uint16_t idx54 = dhcp_parse_option_bounded(offer, sp.size, 54); + if (idx54 != UINT16_MAX && offer->options[idx54+1] >= 4) memcpy(&st->server_ip_net, &offer->options[idx54+2], 4); + memcpy(&req.offered_ip, &offer->yiaddr, 4); + req.server_ip = st->server_ip_net; + free((void*)sp.ptr, sp.size); + dhcp_send_request_select_for(st, &req); + st->state = DHCP_S_REQUESTING; + dhcp_reset_backoff(st); + } break; + case DHCP_S_REQUESTING: { + dhcp_packet* resp = NULL; sizedptr sp = (sizedptr){0,0}; uint8_t mtype = 0; + if (!udp_wait_for_ack_or_nak(st->sock, st->last_xid, st->mac_ok ? st->mac : NULL, &resp, &sp, 5000, &mtype)) { + st->state = DHCP_S_INIT; + schedule_retry(st); + } else { + if (mtype == DHCPACK) { + apply_offer_to_l3(st->ifindex, st->l3_id, resp, sp, st->last_xid, st); + free((void*)sp.ptr, sp.size); + st->state = DHCP_S_BOUND; + dhcp_reset_backoff(st); + } else { + free((void*)sp.ptr, sp.size); + l3_ipv4_update(st->l3_id, 0, 0, 0, IPV4_CFG_DHCP, NULL); + st->t1_left_ms = 0; + st->t2_left_ms = 0; + st->lease_left_ms = 0; + st->server_ip_net = 0; + st->state = DHCP_S_INIT; + schedule_retry(st); + } + } + } break; + case DHCP_S_BOUND: { + if (g_force_renew) { + g_force_renew = false; + dhcp_send_renew_for(st); + st->last_xid = st->trans_xid; + st->state = DHCP_S_RENEWING; + } else if (st->t2_left_ms == 0 && st->lease_left_ms != 0) { + dhcp_send_rebind_for(st); + st->last_xid = st->trans_xid; + st->state = DHCP_S_REBINDING; + } else if (st->t1_left_ms == 0 && st->lease_left_ms != 0) { + dhcp_send_renew_for(st); + st->last_xid = st->trans_xid; + st->state = DHCP_S_RENEWING; + } + } break; + case DHCP_S_RENEWING: { + dhcp_packet* p = NULL; sizedptr sp = (sizedptr){0,0}; uint8_t mtype = 0; + if (udp_wait_for_ack_or_nak(st->sock, st->last_xid, st->mac_ok ? st->mac : NULL, &p, &sp, 2000, &mtype)) { + if (mtype == DHCPACK) { + apply_offer_to_l3(st->ifindex, st->l3_id, p, sp, st->last_xid, st); + free((void*)sp.ptr, sp.size); + st->state = DHCP_S_BOUND; + dhcp_reset_backoff(st); + } else { + free((void*)sp.ptr, sp.size); + l3_ipv4_update(st->l3_id, 0, 0, 0, IPV4_CFG_DHCP, NULL); + st->t1_left_ms = 0; + st->t2_left_ms = 0; + st->lease_left_ms = 0; + st->server_ip_net = 0; + st->state = DHCP_S_INIT; + schedule_retry(st); + } + } else { + dhcp_send_rebind_for(st); + st->last_xid = st->trans_xid; + st->state = DHCP_S_REBINDING; + } + } break; + case DHCP_S_REBINDING: { + dhcp_packet* p = NULL; sizedptr sp = (sizedptr){0,0}; uint8_t mtype = 0; + if (udp_wait_for_ack_or_nak(st->sock, st->last_xid, st->mac_ok ? st->mac : NULL, &p, &sp, 2000, &mtype)) { + if (mtype == DHCPACK) { + apply_offer_to_l3(st->ifindex, st->l3_id, p, sp, st->last_xid, st); + free((void*)sp.ptr, sp.size); + st->state = DHCP_S_BOUND; + dhcp_reset_backoff(st); + } else { + free((void*)sp.ptr, sp.size); + l3_ipv4_update(st->l3_id, 0, 0, 0, IPV4_CFG_DHCP, NULL); + st->t1_left_ms = 0; + st->t2_left_ms = 0; + st->lease_left_ms = 0; + st->server_ip_net = 0; + st->state = DHCP_S_INIT; + schedule_retry(st); + } + } else { + l3_ipv4_update(st->l3_id, 0, 0, 0, IPV4_CFG_DHCP, NULL); + st->t1_left_ms = 0; + st->t2_left_ms = 0; + st->lease_left_ms = 0; + st->server_ip_net = 0; + st->state = DHCP_S_INIT; + schedule_retry(st); + } + } break; + } + if (old != st->state) kprintf("[DHCP] ifx=%i l3=%i state %i -> %i", st->ifindex, st->l3_id, old, st->state); +} + +static void tick_timers() { + for (int i = 0; i < g_if_count; i++) { + if (g_if[i].state == DHCP_S_BOUND) { + if (g_if[i].t1_left_ms > 100) g_if[i].t1_left_ms -= 100; else if (g_if[i].t1_left_ms) g_if[i].t1_left_ms = 0; + if (g_if[i].t2_left_ms > 100) g_if[i].t2_left_ms -= 100; else if (g_if[i].t2_left_ms) g_if[i].t2_left_ms = 0; + if (g_if[i].lease_left_ms > 100) g_if[i].lease_left_ms -= 100; else if (g_if[i].lease_left_ms) g_if[i].lease_left_ms = 0; + } + if (g_if[i].retry_left_ms > 100) g_if[i].retry_left_ms -= 100; else if (g_if[i].retry_left_ms) g_if[i].retry_left_ms = 0; + } +} + +static void maybe_send_inform() { + for (int i = 0; i < g_if_count; i++) { + if (!g_if[i].needs_inform) continue; + l3_ipv4_interface_t* v4 = l3_ipv4_find_by_id(g_if[i].l3_id); + if (!v4 || v4->mode != IPV4_CFG_STATIC || !v4->ip) { g_if[i].needs_inform = false; continue; } + dhcp_send_inform_for(&g_if[i]); + g_if[i].needs_inform = false; + } +} + +int dhcp_daemon_entry(int argc, char* argv[]) { + (void)argc; (void)argv; + g_pid_dhcpd = (uint16_t)get_current_proc_pid(); + dhcp_set_pid(g_pid_dhcpd); + for (;;) { + ensure_inventory(); + if (g_if_count == 0) { sleep(250); continue; } + for (int i = 0; i < g_if_count; i++) { + l3_ipv4_interface_t* v4 = l3_ipv4_find_by_id(g_if[i].l3_id); + if (!v4) continue; + if (v4->mode == IPV4_CFG_DHCP) fsm_once_for(&g_if[i]); + } + maybe_send_inform(); + sleep(100); + tick_timers(); + } } diff --git a/shared/net/application_layer/dns.c b/shared/net/application_layer/dns.c index 9e27c8f3..0199a807 100644 --- a/shared/net/application_layer/dns.c +++ b/shared/net/application_layer/dns.c @@ -2,11 +2,12 @@ #include "std/memory.h" #include "math/rng.h" #include "process/scheduler.h" +#include "types.h" #include "net/internet_layer/ipv4.h" +#include "networking/interface_manager.h" #include "dns_daemon.h" -#include "types.h" +#include "syscalls/syscalls.h" -extern void sleep(uint64_t ms); static uint32_t encode_dns_qname(uint8_t* dst, const char* name){ uint32_t index = 0; @@ -66,7 +67,37 @@ static dns_result_t parse_dns_a_record(uint8_t* buffer, uint32_t buffer_len, uin return DNS_ERR_NO_ANSWER; } -static dns_result_t perform_dns_query_once(socket_handle_t sock, uint32_t dns_ip_host, const char* name, uint32_t timeout_ms, uint32_t* out_ip){ +static dns_result_t parse_dns_aaaa_record(uint8_t* buffer, uint32_t buffer_len, uint16_t message_id, uint8_t out_ipv6[16]){ + if (buffer_len < 12) return DNS_ERR_FORMAT; + if (rd_be16(buffer+0) != message_id) return DNS_ERR_FORMAT; + uint16_t flags = rd_be16(buffer+2); + uint16_t question_count = rd_be16(buffer+4); + uint16_t answer_count = rd_be16(buffer+6); + if ((flags & 0x000F) == 3) return DNS_ERR_NXDOMAIN; + uint32_t offset = 12; + for (uint16_t i = 0; i < question_count; ++i){ + offset = skip_dns_name(buffer, buffer_len, offset); + if (offset + 4 > buffer_len) return DNS_ERR_FORMAT; + offset += 4; + } + for (uint16_t i = 0; i < answer_count; ++i){ + offset = skip_dns_name(buffer, buffer_len, offset); + if (offset + 10 > buffer_len) return DNS_ERR_FORMAT; + uint16_t type = rd_be16(buffer+offset+0); + uint16_t klass = rd_be16(buffer+offset+2); + uint16_t rdlength = rd_be16(buffer+offset+8); + offset += 10; + if (offset + rdlength > buffer_len) return DNS_ERR_FORMAT; + if (type == 28 && klass == 1 && rdlength == 16){ + memcpy(out_ipv6, buffer+offset, 16); + return DNS_OK; + } + offset += rdlength; + } + return DNS_ERR_NO_ANSWER; +} + +static dns_result_t perform_dns_query_once_a(socket_handle_t sock, uint32_t dns_ip_host, const char* name, uint32_t timeout_ms, uint32_t* out_ip){ uint8_t request_buffer[512]; memset(request_buffer,0,sizeof(request_buffer)); rng_t rng; rng_init_random(&rng); uint16_t message_id = (uint16_t)(rng_next32(&rng) & 0xFFFF); @@ -78,14 +109,14 @@ static dns_result_t perform_dns_query_once(socket_handle_t sock, uint32_t dns_ip wr_be16(request_buffer+offset+0, 1); wr_be16(request_buffer+offset+2, 1); offset += 4; - int64_t sent = socket_sendto_udp(sock, dns_ip_host, 53, request_buffer, offset); + int64_t sent = socket_sendto_udp_ex(sock, DST_ENDPOINT, &dns_ip_host, 53, request_buffer, offset); if (sent < 0) return DNS_ERR_SEND; uint32_t waited_ms = 0; while (waited_ms < timeout_ms){ uint8_t response_buffer[512]; - uint32_t source_ip; uint16_t source_port; - int64_t received = socket_recvfrom_udp(sock, response_buffer, sizeof(response_buffer), &source_ip, &source_port); - if (received > 0 && source_port == 53 && source_ip == dns_ip_host){ + net_l4_endpoint source; + int64_t received = socket_recvfrom_udp_ex(sock, response_buffer, sizeof(response_buffer), &source); + if (received > 0 && source.port == 53 && source.ver == IP_VER4 && *(uint32_t*)source.ip == dns_ip_host){ uint32_t ip_host; dns_result_t pr = parse_dns_a_record(response_buffer, (uint32_t)received, message_id, &ip_host); if (pr == DNS_OK){ *out_ip = ip_host; return DNS_OK; } @@ -98,22 +129,123 @@ static dns_result_t perform_dns_query_once(socket_handle_t sock, uint32_t dns_ip return DNS_ERR_TIMEOUT; } -dns_result_t dns_resolve_a(const char* hostname, uint32_t* out_ip, dns_server_sel_t which, uint32_t timeout_ms){ - const net_cfg_t* cfg = ipv4_get_cfg(); - if (!cfg || !cfg->rt) return DNS_ERR_NO_DNS; - uint32_t dns_primary = cfg->rt->dns[0]; - uint32_t dns_secondary = cfg->rt->dns[1]; - if (which == DNS_USE_PRIMARY && dns_primary == 0) return DNS_ERR_NO_DNS; - if (which == DNS_USE_SECONDARY && dns_secondary == 0) return DNS_ERR_NO_DNS; - if (which == DNS_USE_BOTH && dns_primary == 0 && dns_secondary == 0) return DNS_ERR_NO_DNS; +static dns_result_t perform_dns_query_once_aaaa(socket_handle_t sock, uint32_t dns_ip_host, const char* name, uint32_t timeout_ms, uint8_t out_ipv6[16]){ + uint8_t request_buffer[512]; memset(request_buffer, 0, sizeof(request_buffer)); + rng_t rng; rng_init_random(&rng); + uint16_t message_id = (uint16_t)(rng_next32(&rng) & 0xFFFF); + wr_be16(request_buffer+0, message_id); + wr_be16(request_buffer+2, 0x0100); + wr_be16(request_buffer+4, 1); + uint32_t offset = 12; + offset += encode_dns_qname(request_buffer+offset, name); + wr_be16(request_buffer+offset+0, 28); + wr_be16(request_buffer+offset+2, 1); + offset += 4; + int64_t sent = socket_sendto_udp_ex(sock, DST_ENDPOINT, &dns_ip_host, 53, request_buffer, offset); + if (sent < 0) return DNS_ERR_SEND; + uint32_t waited_ms = 0; + while (waited_ms < timeout_ms){ + uint8_t response_buffer[512]; + net_l4_endpoint source; + int64_t received = socket_recvfrom_udp_ex(sock, response_buffer, sizeof(response_buffer), &source); + if (received > 0 && source.port == 53 && source.ver == IP_VER4 && *(uint32_t*)source.ip == dns_ip_host){ + dns_result_t pr = parse_dns_aaaa_record(response_buffer, (uint32_t)received, message_id, out_ipv6); + if (pr == DNS_OK) return DNS_OK; + if (pr == DNS_ERR_NXDOMAIN) return pr; + } else { + sleep(50); + waited_ms += 50; + } + } + return DNS_ERR_TIMEOUT; +} + +static bool pick_dns_on_l3(uint8_t l3_id, uint32_t* out_primary, uint32_t* out_secondary){ + l3_ipv4_interface_t* v4 = l3_ipv4_find_by_id(l3_id); + if (!v4) return false; + uint32_t p = v4->runtime_opts_v4.dns[0]; + uint32_t s = v4->runtime_opts_v4.dns[1]; + if (out_primary) *out_primary = p; + if (out_secondary) *out_secondary = s; + return (p != 0) || (s != 0); +} + +static bool pick_dns_first_iface(uint8_t* out_l3, uint32_t* out_primary, uint32_t* out_secondary){ + uint8_t n = l2_interface_count(); + for (uint8_t i = 0; i < n; ++i){ + l2_interface_t* l2 = l2_interface_at(i); + if (!l2) continue; + for (int s = 0; s < MAX_IPV4_PER_INTERFACE; ++s){ + l3_ipv4_interface_t* v4 = l2->l3_v4[s]; + if (!v4 || v4->mode == IPV4_CFG_DISABLED) continue; + + uint32_t p = v4->runtime_opts_v4.dns[0]; + uint32_t q = v4->runtime_opts_v4.dns[1]; + if (p || q){ + if (out_l3) *out_l3 = v4->l3_id; + if (out_primary) *out_primary = p; + if (out_secondary)*out_secondary= q; + return true; + } + } + } + return false; +} + +static dns_result_t query_with_selection_a(uint32_t primary, uint32_t secondary, dns_server_sel_t which, const char* hostname, uint32_t timeout_ms, uint32_t* out_ip){ + if (which == DNS_USE_PRIMARY && primary == 0) return DNS_ERR_NO_DNS; + if (which == DNS_USE_SECONDARY && secondary == 0) return DNS_ERR_NO_DNS; + if (which == DNS_USE_BOTH && primary == 0 && secondary == 0) return DNS_ERR_NO_DNS; + socket_handle_t sock = dns_socket_handle(); + if (sock == 0) return DNS_ERR_SOCKET; + dns_result_t res = DNS_ERR_NO_DNS; + if (which == DNS_USE_PRIMARY) res = perform_dns_query_once_a(sock, primary, hostname, timeout_ms, out_ip); + else if (which == DNS_USE_SECONDARY) res = perform_dns_query_once_a(sock, secondary, hostname, timeout_ms, out_ip); + else { + res = perform_dns_query_once_a(sock, primary ? primary : secondary, hostname, timeout_ms, out_ip); + if (res != DNS_OK && secondary && secondary != primary) res = perform_dns_query_once_a(sock, secondary, hostname, timeout_ms, out_ip); + } + return res; +} + +static dns_result_t query_with_selection_aaaa(uint32_t primary, uint32_t secondary, dns_server_sel_t which, const char* hostname, uint32_t timeout_ms, uint8_t out_ipv6[16]){ + if (which == DNS_USE_PRIMARY && primary == 0) return DNS_ERR_NO_DNS; + if (which == DNS_USE_SECONDARY && secondary == 0) return DNS_ERR_NO_DNS; + if (which == DNS_USE_BOTH && primary == 0 && secondary == 0) return DNS_ERR_NO_DNS; socket_handle_t sock = dns_socket_handle(); if (sock == 0) return DNS_ERR_SOCKET; dns_result_t res = DNS_ERR_NO_DNS; - if (which == DNS_USE_PRIMARY) res = perform_dns_query_once(sock, dns_primary, hostname, timeout_ms, out_ip); - else if (which == DNS_USE_SECONDARY) res = perform_dns_query_once(sock, dns_secondary, hostname, timeout_ms, out_ip); + if (which == DNS_USE_PRIMARY) res = perform_dns_query_once_aaaa(sock, primary, hostname, timeout_ms, out_ipv6); + else if (which == DNS_USE_SECONDARY) res = perform_dns_query_once_aaaa(sock, secondary, hostname, timeout_ms, out_ipv6); else { - res = perform_dns_query_once(sock, dns_primary ? dns_primary : dns_secondary, hostname, timeout_ms, out_ip); - if (res != DNS_OK && dns_secondary && dns_secondary != dns_primary) res = perform_dns_query_once(sock, dns_secondary, hostname, timeout_ms, out_ip); + res = perform_dns_query_once_aaaa(sock, primary ? primary : secondary, hostname, timeout_ms, out_ipv6); + if (res != DNS_OK && secondary && secondary != primary) res = perform_dns_query_once_aaaa(sock, secondary, hostname, timeout_ms, out_ipv6); } return res; } + +dns_result_t dns_resolve_a(const char* hostname, uint32_t* out_ip, dns_server_sel_t which, uint32_t timeout_ms){ + uint8_t l3 = 0; + uint32_t p = 0, s = 0; + if (!pick_dns_first_iface(&l3, &p, &s)) return DNS_ERR_NO_DNS; + return query_with_selection_a(p, s, which, hostname, timeout_ms, out_ip); +} + +dns_result_t dns_resolve_a_on_l3(uint8_t l3_id, const char* hostname, uint32_t* out_ip, dns_server_sel_t which, uint32_t timeout_ms){ + uint32_t p = 0, s = 0; + if (!pick_dns_on_l3(l3_id, &p, &s)) return DNS_ERR_NO_DNS; + return query_with_selection_a(p, s, which, hostname, timeout_ms, out_ip); +} + +dns_result_t dns_resolve_aaaa(const char* hostname, uint8_t out_ipv6[16], dns_server_sel_t which, uint32_t timeout_ms){ + uint8_t l3 = 0; + uint32_t p = 0, s = 0; + if (!pick_dns_first_iface(&l3, &p, &s)) return DNS_ERR_NO_DNS; + return query_with_selection_aaaa(p, s, which, hostname, timeout_ms, out_ipv6); +} + +dns_result_t dns_resolve_aaaa_on_l3(uint8_t l3_id, const char* hostname, uint8_t out_ipv6[16], dns_server_sel_t which, uint32_t timeout_ms){ + uint32_t p = 0, s = 0; + if (!pick_dns_on_l3(l3_id, &p, &s)) return DNS_ERR_NO_DNS; + return query_with_selection_aaaa(p, s, which, hostname, timeout_ms, out_ipv6); +} diff --git a/shared/net/application_layer/dns.h b/shared/net/application_layer/dns.h index 8d429627..d85ce336 100644 --- a/shared/net/application_layer/dns.h +++ b/shared/net/application_layer/dns.h @@ -21,6 +21,10 @@ typedef enum { } dns_server_sel_t; dns_result_t dns_resolve_a(const char* hostname, uint32_t* out_ip, dns_server_sel_t which, uint32_t timeout_ms); +dns_result_t dns_resolve_a_on_l3(uint8_t l3_id, const char* hostname, uint32_t* out_ip, dns_server_sel_t which, uint32_t timeout_ms); +dns_result_t dns_resolve_aaaa(const char* hostname, uint8_t out_ipv6[16], dns_server_sel_t which, uint32_t timeout_ms); +dns_result_t dns_resolve_aaaa_on_l3(uint8_t l3_id, const char* hostname, uint8_t out_ipv6[16], dns_server_sel_t which, uint32_t timeout_ms); + #ifdef __cplusplus } -#endif \ No newline at end of file +#endif diff --git a/shared/net/application_layer/dns_daemon.c b/shared/net/application_layer/dns_daemon.c index b1cf796d..be2ab822 100644 --- a/shared/net/application_layer/dns_daemon.c +++ b/shared/net/application_layer/dns_daemon.c @@ -1,8 +1,6 @@ #include "dns_daemon.h" #include "process/scheduler.h" -#include "std/memory.h" - -extern void sleep(uint64_t ms); +#include "syscalls/syscalls.h" static uint16_t g_pid_dnsd = 0xFFFF; static socket_handle_t g_sock = 0; diff --git a/shared/net/application_layer/http.c b/shared/net/application_layer/http.c index fa8d2e43..ebb96875 100644 --- a/shared/net/application_layer/http.c +++ b/shared/net/application_layer/http.c @@ -1,9 +1,7 @@ #include "http.h" #include "std/string.h" #include "std/memory.h" -extern uintptr_t malloc(uint64_t size); -extern void free(void *ptr, uint64_t size); -extern void sleep(uint64_t ms); +#include "syscalls/syscalls.h" static inline bool is_space(char c) { return c == ' ' || c == '\t'; diff --git a/shared/net/application_layer/sntp.c b/shared/net/application_layer/sntp.c index 15367db1..8b38448b 100644 --- a/shared/net/application_layer/sntp.c +++ b/shared/net/application_layer/sntp.c @@ -2,16 +2,15 @@ #include "exceptions/timer.h" #include "std/memory.h" #include "net/internet_layer/ipv4.h" -#include "net/transport_layer/csocket_udp.h" #include "process/scheduler.h" #include "console/kio.h" #include "types.h" +#include "net/transport_layer/csocket_udp.h" +#include "syscalls/syscalls.h" #define NTP_PORT 123 #define NTP_UNIX_EPOCH_DELTA 2208988800UL -extern void sleep(uint64_t ms); - typedef struct __attribute__((packed)) { uint8_t li_vn_mode; uint8_t stratum; @@ -43,26 +42,54 @@ static uint64_t ntp64_be_to_unix_us(uint64_t ntp_be){ return sec * 1000000ULL + ((frac * 1000000ULL) >> 32); } -static sntp_result_t sntp_send_query(socket_handle_t sock, uint32_t server_ip_host, uint64_t* t1_us_out){ +static void make_v4_ep(uint32_t ip_host, uint16_t port, net_l4_endpoint* ep){ + memset(ep, 0, sizeof(*ep)); + ep->ver = IP_VER4; + memcpy(ep->ip, &ip_host, 4); + ep->port = port; +} + +static sntp_result_t sntp_send_query(socket_handle_t sock, uint32_t server_ip_host, uint64_t* t1_us_out) { ntp_packet_t p; memset(&p, 0, sizeof(p)); p.li_vn_mode = (0u<<6) | (4u<<3) | 3u; - uint64_t t1_us = timer_now_usec(); p.txTs = unix_us_to_ntp64_be(t1_us); - - int64_t sent = socket_sendto_udp(sock, server_ip_host, NTP_PORT, &p, sizeof(p)); + net_l4_endpoint dst; + make_v4_ep(server_ip_host, 0, &dst); + int64_t sent = socket_sendto_udp_ex(sock, DST_ENDPOINT, &dst, NTP_PORT, &p, sizeof(p)); if (sent < 0) return SNTP_ERR_SEND; *t1_us_out = t1_us; return SNTP_OK; } sntp_result_t sntp_poll_once(uint32_t timeout_ms){ - const net_cfg_t* cfg = ipv4_get_cfg(); - if (!cfg || !cfg->rt) return SNTP_ERR_NO_CFG; + uint32_t s0 = 0; + uint32_t s1 = 0; + + uint8_t l2n = l2_interface_count(); + for (uint8_t i = 0; i < l2n && (s0 == 0 || s1 == 0); i++) { + l2_interface_t* l2 = l2_interface_at(i); + if (!l2) continue; + for (int s = 0; s < MAX_IPV4_PER_INTERFACE && (s0 == 0 || s1 == 0); s++) { + l3_ipv4_interface_t* v4 = l2->l3_v4[s]; + if (!v4) continue; + if (v4->mode == IPV4_CFG_DISABLED) continue; + const net_runtime_opts_t* rt = &v4->runtime_opts_v4; + if (!rt) continue; + uint32_t c0 = rt->ntp[0]; + uint32_t c1 = rt->ntp[1]; + if (c0 && c0 != s0 && c0 != s1){ + if (!s0) s0 = c0; + else if (!s1) s1 = c0; + } + if (c1 && c1 != s0 && c1 != s1){ + if (!s0) s0 = c1; + else if (!s1) s1 = c1; + } + } + } - uint32_t s0 = cfg->rt->ntp[0]; - uint32_t s1 = cfg->rt->ntp[1]; if (s0 == 0 && s1 == 0) return SNTP_ERR_NO_SERVER; socket_handle_t sock = udp_socket_create(0, (uint32_t)get_current_proc_pid()); @@ -83,45 +110,46 @@ sntp_result_t sntp_poll_once(uint32_t timeout_ms){ while (waited < timeout_ms){ uint8_t buf[96]; - uint32_t rip; uint16_t rport; - int64_t n = socket_recvfrom_udp(sock, buf, sizeof(buf), &rip, &rport); - - if (n >= (int64_t)sizeof(ntp_packet_t) && rport == NTP_PORT && (rip == s0 || rip == s1)){ - ntp_packet_t* r = (ntp_packet_t*)buf; - uint64_t t4_us = timer_now_usec(); - - uint64_t T1 = ntp64_be_to_unix_us(r->origTs); - uint64_t T2 = ntp64_be_to_unix_us(r->recvTs); - uint64_t T3 = ntp64_be_to_unix_us(r->txTs); - - if (T1 != 0 && T3 != 0) { - uint64_t t1_us = (rip == s0) ? t1_0 : t1_1; - uint64_t d = (T1 > t1_us) ? (T1 - t1_us) : (t1_us - T1); - if (t1_us != 0 && d <= 1000000ULL) { - int64_t rtt = (int64_t)(t4_us - t1_us) - (int64_t)(T3 - T2); - if (rtt < 0) rtt = 0; - int64_t off = ((int64_t)(T2 - t1_us) + (int64_t)(T3 - t4_us)) / 2; - - uint64_t server_unix_us = (uint64_t)((int64_t)t4_us + off); - - const uint64_t year2000 = 946684800ULL * 1000000ULL; - bool ok_range = false; - - if (timer_is_synchronised()) { - uint64_t now_wall_ms = timer_unix_time_ms(); - uint64_t now_wall_us = now_wall_ms ? (now_wall_ms * 1000ULL) : 0; - const uint64_t plus1d = 86400ULL * 1000000ULL; - ok_range = (server_unix_us >= year2000) &&(now_wall_us == 0||server_unix_us <= now_wall_us + plus1d); - } else { - ok_range = (server_unix_us >= year2000); - } - - if (ok_range) { - - - if ((uint64_t)rtt < best_rtt_us){ - best_rtt_us = (uint64_t)rtt; - best_server_unix_us = server_unix_us; + net_l4_endpoint src; + int64_t n = socket_recvfrom_udp_ex(sock, buf, sizeof(buf), &src); + + if (n >= (int64_t)sizeof(ntp_packet_t) && src.ver == IP_VER4 && src.port == NTP_PORT){ + uint32_t rip = 0; + memcpy(&rip, src.ip, 4); + if (rip == s0 || rip == s1){ + ntp_packet_t* r = (ntp_packet_t*)buf; + uint64_t t4_us = timer_now_usec(); + + uint64_t T1 = ntp64_be_to_unix_us(r->origTs); + uint64_t T2 = ntp64_be_to_unix_us(r->recvTs); + uint64_t T3 = ntp64_be_to_unix_us(r->txTs); + + if (T1 != 0 && T3 != 0) { + uint64_t t1_us = (rip == s0) ? t1_0 : t1_1; + uint64_t d = (T1 > t1_us) ? (T1 - t1_us) : (t1_us - T1); + if (t1_us != 0 && d <= 1000000ULL) { + int64_t rtt = (int64_t)(t4_us - t1_us) - (int64_t)(T3 - T2); + if (rtt < 0) rtt = 0; + int64_t off = ((int64_t)(T2 - t1_us) + (int64_t)(T3 - t4_us)) / 2; + + uint64_t server_unix_us = (uint64_t)((int64_t)t4_us + off); + + const uint64_t year2000 = 946684800ULL * 1000000ULL; + bool ok_range = false; + + if (timer_is_synchronised()) { + uint64_t now_wall_ms = timer_unix_time_ms(); + uint64_t now_wall_us = now_wall_ms ? (now_wall_ms * 1000ULL) : 0; + const uint64_t plus1d = 86400ULL * 1000000ULL; + ok_range = (server_unix_us >= year2000) &&(now_wall_us == 0 || server_unix_us <= now_wall_us + plus1d); + } else { + ok_range = (server_unix_us >= year2000); + } + if (ok_range) { + if ((uint64_t)rtt < best_rtt_us){ + best_rtt_us = (uint64_t)rtt; + best_server_unix_us = server_unix_us; + } } } } diff --git a/shared/net/application_layer/sntp_daemon.c b/shared/net/application_layer/sntp_daemon.c index 0e123239..f37a6842 100644 --- a/shared/net/application_layer/sntp_daemon.c +++ b/shared/net/application_layer/sntp_daemon.c @@ -3,9 +3,9 @@ #include "exceptions/timer.h" #include "process/scheduler.h" #include "net/internet_layer/ipv4.h" -#include "process/scheduler.h" +#include "networking/interface_manager.h" +#include "syscalls/syscalls.h" -extern void sleep(uint64_t ms); static uint16_t g_pid_sntp = 0xFFFF; static socket_handle_t g_sock = 0; @@ -19,6 +19,26 @@ socket_handle_t sntp_socket_handle(void){ return g_sock; } #define SNTP_QUERY_TIMEOUT_MS 1200u #define SNTP_BOOTSTRAP_MAX_RETRY 5u +static inline int ipv4_is_loopback_u32(uint32_t ip){ return ((ip & 0xFF000000u) == 0x7F000000u); } + +static bool any_ipv4_configured_nonlocal(void){ + uint8_t n = l2_interface_count(); + for (uint8_t i = 0; i < n; i++) { + l2_interface_t* l2 = l2_interface_at(i); + if (!l2 || !l2->is_up) continue; + for (int s = 0; s < MAX_IPV4_PER_INTERFACE; s++) { + l3_ipv4_interface_t* v4 = l2->l3_v4[s]; + if (!v4) continue; + if (v4->mode == IPV4_CFG_DISABLED) continue; + if (!v4->ip) continue; + if (v4->is_localhost) continue; + if (ipv4_is_loopback_u32(v4->ip)) continue; + return true; + } + } + return false; +} + int sntp_daemon_entry(int argc, char* argv[]){ (void)argc; (void)argv; g_pid_sntp = (uint16_t)get_current_proc_pid(); @@ -26,12 +46,10 @@ int sntp_daemon_entry(int argc, char* argv[]){ sntp_set_pid(get_current_proc_pid()); uint32_t attempts = 0; while (attempts < SNTP_BOOTSTRAP_MAX_RETRY){ - const net_cfg_t* cfg = ipv4_get_cfg(); - if (!cfg || cfg->mode == -1 || cfg->ip == 0){ //NET_MODE_DISABLED + if (!any_ipv4_configured_nonlocal()){ sleep(500); continue; } - sntp_result_t r = sntp_poll_once(SNTP_QUERY_TIMEOUT_MS); if (r == SNTP_OK){ break; @@ -41,10 +59,9 @@ int sntp_daemon_entry(int argc, char* argv[]){ uint32_t jitter = backoff_ms / 10u; sleep(backoff_ms + (jitter / 2u)); } - for(;;){ sntp_poll_once(SNTP_QUERY_TIMEOUT_MS); sleep(SNTP_POLL_INTERVAL_MS); } return 1; -} +} \ No newline at end of file diff --git a/shared/net/application_layer/socket_http_client.hpp b/shared/net/application_layer/socket_http_client.hpp index b3251b9e..58eeb6c4 100644 --- a/shared/net/application_layer/socket_http_client.hpp +++ b/shared/net/application_layer/socket_http_client.hpp @@ -4,136 +4,120 @@ #include "http.h" #include "std/string.h" #include "std/memory.h" +#include "net/transport_layer/socket_types.h" class HTTPClient { private: TCPSocket sock; public: - explicit HTTPClient(uint16_t pid); - ~HTTPClient(); - int32_t connect(uint32_t ip, uint16_t port); - HTTPResponseMsg send_request(const HTTPRequestMsg &req); - int32_t close(); -}; - -HTTPClient::HTTPClient(uint16_t pid) - : sock(SOCK_ROLE_CLIENT, pid) -{} - -HTTPClient::~HTTPClient() { - sock.close(); -} + explicit HTTPClient(uint16_t pid) : sock(SOCK_ROLE_CLIENT, pid){} + ~HTTPClient() {sock.close();} -int32_t HTTPClient::connect(uint32_t ip, uint16_t port) { - return sock.connect(ip, port); -} - -HTTPResponseMsg HTTPClient::send_request(const HTTPRequestMsg &req) { - string out = http_request_builder(&req); - int64_t sent = sock.send(out.data, out.length); - free(out.data, out.mem_length); + int32_t connect(SockDstKind kind, const void* dst, uint16_t port) { return sock.connect(kind, dst, port); } - HTTPResponseMsg resp{}; - if (sent < 0) { - resp.status_code = (HttpError)sent; - return resp; - } + HTTPResponseMsg send_request(const HTTPRequestMsg &req) { + string out = http_request_builder(&req); + int64_t sent = sock.send(out.data, out.length); + free(out.data, out.mem_length); - string buf = string_repeat('\0', 0); - char tmp[512]; - int attempts = 0; - int hdr_end = -1; - while (true) { - int64_t r = sock.recv(tmp, sizeof(tmp)); - if (r < 0) { - free(buf.data, buf.mem_length); - resp.status_code = (HttpError)SOCK_ERR_SYS; + HTTPResponseMsg resp{}; + if (sent < 0) { + resp.status_code = (HttpError)sent; return resp; } - if (r > 0) { - string_append_bytes(&buf, tmp, (uint32_t)r); - } - hdr_end = find_crlfcrlf(buf.data, buf.length); - if (hdr_end >= 0) break; - if (++attempts > 50) { - free(buf.data, buf.mem_length); - resp.status_code = (HttpError)SOCK_ERR_PROTO; - return resp; - } - sleep(10); - } - { - uint32_t i = 0; - while (i < (uint32_t)hdr_end && buf.data[i] != ' ') i++; - uint32_t code = 0, j = i+1; - while (j < (uint32_t)hdr_end && buf.data[j] >= '0' && buf.data[j] <= '9') { - code = code*10 + (buf.data[j]-'0'); ++j; + string buf = string_repeat('\0', 0); + char tmp[512]; + int attempts = 0; + int hdr_end = -1; + while (true) { + int64_t r = sock.recv(tmp, sizeof(tmp)); + if (r < 0) { + free(buf.data, buf.mem_length); + resp.status_code = (HttpError)SOCK_ERR_SYS; + return resp; + } + if (r > 0) { + string_append_bytes(&buf, tmp, (uint32_t)r); + } + hdr_end = find_crlfcrlf(buf.data, buf.length); + if (hdr_end >= 0) break; + if (++attempts > 50) { + free(buf.data, buf.mem_length); + resp.status_code = (HttpError)SOCK_ERR_PROTO; + return resp; + } + sleep(10); } - resp.status_code = (HttpError)code; - while (j < (uint32_t)hdr_end && buf.data[j]==' ') ++j; - if (j < (uint32_t)hdr_end) { - uint32_t rlen = hdr_end - j; - resp.reason = string_repeat('\0', 0); - string_append_bytes(&resp.reason, buf.data+j, rlen); + + { + uint32_t i = 0; + while (i < (uint32_t)hdr_end && buf.data[i] != ' ') i++; + uint32_t code = 0, j = i+1; + while (j < (uint32_t)hdr_end && buf.data[j] >= '0' && buf.data[j] <= '9') { + code = code*10 + (buf.data[j]-'0'); ++j; + } + resp.status_code = (HttpError)code; + while (j < (uint32_t)hdr_end && buf.data[j]==' ') ++j; + if (j < (uint32_t)hdr_end) { + uint32_t rlen = hdr_end - j; + resp.reason = string_repeat('\0', 0); + string_append_bytes(&resp.reason, buf.data+j, rlen); + } } - } - HTTPHeader *extras = nullptr; - uint32_t extra_count = 0; - int status_line_end = strindex((char*)buf.data, "\r\n"); - http_header_parser( - (char*)buf.data + status_line_end + 2, - buf.length - (uint32_t)(status_line_end + 2), - &resp.headers_common, - &extras, - &extra_count); - resp.extra_headers = extras; - resp.extra_header_count = extra_count; + HTTPHeader *extras = nullptr; + uint32_t extra_count = 0; + int status_line_end = strindex((char*)buf.data, "\r\n"); + http_header_parser( + (char*)buf.data + status_line_end + 2, + buf.length - (uint32_t)(status_line_end + 2), + &resp.headers_common, + &extras, + &extra_count); + resp.extra_headers = extras; + resp.extra_header_count = extra_count; - uint32_t body_start = hdr_end + 4; - uint32_t have = (buf.length > body_start) - ? buf.length - body_start - : 0; + uint32_t body_start = hdr_end + 4; + uint32_t have = (buf.length > body_start) ? buf.length - body_start : 0; - uint32_t need = resp.headers_common.length; - if (need > 0) { - while (have < need) { - int64_t r = sock.recv(tmp, sizeof(tmp)); - if (r <= 0) break; - string_append_bytes(&buf, tmp, (uint32_t)r); - have += (uint32_t)r; - } - } else { - int idle = 0; - while (idle < 5) { - int64_t r = sock.recv(tmp, sizeof(tmp)); - if (r > 0) { + uint32_t need = resp.headers_common.length; + if (need > 0) { + while (have < need) { + int64_t r = sock.recv(tmp, sizeof(tmp)); + if (r <= 0) break; string_append_bytes(&buf, tmp, (uint32_t)r); have += (uint32_t)r; - idle = 0; - } else { - ++idle; - sleep(20); + } + } else { + int idle = 0; + while (idle < 5) { + int64_t r = sock.recv(tmp, sizeof(tmp)); + if (r > 0) { + string_append_bytes(&buf, tmp, (uint32_t)r); + have += (uint32_t)r; + idle = 0; + } else { + ++idle; + sleep(20); + } } } - } - if (have > 0) { - char *body_copy = (char*)malloc(have + 1); - if (body_copy) { - memcpy(body_copy, - buf.data + body_start, - have); - body_copy[have] = '\0'; - resp.body.ptr = (uintptr_t)body_copy; - resp.body.size = have; + if (have > 0) { + char *body_copy = (char*)malloc(have + 1); + if (body_copy) { + memcpy(body_copy, buf.data + body_start, have); + body_copy[have] = '\0'; + resp.body.ptr = (uintptr_t)body_copy; + resp.body.size = have; + } } + free(buf.data, buf.mem_length); + return resp; } - free(buf.data, buf.mem_length); - return resp; -} -int32_t HTTPClient::close() { + int32_t close() { return sock.close(); } +}; diff --git a/shared/net/application_layer/socket_http_server.hpp b/shared/net/application_layer/socket_http_server.hpp index 73ea8e41..a1cb8ff0 100644 --- a/shared/net/application_layer/socket_http_server.hpp +++ b/shared/net/application_layer/socket_http_server.hpp @@ -3,6 +3,7 @@ #include "http.h" #include "std/string.h" #include "std/memory.h" +#include "net/transport_layer/socket_types.h" class HTTPServer { private: @@ -13,7 +14,7 @@ class HTTPServer { ~HTTPServer() { close(); } - int32_t bind(uint16_t port) { return sock.bind(port); } + int32_t bind(const SockBindSpec& spec, uint16_t port) { return sock.bind(spec, port); } int32_t listen(int backlog = 4) { return sock.listen(backlog); } TCPSocket* accept() { return sock.accept(); } diff --git a/shared/net/internet_layer/icmp.c b/shared/net/internet_layer/icmp.c index c5d61af1..17871560 100644 --- a/shared/net/internet_layer/icmp.c +++ b/shared/net/internet_layer/icmp.c @@ -4,10 +4,8 @@ #include "networking/interface_manager.h" #include "net/internet_layer/ipv4.h" #include "net/internet_layer/ipv4_route.h" +#include "syscalls/syscalls.h" -extern uintptr_t malloc(uint64_t size); -extern void free(void *ptr, uint64_t size); -extern void sleep(uint64_t ms); #define MAX_PENDING 16 #define POLL_MS 1 @@ -109,9 +107,9 @@ void icmp_input(uintptr_t ptr, create_icmp_packet(buf, &d); ((icmp_packet*)buf)->checksum = checksum16((uint16_t*)buf, reply_len); - l3_ipv4_interface_t *l3 = l3_ipv4_find_by_ip(dst_ip); // nostro IP + l3_ipv4_interface_t *l3 = l3_ipv4_find_by_ip(dst_ip); if (l3 && l3->l2) { - ipv4_tx_opts_t o = { .index = l3->l3_id, .int_type = 1 }; + ipv4_tx_opts_t o = { .index = l3->l3_id, .scope = IPV4_TX_BOUND_L2 }; char sbuf[16], dbuf[16]; ipv4_to_string(src_ip, sbuf); diff --git a/shared/net/internet_layer/ipv4.c b/shared/net/internet_layer/ipv4.c index 0ceb398a..b40c2fe0 100644 --- a/shared/net/internet_layer/ipv4.c +++ b/shared/net/internet_layer/ipv4.c @@ -7,98 +7,7 @@ #include "net/transport_layer/tcp.h" #include "net/transport_layer/udp.h" #include "console/kio.h" -extern uintptr_t malloc(uint64_t size); -extern void free(void *ptr, uint64_t size); -extern void sleep(uint64_t ms); - -static net_cfg_t g_ipv4_compat_cfg; -static bool g_ipv4_compat_valid; - -static l3_ipv4_interface_t* first_ipv4_if(void) { - uint8_t n = l2_interface_count(); - for (uint8_t i = 0; i < n; i++) { - l2_interface_t* l2 = l2_interface_at(i); - if (!l2) continue; - for (int s = 0; s < MAX_IPV4_PER_INTERFACE; s++) { - l3_ipv4_interface_t* v4 = l2->l3_v4[s]; - if (!v4) continue; - if (v4->mode == IPV4_CFG_DISABLED) continue; - return v4; - } - } - return NULL; -} - -static void ipv4_compat_refresh(void) { - l3_ipv4_interface_t* v4 = first_ipv4_if(); - if (!v4) { - memset(&g_ipv4_compat_cfg, 0, sizeof(g_ipv4_compat_cfg)); - g_ipv4_compat_valid = false; - return; - } - g_ipv4_compat_cfg.ip = v4->ip; - g_ipv4_compat_cfg.mask = v4->mask; - g_ipv4_compat_cfg.gw = v4->gw; - g_ipv4_compat_cfg.mode = (int8_t)v4->mode; - g_ipv4_compat_cfg.rt = (net_runtime_opts_t*)v4->runtime_opts_v4; - g_ipv4_compat_valid = true; -} - - - - - -// LEGACY -void ipv4_cfg_init(void) { - memset(&g_ipv4_compat_cfg, 0, sizeof(g_ipv4_compat_cfg)); - g_ipv4_compat_valid = false; -} - -void ipv4_set_cfg(const net_cfg_t* src) { - if (!src) { - g_ipv4_compat_valid = false; - memset(&g_ipv4_compat_cfg, 0, sizeof(g_ipv4_compat_cfg)); - l2_interface_t* l2 = l2_interface_find_by_index(1); - if (l2) { - for (int s = 0; s < MAX_IPV4_PER_INTERFACE; ++s) { - if (l2->l3_v4[s]) { - l3_ipv4_remove_from_interface(l2->l3_v4[s]->l3_id); - } - } - } - return; - } - - g_ipv4_compat_cfg = *src; - g_ipv4_compat_valid = true; - - l2_interface_t* l2 = l2_interface_find_by_index(1); - if (!l2) return; - - l3_ipv4_interface_t* v4 = NULL; - for (int s = 0; s < MAX_IPV4_PER_INTERFACE; ++s) { - if (l2->l3_v4[s]) { v4 = l2->l3_v4[s]; break; } - } - - ipv4_cfg_t mode = (src->mode == 0) ? IPV4_CFG_DHCP : IPV4_CFG_STATIC; - char buf[16]; - ipv4_to_string(src->ip, buf); - if (v4) { - kprintf("update ip=%s", buf); - l3_ipv4_update(v4->l3_id, src->ip, src->mask, src->gw, mode, (net_runtime_opts_t*)src->rt); - } - - if (!l2->is_up) l2_interface_set_up(1, true); -} - - -const net_cfg_t* ipv4_get_cfg(void) { - ipv4_compat_refresh(); - return g_ipv4_compat_valid ? &g_ipv4_compat_cfg : NULL; -} - - - +#include "syscalls/syscalls.h" static char* u8_to_str(uint8_t val, char* out) { if (val >= 100) { @@ -128,7 +37,13 @@ static int mask_prefix_len(uint32_t m) { } static inline bool is_lbcast(uint32_t ip) { return ip == 0xFFFFFFFFu; } - +static inline bool is_mcast(uint32_t ip) { return (ip & 0xF0000000u) == 0xE0000000u; } +static inline bool is_directed_bcast_for(const l3_ipv4_interface_t* v4, uint32_t dst) { + if (!v4) return false; + if (!v4->mask) return false; + uint32_t b = ipv4_broadcast_calc(v4->ip, v4->mask); + return b == dst; +} static l3_ipv4_interface_t* best_v4_on_l2_for_dst(l2_interface_t* l2, uint32_t dst) { l3_ipv4_interface_t* best = NULL; int best_pl = -1; @@ -350,9 +265,9 @@ static bool pick_route_bound_l2(uint8_t ifindex, uint32_t dst, uint8_t* out_ifx, static bool pick_route(uint32_t dst, const ipv4_tx_opts_t* opts, uint8_t* out_ifx, uint32_t* out_src, uint32_t* out_nh) { if (opts) { - return opts->int_type - ? pick_route_bound_l3(opts->index, dst, out_ifx, out_src, out_nh) - : pick_route_bound_l2(opts->index, dst, out_ifx, out_src, out_nh); + if (opts->scope == IPV4_TX_BOUND_L3) return pick_route_bound_l3(opts->index, dst, out_ifx, out_src, out_nh); + if (opts->scope == IPV4_TX_BOUND_L2) return pick_route_bound_l2(opts->index, dst, out_ifx, out_src, out_nh); + return pick_route_global(dst, out_ifx, out_src, out_nh); } return pick_route_global(dst, out_ifx, out_src, out_nh); } @@ -380,7 +295,21 @@ void ipv4_send_packet(uint32_t dst_ip, uint8_t proto, sizedptr segment, const ip if (!pick_route(dst_ip, opts, &ifx, &src_ip, &nh)) return; uint8_t dst_mac[6]; - if (!arp_resolve_on(ifx, nh, dst_mac, 200)) return; + bool is_dbcast = false; + l2_interface_t* l2 = l2_interface_find_by_index(ifx); + if (l2) { + for (int s = 0; s < MAX_IPV4_PER_INTERFACE; ++s) { + l3_ipv4_interface_t* v4 = l2->l3_v4[s]; + if (!v4 || v4->mode == IPV4_CFG_DISABLED) continue; + if (is_directed_bcast_for(v4, dst_ip)) { is_dbcast = true; break; } + } + } + + if (is_dbcast) { + memset(dst_mac, 0xFF, 6); + } else { + if (!arp_resolve_on(ifx, nh, dst_mac, 200)) return; + } uint32_t hdr_len = IP_IHL_NOOPTS * 4; uint32_t total = hdr_len + (uint32_t)segment.size; @@ -429,6 +358,13 @@ void ipv4_input(uint16_t ifindex, uintptr_t ip_ptr, uint32_t ip_len, const uint8 } ip->header_checksum = saved; + uint16_t ip_totlen = bswap16(ip->total_length); + if (ip_totlen < hdr_len) return; + if (ip_len < ip_totlen) return; + + uintptr_t l4 = ip_ptr + hdr_len; + uint32_t l4_len = (uint32_t)ip_totlen - hdr_len; + uint32_t src = bswap32(ip->src_ip); uint32_t dst = bswap32(ip->dst_ip); @@ -443,20 +379,99 @@ void ipv4_input(uint16_t ifindex, uintptr_t ip_ptr, uint32_t ip_len, const uint8 } uint8_t proto = ip->protocol; - uintptr_t l4 = ip_ptr + hdr_len; - uint32_t l4_len = ip_len - hdr_len; - - switch (proto) { - case 1://icmp - icmp_input(l4, l4_len, src, dst); - break; - case 6: //tcp - tcp_input(l4, l4_len, src, dst); - break; - case 17://udp - udp_input(l4, l4_len, src, dst); - break; - default: - break; + + l2_interface_t* l2 = l2_interface_find_by_index((uint8_t)ifindex); + if (!l2) return; + + l3_ipv4_interface_t* cand[MAX_IPV4_PER_INTERFACE]; + int ccount = 0; + for (int s = 0; s < MAX_IPV4_PER_INTERFACE; ++s) { + l3_ipv4_interface_t* v4 = l2->l3_v4[s]; + if (!v4) continue; + if (v4->mode == IPV4_CFG_DISABLED) continue; + cand[ccount++] = v4; } + if (ccount == 0) return; + + if (is_mcast(dst)) return; + + if (is_lbcast(dst)) { + if (ccount == 1) { + uint8_t l3id = cand[0]->l3_id; + switch (proto) { + case 1: icmp_input(l4, l4_len, src, dst); break; + case 6: tcp_input(IP_VER4, &src, &dst, l3id, l4, l4_len); break; + case 17: udp_input(IP_VER4, &src, &dst, l3id, l4, l4_len); break; + default: break; + } + return; + } else { + for (int i = 0; i < ccount; ++i) { + uint8_t l3id = cand[i]->l3_id; + switch (proto) { + case 1: icmp_input(l4, l4_len, src, dst); break; + case 6: tcp_input(IP_VER4, &src, &dst, l3id, l4, l4_len); break; + case 17: udp_input(IP_VER4, &src, &dst, l3id, l4, l4_len); break; + default: break; + } + } + return; + } + } + + int match_count = 0; + uint8_t match_l3id = 0; + for (int i = 0; i < ccount; ++i) { + if (cand[i]->ip && cand[i]->ip == dst) { + match_count++; + match_l3id = cand[i]->l3_id; + } + } + if (match_count == 1) { + switch (proto) { + case 1: icmp_input(l4, l4_len, src, dst); break; + case 6: tcp_input(IP_VER4, &src, &dst, match_l3id, l4, l4_len); break; + case 17: udp_input(IP_VER4, &src, &dst, match_l3id, l4, l4_len); break; + default: break; + } + return; + } + if (match_count > 1) { + for (int i = 0; i < ccount; ++i) { + if (cand[i]->ip == dst) { + uint8_t l3id = cand[i]->l3_id; + switch (proto) { + case 1: icmp_input(l4, l4_len, src, dst); break; + case 6: tcp_input(IP_VER4, &src, &dst, l3id, l4, l4_len); break; + case 17: udp_input(IP_VER4, &src, &dst, l3id, l4, l4_len); break; + default: break; + } + } + } + return; + } + + int any_dbcast = 0; + for (uint8_t i = 0, n = l2_interface_count(); i < n; ++i) { + l2_interface_t* l2x = l2_interface_at(i); + if (!l2x) continue; + for (int s = 0; s < MAX_IPV4_PER_INTERFACE; ++s) { + l3_ipv4_interface_t* v4 = l2x->l3_v4[s]; + if (!v4) continue; + if (v4->mode == IPV4_CFG_DISABLED) continue; + if (is_directed_bcast_for(v4, dst)) { + any_dbcast = 1; + uint8_t l3id = v4->l3_id; + switch (proto) { + case 1: icmp_input(l4, l4_len, src, dst); break; + case 6: tcp_input(IP_VER4, &src, &dst, l3id, l4, l4_len); break; + case 17: udp_input(IP_VER4, &src, &dst, l3id, l4, l4_len); break; + default: break; + } + } + } + } + if (any_dbcast) return; + + return; } \ No newline at end of file diff --git a/shared/net/internet_layer/ipv4.h b/shared/net/internet_layer/ipv4.h index 50f5c369..006c49fe 100644 --- a/shared/net/internet_layer/ipv4.h +++ b/shared/net/internet_layer/ipv4.h @@ -23,9 +23,14 @@ typedef struct __attribute__((packed)) ipv4_hdr_t { uint32_t dst_ip; } ipv4_hdr_t; +typedef enum { IPV4_TX_AUTO=0, + IPV4_TX_BOUND_L2=1, + IPV4_TX_BOUND_L3=2 +} ipv4_tx_scope_t; + typedef struct { uint8_t index; - bool int_type; //0 = l2 index, 1= l3 index + ipv4_tx_scope_t scope; } ipv4_tx_opts_t; void ipv4_to_string(uint32_t ip, char* buf); @@ -39,24 +44,6 @@ void ipv4_input(uint16_t ifindex, uintptr_t ip_ptr, uint32_t ip_len, const uint8_t src_mac[6]); - - - - - -//LEGACY - -typedef struct net_cfg { - uint32_t ip; - uint32_t mask; - uint32_t gw; - int8_t mode; - net_runtime_opts_t *rt; -} net_cfg_t; -void ipv4_cfg_init(void); -void ipv4_set_cfg(const net_cfg_t *src); -const net_cfg_t* ipv4_get_cfg(void); - #ifdef __cplusplus } #endif diff --git a/shared/net/internet_layer/ipv4_route.c b/shared/net/internet_layer/ipv4_route.c index cc99dabe..1b84c98a 100644 --- a/shared/net/internet_layer/ipv4_route.c +++ b/shared/net/internet_layer/ipv4_route.c @@ -1,8 +1,7 @@ #include "ipv4_route.h" #include "std/memory.h" - -extern uintptr_t malloc(uint64_t size); -extern void free(void* ptr, uint64_t size); +#include "networking/interface_manager.h" +#include "syscalls/syscalls.h" struct ipv4_rt_table { ipv4_rt_entry_t e[IPV4_RT_PER_IF_MAX]; @@ -109,3 +108,42 @@ void ipv4_rt_sync_basics(ipv4_rt_table_t* t, uint32_t ip, uint32_t mask, uint32_ (void)ipv4_rt_add_in(t, net, mask, 0, base_metric); } } +bool ipv4_rt_pick_best_l3_in(const uint8_t* l3_ids, int n_ids, uint32_t dst, uint8_t* out_l3){ + int best_pl = -1; + int best_cost = 0x7FFFFFFF; + uint8_t best_l3 = 0; + for (int i=0;il2) continue; + if (x->mode == IPV4_CFG_DISABLED) continue; + int l2base = (int)x->l2->base_metric; + int pl_conn = -1; + if (x->mask){ + uint32_t netx = x->ip & x->mask; + if ((dst & x->mask) == netx) pl_conn = prefix_len(x->mask); + } + int pl_tab = -1, met_tab = 0x7FFF; + if (x->routing_table){ + int out_pl = -1, out_met = 0x7FFF; + uint32_t nh; + if (ipv4_rt_lookup_in((const ipv4_rt_table_t*)x->routing_table, dst, &nh, &out_pl, &out_met)){ + pl_tab = out_pl; + met_tab = out_met; + } + } + int cand_pl = pl_conn; + int cand_cost = l2base; + if (pl_tab > cand_pl || (pl_tab == cand_pl && (l2base + met_tab) < cand_cost)){ + cand_pl = pl_tab; + cand_cost = l2base + met_tab; + } + if (cand_pl > best_pl || (cand_pl == best_pl && cand_cost < best_cost) || (cand_pl == best_pl && cand_cost == best_cost && l3_ids[i] < best_l3)){ + best_pl = cand_pl; + best_cost = cand_cost; + best_l3 = l3_ids[i]; + } + } + if (best_pl < 0) return false; + if (out_l3) *out_l3 = best_l3; + return true; +} diff --git a/shared/net/internet_layer/ipv4_route.h b/shared/net/internet_layer/ipv4_route.h index 30b6cd11..59fd03df 100644 --- a/shared/net/internet_layer/ipv4_route.h +++ b/shared/net/internet_layer/ipv4_route.h @@ -28,6 +28,8 @@ bool ipv4_rt_lookup_in(const ipv4_rt_table_t* t, uint32_t dst, uint32_t *next_ho void ipv4_rt_ensure_basics(ipv4_rt_table_t* t, uint32_t ip, uint32_t mask, uint32_t gw, uint16_t base_metric); void ipv4_rt_sync_basics(ipv4_rt_table_t* t, uint32_t ip, uint32_t mask, uint32_t gw, uint16_t base_metric); +bool ipv4_rt_pick_best_l3_in(const uint8_t* l3_ids, int n_ids, uint32_t dst, uint8_t* out_l3); + #ifdef __cplusplus } #endif diff --git a/shared/net/link_layer/arp.c b/shared/net/link_layer/arp.c index fd5b6019..7641748e 100644 --- a/shared/net/link_layer/arp.c +++ b/shared/net/link_layer/arp.c @@ -6,9 +6,7 @@ #include "process/scheduler.h" #include "console/kio.h" #include "net/internet_layer/ipv4.h" -extern void sleep(uint64_t ms); -extern uintptr_t malloc(uint64_t size); -extern void free(void *ptr, uint64_t size); +#include "syscalls/syscalls.h" typedef struct arp_table { arp_entry_t entries[ARP_TABLE_MAX]; diff --git a/shared/net/link_layer/eth.c b/shared/net/link_layer/eth.c index 33a787b3..68288217 100644 --- a/shared/net/link_layer/eth.c +++ b/shared/net/link_layer/eth.c @@ -3,12 +3,10 @@ #include "networking/network.h" #include "arp.h" #include "net/internet_layer/ipv4.h" -#include "networking/network.h" //#include "net/internet_layer/ipv6.h" #include "console/kio.h" +#include "syscalls/syscalls.h" -extern uintptr_t malloc(uint64_t size); -extern void free(void *ptr, uint64_t size); uintptr_t create_eth_packet(uintptr_t p, const uint8_t src_mac[6], diff --git a/shared/net/network_types.h b/shared/net/network_types.h index d255e4ed..629fcf22 100644 --- a/shared/net/network_types.h +++ b/shared/net/network_types.h @@ -6,10 +6,17 @@ extern "C" { #include "types.h" +typedef enum { + IP_VER4 = 4, + IP_VER6 = 6 +} ip_version_t; + typedef struct net_l4_endpoint { - uint32_t ip; + ip_version_t ver; + uint8_t ip[16]; uint16_t port; } net_l4_endpoint; + #ifdef __cplusplus } #endif \ No newline at end of file diff --git a/shared/net/transport_layer/csocket_tcp.cpp b/shared/net/transport_layer/csocket_tcp.cpp index ceb86119..6ea7b868 100644 --- a/shared/net/transport_layer/csocket_tcp.cpp +++ b/shared/net/transport_layer/csocket_tcp.cpp @@ -8,66 +8,81 @@ socket_handle_t socket_tcp_create(uint8_t role, uint32_t pid) { return reinterpret_cast(new TCPSocket(role, pid)); } -int32_t socket_bind_tcp(socket_handle_t sh, uint16_t port) { - return reinterpret_cast(sh)->bind(port); +int32_t socket_bind_tcp_ex(socket_handle_t sh, const SockBindSpec* spec, uint16_t port) { + if (!sh || !spec) return SOCK_ERR_INVAL; + return reinterpret_cast(sh)->bind(*spec, port); } int32_t socket_listen_tcp(socket_handle_t sh, int32_t backlog) { + if (!sh) return SOCK_ERR_INVAL; return reinterpret_cast(sh)->listen(backlog); } socket_handle_t socket_accept_tcp(socket_handle_t sh) { + if (!sh) return nullptr; TCPSocket* srv = reinterpret_cast(sh); TCPSocket* client = srv->accept(); return reinterpret_cast(client); } -int32_t socket_connect_tcp(socket_handle_t sh, uint32_t ip, uint16_t port) { - return reinterpret_cast(sh)->connect(ip, port); +int32_t socket_connect_tcp_ex(socket_handle_t sh, uint8_t dst_kind, const void* dst, uint16_t port) { + if (!sh || !dst) return SOCK_ERR_INVAL; + return reinterpret_cast(sh)->connect(static_cast(dst_kind), dst, port); } int64_t socket_send_tcp(socket_handle_t sh, const void* buf, uint64_t len) { + if (!sh) return SOCK_ERR_INVAL; return reinterpret_cast(sh)->send(buf, len); } int64_t socket_recv_tcp(socket_handle_t sh, void* buf, uint64_t len) { + if (!sh) return SOCK_ERR_INVAL; return reinterpret_cast(sh)->recv(buf, len); } int32_t socket_close_tcp(socket_handle_t sh) { - return reinterpret_cast(sh)->close(); + if (!sh) return SOCK_ERR_INVAL; + return reinterpret_cast(sh)->close(); } void socket_destroy_tcp(socket_handle_t sh) { - delete reinterpret_cast(sh); + if (!sh) return; + delete reinterpret_cast(sh); } uint16_t socket_get_local_port_tcp(socket_handle_t sh) { - return reinterpret_cast(sh)->get_local_port(); + if (!sh) return 0; + return reinterpret_cast(sh)->get_local_port(); } -uint32_t socket_get_remote_ip_tcp(socket_handle_t sh) { - return reinterpret_cast(sh)->get_remote_ip(); +uint16_t socket_get_remote_port_tcp(socket_handle_t sh) { + if (!sh) return 0; + return reinterpret_cast(sh)->get_remote_port(); } -uint16_t socket_get_remote_port_tcp(socket_handle_t sh) { - return reinterpret_cast(sh)->get_remote_port(); +void socket_get_remote_ep_tcp(socket_handle_t sh, net_l4_endpoint* out) { + if (!sh || !out) return; + *out = reinterpret_cast(sh)->get_remote_ep(); } uint8_t socket_get_protocol_tcp(socket_handle_t sh) { - return reinterpret_cast(sh)->get_protocol(); + if (!sh) return 0xFF; + return reinterpret_cast(sh)->get_protocol(); } uint8_t socket_get_role_tcp(socket_handle_t sh) { - return reinterpret_cast(sh)->get_role(); + if (!sh) return 0xFF; + return reinterpret_cast(sh)->get_role(); } bool socket_is_bound_tcp(socket_handle_t sh) { - return reinterpret_cast(sh)->is_bound(); + if (!sh) return false; + return reinterpret_cast(sh)->is_bound(); } bool socket_is_connected_tcp(socket_handle_t sh) { - return reinterpret_cast(sh)->is_connected(); + if (!sh) return false; + return reinterpret_cast(sh)->is_connected(); } } diff --git a/shared/net/transport_layer/csocket_tcp.h b/shared/net/transport_layer/csocket_tcp.h index 300ae33a..eb815ef2 100644 --- a/shared/net/transport_layer/csocket_tcp.h +++ b/shared/net/transport_layer/csocket_tcp.h @@ -1,6 +1,8 @@ #pragma once - #include "types.h" +#include "net/network_types.h" +#include "socket.hpp" +#include "net/transport_layer/socket_types.h" #ifdef __cplusplus extern "C" { @@ -9,18 +11,18 @@ extern "C" { typedef void* socket_handle_t; socket_handle_t socket_tcp_create(uint8_t role, uint32_t pid); -int32_t socket_bind_tcp(socket_handle_t sh, uint16_t port); +int32_t socket_bind_tcp_ex(socket_handle_t sh, const SockBindSpec* spec, uint16_t port); int32_t socket_listen_tcp(socket_handle_t sh, int32_t backlog); socket_handle_t socket_accept_tcp(socket_handle_t sh); -int32_t socket_connect_tcp(socket_handle_t sh, uint32_t ip, uint16_t port); +int32_t socket_connect_tcp_ex(socket_handle_t sh, uint8_t dst_kind, const void* dst, uint16_t port); int64_t socket_send_tcp(socket_handle_t sh, const void* buf, uint64_t len); int64_t socket_recv_tcp(socket_handle_t sh, void* buf, uint64_t len); int32_t socket_close_tcp(socket_handle_t sh); void socket_destroy_tcp(socket_handle_t sh); uint16_t socket_get_local_port_tcp(socket_handle_t sh); -uint32_t socket_get_remote_ip_tcp(socket_handle_t sh); uint16_t socket_get_remote_port_tcp(socket_handle_t sh); +void socket_get_remote_ep_tcp(socket_handle_t sh, net_l4_endpoint* out); uint8_t socket_get_protocol_tcp(socket_handle_t sh); uint8_t socket_get_role_tcp(socket_handle_t sh); bool socket_is_bound_tcp(socket_handle_t sh); diff --git a/shared/net/transport_layer/csocket_udp.cpp b/shared/net/transport_layer/csocket_udp.cpp index 4dae93c3..0663e5f4 100644 --- a/shared/net/transport_layer/csocket_udp.cpp +++ b/shared/net/transport_layer/csocket_udp.cpp @@ -6,56 +6,62 @@ extern "C" socket_handle_t udp_socket_create(uint8_t role, uint32_t pid) { return reinterpret_cast(new UDPSocket(role, pid)); } -extern "C" int32_t socket_bind_udp(socket_handle_t sh, uint16_t port) { - return reinterpret_cast(sh)->bind(port); +extern "C" int32_t socket_bind_udp_ex(socket_handle_t sh, const SockBindSpec* spec, uint16_t port) { + if (!sh || !spec) return SOCK_ERR_INVAL; + return reinterpret_cast(sh)->bind(*spec, port); } -extern "C" int64_t socket_sendto_udp(socket_handle_t sh, - uint32_t ip, uint16_t port, - const void* buf, uint64_t len) { - auto sock = reinterpret_cast(sh); - return sock->sendto(ip, port, buf, len); +extern "C" int64_t socket_sendto_udp_ex(socket_handle_t sh, uint8_t dst_kind, const void* dst, uint16_t port, const void* buf, uint64_t len) { + if (!sh || !dst || !buf || !len) return SOCK_ERR_INVAL; + return reinterpret_cast(sh)->sendto(static_cast(dst_kind), dst, port, buf, len); } -extern "C" int64_t socket_recvfrom_udp(socket_handle_t sh, - void* buf, uint64_t len, - uint32_t* out_ip, uint16_t* out_port) { - auto sock = reinterpret_cast(sh); - return sock->recvfrom(buf, len, out_ip, out_port); +extern "C" int64_t socket_recvfrom_udp_ex(socket_handle_t sh, void* buf, uint64_t len, net_l4_endpoint* out_src) { + if (!sh || !buf || !len) return 0; + return reinterpret_cast(sh)->recvfrom(buf, len, out_src); } extern "C" int32_t socket_close_udp(socket_handle_t sh) { + if (!sh) return SOCK_ERR_INVAL; return reinterpret_cast(sh)->close(); } extern "C" void socket_destroy_udp(socket_handle_t sh) { + if (!sh) return; delete reinterpret_cast(sh); } extern "C" uint16_t socket_get_local_port_udp(socket_handle_t sh) { + if (!sh) return 0; return reinterpret_cast(sh)->get_local_port(); } extern "C" uint16_t socket_get_remote_port_udp(socket_handle_t sh) { + if (!sh) return 0; return reinterpret_cast(sh)->get_remote_port(); } -extern "C" uint32_t socket_get_remote_ip_udp(socket_handle_t sh) { - return reinterpret_cast(sh)->get_remote_ip(); +extern "C" void socket_get_remote_ep_udp(socket_handle_t sh, net_l4_endpoint* out) { + if (!sh || !out) return; + *out = reinterpret_cast(sh)->get_remote_ep(); } extern "C" uint8_t socket_get_protocol_udp(socket_handle_t sh) { + if (!sh) return 0xFF; return reinterpret_cast(sh)->get_protocol(); } extern "C" uint8_t socket_get_role_udp(socket_handle_t sh) { + if (!sh) return 0xFF; return reinterpret_cast(sh)->get_role(); } extern "C" bool socket_is_bound_udp(socket_handle_t sh) { + if (!sh) return false; return reinterpret_cast(sh)->is_bound(); } extern "C" bool socket_is_connected_udp(socket_handle_t sh) { + if (!sh) return false; return reinterpret_cast(sh)->is_connected(); } diff --git a/shared/net/transport_layer/csocket_udp.h b/shared/net/transport_layer/csocket_udp.h index dd37c1ec..b0440d38 100644 --- a/shared/net/transport_layer/csocket_udp.h +++ b/shared/net/transport_layer/csocket_udp.h @@ -1,5 +1,8 @@ #pragma once #include "types.h" +#include "net/network_types.h" +#include "net/transport_layer/socket.hpp" +#include "net/transport_layer/socket_types.h" #ifdef __cplusplus extern "C" { @@ -8,34 +11,21 @@ extern "C" { typedef void* socket_handle_t; socket_handle_t udp_socket_create(uint8_t role, uint32_t pid); - -int32_t socket_bind_udp(socket_handle_t sh, uint16_t port); - -int64_t socket_sendto_udp(socket_handle_t sh, - uint32_t ip, uint16_t port, - const void* buf, uint64_t len); - -int64_t socket_recvfrom_udp(socket_handle_t sh, - void* buf, uint64_t len, - uint32_t* out_ip, uint16_t* out_port); - +int32_t socket_bind_udp_ex(socket_handle_t sh, const SockBindSpec* spec, uint16_t port); +int64_t socket_sendto_udp_ex(socket_handle_t sh, uint8_t dst_kind, const void* dst, uint16_t port, const void* buf, uint64_t len); +int64_t socket_recvfrom_udp_ex(socket_handle_t sh, void* buf, uint64_t len, net_l4_endpoint* out_src); int32_t socket_close_udp(socket_handle_t sh); - void socket_destroy_udp(socket_handle_t sh); uint16_t socket_get_local_port_udp(socket_handle_t sh); - uint16_t socket_get_remote_port_udp(socket_handle_t sh); - -uint32_t socket_get_remote_ip_udp(socket_handle_t sh); +void socket_get_remote_ep_udp(socket_handle_t sh, net_l4_endpoint* out); uint8_t socket_get_protocol_udp(socket_handle_t sh); - uint8_t socket_get_role_udp(socket_handle_t sh); - bool socket_is_bound_udp(socket_handle_t sh); - bool socket_is_connected_udp(socket_handle_t sh); + #ifdef __cplusplus } #endif diff --git a/shared/net/transport_layer/socket.hpp b/shared/net/transport_layer/socket.hpp index 0454a409..4c9988dd 100644 --- a/shared/net/transport_layer/socket.hpp +++ b/shared/net/transport_layer/socket.hpp @@ -1,20 +1,15 @@ #pragma once - #include "types.h" #include "net/network_types.h" #include "networking/port_manager.h" #include "tcp.h" #include "udp.h" +#include "net/transport_layer/socket_types.h" #ifdef __cplusplus extern "C" { #endif -//protos -#define PROTO_TCP 1 -#define PROTO_UDP 2 - -//roles #define SOCK_ROLE_CLIENT 0 #define SOCK_ROLE_SERVER 1 @@ -27,54 +22,73 @@ extern "C" { #define SOCK_ERR_SYS -6 #define SOCK_ERR_PROTO -7 #define SOCK_ERR_STATE -8 +#define SOCK_ERR_DNS -9 #ifdef __cplusplus } #endif - #ifdef __cplusplus class Socket { protected: - uint16_t localPort = 0; - uint32_t remoteIP = 0; - uint16_t remotePort = 0; - uint8_t proto; - uint8_t role; - bool bound = false; - bool connected = false; - uint16_t pid = 0; - - Socket(uint8_t protocol, uint8_t r) - : proto(protocol), role(r) {} + static constexpr int SOCK_MAX_L3 = 32; + + uint16_t localPort = 0; + net_l4_endpoint remoteEP = { IP_VER4, {0}, 0 }; + + uint8_t proto = 0; + uint8_t role = 0; + bool bound = false; + bool connected = false; + uint16_t pid = 0; + + uint8_t bound_l3[SOCK_MAX_L3] = {0}; + int bound_l3_count = 0; + + Socket(uint8_t protocol, uint8_t r) : proto(protocol), role(r) {} + + virtual void do_unbind_one(uint8_t l3_id, uint16_t port, uint16_t pid) = 0; + + void clear_bound_l3() { bound_l3_count = 0; } + bool add_bound_l3(uint8_t l3_id) { if (bound_l3_count >= SOCK_MAX_L3) return false; bound_l3[bound_l3_count++] = l3_id; return true; } + void set_remote_endpoint(const net_l4_endpoint& ep) { remoteEP = ep; } public: virtual ~Socket() { close(); } - virtual int32_t bind(uint16_t port) = 0; + virtual int32_t bind(const SockBindSpec& spec, uint16_t port) = 0; virtual int32_t close() { if (bound) { - if (proto == PROTO_UDP) { - udp_unbind(localPort, pid); - } else if (proto == PROTO_TCP) { - tcp_unbind(localPort, pid); + for (int i = 0; i < bound_l3_count; ++i) { + do_unbind_one(bound_l3[i], localPort, pid); } - bound = false; + bound = false; localPort = 0; + clear_bound_l3(); } connected = false; + remoteEP.port = 0; + remoteEP.ver = IP_VER4; + memset(remoteEP.ip, 0, 16); return SOCK_OK; } uint16_t get_local_port() const { return localPort; } - uint16_t get_remote_port() const { return remotePort; } - uint32_t get_remote_ip() const { return remoteIP; } + uint16_t get_remote_port() const { return remoteEP.port; } uint8_t get_protocol() const { return proto; } uint8_t get_role() const { return role; } + uint16_t get_pid() const { return pid; } bool is_bound() const { return bound; } bool is_connected() const { return connected; } + + ip_version_t get_remote_ip_version() const { return remoteEP.ver; } + const uint8_t* get_remote_ip_bytes() const { return remoteEP.ip; } + const net_l4_endpoint& get_remote_endpoint() const { return remoteEP; } + + int get_bound_l3_count() const { return bound_l3_count; } + uint8_t get_bound_l3_id(int idx) const { return (idx >= 0 && idx < bound_l3_count) ? bound_l3[idx] : 0; } }; #endif diff --git a/shared/net/transport_layer/socket_tcp.hpp b/shared/net/transport_layer/socket_tcp.hpp index d1dd311f..867a78a7 100644 --- a/shared/net/transport_layer/socket_tcp.hpp +++ b/shared/net/transport_layer/socket_tcp.hpp @@ -1,25 +1,23 @@ #pragma once -#include "console/kio.h" -#include "std/string.h" -#include "net/internet_layer/ipv4.h" #include "std/memory.h" +#include "std/string.h" #include "socket.hpp" #include "net/transport_layer/tcp.h" +#include "net/internet_layer/ipv4.h" +#include "net/application_layer/dns.h" #include "types.h" #include "data_struct/ring_buffer.hpp" - -extern "C" { - void sleep(uint64_t ms); - uintptr_t malloc(uint64_t size); - void free(void *ptr, uint64_t size); -} +#include "net/transport_layer/socket_types.h" +#include "net/internet_layer/ipv4_route.h" +#include "syscalls/syscalls.h" static constexpr int TCP_MAX_BACKLOG = 8; +static constexpr dns_server_sel_t TCP_DNS_SEL = DNS_USE_BOTH; +static constexpr uint32_t TCP_DNS_TIMEOUT_MS = 3000; class TCPSocket : public Socket { - inline static TCPSocket* s_by_port[MAX_PORTS] = { nullptr }; inline static TCPSocket* s_list_head = nullptr; static constexpr int TCP_RING_CAP = 1024; @@ -29,50 +27,140 @@ class TCPSocket : public Socket { TCPSocket* pending[TCP_MAX_BACKLOG] = { nullptr }; int backlogCap = 0; int backlogLen = 0; + TCPSocket* next = nullptr; - static void dispatch(uintptr_t ptr, - uint32_t len, - uint32_t src_ip, - uint16_t src_port, - uint16_t dst_port) - { - if (len == 0) { - TCPSocket* srv = s_by_port[dst_port]; - if (!srv || srv->role != SOCK_ROLE_SERVER) return; - if (srv->backlogLen >= srv->backlogCap) return; - - TCPSocket* child = new TCPSocket(); - child->localPort = dst_port; - child->remoteIP = src_ip; - child->remotePort = src_port; - child->bound = true; - child->connected = true; - child->flow = tcp_get_ctx(dst_port, src_ip, src_port); - child->pid = srv->pid; - child->insert_in_global_list(); - srv->pending[srv->backlogLen++] = child; - return; + static bool contains_id(const uint8_t* arr, int n, uint8_t id){ + for (int i=0;il2) return false; + if (!v4->l2->is_up) return false; + if (v4->is_localhost) return false; + if (v4->mode == IPV4_CFG_DISABLED) return false; + if (v4->ip == 0) return false; + if (!v4->port_manager) return false; + return true; + } + + static bool socket_matches_dst(TCPSocket* s, uint8_t ifx, ip_version_t ver, const void* dst_ip_addr, uint16_t dst_port){ + if (!s->bound) return false; + if (s->localPort != dst_port) return false; + for (int i=0;ibound_l3_count;++i){ + uint8_t id = s->bound_l3[i]; + if (ver == IP_VER4){ + l3_ipv4_interface_t* v4 = l3_ipv4_find_by_id(id); + if (!is_valid_v4_l3_for_bind(v4)) continue; + if (v4->l2->ifindex != ifx) continue; + if (v4->ip == *(const uint32_t*)dst_ip_addr) return true; + } else if (ver == IP_VER6){ + l3_ipv6_interface_t* v6 = l3_ipv6_find_by_id(id); + if (!v6 || !v6->l2 || !v6->l2->is_up || v6->is_localhost || v6->cfg == IPV6_CFG_DISABLE) continue; + if (v6->l2->ifindex != ifx) continue; + if (memcmp(v6->ip, dst_ip_addr, 16) == 0) return true; + } } + return false; + } - for (TCPSocket* s = s_list_head; s; s = s->next) { - if (s->connected && - s->localPort == dst_port && - s->remoteIP == src_ip && - s->remotePort == src_port) - { - s->on_receive(ptr, len); - return; + static uint8_t find_matching_l3(TCPSocket* s, uint8_t ifx, ip_version_t ver, const void* dst_ip_addr){ + for (int i=0;ibound_l3_count;++i){ + uint8_t id = s->bound_l3[i]; + if (ver == IP_VER4){ + l3_ipv4_interface_t* v4 = l3_ipv4_find_by_id(id); + if (!is_valid_v4_l3_for_bind(v4)) continue; + if (v4->l2->ifindex != ifx) continue; + if (v4->ip == *(const uint32_t*)dst_ip_addr) return id; + } else if (ver == IP_VER6){ + l3_ipv6_interface_t* v6 = l3_ipv6_find_by_id(id); + if (!v6 || !v6->l2 || !v6->l2->is_up || v6->is_localhost || v6->cfg == IPV6_CFG_DISABLE) continue; + if (v6->l2->ifindex != ifx) continue; + if (memcmp(v6->ip, dst_ip_addr, 16) == 0) return id; } } + if (ver == IP_VER4){ + uint32_t v4dst; memcpy(&v4dst, dst_ip_addr, 4); + l3_ipv4_interface_t* v4 = l3_ipv4_find_by_ip(v4dst); + if (is_valid_v4_l3_for_bind(v4) && v4->l2 && v4->l2->ifindex == ifx) return v4->l3_id; + } + return 0; + } + + static bool socket_matches_flow(TCPSocket* s, uint8_t ifx, ip_version_t ver, const void* dst_ip_addr, uint16_t dst_port, const void* src_ip_addr, uint16_t src_port){ + (void)ifx; + if (!s->connected) return false; + if (s->localPort != dst_port) return false; + if (s->remoteEP.port != src_port) return false; + if (s->remoteEP.ver != ver) return false; + if (ver == IP_VER4){ + if (*(const uint32_t*)s->remoteEP.ip != *(const uint32_t*)src_ip_addr) return false; + } else { + if (memcmp(s->remoteEP.ip, src_ip_addr, 16) != 0) return false; + } + return true; + } + + static void dispatch(uint8_t ifindex, ip_version_t ipver, const void* src_ip_addr, const void* dst_ip_addr, + uintptr_t frame_ptr, uint32_t frame_len, uint16_t src_port, uint16_t dst_port) + { + if (frame_len == 0){ + for (TCPSocket* srv = s_list_head; srv; srv = srv->next){ + if (srv->role != SOCK_ROLE_SERVER) continue; + if (!socket_matches_dst(srv, ifindex, ipver, dst_ip_addr, dst_port)) continue; + if (srv->backlogLen >= srv->backlogCap) break; + TCPSocket* child = new TCPSocket(SOCK_ROLE_CLIENT, srv->pid); + child->localPort = dst_port; + child->connected = true; + child->remoteEP.ver = ipver; + memset(child->remoteEP.ip, 0, 16); + if (ipver == IP_VER4) memcpy(child->remoteEP.ip, src_ip_addr, 4); + else memcpy(child->remoteEP.ip, src_ip_addr, 16); + child->remoteEP.port = src_port; + uint8_t l3id = find_matching_l3(srv, ifindex, ipver, dst_ip_addr); + child->clear_bound_l3(); + if (l3id) { + child->add_bound_l3(l3id); + } else if (ipver == IP_VER4){ + uint32_t v4dst; memcpy(&v4dst, dst_ip_addr, 4); + l3_ipv4_interface_t* v4 = l3_ipv4_find_by_ip(v4dst); + if (is_valid_v4_l3_for_bind(v4) && v4->l2 && v4->l2->ifindex == ifindex){ + child->add_bound_l3(v4->l3_id); + } else { + for (int i=0;ibound_l3_count;i++){ + l3_ipv4_interface_t* sv4 = l3_ipv4_find_by_id(srv->bound_l3[i]); + if (sv4 && sv4->l2 && sv4->l2->is_up && sv4->l2->ifindex == ifindex){ + child->add_bound_l3(sv4->l3_id); + } + } + } + } + child->flow = tcp_get_ctx(dst_port, ipver, child->remoteEP.ip, src_port); + if (!child->flow){ + child->close(); + delete child; + break; + } + srv->pending[srv->backlogLen++] = child; + break; + } + return; + } + for (TCPSocket* s = s_list_head; s; s = s->next){ + if (!socket_matches_flow(s, ifindex, ipver, dst_ip_addr, dst_port, src_ip_addr, src_port)) continue; + s->on_receive(frame_ptr, frame_len); + return; + } + if (frame_ptr && frame_len){ + free((void*)frame_ptr, frame_len); + } } void on_receive(uintptr_t ptr, uint32_t len) { - auto data = reinterpret_cast(malloc(len)); + uint8_t* data = (uint8_t*)malloc(len); if (!data) return; - memcpy(data, (void*)ptr, len); - sizedptr packet = { (uintptr_t)data, len }; - + sizedptr packet { (uintptr_t)data, len }; if (!ring.push(packet)) { sizedptr dropped; ring.pop(dropped); @@ -81,80 +169,233 @@ class TCPSocket : public Socket { } } - void insert_in_global_list() { + void insert_in_list() { + for (TCPSocket* it = s_list_head; it; it = it->next){ + if (it == this) { + return; + } + } next = s_list_head; s_list_head = this; } - void remove_from_global_list() { + void remove_from_list() { TCPSocket** cur = &s_list_head; while (*cur) { - if (*cur == this) { - *cur = (*cur)->next; - break; - } + if (*cur == this) { *cur = (*cur)->next; break; } cur = &((*cur)->next); } + next = nullptr; } - TCPSocket* next =nullptr; + void do_unbind_one(uint8_t l3_id, uint16_t port, uint16_t pid_) override { + (void)pid_; + if (role != SOCK_ROLE_SERVER) return; + (void)tcp_unbind_l3(l3_id, port, pid); + } -public: - explicit TCPSocket(uint8_t r = SOCK_ROLE_CLIENT, uint32_t pid_ = 0) - : Socket(PROTO_TCP, r) - { - if (pid_ != 0) { - pid = pid_; - insert_in_global_list(); + bool add_all_l3_on_l2(uint8_t ifindex, uint8_t* tmp_ids, int& n){ + l2_interface_t* l2 = l2_interface_find_by_index(ifindex); + if (!l2 || !l2->is_up) return false; + for (int s=0; sl3_v4[s]; + if (is_valid_v4_l3_for_bind(v4)){ if (n < SOCK_MAX_L3) tmp_ids[n++] = v4->l3_id; } + } + return n > 0; + } + + bool add_all_l3_any(uint8_t* tmp_ids, int& n){ + uint8_t cnt = l2_interface_count(); + for (uint8_t i=0;iis_up) continue; + for (int s=0; sl3_v4[s]; + if (is_valid_v4_l3_for_bind(v4)){ if (n < SOCK_MAX_L3) tmp_ids[n++] = v4->l3_id; } + } } + return n > 0; + } + + static bool is_zero_ip16(const uint8_t ip[16]){ + for (int i=0;i<16;++i) if (ip[i]) return false; + return true; + } + +public: + explicit TCPSocket(uint8_t r = SOCK_ROLE_CLIENT, uint32_t pid_ = 0) : Socket(PROTO_TCP, r){ + pid = pid_; + insert_in_list(); } ~TCPSocket() override { close(); - remove_from_global_list(); + remove_from_list(); } - int32_t bind(uint16_t port) override { + int32_t bind(const SockBindSpec& spec_in, uint16_t port) override { if (role != SOCK_ROLE_SERVER) return SOCK_ERR_PERM; if (bound) return SOCK_ERR_BOUND; - if (!tcp_bind(port, pid, dispatch)) - return SOCK_ERR_SYS; - s_by_port[port] = this; - localPort = port; bound = true; + + SockBindSpec spec = spec_in; + bool empty = spec.kind == BIND_L3 && spec.l3_id==0 && spec.ifindex==0 && spec.ver==0 && is_zero_ip16(spec.ip); + if (empty) spec.kind = BIND_ANY; + + uint8_t ids[SOCK_MAX_L3]; + int n = 0; + + if (spec.kind == BIND_L3){ + if (spec.l3_id) ids[n++] = spec.l3_id; + if (n==0) return SOCK_ERR_INVAL; + } else if (spec.kind == BIND_L2){ + if (!add_all_l3_on_l2(spec.ifindex, ids, n)) return SOCK_ERR_INVAL; + } else if (spec.kind == BIND_IP){ + if (spec.ver == IP_VER4){ + uint32_t v4; memcpy(&v4, spec.ip, 4); + l3_ipv4_interface_t* ipif = l3_ipv4_find_by_ip(v4); + if (!is_valid_v4_l3_for_bind(ipif)) return SOCK_ERR_INVAL; + ids[n++] = ipif->l3_id; + } else if (spec.ver == IP_VER6){ + return SOCK_ERR_PROTO; + } else return SOCK_ERR_INVAL; + } else if (spec.kind == BIND_ANY){ + if (!add_all_l3_any(ids, n)) return SOCK_ERR_INVAL; + } else return SOCK_ERR_INVAL; + + if (n==0) return SOCK_ERR_INVAL; + + uint8_t dedup[SOCK_MAX_L3]; int m=0; + for (int i=0;i TCP_MAX_BACKLOG ? TCP_MAX_BACKLOG : max_backlog; + backlogLen = 0; return SOCK_OK; } - int32_t connect(uint32_t ip, uint16_t port) { + TCPSocket* accept(){ + const int max_iters = 100; + int iter = 0; + while (backlogLen == 0){ + if (++iter > max_iters) return nullptr; + sleep(10); + } + TCPSocket* client = pending[0]; + for (int i=1;iis_up) continue; + for (int s = 0; s < MAX_IPV4_PER_INTERFACE && n < SOCK_MAX_L3; ++s){ + l3_ipv4_interface_t* v4 = l2->l3_v4[s]; + if (!is_valid_v4_l3_for_bind(v4)) continue; + ids[n++] = v4->l3_id; + } + } + if (n == 0) return SOCK_ERR_SYS; + uint32_t dip; memcpy(&dip, d.ip, 4); + if (!ipv4_rt_pick_best_l3_in(ids, n, dip, &chosen_l3)) return SOCK_ERR_SYS; + l3_ipv4_interface_t* v4 = l3_ipv4_find_by_id(chosen_l3); + if (!is_valid_v4_l3_for_bind(v4)) return SOCK_ERR_SYS; + int p = tcp_alloc_ephemeral_l3(chosen_l3, pid, dispatch); + if (p < 0) return SOCK_ERR_NO_PORT; + localPort = (uint16_t)p; + clear_bound_l3(); + add_bound_l3(chosen_l3); + } else if (bound_l3_count == 1){ + chosen_l3 = bound_l3[0]; + l3_ipv4_interface_t* v4 = l3_ipv4_find_by_id(chosen_l3); + if (!is_valid_v4_l3_for_bind(v4)) return SOCK_ERR_SYS; + if (localPort == 0){ + int p = tcp_alloc_ephemeral_l3(chosen_l3, pid, dispatch); + if (p < 0) return SOCK_ERR_NO_PORT; + localPort = (uint16_t)p; + } + } else { + uint32_t dip; memcpy(&dip, d.ip, 4); + if (!ipv4_rt_pick_best_l3_in(bound_l3, bound_l3_count, dip, &chosen_l3)) return SOCK_ERR_SYS; + l3_ipv4_interface_t* v4 = l3_ipv4_find_by_id(chosen_l3); + if (!is_valid_v4_l3_for_bind(v4)) return SOCK_ERR_SYS; + if (localPort == 0){ + int p = tcp_alloc_ephemeral_l3(chosen_l3, pid, dispatch); + if (p < 0) return SOCK_ERR_NO_PORT; + localPort = (uint16_t)p; + } + } tcp_data ctx_copy{}; - net_l4_endpoint dst{ip, port}; - if (!tcp_handshake(p, &dst, &ctx_copy, 0)) return SOCK_ERR_SYS; + if (!tcp_handshake_l3(chosen_l3, localPort, &d, &ctx_copy, pid)) return SOCK_ERR_SYS; - flow = tcp_get_ctx(p, ip, port); + flow = tcp_get_ctx(localPort, d.ver, (const void*)d.ip, d.port); if (!flow) return SOCK_ERR_SYS; - remoteIP = ip; - remotePort = port; + remoteEP = d; connected = true; return SOCK_OK; } - int64_t send(const void* buf, uint64_t len) { + int64_t send(const void* buf, uint64_t len){ if (!connected || !flow) return SOCK_ERR_STATE; flow->payload = { (uintptr_t)buf, (uint32_t)len }; - flow->flags = (1<flags = (1u<(len) : static_cast(res); + return (res == TCP_OK) ? (int64_t)len : (int64_t)res; } - int64_t recv(void* buf, uint64_t len) { + int64_t recv(void* buf, uint64_t len){ sizedptr p; if (!ring.pop(p)) return 0; uint32_t tocpy = p.size < (uint32_t)len ? p.size : (uint32_t)len; @@ -163,65 +404,26 @@ class TCPSocket : public Socket { return tocpy; } - int32_t listen(int max_backlog) { - if (!bound || role != SOCK_ROLE_SERVER) return SOCK_ERR_STATE; - backlogCap = max_backlog > TCP_MAX_BACKLOG ? TCP_MAX_BACKLOG : max_backlog; - backlogLen = 0; - return SOCK_OK; - } - - TCPSocket* accept() { - const int max_iters = 100; - int iter = 0; - while (backlogLen == 0) { - if (++iter > max_iters) return nullptr; - sleep(10); - } - TCPSocket* client = pending[0]; - for (int i = 1; i < backlogLen; ++i) - pending[i - 1] = pending[i]; - pending[--backlogLen] = nullptr; - return client; - } - - int32_t close_client() { - - if (connected && flow) { + int32_t close() override { + if (connected && flow){ tcp_flow_close(flow); connected = false; - } - if (bound) { - if (s_by_port[localPort] == this) { - tcp_unbind(localPort, pid); - s_by_port[localPort] = nullptr; - } - bound = false; + flow = nullptr; } sizedptr pkt; - while (ring.pop(pkt)) { - free((void*)pkt.ptr, pkt.size); - } - return SOCK_OK; - } + while (ring.pop(pkt)){ free((void*)pkt.ptr, pkt.size); } + for (int i=0;iremotePort != 0 && sock->remotePort != src_port)return; + static bool is_lbcast_ip(uint32_t ip) { + return ip == 0xFFFFFFFFu; + } - //if (sock->remoteIP != 0 && sock->remoteIP != src_ip)return; + static bool is_dbcast_for(const l3_ipv4_interface_t* v4, uint32_t dst) { + if (!v4 || !v4->mask) return false; + uint32_t b = ipv4_broadcast_calc(v4->ip, v4->mask); + return b == dst; + } - sock->on_receive(ptr, len, src_ip, src_port); + static bool socket_matches_dst(UDPSocket* s, uint8_t ifx, ip_version_t ver, const void* dst_ip_addr, uint16_t dst_port) { + if (!s->bound) return false; + if (s->localPort != dst_port) return false; + if (ver == IP_VER4) { + uint32_t dip = *(const uint32_t*)dst_ip_addr; + bool lb = is_lbcast_ip(dip); + for (int i = 0; i < s->bound_l3_count; ++i) { + uint8_t id = s->bound_l3[i]; + l3_ipv4_interface_t* v4 = l3_ipv4_find_by_id(id); + if (!v4 || !v4->l2) continue; + if (v4->l2->ifindex != ifx) continue; + if (lb) return true; + if (is_dbcast_for(v4, dip)) return true; + if (v4->ip && v4->ip == dip) return true; + } + return false; + } else if (ver == IP_VER6) { + for (int i = 0; i < s->bound_l3_count; ++i) { + uint8_t id = s->bound_l3[i]; + l3_ipv6_interface_t* v6 = l3_ipv6_find_by_id(id); + if (!v6 || !v6->l2) continue; + if (v6->l2->ifindex != ifx) continue; + if (memcmp(v6->ip, dst_ip_addr, 16) == 0) return true; + } + return false; + } else { + return false; + } } - void on_receive(uintptr_t ptr, - uint32_t len, - uint32_t src_ip, - uint16_t src_port) - { - this->remoteIP = src_ip; - this->remotePort = src_port; + static void dispatch(uint8_t ifindex, ip_version_t ipver, const void* src_ip_addr, const void* dst_ip_addr, uintptr_t frame_ptr, uint32_t frame_len, uint16_t src_port, uint16_t dst_port) { + for (UDPSocket* s = s_list_head; s; s = s->next) { + if (socket_matches_dst(s, ifindex, ipver, dst_ip_addr, dst_port)) { + s->on_receive(ipver, src_ip_addr, src_port, frame_ptr, frame_len); + return; + } + } + if (frame_ptr && frame_len) free((void*)frame_ptr, frame_len); + } + void on_receive(ip_version_t ver, const void* src_ip_addr, uint16_t src_port, uintptr_t ptr, uint32_t len) { uintptr_t copy = malloc(len); if (!copy) { - free((void*)ptr, len); + if (ptr && len) free((void*)ptr, len); return; } memcpy((void*)copy, (void*)ptr, len); - free((void*)ptr, len); + if (ptr && len) free((void*)ptr, len); - int next = (r_tail + 1) % UDP_RING_CAP; - if (next == r_head) { + int nexti = (r_tail + 1) % UDP_RING_CAP; + if (nexti == r_head) { free((void*)ring[r_head].ptr, ring[r_head].size); r_head = (r_head + 1) % UDP_RING_CAP; } ring[r_tail] = { (uintptr_t)copy, len }; - src_ips[r_tail] = src_ip; - src_ports[r_tail] = src_port; - r_tail = next; + src_eps[r_tail].ver = ver; + memset(src_eps[r_tail].ip, 0, 16); + if (ver == IP_VER4) { + uint32_t v4 = *(const uint32_t*)src_ip_addr; + memcpy(src_eps[r_tail].ip, &v4, 4); + } else if (ver == IP_VER6) { + memcpy(src_eps[r_tail].ip, src_ip_addr, 16); + } + src_eps[r_tail].port = src_port; + r_tail = nexti; + remoteEP = src_eps[(r_tail + UDP_RING_CAP - 1) % UDP_RING_CAP]; } -public: - UDPSocket(uint8_t r, uint32_t pid_) : Socket(PROTO_UDP, r) { - this->pid = pid_; - this->role = r; - this->proto = PROTO_UDP; - if (this->role == SOCK_ROLE_CLIENT) { - int p = udp_alloc_ephemeral(pid_, dispatch); - if (p >= 0) { - s_by_port[p] = this; - this->localPort = p; - this->bound = true; + void insert_in_list() { + next = s_list_head; + s_list_head = this; + } + + void remove_from_list() { + UDPSocket** cur = &s_list_head; + while (*cur) { + if (*cur == this) { + *cur = (*cur)->next; + break; + } + cur = &((*cur)->next); + } + next = nullptr; + } + + bool add_all_l3_on_l2(uint8_t ifindex, uint8_t* tmp_ids, int& n) { + l2_interface_t* l2 = l2_interface_find_by_index(ifindex); + if (!l2) return false; + for (int s = 0; s < MAX_IPV4_PER_INTERFACE; ++s) { + l3_ipv4_interface_t* v4 = l2->l3_v4[s]; + if (v4 && v4->mode != IPV4_CFG_DISABLED) { + if (n < SOCK_MAX_L3) tmp_ids[n++] = v4->l3_id; + } + } + for (int s = 0; s < MAX_IPV6_PER_INTERFACE; ++s) { + l3_ipv6_interface_t* v6 = l2->l3_v6[s]; + if (v6 && v6->cfg != IPV6_CFG_DISABLE) { + if (n < SOCK_MAX_L3) tmp_ids[n++] = v6->l3_id; + } + } + return n > 0; + } + + bool add_all_l3_any(uint8_t* tmp_ids, int& n) { + uint8_t cnt = l2_interface_count(); + for (uint8_t i = 0; i < cnt; ++i) { + l2_interface_t* l2 = l2_interface_at(i); + if (!l2) continue; + for (int s = 0; s < MAX_IPV4_PER_INTERFACE; ++s) { + l3_ipv4_interface_t* v4 = l2->l3_v4[s]; + if (v4 && v4->mode != IPV4_CFG_DISABLED) { + if (n < SOCK_MAX_L3) tmp_ids[n++] = v4->l3_id; + } + } + for (int s = 0; s < MAX_IPV6_PER_INTERFACE; ++s) { + l3_ipv6_interface_t* v6 = l2->l3_v6[s]; + if (v6 && v6->cfg != IPV6_CFG_DISABLE) { + if (n < SOCK_MAX_L3) tmp_ids[n++] = v6->l3_id; + } + } + } + return n > 0; + } + + void do_unbind_one(uint8_t l3_id, uint16_t port, uint16_t pid_) override { + (void)pid_; + udp_unbind_l3(l3_id, port, pid); + } + + static bool contains_id(const uint8_t* arr, int n, uint8_t id) { + for (int i = 0; i < n; ++i) if (arr[i] == id) return true; + return false; + } + + static bool is_lbcast(uint32_t ip) { + return ip == 0xFFFFFFFFu; + } + + static bool is_dbcast(uint32_t ip, uint8_t* out_l3) { + uint8_t cnt = l2_interface_count(); + for (uint8_t i = 0; i < cnt; ++i) { + l2_interface_t* l2 = l2_interface_at(i); + if (!l2) continue; + for (int s = 0; s < MAX_IPV4_PER_INTERFACE; ++s) { + l3_ipv4_interface_t* v4 = l2->l3_v4[s]; + if (!v4) continue; + if (v4->mode == IPV4_CFG_DISABLED) continue; + if (!v4->ip || !v4->mask) continue; + uint32_t b = ipv4_broadcast_calc(v4->ip, v4->mask); + if (b == ip) { if (out_l3) *out_l3 = v4->l3_id; return true; } } } + return false; + } + +public: + UDPSocket(uint8_t r, uint32_t pid_) : Socket(PROTO_UDP, r) { + pid = pid_; + insert_in_list(); } - - ~UDPSocket() override { close(); } - int32_t bind(uint16_t port) override { + ~UDPSocket() override { + close(); + remove_from_list(); + } + + int32_t bind(const SockBindSpec& spec, uint16_t port) override { if (role != SOCK_ROLE_SERVER) return SOCK_ERR_PERM; - if (bound) return SOCK_ERR_BOUND; - if (!udp_bind(port, pid, dispatch)) - return SOCK_ERR_SYS; - s_by_port[port] = this; - this->localPort = port; - this->bound = true; + if (bound) return SOCK_ERR_BOUND; + uint8_t ids[SOCK_MAX_L3]; + int n = 0; + if (spec.kind == BIND_L3) { + if (spec.l3_id) { ids[n++] = spec.l3_id; } + } else if (spec.kind == BIND_L2) { + if (!add_all_l3_on_l2(spec.ifindex, ids, n)) return SOCK_ERR_INVAL; + } else if (spec.kind == BIND_IP) { + if (spec.ver == IP_VER4) { + uint32_t v4; + memcpy(&v4, spec.ip, 4); + ip_resolution_result_t r = resolve_ipv4_to_interface(v4); + if (!r.found || !r.ipv4) return SOCK_ERR_INVAL; + ids[n++] = r.ipv4->l3_id; + } else if (spec.ver == IP_VER6) { + ip_resolution_result_t r6 = resolve_ipv6_to_interface(spec.ip); + if (!r6.found || !r6.ipv6) return SOCK_ERR_INVAL; + ids[n++] = r6.ipv6->l3_id; + } else { + return SOCK_ERR_INVAL; + } + } else if (spec.kind == BIND_ANY) { + if (!add_all_l3_any(ids, n)) return SOCK_ERR_INVAL; + } else { + return SOCK_ERR_INVAL; + } + uint8_t dedup[SOCK_MAX_L3]; + int m = 0; + for (int i = 0; i < n; ++i) { if (!contains_id(dedup, m, ids[i])) dedup[m++] = ids[i]; } + int bdone = 0; + for (int i = 0; i < m; ++i) { + uint8_t id = dedup[i]; + bool ok = udp_bind_l3(id, port, pid, dispatch); + if (!ok) { + for (int j = 0; j < bdone; ++j) { + uint8_t rid = dedup[j]; + udp_unbind_l3(rid, port, pid); + } + return SOCK_ERR_SYS; + } + bdone++; + } + clear_bound_l3(); + for (int i = 0; i < m; ++i) add_bound_l3(dedup[i]); + localPort = port; + bound = true; return SOCK_OK; } - - int64_t sendto(uint32_t ip, uint16_t port, const void* buf, uint64_t len) { - if (!bound) return SOCK_ERR_NOT_BOUND; - net_l4_endpoint src{ ipv4_get_cfg()->ip, localPort }; - net_l4_endpoint dst{ ip, port }; - sizedptr pay{ (uintptr_t)buf, (uint32_t)len }; - udp_send_segment(&src, &dst, pay); - this->remoteIP = ip; - this->remotePort = port; - return (int64_t)len; - } - - int64_t recvfrom(void* buf, uint64_t len, //b UDPSocket::recvfrom - uint32_t* src_ip, - uint16_t* src_port) - { - if (r_head == r_tail)return 0; - - auto p = ring[r_head]; - uint32_t ip = src_ips[r_head]; - uint16_t pt = src_ports[r_head]; - r_head = (r_head + 1) % UDP_RING_CAP; - uint32_t tocpy = p.size < len ? p.size : (uint32_t)len; - memcpy(buf, (void*)p.ptr, tocpy); + int64_t sendto(SockDstKind kind, const void* dst, uint16_t port, const void* buf, uint64_t len) { + if (!dst || !buf || len == 0) return SOCK_ERR_INVAL; + net_l4_endpoint d{}; + if (kind == DST_ENDPOINT) { + const net_l4_endpoint* ed = (const net_l4_endpoint*)dst; + d = *ed; + if (!d.port && port) d.port = port; + if (!d.port) return SOCK_ERR_INVAL; + } else if (kind == DST_DOMAIN) { + const char* host = (const char*)dst; + if (!port) return SOCK_ERR_INVAL; + uint32_t a4 = 0; + dns_result_t dr = dns_resolve_a(host, &a4, UDP_DNS_SEL, UDP_DNS_TIMEOUT_MS); + if (dr != DNS_OK) return SOCK_ERR_DNS; + d.ver = IP_VER4; + memset(d.ip, 0, 16); + memcpy(d.ip, &a4, 4); + d.port = port; + } else { + return SOCK_ERR_INVAL; + } - if (src_ip) *src_ip = ip; - if (src_port) *src_port = pt; + if (d.ver == IP_VER4) { + uint32_t dip; memcpy(&dip, d.ip, 4); + uint8_t chosen_l3 = 0; + bool is_bcast = false; + uint8_t db_l3 = 0; + if (is_lbcast(dip)) { + is_bcast = true; + } else if (is_dbcast(dip, &db_l3)) { + is_bcast = true; + chosen_l3 = db_l3; + } - this->remoteIP = ip; - this->remotePort = pt; + if (is_bcast) { + if (dip == 0xFFFFFFFFu) { + if (bound_l3_count == 0) return SOCK_ERR_SYS; + for (int i = 0; i < bound_l3_count; ++i) { + uint8_t bl3 = bound_l3[i]; + l3_ipv4_interface_t* v4 = l3_ipv4_find_by_id(bl3); + if (!v4 || !v4->l2) continue; + if (!bound) { + int p = udp_alloc_ephemeral_l3(bl3, pid, dispatch); + if (p < 0) continue; + localPort = (uint16_t)p; + add_bound_l3(bl3); + bound = true; + } else { + bool present = false; + for (int k = 0; k < bound_l3_count; ++k) if (bound_l3[k] == bl3) { present = true; break; } + if (!present) { + if (!udp_bind_l3(bl3, localPort, pid, dispatch)) continue; + add_bound_l3(bl3); + } + } + net_l4_endpoint src; + src.ver = IP_VER4; + memset(src.ip, 0, 16); + memcpy(src.ip, &v4->ip, 4); + src.port = localPort; + sizedptr pay{ (uintptr_t)buf, (uint32_t)len }; + ipv4_tx_opts_t tx; tx.scope = IPV4_TX_BOUND_L3; tx.index = bl3; + udp_send_segment(&src, &d, pay, &tx); + } + remoteEP = d; + return (int64_t)len; + } else { + if (!chosen_l3) return SOCK_ERR_SYS; + l3_ipv4_interface_t* v4 = l3_ipv4_find_by_id(chosen_l3); + if (!v4 || !v4->l2) return SOCK_ERR_SYS; + if (!bound) { + int p = udp_alloc_ephemeral_l3(chosen_l3, pid, dispatch); + if (p < 0) return SOCK_ERR_NO_PORT; + localPort = (uint16_t)p; + add_bound_l3(chosen_l3); + bound = true; + } else { + bool present = false; + for (int i = 0; i < bound_l3_count; ++i) if (bound_l3[i] == chosen_l3) { present = true; break; } + if (!present) { + if (!udp_bind_l3(chosen_l3, localPort, pid, dispatch)) return SOCK_ERR_SYS; + add_bound_l3(chosen_l3); + } + } + net_l4_endpoint src; + src.ver = IP_VER4; + memset(src.ip, 0, 16); + memcpy(src.ip, &v4->ip, 4); + src.port = localPort; + sizedptr pay{ (uintptr_t)buf, (uint32_t)len }; + ipv4_tx_opts_t tx; tx.scope = IPV4_TX_BOUND_L3; tx.index = chosen_l3; + udp_send_segment(&src, &d, pay, &tx); + remoteEP = d; + return (int64_t)len; + } + } else { + if (bound_l3_count == 0) { + uint8_t ids[SOCK_MAX_L3]; int n = 0; + uint8_t cnt = l2_interface_count(); + for (uint8_t i = 0; i < cnt; ++i) { + l2_interface_t* l2 = l2_interface_at(i); + if (!l2 || !l2->is_up) continue; + for (int s = 0; s < MAX_IPV4_PER_INTERFACE && n < SOCK_MAX_L3; ++s) { + l3_ipv4_interface_t* v4 = l2->l3_v4[s]; + if (!v4) continue; + if (v4->mode == IPV4_CFG_DISABLED) continue; + ids[n++] = v4->l3_id; + } + } + if (n == 0) return SOCK_ERR_SYS; + if (!ipv4_rt_pick_best_l3_in(ids, n, dip, &chosen_l3)) return SOCK_ERR_SYS; + l3_ipv4_interface_t* v4 = l3_ipv4_find_by_id(chosen_l3); + if (!v4 || !v4->l2) return SOCK_ERR_SYS; + int p = udp_alloc_ephemeral_l3(chosen_l3, pid, dispatch); + if (p < 0) return SOCK_ERR_NO_PORT; + localPort = (uint16_t)p; + add_bound_l3(chosen_l3); + bound = true; + net_l4_endpoint src; + src.ver = IP_VER4; + memset(src.ip, 0, 16); + memcpy(src.ip, &v4->ip, 4); + src.port = localPort; + sizedptr pay{ (uintptr_t)buf, (uint32_t)len }; + const ipv4_tx_opts_t* txp = nullptr; + udp_send_segment(&src, &d, pay, txp); + remoteEP = d; + return (int64_t)len; + } else if (bound_l3_count == 1) { + chosen_l3 = bound_l3[0]; + l3_ipv4_interface_t* v4 = l3_ipv4_find_by_id(chosen_l3); + if (!v4 || !v4->l2) return SOCK_ERR_SYS; + net_l4_endpoint src; + src.ver = IP_VER4; + memset(src.ip, 0, 16); + memcpy(src.ip, &v4->ip, 4); + src.port = localPort; + sizedptr pay{ (uintptr_t)buf, (uint32_t)len }; + const ipv4_tx_opts_t* txp = nullptr; + udp_send_segment(&src, &d, pay, txp); + remoteEP = d; + return (int64_t)len; + } else { + if (!ipv4_rt_pick_best_l3_in(bound_l3, bound_l3_count, dip, &chosen_l3)) return SOCK_ERR_SYS; + l3_ipv4_interface_t* v4 = l3_ipv4_find_by_id(chosen_l3); + if (!v4 || !v4->l2) return SOCK_ERR_SYS; + bool present = false; + for (int i = 0; i < bound_l3_count; ++i) if (bound_l3[i] == chosen_l3) { present = true; break; } + if (!present) { + if (!udp_bind_l3(chosen_l3, localPort, pid, dispatch)) return SOCK_ERR_SYS; + add_bound_l3(chosen_l3); + } + net_l4_endpoint src; + src.ver = IP_VER4; + memset(src.ip, 0, 16); + memcpy(src.ip, &v4->ip, 4); + src.port = localPort; + sizedptr pay{ (uintptr_t)buf, (uint32_t)len }; + ipv4_tx_opts_t tx; tx.scope = IPV4_TX_BOUND_L3; tx.index = chosen_l3; + udp_send_segment(&src, &d, pay, &tx); + remoteEP = d; + return (int64_t)len; + } + } + } else if (d.ver == IP_VER6) { + return SOCK_ERR_PROTO; + } else { + return SOCK_ERR_INVAL; + } + } + int64_t recvfrom(void* buf, uint64_t len, net_l4_endpoint* src) { + if (r_head == r_tail) return 0; + sizedptr p = ring[r_head]; + net_l4_endpoint se = src_eps[r_head]; + r_head = (r_head + 1) % UDP_RING_CAP; + uint32_t tocpy = p.size < len ? p.size : (uint32_t)len; + memcpy(buf, (void*)p.ptr, tocpy); + if (src) *src = se; free((void*)p.ptr, p.size); + remoteEP = se; return tocpy; } int32_t close() override { - while (r_head != r_tail) { - free((void*)ring[r_head].ptr, - ring[r_head].size); - r_head = (r_head + 1) % UDP_RING_CAP; + while (r_head != r_tail) { + free((void*)ring[r_head].ptr, ring[r_head].size); + r_head = (r_head + 1) % UDP_RING_CAP; + } + return Socket::close(); } - udp_unbind(localPort, pid); - s_by_port[localPort] = nullptr; - bound = connected = false; - return Socket::close(); -} -}; -UDPSocket* UDPSocket::s_by_port[MAX_PORTS] = { nullptr }; + net_l4_endpoint get_remote_ep() const { + return remoteEP; + } +}; diff --git a/shared/net/transport_layer/tcp.c b/shared/net/transport_layer/tcp.c index ab64737e..b7b52d12 100644 --- a/shared/net/transport_layer/tcp.c +++ b/shared/net/transport_layer/tcp.c @@ -4,56 +4,30 @@ #include "net/internet_layer/ipv4.h" #include "std/memory.h" #include "math/rng.h" -//TODO: add mtu check and fragmentation. also fragment rebuild -extern uintptr_t malloc(uint64_t size); -extern void free(void *ptr, uint64_t size); -extern void sleep(uint64_t ms); +#include "syscalls/syscalls.h" static tcp_flow_t tcp_flows[MAX_TCP_FLOWS]; -static inline uint16_t htons(uint16_t x) { - return (uint16_t)((x << 8) | (x >> 8)); -} -static inline uint16_t ntohs(uint16_t x) { - return htons(x); -} -static inline uint32_t htonl(uint32_t x) { - return ((x & 0x000000FFU) << 24) | - ((x & 0x0000FF00U) << 8) | - ((x & 0x00FF0000U) >> 8) | - ((x & 0xFF000000U) >> 24); -} -static inline uint32_t ntohl(uint32_t x) { - return htonl(x); -} -tcp_data* tcp_get_ctx(uint16_t local_port, - uint32_t remote_ip, - uint16_t remote_port) -{ - int idx = find_flow(local_port, remote_ip, remote_port); - if (idx < 0) - return NULL; - return &tcp_flows[idx].ctx; +static inline int ip_len(ip_version_t ver){ return ver==IP_VER6 ? 16 : 4; } +static inline uint32_t v4_u32_from_ptr(const void *p){ return *(const uint32_t*)p; } + +tcp_data* tcp_get_ctx(uint16_t local_port, ip_version_t ver, const void *remote_ip, uint16_t remote_port){ + int idx = find_flow(local_port, ver, remote_ip, remote_port); + return (idx < 0) ? NULL : &tcp_flows[idx].ctx; } -static uint32_t checksum_add(uint32_t sum, uint16_t val) { + +static uint32_t checksum_add(uint32_t sum, uint16_t val){ sum += val; - if (sum > 0xFFFF) { - sum = (sum & 0xFFFF) + 1; - } + if (sum > 0xFFFF) sum = (sum & 0xFFFF) + 1; return sum; } -uint16_t tcp_compute_checksum(const void *segment, - uint16_t seg_len, - uint32_t src_ip, - uint32_t dst_ip) -{ - const uint8_t *seg = (const uint8_t *)segment; + +static uint16_t tcp_compute_checksum_v4(const void *segment, uint16_t seg_len, uint32_t src_ip, uint32_t dst_ip){ + const uint8_t *seg = (const uint8_t*)segment; const uint64_t total_len = 12 + seg_len; uintptr_t raw = malloc(total_len); - if (!raw) { - return 0; - } + if (!raw) return 0; uint8_t *buf = (uint8_t *)raw; buf[0] = (src_ip >> 24) & 0xFF; @@ -77,31 +51,33 @@ uint16_t tcp_compute_checksum(const void *segment, uint16_t word = (uint16_t)buf[i] << 8 | buf[i + 1]; sum = checksum_add(sum, word); } - if (total_len & 1) { uint16_t word = (uint16_t)buf[total_len - 1] << 8; sum = checksum_add(sum, word); } + uint16_t res = (uint16_t)(~sum & 0xFFFF); free((void *)raw, total_len); + return bswap16(res); +} - return htons((uint16_t)(~sum & 0xFFFF)); +static uint16_t tcp_compute_checksum_v6(const void*, uint16_t, const uint8_t[16], const uint8_t[16]) { + //TODO IPV6 + return 0; } -int find_flow(uint16_t local_port, uint32_t remote_ip, uint16_t remote_port) { +int find_flow(uint16_t local_port, ip_version_t ver, const void *remote_ip, uint16_t remote_port) { for (int i = 0; i < MAX_TCP_FLOWS; ++i) { tcp_flow_t *f = &tcp_flows[i]; - if (f->state != TCP_STATE_CLOSED) { - if (f->local_port == local_port) { - if (f->state == TCP_LISTEN) { - if (remote_ip == 0 && remote_port == 0) { - return i; - } - } - if (f->remote.ip == remote_ip && f->remote.port == remote_port) { - return i; - } - } + if (f->state == TCP_STATE_CLOSED) continue; + if (f->local_port != local_port) continue; + + if (f->state == TCP_LISTEN){ + if (!remote_ip && remote_port == 0) return i; + continue; + } + if (f->remote.ver == ver && f->remote.port == remote_port && remote_ip) { + if (memcmp(f->remote.ip, remote_ip, (uint64_t)ip_len(ver)) == 0) return i; } } return -1; @@ -110,7 +86,6 @@ int find_flow(uint16_t local_port, uint32_t remote_ip, uint16_t remote_port) { static int allocate_flow_entry() { for (int i = 0; i < MAX_TCP_FLOWS; ++i) { if (tcp_flows[i].state == TCP_STATE_CLOSED) { - tcp_flows[i].state = TCP_STATE_CLOSED; tcp_flows[i].retries = 0; return i; } @@ -119,123 +94,188 @@ static int allocate_flow_entry() { } static void free_flow_entry(int idx) { - if (idx >= 0 && idx < MAX_TCP_FLOWS) { - tcp_flows[idx].state = TCP_STATE_CLOSED; - tcp_flows[idx].local_port = 0; - tcp_flows[idx].remote.ip = 0; - tcp_flows[idx].remote.port = 0; - tcp_flows[idx].ctx.sequence = 0; - tcp_flows[idx].ctx.ack = 0; - tcp_flows[idx].ctx.flags = 0; - tcp_flows[idx].ctx.window = 0; - tcp_flows[idx].ctx.options.ptr = 0; - tcp_flows[idx].ctx.options.size = 0; - tcp_flows[idx].ctx.payload.ptr = 0; - tcp_flows[idx].ctx.payload.size = 0; - tcp_flows[idx].ctx.expected_ack = 0; - tcp_flows[idx].ctx.ack_received = 0; - tcp_flows[idx].retries = 0; + if (idx < 0 || idx >= MAX_TCP_FLOWS) return; + tcp_flow_t *f = &tcp_flows[idx]; + + f->state = TCP_STATE_CLOSED; + f->local_port = 0; + + f->local.ver = 0; + memset(f->local.ip, 0, 16); + f->local.port = 0; + f->remote.ver = 0; + memset(f->remote.ip, 0, 16); + f->remote.port = 0; + + f->ctx.sequence = 0; + f->ctx.ack = 0; + f->ctx.flags = 0; + f->ctx.window = 0; + f->ctx.options.ptr = 0; + f->ctx.options.size = 0; + f->ctx.payload.ptr = 0; + f->ctx.payload.size = 0; + f->ctx.expected_ack = 0; + f->ctx.ack_received = 0; + f->retries = 0; +} + +static inline port_manager_t* pm_for_l3(uint8_t l3_id){ + if (l3_ipv4_find_by_id(l3_id)) return ifmgr_pm_v4(l3_id); + if (l3_ipv6_find_by_id(l3_id)) return ifmgr_pm_v6(l3_id); + return NULL; +} + +static bool build_tx_opts_from_local_v4(const void* src_ip_addr, ipv4_tx_opts_t* out){ + if (!out) return false; + uint32_t lip = v4_u32_from_ptr(src_ip_addr); + l3_ipv4_interface_t* v4 = l3_ipv4_find_by_ip(lip); + if (v4){ + out->scope = IPV4_TX_BOUND_L3; + out->index = v4->l3_id; + } else { + out->scope = IPV4_TX_AUTO; + out->index = 0; } + return true; } -static bool send_tcp_segment(uint32_t src_ip, uint32_t dst_ip, tcp_hdr_t *hdr, const uint8_t *payload, uint16_t payload_len) { +static bool build_tx_opts_from_l3(uint8_t l3_id, ipv4_tx_opts_t* out){ + if (!out) return false; + out->scope = IPV4_TX_BOUND_L3; + out->index = l3_id; + return true; +} + +static bool send_tcp_segment(ip_version_t ver, const void *src_ip_addr, const void *dst_ip_addr, tcp_hdr_t *hdr, const uint8_t *payload, uint16_t payload_len, const ipv4_tx_opts_t* txp){ uint8_t header_words = sizeof(tcp_hdr_t) / 4; - hdr->data_offset_reserved = (header_words << 4) | 0x0; - hdr->window = htons(hdr->window); - uint16_t tcp_len = sizeof(tcp_hdr_t) + payload_len; + hdr->data_offset_reserved = (uint8_t)((header_words << 4) | 0x0); + hdr->window = bswap16(hdr->window); + + uint16_t tcp_len = (uint16_t)(sizeof(tcp_hdr_t) + payload_len); uint8_t *segment = (uint8_t*) malloc(tcp_len); - if (!segment) { - return false; - } + if (!segment) return false; + memcpy(segment, hdr, sizeof(tcp_hdr_t)); - if (payload_len > 0) { - memcpy(segment + sizeof(tcp_hdr_t), payload, payload_len); - } - tcp_hdr_t *hdr_on_buf = (tcp_hdr_t*) segment; + if (payload_len) memcpy(segment + sizeof(tcp_hdr_t), payload, payload_len); + tcp_hdr_t *hdr_on_buf = (tcp_hdr_t*)segment; hdr_on_buf->checksum = 0; - uint16_t csum = tcp_compute_checksum(segment, tcp_len, src_ip, dst_ip); - hdr_on_buf->checksum = csum; - ipv4_send_packet(dst_ip, 6, (sizedptr){ .ptr = (uintptr_t)segment, .size = tcp_len }, NULL); + + if (ver == IP_VER4){ + uint32_t s = v4_u32_from_ptr(src_ip_addr); + uint32_t d = v4_u32_from_ptr(dst_ip_addr); + hdr_on_buf->checksum = tcp_compute_checksum_v4(segment, tcp_len, s, d); + ipv4_send_packet(d, 6, (sizedptr){ (uintptr_t)segment, tcp_len }, txp); + } else { + free(segment, tcp_len); + return false; + } + free(segment, tcp_len); return true; } -static void send_reset(uint32_t src_ip, uint32_t dst_ip, - uint16_t src_port, uint16_t dst_port, - uint32_t seq, uint32_t ack, bool ack_valid) { +static void send_reset(ip_version_t ver, const void *src_ip_addr, const void *dst_ip_addr, + uint16_t src_port, uint16_t dst_port, uint32_t seq, uint32_t ack, bool ack_valid) { tcp_hdr_t rst_hdr; - rst_hdr.src_port = htons(src_port); - rst_hdr.dst_port = htons(dst_port); - if (ack_valid) { - rst_hdr.sequence = htonl(0); - rst_hdr.ack = htonl(seq + 1); + rst_hdr.src_port = bswap16(src_port); + rst_hdr.dst_port = bswap16(dst_port); + if (ack_valid){ + rst_hdr.sequence = bswap32(0); + rst_hdr.ack = bswap32(seq + 1); rst_hdr.flags = (1 << RST_F) | (1 << ACK_F); } else { - rst_hdr.sequence = htonl(ack); - rst_hdr.ack = htonl(0); + rst_hdr.sequence = bswap32(ack); + rst_hdr.ack = bswap32(0); rst_hdr.flags = (1 << RST_F); } rst_hdr.window = 0; rst_hdr.urgent_ptr = 0; - - send_tcp_segment(src_ip, dst_ip, &rst_hdr, NULL, 0); + ipv4_tx_opts_t tx; build_tx_opts_from_local_v4(src_ip_addr, &tx); + send_tcp_segment(ver, src_ip_addr, dst_ip_addr, &rst_hdr, NULL, 0, (ver==IP_VER4? &tx : NULL)); } -bool tcp_bind(uint16_t port, uint16_t pid, port_recv_handler_t handler) { - if (!port_bind_manual(PROTO_TCP, port, pid, handler)) { - return false; - } +bool tcp_bind_l3(uint8_t l3_id, uint16_t port, uint16_t pid, port_recv_handler_t handler) { + port_manager_t* pm = pm_for_l3(l3_id); + if (!pm) return false; + if (!port_bind_manual(pm, PROTO_TCP, port, pid, handler)) return false; int idx = allocate_flow_entry(); - if (idx >= 0) { - tcp_flows[idx].local_port = port; - tcp_flows[idx].remote.ip = 0; - tcp_flows[idx].remote.port = 0; - tcp_flows[idx].state = TCP_LISTEN; - tcp_flows[idx].ctx.sequence = 0; - tcp_flows[idx].ctx.ack = 0; - tcp_flows[idx].ctx.flags = 0; - tcp_flows[idx].ctx.window = 0xFFFF; - tcp_flows[idx].ctx.options.ptr = 0; - tcp_flows[idx].ctx.options.size = 0; - tcp_flows[idx].ctx.payload.ptr = 0; - tcp_flows[idx].ctx.payload.size = 0; - tcp_flows[idx].ctx.expected_ack = 0; - tcp_flows[idx].ctx.ack_received = 0; - tcp_flows[idx].retries = 0; + if (idx >= 0){ + tcp_flow_t *f = &tcp_flows[idx]; + f->local_port = port; + + f->local.ver = 0; + memset(f->local.ip, 0, 16); + f->local.port = 0; + f->remote.ver = 0; + memset(f->remote.ip, 0, 16); + f->remote.port = 0; + f->state = TCP_LISTEN; + f->ctx.sequence = 0; + f->ctx.ack = 0; + f->ctx.flags = 0; + f->ctx.window = 0xFFFF; + f->ctx.options.ptr = 0; + f->ctx.options.size = 0; + f->ctx.payload.ptr = 0; + f->ctx.payload.size = 0; + f->ctx.expected_ack = 0; + f->ctx.ack_received = 0; + f->retries = 0; } return true; } -int tcp_alloc_ephemeral(uint16_t pid, port_recv_handler_t handler) { - int port = port_alloc_ephemeral(PROTO_TCP, pid, handler); - return port; +int tcp_alloc_ephemeral_l3(uint8_t l3_id, uint16_t pid, port_recv_handler_t handler) { + port_manager_t* pm = pm_for_l3(l3_id); + if (!pm) return -1; + return port_alloc_ephemeral(pm, PROTO_TCP, pid, handler); } -bool tcp_unbind(uint16_t port, uint16_t pid) { - bool res = port_unbind(PROTO_TCP, port, pid); +bool tcp_unbind_l3(uint8_t l3_id, uint16_t port, uint16_t pid) { + port_manager_t* pm = pm_for_l3(l3_id); + if (!pm) return false; + + bool res = port_unbind(pm, PROTO_TCP, port, pid); if (res) { for (int i = 0; i < MAX_TCP_FLOWS; ++i) { if (tcp_flows[i].local_port == port) { - free_flow_entry(i); + if (tcp_flows[i].state == TCP_LISTEN) free_flow_entry(i); } } } return res; } -bool tcp_handshake(uint16_t local_port, net_l4_endpoint *dst, tcp_data *flow_ctx, uint16_t pid) { +bool tcp_handshake_l3(uint8_t l3_id, uint16_t local_port, net_l4_endpoint *dst, tcp_data *flow_ctx, uint16_t pid) { int idx = allocate_flow_entry(); - if (idx < 0) { - return false; - } + if (idx < 0) return false; + tcp_flow_t *flow = &tcp_flows[idx]; flow->local_port = local_port; - flow->remote.ip = dst->ip; + + flow->remote.ver = dst->ver; + memcpy(flow->remote.ip, dst->ip, (uint64_t)ip_len(dst->ver)); flow->remote.port = dst->port; + + if (dst->ver == IP_VER4){ + l3_ipv4_interface_t *v4 = l3_ipv4_find_by_id(l3_id); + if (!v4 || !v4->ip) { free_flow_entry(idx); return false; } + flow->local.ver = IP_VER4; + memset(flow->local.ip, 0, 16); + memcpy(flow->local.ip, &v4->ip, 4); + flow->local.port = local_port; + } else { + memset(flow->local.ip, 0, 16); + flow->local.ver = IP_VER6; + flow->local.port = local_port; + } + flow->state = TCP_SYN_SENT; flow->retries = TCP_SYN_RETRIES; - uint32_t iss = 1; + + const uint32_t iss = 1; flow->ctx.sequence = iss; flow->ctx.ack = 0; flow->ctx.window = 0xFFFF; @@ -243,84 +283,83 @@ bool tcp_handshake(uint16_t local_port, net_l4_endpoint *dst, tcp_data *flow_ctx flow->ctx.options.size = 0; flow->ctx.payload.ptr = 0; flow->ctx.payload.size = 0; - flow->ctx.flags = (1 << SYN_F); + flow->ctx.flags = (uint8_t)(1 << SYN_F); flow->ctx.expected_ack = iss + 1; flow->ctx.ack_received = 0; + tcp_hdr_t syn_hdr; - syn_hdr.src_port = htons(local_port); - syn_hdr.dst_port = htons(dst->port); - syn_hdr.sequence = htonl(flow->ctx.sequence); - syn_hdr.ack = htonl(0); - syn_hdr.flags = (1 << SYN_F); + syn_hdr.src_port = bswap16(local_port); + syn_hdr.dst_port = bswap16(dst->port); + syn_hdr.sequence = bswap32(flow->ctx.sequence); + syn_hdr.ack = bswap32(0); + syn_hdr.flags = (uint8_t)(1<ctx.window; syn_hdr.urgent_ptr = 0; - uint32_t src_ip = ipv4_get_cfg()->ip; + bool sent = false; - while (flow->retries-- > 0) { - sent = send_tcp_segment(src_ip, dst->ip, &syn_hdr, NULL, 0); - if (!sent) { - break; - } - uint64_t wait_ms = TCP_RETRY_TIMEOUT_MS; - uint64_t elapsed = 0; - const uint64_t interval = 50; - while (elapsed < wait_ms) { - if (flow->state == TCP_ESTABLISHED) { - *flow_ctx = flow->ctx; - return true; + if (dst->ver == IP_VER4) { + ipv4_tx_opts_t tx; build_tx_opts_from_l3(l3_id, &tx); + while (flow->retries-- > 0) { + sent = send_tcp_segment(IP_VER4, flow->local.ip, flow->remote.ip, &syn_hdr, NULL, 0, &tx); + if (!sent) { + break; } - if (flow->state == TCP_STATE_CLOSED) { - free_flow_entry(idx); - return false; + uint64_t wait_ms = TCP_RETRY_TIMEOUT_MS, elapsed = 0; + const uint64_t interval = 50; + while (elapsed < wait_ms) { + if (flow->state == TCP_ESTABLISHED) { + *flow_ctx = flow->ctx; + return true; + } + if (flow->state == TCP_STATE_CLOSED) { + free_flow_entry(idx); + return false; + } + sleep(interval); + elapsed += interval; } - sleep(interval); - elapsed += interval; } + } else { + //TODO IPV6 } + free_flow_entry(idx); return false; } tcp_result_t tcp_flow_send(tcp_data *flow_ctx) { - if (!flow_ctx) { - return TCP_INVALID; - } + if (!flow_ctx) return TCP_INVALID; + tcp_flow_t *flow = NULL; for (int i = 0; i < MAX_TCP_FLOWS; ++i) { - if (&tcp_flows[i].ctx == flow_ctx) { - flow = &tcp_flows[i]; - break; - } - } - if (!flow) { - return TCP_INVALID; + if (&tcp_flows[i].ctx == flow_ctx) { flow = &tcp_flows[i]; break; } } - - uint8_t flags = flow_ctx->flags; + if (!flow) return TCP_INVALID; + + const uint8_t flags = flow_ctx->flags; uint8_t *payload_ptr = (uint8_t*) flow_ctx->payload.ptr; uint16_t payload_len = flow_ctx->payload.size; if (flow->state != TCP_ESTABLISHED && !(flags & (1<state == TCP_CLOSE_WAIT && (flags & (1<state == TCP_CLOSE_WAIT && (flags & (1<local_port); - hdr.dst_port = htons(flow->remote.port); - hdr.sequence = htonl(flow_ctx->sequence); - hdr.ack = htonl(flow_ctx->ack); + hdr.src_port = bswap16(flow->local_port); + hdr.dst_port = bswap16(flow->remote.port); + hdr.sequence = bswap32(flow_ctx->sequence); + hdr.ack = bswap32(flow_ctx->ack); hdr.flags = flags; hdr.window = flow_ctx->window ? flow_ctx->window : 0xFFFF; hdr.urgent_ptr = 0; - uint32_t src_ip = ipv4_get_cfg()->ip; - uint32_t dst_ip = flow->remote.ip; - - bool sent = send_tcp_segment(src_ip, dst_ip, &hdr, payload_ptr, payload_len); - if (!sent) { - return TCP_RESET; + bool sent = false; + if (flow->remote.ver == IP_VER4) { + ipv4_tx_opts_t tx; build_tx_opts_from_local_v4(flow->local.ip, &tx); + sent = send_tcp_segment(IP_VER4, flow->local.ip, flow->remote.ip, &hdr, payload_ptr, payload_len, &tx); + } else { + sent = false; //TODO IPV6 } + if (!sent) return TCP_RESET; uint32_t seq_incr = payload_len; if (flags & (1<ack_received >= flow_ctx->expected_ack) { - break; - } - if (flow->state == TCP_STATE_CLOSED) { - return TCP_RESET; - } + if (flow_ctx->ack_received >= flow_ctx->expected_ack) break; + if (flow->state == TCP_STATE_CLOSED) return TCP_RESET; sleep(interval); elapsed += interval; } - if (flow_ctx->ack_received >= flow_ctx->expected_ack) { - break; - } - - if (flow->state >= TCP_CLOSING || flow->state == TCP_STATE_CLOSED) { - break; - } + if (flow_ctx->ack_received >= flow_ctx->expected_ack) break; + if (flow->state >= TCP_CLOSING || flow->state == TCP_STATE_CLOSED) break; flow_ctx->sequence -= seq_incr; - send_tcp_segment(src_ip, dst_ip, &hdr, payload_ptr, payload_len); + if (flow->remote.ver == IP_VER4) { + ipv4_tx_opts_t tx; build_tx_opts_from_local_v4(flow->local.ip, &tx); + send_tcp_segment(IP_VER4, flow->local.ip, flow->remote.ip, &hdr, payload_ptr, payload_len, &tx); + } flow_ctx->sequence += seq_incr; } if (flow_ctx->ack_received < flow_ctx->expected_ack) { @@ -374,17 +407,19 @@ tcp_result_t tcp_flow_close(tcp_data *flow_ctx) { if (!flow) return TCP_INVALID; if (flow->state == TCP_ESTABLISHED || flow->state == TCP_CLOSE_WAIT) { + flow_ctx->sequence = flow->ctx.sequence; + flow_ctx->ack = flow->ctx.ack; + flow_ctx->window = flow->ctx.window ? flow->ctx.window : 0xFFFF; flow_ctx->payload.ptr = 0; flow_ctx->payload.size = 0; - flow_ctx->flags = (1u << FIN_F) | (1u << ACK_F); + flow_ctx->flags = (uint8_t)((1u << FIN_F) | (1u << ACK_F)); tcp_result_t res = tcp_flow_send(flow_ctx); if (res != TCP_OK) return res; - if (flow->state == TCP_ESTABLISHED) { - flow->state = TCP_FIN_WAIT_1; - } else { flow->state = TCP_LAST_ACK; } + if (flow->state == TCP_ESTABLISHED) flow->state = TCP_FIN_WAIT_1; + else flow->state = TCP_LAST_ACK; const uint64_t max_wait = 2000; const uint64_t interval = 100; @@ -399,39 +434,45 @@ tcp_result_t tcp_flow_close(tcp_data *flow_ctx) { free_flow_entry(idx); return TCP_OK; } - return TCP_INVALID; } +void tcp_input(ip_version_t ipver, const void *src_ip_addr, const void *dst_ip_addr, uint8_t l3_id, uintptr_t ptr, uint32_t len) { + if (len < sizeof(tcp_hdr_t)) return; -void tcp_input(uintptr_t ptr, uint32_t len, uint32_t src_ip, uint32_t dst_ip) { - if (len < sizeof(tcp_hdr_t)) { - return; - } tcp_hdr_t *hdr = (tcp_hdr_t*) ptr; - uint16_t recv_checksum = hdr->checksum; - hdr->checksum = 0; - uint16_t calc_checksum = tcp_compute_checksum((uint8_t*)hdr, (uint16_t)len, src_ip, dst_ip); - hdr->checksum = recv_checksum; - if (recv_checksum != calc_checksum) return; + if (ipver == IP_VER4){ + uint16_t recv_checksum = hdr->checksum; + hdr->checksum = 0; + uint16_t calc = tcp_compute_checksum_v4((uint8_t*)hdr, (uint16_t)len, v4_u32_from_ptr(src_ip_addr), v4_u32_from_ptr(dst_ip_addr)); + hdr->checksum = recv_checksum; + if (recv_checksum != calc) return; + } else { + //TODO IPV6 + } - uint16_t src_port = ntohs(hdr->src_port); - uint16_t dst_port = ntohs(hdr->dst_port); - uint32_t seq = ntohl(hdr->sequence); - uint32_t ack = ntohl(hdr->ack); + uint16_t src_port = bswap16(hdr->src_port); + uint16_t dst_port = bswap16(hdr->dst_port); + uint32_t seq = bswap32(hdr->sequence); + uint32_t ack = bswap32(hdr->ack); uint8_t flags = hdr->flags; - uint16_t window = ntohs(hdr->window); - int idx = find_flow(dst_port, src_ip, src_port); + uint16_t window = bswap16(hdr->window); + + int idx = find_flow(dst_port, ipver, src_ip_addr, src_port); tcp_flow_t *flow = (idx >= 0 ? &tcp_flows[idx] : NULL); - if (flow) { - flow->ctx.window = window; - } + if (flow) flow->ctx.window = window; + + l3_ipv4_interface_t *v4 = l3_ipv4_find_by_id(l3_id); + l3_ipv6_interface_t *v6 = v4 ? NULL : l3_ipv6_find_by_id(l3_id); + port_manager_t *pm = v4 ? ifmgr_pm_v4(l3_id) : (v6 ? ifmgr_pm_v6(l3_id) : NULL); + if (!pm) return; + + uint8_t ifx = v4 ? (v4->l2 ? v4->l2->ifindex : 0) : (v6 && v6->l2 ? v6->l2->ifindex : 0); if (!flow) { - int listen_idx = find_flow(dst_port, 0, 0); + int listen_idx = find_flow(dst_port, IP_VER4, NULL, 0); if ((flags & (1u<= 0) { - // TODO syscall for rng rng_t rng; rng_init_random(&rng); @@ -441,8 +482,17 @@ void tcp_input(uintptr_t ptr, uint32_t len, uint32_t src_ip, uint32_t dst_ip) { flow = &tcp_flows[new_idx]; flow->local_port = dst_port; - flow->remote.ip = src_ip; + + flow->remote.ver = ipver; + memset(flow->remote.ip, 0, 16); + memcpy(flow->remote.ip, src_ip_addr, (uint64_t)ip_len(ipver)); flow->remote.port = src_port; + + flow->local.ver = ipver; + memset(flow->local.ip, 0, 16); + if (ipver == IP_VER4 && v4) memcpy(flow->local.ip, &v4->ip, 4); + flow->local.port = dst_port; + flow->state = TCP_SYN_RECEIVED; flow->retries = TCP_SYN_RETRIES; @@ -459,22 +509,25 @@ void tcp_input(uintptr_t ptr, uint32_t len, uint32_t src_ip, uint32_t dst_ip) { flow->ctx.ack_received = 0; tcp_hdr_t synack_hdr; - synack_hdr.src_port = htons(dst_port); - synack_hdr.dst_port = htons(src_port); - synack_hdr.sequence = htonl(iss); - synack_hdr.ack = htonl(seq + 1); - synack_hdr.flags = (uint8_t)((1u<ctx.window); + synack_hdr.src_port = bswap16(dst_port); + synack_hdr.dst_port = bswap16(src_port); + synack_hdr.sequence = bswap32(iss); + synack_hdr.ack = bswap32(seq + 1); + synack_hdr.flags = (uint8_t)((1u<ctx.window; synack_hdr.urgent_ptr = 0; - uint32_t src_ip_local = ipv4_get_cfg()->ip; - send_tcp_segment(src_ip_local, src_ip, &synack_hdr, NULL, 0); + + if (ipver == IP_VER4 && v4) { + ipv4_tx_opts_t tx; build_tx_opts_from_l3(l3_id, &tx); + send_tcp_segment(IP_VER4, flow->local.ip, src_ip_addr, &synack_hdr, NULL, 0, &tx); + } return; } else { if (!(flags & (1u<ctx.expected_ack) { - flow->ctx.ack = seq + 1; flow->ctx.ack_received = ack; flow->ctx.sequence += 1; tcp_hdr_t final_ack; - final_ack.src_port = htons(flow->local_port); - final_ack.dst_port = htons(flow->remote.port); - final_ack.sequence = htonl(flow->ctx.sequence + 1); - final_ack.ack = htonl(flow->ctx.ack); + final_ack.src_port = bswap16(flow->local_port); + final_ack.dst_port = bswap16(flow->remote.port); + final_ack.sequence = bswap32(flow->ctx.sequence); + final_ack.ack = bswap32(flow->ctx.ack); final_ack.flags = (1<ctx.window; final_ack.urgent_ptr = 0; - uint32_t src_ip_local = ipv4_get_cfg()->ip; - send_tcp_segment(src_ip_local, flow->remote.ip, &final_ack, NULL, 0); + if (flow->remote.ver == IP_VER4){ + ipv4_tx_opts_t tx; build_tx_opts_from_local_v4(flow->local.ip, &tx); + (void)send_tcp_segment(IP_VER4, flow->local.ip, flow->remote.ip, &final_ack, NULL, 0, &tx); + } flow->state = TCP_ESTABLISHED; } } else if (flags & (1<ctx.sequence += 1; flow->state = TCP_ESTABLISHED; flow->ctx.ack_received = ack; - port_recv_handler_t h = port_get_handler(PROTO_TCP, dst_port); - if (h) { - h(0, 0, src_ip, src_port, dst_port); + + if (pm){ + port_recv_handler_t h = port_get_handler(pm, PROTO_TCP, dst_port); + if (h) h(ifx, ipver, src_ip_addr, dst_ip_addr, 0, 0, src_port, dst_port); } } - } else if (flags & (1<data_offset_reserved >> 4) * 4); - if (len < hdr_len) return; - - uint32_t data_len = len - hdr_len; - const bool is_ack_only = - ( (flags & (1u << ACK_F)) != 0 ) && - ( (flags & ((1u << SYN_F) | (1u << FIN_F) | (1u << RST_F))) == 0 ) && - ( data_len == 0 ) && - ( seq + 1u == flow->ctx.ack ); - - if (is_ack_only) { - tcp_hdr_t ack_hdr = (tcp_hdr_t){ - .src_port = htons(flow->local_port), - .dst_port = htons(flow->remote.port), - .sequence = htonl(flow->ctx.sequence), - .ack = htonl(flow->ctx.ack), - .flags = (uint8_t)(1u << ACK_F), - .window = htons(flow->ctx.window), - .urgent_ptr = 0 - }; - send_tcp_segment( - ipv4_get_cfg()->ip, - flow->remote.ip, - &ack_hdr, NULL, 0 - ); - return; - } - __attribute__((fallthrough)); - } + case TCP_ESTABLISHED: case TCP_FIN_WAIT_1: case TCP_FIN_WAIT_2: case TCP_CLOSE_WAIT: case TCP_CLOSING: case TCP_LAST_ACK: { - if (flags & (1 << RST_F)) { - free_flow_entry(idx); - return; - } - uint8_t hdr_len =(hdr->data_offset_reserved >> 4) * 4; - if (len < hdr_len) - return; - uint32_t data_len = len - hdr_len; - bool fin_set = (flags & (1 << FIN_F)) != 0; - bool fin_inseq = fin_set && (seq == flow->ctx.ack); - - if (data_len && seq == flow->ctx.ack) { - flow->ctx.ack += data_len; - port_recv_handler_t h = port_get_handler(PROTO_TCP, dst_port); - if (h) h(ptr + hdr_len, data_len, src_ip, src_port, dst_port); - } + if (flags & (1 << RST_F)) { + free_flow_entry(idx); + return; + } - if (fin_inseq) { - flow->ctx.ack += 1; - } + uint8_t hdr_len = (uint8_t)((hdr->data_offset_reserved >> 4) * 4); + if (len < hdr_len) return; + uint32_t data_len = len - hdr_len; - if ((data_len && seq == flow->ctx.ack - data_len) || fin_inseq) { - tcp_hdr_t ackhdr = { - .src_port = htons(flow->local_port), - .dst_port = htons(flow->remote.port), - .sequence = htonl(flow->ctx.sequence), - .ack = htonl(flow->ctx.ack), - .flags = (1 << ACK_F), - .window = flow->ctx.window, - .urgent_ptr = 0 - }; - send_tcp_segment(ipv4_get_cfg()->ip, - flow->remote.ip, &ackhdr, NULL, 0); - } + if ((flags & (1u << ACK_F)) && ack > flow->ctx.ack_received) { + flow->ctx.ack_received = ack; + if (flow->state == TCP_FIN_WAIT_1 && ack == flow->ctx.expected_ack){ + flow->state = TCP_FIN_WAIT_2; + } else if ((flow->state == TCP_LAST_ACK || flow->state == TCP_CLOSING) && ack == flow->ctx.expected_ack) { + free_flow_entry(idx); + return; + } + } - if ((flags & (1 << ACK_F)) && - ack > flow->ctx.ack_received) { - flow->ctx.ack_received = ack; + uint32_t rcv_next_old = flow->ctx.ack; + uint32_t rcv_next_new = rcv_next_old; - if (flow->state == TCP_FIN_WAIT_1 && - ack == flow->ctx.expected_ack) { - flow->state = TCP_FIN_WAIT_2; - } else if ((flow->state == TCP_LAST_ACK || - flow->state == TCP_CLOSING) && - ack == flow->ctx.expected_ack) { - free_flow_entry(idx); - return; + bool data_inseq = (data_len > 0) && (seq == rcv_next_old); + if (data_inseq) { + rcv_next_new += data_len; + if (pm){ + port_recv_handler_t h = port_get_handler(pm, PROTO_TCP, dst_port); + if (h) h(ifx, ipver, src_ip_addr, dst_ip_addr, ptr + hdr_len, data_len, src_port, dst_port); + } } - } - if (fin_inseq) { - if (flow->state == TCP_ESTABLISHED) - flow->state = TCP_CLOSE_WAIT; - else if (flow->state == TCP_FIN_WAIT_1) - flow->state = TCP_CLOSING; - else if (flow->state == TCP_FIN_WAIT_2) - flow->state = TCP_TIME_WAIT; - else if (flow->state == TCP_CLOSING) - flow->state = TCP_TIME_WAIT; - else if (flow->state == TCP_LAST_ACK) - flow->state = TCP_TIME_WAIT; + bool fin_set = (flags & (1<ctx.ack = rcv_next_new; + + tcp_hdr_t ackhdr = { + .src_port = bswap16(flow->local_port), + .dst_port = bswap16(flow->remote.port), + .sequence = bswap32(flow->ctx.sequence), + .ack = bswap32(flow->ctx.ack), + .flags = (uint8_t)(1<ctx.window ? flow->ctx.window : 0xFFFF, + .urgent_ptr = 0 + }; + if (flow->remote.ver == IP_VER4){ + ipv4_tx_opts_t tx; build_tx_opts_from_local_v4(flow->local.ip, &tx); + (void)send_tcp_segment(IP_VER4, flow->local.ip, flow->remote.ip, &ackhdr, NULL, 0, &tx); + } + } + + if (fin_inseq){ + tcp_state_t old = flow->state; + if (old == TCP_ESTABLISHED) flow->state = TCP_CLOSE_WAIT; + else if (old == TCP_FIN_WAIT_1) flow->state = TCP_CLOSING; + else if (old == TCP_FIN_WAIT_2) flow->state = TCP_TIME_WAIT; + else if (old == TCP_CLOSING) flow->state = TCP_TIME_WAIT; + else if (old == TCP_LAST_ACK) flow->state = TCP_TIME_WAIT; + } + return; } - return; -} + default: break; } diff --git a/shared/net/transport_layer/tcp.h b/shared/net/transport_layer/tcp.h index dcfca186..222215d7 100644 --- a/shared/net/transport_layer/tcp.h +++ b/shared/net/transport_layer/tcp.h @@ -70,8 +70,9 @@ typedef enum { typedef struct { uint16_t local_port; + net_l4_endpoint local; net_l4_endpoint remote; - tcp_state_t state; + tcp_state_t state; tcp_data ctx; uint8_t retries; } tcp_flow_t; @@ -81,36 +82,19 @@ typedef struct { #define TCP_DATA_RETRIES 5 #define TCP_RETRY_TIMEOUT_MS 1000 -int find_flow(uint16_t local_port, uint32_t remote_ip, uint16_t remote_port); +int find_flow(uint16_t local_port, ip_version_t ver, const void *remote_ip, uint16_t remote_port); +tcp_data* tcp_get_ctx(uint16_t local_port, ip_version_t ver, const void *remote_ip, uint16_t remote_port); -tcp_data* tcp_get_ctx(uint16_t local_port, - uint32_t remote_ip, - uint16_t remote_port); - -bool tcp_bind(uint16_t port, - uint16_t pid, - port_recv_handler_t handler); - -int tcp_alloc_ephemeral(uint16_t pid, - port_recv_handler_t handler); - -bool tcp_unbind(uint16_t port, - uint16_t pid); - -bool tcp_handshake(uint16_t local_port, - net_l4_endpoint *dst, - tcp_data *flow_ctx, - uint16_t pid); +bool tcp_bind_l3(uint8_t l3_id, uint16_t port, uint16_t pid, port_recv_handler_t handler); +int tcp_alloc_ephemeral_l3(uint8_t l3_id, uint16_t pid, port_recv_handler_t handler); +bool tcp_unbind_l3(uint8_t l3_id, uint16_t port, uint16_t pid); +bool tcp_handshake_l3(uint8_t l3_id, uint16_t local_port, net_l4_endpoint *dst, tcp_data *flow_ctx, uint16_t pid); tcp_result_t tcp_flow_send(tcp_data *flow_ctx); - tcp_result_t tcp_flow_close(tcp_data *flow_ctx); -void tcp_input(uintptr_t ptr, - uint32_t len, - uint32_t src_ip, - uint32_t dst_ip); +void tcp_input(ip_version_t ipver, const void *src_ip_addr, const void *dst_ip_addr, uint8_t l3_id, uintptr_t ptr, uint32_t len); #ifdef __cplusplus } -#endif +#endif \ No newline at end of file diff --git a/shared/net/transport_layer/udp.c b/shared/net/transport_layer/udp.c index 4f295c85..64f01d79 100644 --- a/shared/net/transport_layer/udp.c +++ b/shared/net/transport_layer/udp.c @@ -1,81 +1,64 @@ #include "udp.h" #include "net/checksums.h" #include "net/internet_layer/ipv4.h" -#include "networking/port_manager.h" +#include "networking/port_manager.h" #include "std/memory.h" #include "types.h" +#include "syscalls/syscalls.h" -extern void sleep(uint64_t ms); -extern uintptr_t malloc(uint64_t size); -extern void free(void *ptr, uint64_t size); - -bool udp_bind(uint16_t port, - uint16_t pid, - port_recv_handler_t handler) -{ - return port_bind_manual(PROTO_UDP, port, pid, handler); -} - -int udp_alloc_ephemeral(uint16_t pid, - port_recv_handler_t handler) -{ - return port_alloc_ephemeral(PROTO_UDP, pid, handler); +static inline uint32_t v4_u32_from_arr(const uint8_t ip16[16]) { + uint32_t v = 0; + memcpy(&v, ip16, 4); + return v; } -bool udp_unbind(uint16_t port, - uint16_t pid) -{ - return port_unbind(PROTO_UDP, port, pid); -} - - -size_t create_udp_segment(uintptr_t buf, - const net_l4_endpoint *src, - const net_l4_endpoint *dst, - sizedptr payload) -{ - udp_hdr_t *udp = (udp_hdr_t*)buf; +size_t create_udp_segment(uintptr_t buf, const net_l4_endpoint *src, const net_l4_endpoint *dst, sizedptr payload) { + udp_hdr_t *udp = (udp_hdr_t *)buf; udp->src_port = bswap16(src->port); udp->dst_port = bswap16(dst->port); - uint16_t full_len = sizeof(*udp) + payload.size; - udp->length= bswap16(full_len); + uint16_t full_len = (uint16_t)(sizeof(*udp) + payload.size); + udp->length = bswap16(full_len); udp->checksum = 0; - memcpy((void*)(buf + sizeof(*udp)), (void*)payload.ptr, payload.size); + memcpy((void *)(buf + sizeof(*udp)), (void *)payload.ptr, payload.size); + + if (src->ver == IP_VER4) { + uint32_t s = v4_u32_from_arr(src->ip); + uint32_t d = v4_u32_from_arr(dst->ip); + uint16_t csum = checksum16_pipv4(s, d, 0x11, (const uint8_t *)udp, full_len); + udp->checksum = bswap16(csum); + } else if (src->ver == IP_VER6) { + //TODO IPV6 + udp->checksum = 0; + } - uint16_t csum = checksum16_pipv4( src->ip, dst->ip, 0x11, (const uint8_t*)udp, full_len); - udp->checksum = bswap16(csum); return full_len; } -void udp_send_segment(const net_l4_endpoint *src, - const net_l4_endpoint *dst, - sizedptr payload) -{ - uint32_t udp_max = sizeof(udp_hdr_t) + payload.size; - uint32_t ip_max = sizeof(ipv4_hdr_t) + udp_max; - uint32_t eth_total = sizeof(eth_hdr_t) + ip_max; - - uintptr_t buf = (uintptr_t)malloc(eth_total); - if (!buf) return; +void udp_send_segment(const net_l4_endpoint *src, const net_l4_endpoint *dst, sizedptr payload, const ipv4_tx_opts_t* tx_opts) { + if (src->ver == IP_VER4) { + uint32_t udp_len = (uint32_t)(sizeof(udp_hdr_t) + payload.size); + uintptr_t buf = (uintptr_t)malloc(udp_len); + if (!buf) return; - uintptr_t udp_buf = buf + sizeof(eth_hdr_t) + sizeof(ipv4_hdr_t); - size_t udp_len = create_udp_segment(udp_buf, src, dst, payload); + size_t written = create_udp_segment(buf, src, dst, payload); + uint32_t dst_ip = v4_u32_from_arr(dst->ip); - ipv4_tx_opts_t o = { .index = 1, .int_type = 0 }; - ipv4_send_packet(0xFFFFFFFFu, 0x11,(sizedptr){ udp_buf, (uint32_t)udp_len }, &o); - - free((void*)buf, eth_total); + ipv4_send_packet(dst_ip, 0x11, (sizedptr){ buf, (uint32_t)written }, tx_opts); + free((void *)buf, udp_len); + } else if (src->ver == IP_VER6) { + //TODO IPV6 + } } sizedptr udp_strip_header(uintptr_t ptr, uint32_t len) { if (len < sizeof(udp_hdr_t)) { - return (sizedptr){0,0}; + return (sizedptr){ 0, 0 }; } - udp_hdr_t *hdr = (udp_hdr_t*)ptr; + udp_hdr_t *hdr = (udp_hdr_t *)ptr; uint16_t total = bswap16(hdr->length); if (total < sizeof(udp_hdr_t) || total > len) { - return (sizedptr){0,0}; + return (sizedptr){ 0, 0 }; } return (sizedptr){ .ptr = ptr + sizeof(udp_hdr_t), @@ -83,31 +66,66 @@ sizedptr udp_strip_header(uintptr_t ptr, uint32_t len) { }; } -void udp_input(uintptr_t ptr, - uint32_t len, - uint32_t src_ip, - uint32_t dst_ip) -{ +void udp_input(ip_version_t ipver, const void *src_ip_addr, const void *dst_ip_addr, uint8_t l3_id, uintptr_t ptr, uint32_t len) { sizedptr pl = udp_strip_header(ptr, len); if (!pl.ptr) return; - udp_hdr_t *hdr = (udp_hdr_t*)ptr; + udp_hdr_t *hdr = (udp_hdr_t *)ptr; + if (hdr->checksum) { - uint16_t recv = hdr->checksum; - hdr->checksum = 0; - uint16_t calc = checksum16_pipv4( - src_ip, dst_ip, 0x11, - (const uint8_t*)hdr, - pl.size + sizeof(*hdr) - ); - hdr->checksum = recv; - if (calc != bswap16(recv)) return; + if (ipver == IP_VER4) { + uint16_t recv = hdr->checksum; + hdr->checksum = 0; + uint16_t calc = checksum16_pipv4( + *(const uint32_t *)src_ip_addr, *(const uint32_t *)dst_ip_addr, 0x11, + (const uint8_t *)hdr, (uint16_t)(pl.size + sizeof(*hdr)) + ); + hdr->checksum = recv; + if (calc != bswap16(recv)) return; + } else if (ipver == IP_VER6) { + //TODO IPV& + } } uint16_t dst_port = bswap16(hdr->dst_port); uint16_t src_port = bswap16(hdr->src_port); - port_recv_handler_t handler = port_get_handler(PROTO_UDP, dst_port); + + l3_ipv4_interface_t *v4 = l3_ipv4_find_by_id(l3_id); + l3_ipv6_interface_t *v6 = v4 ? NULL : l3_ipv6_find_by_id(l3_id); + port_manager_t *pm = v4 ? ifmgr_pm_v4(l3_id) : (v6 ? ifmgr_pm_v6(l3_id) : NULL); + if (!pm) return; + + port_recv_handler_t handler = port_get_handler(pm, PROTO_UDP, dst_port); if (handler) { - handler(pl.ptr, pl.size, src_ip, src_port, dst_port); + uintptr_t copy = (uintptr_t)malloc(pl.size); + if (!copy) return; + memcpy((void*)copy, (const void*)pl.ptr, pl.size); + + uint8_t ifx = v4 ? v4->l2->ifindex : (v6 && v6->l2 ? v6->l2->ifindex : 0); + handler(ifx, ipver, src_ip_addr, dst_ip_addr, copy, pl.size, src_port, dst_port); } +} + +static inline port_manager_t* pm_for_l3(uint8_t l3_id) { + if (l3_ipv4_find_by_id(l3_id)) return ifmgr_pm_v4(l3_id); + if (l3_ipv6_find_by_id(l3_id)) return ifmgr_pm_v6(l3_id); + return NULL; +} + +bool udp_bind_l3(uint8_t l3_id, uint16_t port, uint16_t pid, port_recv_handler_t handler) { + port_manager_t* pm = pm_for_l3(l3_id); + if (!pm) return false; + return port_bind_manual(pm, PROTO_UDP, port, pid, handler); +} + +bool udp_unbind_l3(uint8_t l3_id, uint16_t port, uint16_t pid) { + port_manager_t* pm = pm_for_l3(l3_id); + if (!pm) return false; + return port_unbind(pm, PROTO_UDP, port, pid); +} + +int udp_alloc_ephemeral_l3(uint8_t l3_id, uint16_t pid, port_recv_handler_t handler) { + port_manager_t* pm = pm_for_l3(l3_id); + if (!pm) return -1; + return port_alloc_ephemeral(pm, PROTO_UDP, pid, handler); } \ No newline at end of file diff --git a/shared/net/transport_layer/udp.h b/shared/net/transport_layer/udp.h index eb5da1d7..5132ed61 100644 --- a/shared/net/transport_layer/udp.h +++ b/shared/net/transport_layer/udp.h @@ -2,6 +2,7 @@ #include "types.h" #include "net/network_types.h" #include "networking/port_manager.h" +#include "net/internet_layer/ipv4.h" #ifdef __cplusplus extern "C" { @@ -19,25 +20,19 @@ size_t create_udp_segment(uintptr_t buf, const net_l4_endpoint *dst, sizedptr payload); +void udp_send_segment(const net_l4_endpoint *src, const net_l4_endpoint *dst, sizedptr payload, const ipv4_tx_opts_t* tx_opts); -void udp_send_segment(const net_l4_endpoint *src, - const net_l4_endpoint *dst, - sizedptr payload); +void udp_input(ip_version_t ipver, + const void *src_ip_addr, + const void *dst_ip_addr, + uint8_t l3_id, + uintptr_t ptr, + uint32_t len); -void udp_input(uintptr_t ptr, - uint32_t len, - uint32_t src_ip, - uint32_t dst_ip); - -bool udp_bind(uint16_t port, - uint16_t pid, - port_recv_handler_t handler); - -int udp_alloc_ephemeral(uint16_t pid, port_recv_handler_t handler); - -bool udp_unbind(uint16_t port, - uint16_t pid); +bool udp_bind_l3(uint8_t l3_id, uint16_t port, uint16_t pid, port_recv_handler_t handler); +bool udp_unbind_l3(uint8_t l3_id, uint16_t port, uint16_t pid); +int udp_alloc_ephemeral_l3(uint8_t l3_id, uint16_t pid, port_recv_handler_t handler); #ifdef __cplusplus } -#endif +#endif \ No newline at end of file diff --git a/shared/std/memory.c b/shared/std/memory.c index b84378a3..7361da29 100644 --- a/shared/std/memory.c +++ b/shared/std/memory.c @@ -11,31 +11,46 @@ int memcmp(const void *s1, const void *s2, unsigned long count) { void* memset(void* dest, uint32_t val, size_t count) { uint8_t *d8 = (uint8_t *)dest; - uint64_t pattern = ((uint64_t)val << 32) | val; + uint8_t byte = (uint8_t)(val & 0xFF); - while (((uintptr_t)d8 & 7) % 8 != 0 && count > 0) { - *d8++ = (uint8_t)(val & 0xFF); + while (((uintptr_t)d8 & 7) && count > 0) { + *d8++ = byte; count--; } - size_t blocks = count / 8; - for (size_t i = 0; i < blocks; i++) { - *((uint64_t *)d8) = pattern; - d8 += 8; + if (count >= 8) { + uint64_t pattern = 0; + for (int i = 0; i < 8; i++) { + pattern <<= 8; + pattern |= byte; + } + size_t blocks = count / 8; + for (size_t i = 0; i < blocks; i++) { + *((uint64_t *)d8) = pattern; + d8 += 8; + } + count %= 8; } - size_t remaining = count % 8; - if (remaining >= 4) { - *((uint32_t *)d8) = (uint32_t)val; + if (count >= 4) { + uint32_t pattern32 = byte; + pattern32 |= pattern32 << 8; + pattern32 |= pattern32 << 16; + *((uint32_t *)d8) = pattern32; d8 += 4; - remaining -= 4; + count -= 4; } - if (remaining >= 2) { - *((uint16_t *)d8) = ((val & 0xFF) << 8) | (val & 0xFF); - remaining -= 2; + + if (count >= 2) { + uint16_t pattern16 = (uint16_t)byte | ((uint16_t)byte << 8); + *((uint16_t *)d8) = pattern16; + d8 += 2; + count -= 2; + } + + if (count == 1) { + *d8 = byte; } - if (remaining >= 1) - *d8 = val & 0xFF; return dest; } From c0cbbef7fa22ce1ef5c71977974f4f1a9c925f8d Mon Sep 17 00:00:00 2001 From: CodeAnarchist Date: Sun, 28 Sep 2025 02:57:47 +0200 Subject: [PATCH 15/23] merge --- kernel/kernel.c | 8 ++++---- kernel/networking/network_dispatch.cpp | 1 + shared/net/application_layer/dhcp_daemon.c | 4 ++-- shared/net/transport_layer/tcp.c | 2 +- shared/std/allocator.hpp | 9 +-------- 5 files changed, 9 insertions(+), 15 deletions(-) diff --git a/kernel/kernel.c b/kernel/kernel.c index 78e53f60..c8154157 100644 --- a/kernel/kernel.c +++ b/kernel/kernel.c @@ -54,12 +54,12 @@ void kernel_main() { load_module(&disk_module); bool input_available = load_module(&input_module); - bool network_available = false; - + bool network_available = true; if (BOARD_TYPE == 1){ //TODO: disabling networking until it is refactored to prevent memory issues - network_available = false;// load_module(&net_module); - + //network_available = false; + load_module(&net_module); + load_module(&audio_module); init_audio_mixer(); diff --git a/kernel/networking/network_dispatch.cpp b/kernel/networking/network_dispatch.cpp index 130347aa..38d03c33 100644 --- a/kernel/networking/network_dispatch.cpp +++ b/kernel/networking/network_dispatch.cpp @@ -10,6 +10,7 @@ #include "console/kio.h" #include "networking/interface_manager.h" #include "syscalls/syscalls.h" +#include "process/scheduler.h" #define RX_INTR_BATCH_LIMIT 32 #define TASK_RX_BATCH_LIMIT 32 diff --git a/shared/net/application_layer/dhcp_daemon.c b/shared/net/application_layer/dhcp_daemon.c index e4642515..c62338c7 100644 --- a/shared/net/application_layer/dhcp_daemon.c +++ b/shared/net/application_layer/dhcp_daemon.c @@ -167,7 +167,7 @@ static bool udp_wait_for_type_on(socket_handle_t sock, uint8_t wanted, uint32_t uint8_t len = p->options[idx+1]; if (len < 1) { continue; } if (p->options[idx+2] != wanted) { continue; } - uintptr_t copy = malloc((uint32_t)r); + uintptr_t copy = (uintptr_t)malloc((uint32_t)r); memcpy((void*)copy, buf, (size_t)r); if (outp) *outp= (dhcp_packet*)copy; if (outsp) *outsp = (sizedptr){ copy, (uint32_t)r }; @@ -199,7 +199,7 @@ static bool udp_wait_for_ack_or_nak(socket_handle_t sock, uint32_t expect_xid, c if (idx == UINT16_MAX || p->options[idx+1] < 1) { continue; } uint8_t mtype = p->options[idx+2]; if (mtype != DHCPACK && mtype != DHCPNAK) { continue; } - uintptr_t copy = malloc((uint32_t)r); + uintptr_t copy = (uintptr_t)malloc((uint32_t)r); memcpy((void*)copy, buf, (size_t)r); if (outp) *outp = (dhcp_packet*)copy; if (outsp) *outsp = (sizedptr){ copy, (uint32_t)r }; diff --git a/shared/net/transport_layer/tcp.c b/shared/net/transport_layer/tcp.c index 30844938..e5013134 100644 --- a/shared/net/transport_layer/tcp.c +++ b/shared/net/transport_layer/tcp.c @@ -28,7 +28,7 @@ static uint16_t tcp_compute_checksum_v4(const void *segment, uint16_t seg_len, u const uint8_t *seg = (const uint8_t*)segment; const uint64_t total_len = 12 + seg_len; - uintptr_t raw = malloc(total_len); + uintptr_t raw = (uintptr_t)malloc(total_len); if (!raw) return 0; uint8_t *buf = (uint8_t *)raw; diff --git a/shared/std/allocator.hpp b/shared/std/allocator.hpp index f1c9ac54..6ec46ac1 100644 --- a/shared/std/allocator.hpp +++ b/shared/std/allocator.hpp @@ -1,5 +1,4 @@ -#pragma once - +#pragma once #include "types.h" void* operator new(size_t size); @@ -11,9 +10,3 @@ void operator delete[](void* ptr) noexcept; void operator delete(void* ptr, size_t size) noexcept; void operator delete[](void* ptr, size_t size) noexcept; - -inline void* operator new(size_t, void* p) noexcept { return p; } -inline void* operator new[](size_t, void* p) noexcept { return p; } - -inline void operator delete(void*, void*) noexcept {} -inline void operator delete[](void*, void*) noexcept {} \ No newline at end of file From 3e2e1d53c5a7a36ded81674bebee7c6c493db6da Mon Sep 17 00:00:00 2001 From: CodeAnarchist Date: Sun, 28 Sep 2025 12:46:54 +0200 Subject: [PATCH 16/23] net: fix dns bug --- shared/net/application_layer/dns.c | 20 +++++++++++++++++--- shared/net/application_layer/dns_daemon.c | 3 ++- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/shared/net/application_layer/dns.c b/shared/net/application_layer/dns.c index 0199a807..08328544 100644 --- a/shared/net/application_layer/dns.c +++ b/shared/net/application_layer/dns.c @@ -109,8 +109,15 @@ static dns_result_t perform_dns_query_once_a(socket_handle_t sock, uint32_t dns_ wr_be16(request_buffer+offset+0, 1); wr_be16(request_buffer+offset+2, 1); offset += 4; - int64_t sent = socket_sendto_udp_ex(sock, DST_ENDPOINT, &dns_ip_host, 53, request_buffer, offset); + + net_l4_endpoint dst = {0}; + dst.ver = IP_VER4; + memcpy(dst.ip, &dns_ip_host, 4); + dst.port = 53; + + int64_t sent = socket_sendto_udp_ex(sock, DST_ENDPOINT, &dst, 0, request_buffer, offset); if (sent < 0) return DNS_ERR_SEND; + uint32_t waited_ms = 0; while (waited_ms < timeout_ms){ uint8_t response_buffer[512]; @@ -141,8 +148,15 @@ static dns_result_t perform_dns_query_once_aaaa(socket_handle_t sock, uint32_t d wr_be16(request_buffer+offset+0, 28); wr_be16(request_buffer+offset+2, 1); offset += 4; - int64_t sent = socket_sendto_udp_ex(sock, DST_ENDPOINT, &dns_ip_host, 53, request_buffer, offset); + + net_l4_endpoint dst = {0}; + dst.ver = IP_VER4; + memcpy(dst.ip, &dns_ip_host, 4); + dst.port = 53; + + int64_t sent = socket_sendto_udp_ex(sock, DST_ENDPOINT, &dst, 0, request_buffer, offset); if (sent < 0) return DNS_ERR_SEND; + uint32_t waited_ms = 0; while (waited_ms < timeout_ms){ uint8_t response_buffer[512]; @@ -248,4 +262,4 @@ dns_result_t dns_resolve_aaaa_on_l3(uint8_t l3_id, const char* hostname, uint8_t uint32_t p = 0, s = 0; if (!pick_dns_on_l3(l3_id, &p, &s)) return DNS_ERR_NO_DNS; return query_with_selection_aaaa(p, s, which, hostname, timeout_ms, out_ipv6); -} +} \ No newline at end of file diff --git a/shared/net/application_layer/dns_daemon.c b/shared/net/application_layer/dns_daemon.c index be2ab822..99e84aec 100644 --- a/shared/net/application_layer/dns_daemon.c +++ b/shared/net/application_layer/dns_daemon.c @@ -1,6 +1,7 @@ #include "dns_daemon.h" #include "process/scheduler.h" #include "syscalls/syscalls.h" +#include "net/transport_layer/socket_types.h" static uint16_t g_pid_dnsd = 0xFFFF; static socket_handle_t g_sock = 0; @@ -13,7 +14,7 @@ socket_handle_t dns_socket_handle(void){ return g_sock; } int dns_deamon_entry(int argc, char* argv[]){ (void)argc; (void)argv; dns_set_pid(get_current_proc_pid()); - g_sock = udp_socket_create(0, g_pid_dnsd); + g_sock = udp_socket_create(SOCK_ROLE_CLIENT, g_pid_dnsd); for(;;){ sleep(250); } return 1; } From 1419c4bba7dfa1acffc5997fdb6c92e2f93bd415 Mon Sep 17 00:00:00 2001 From: CodeAnarchist Date: Sun, 28 Sep 2025 14:14:44 +0200 Subject: [PATCH 17/23] unused method no error --- common.mk | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/common.mk b/common.mk index 89305fe7..aecc26a4 100644 --- a/common.mk +++ b/common.mk @@ -10,7 +10,8 @@ BUILD_DIR := ./build COMMON_FLAGS ?= -ffreestanding -nostdlib -fno-exceptions -fno-unwind-tables \ -fno-asynchronous-unwind-tables -g -O0 -Wall -Wextra \ -Wno-unused-parameter -Wno-address-of-packed-member \ - -mcpu=cortex-a72 -Werror -Wno-error=sized-deallocation + -mcpu=cortex-a72 -Werror -Wno-error=sized-deallocation \ + -Wno-error=unused-method CFLAGS_BASE ?= $(COMMON_FLAGS) -std=c99 CXXFLAGS_BASE ?= $(COMMON_FLAGS) -fno-rtti From b30e123f9669a5540749035ba533322c3676732f Mon Sep 17 00:00:00 2001 From: CodeAnarchist Date: Sun, 28 Sep 2025 14:18:08 +0200 Subject: [PATCH 18/23] -Wno-unused-function --- common.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common.mk b/common.mk index aecc26a4..1a4097ef 100644 --- a/common.mk +++ b/common.mk @@ -11,7 +11,7 @@ COMMON_FLAGS ?= -ffreestanding -nostdlib -fno-exceptions -fno-unwind-tables \ -fno-asynchronous-unwind-tables -g -O0 -Wall -Wextra \ -Wno-unused-parameter -Wno-address-of-packed-member \ -mcpu=cortex-a72 -Werror -Wno-error=sized-deallocation \ - -Wno-error=unused-method + -Wno-unused-function CFLAGS_BASE ?= $(COMMON_FLAGS) -std=c99 CXXFLAGS_BASE ?= $(COMMON_FLAGS) -fno-rtti From 0bcf024f08ef81bd88fc1fd445df8931db098a47 Mon Sep 17 00:00:00 2001 From: Diego Ferrari Date: Sun, 28 Sep 2025 00:00:00 +0000 Subject: [PATCH 19/23] [MEMORY] memset32 --- shared/std/memory.c | 57 +++++++++++++++++++++++++++++++++++++++++-- shared/std/memory.h | 3 ++- shared/ui/draw/draw.c | 6 ++--- 3 files changed, 60 insertions(+), 6 deletions(-) diff --git a/shared/std/memory.c b/shared/std/memory.c index ea5da95c..5405c800 100644 --- a/shared/std/memory.c +++ b/shared/std/memory.c @@ -9,9 +9,62 @@ int memcmp(const void *s1, const void *s2, unsigned long count) { return 0; } -void* memset(void* dest, uint32_t val, size_t count) { +void* memset32(void* dest, uint32_t val, size_t count) { + uint8_t *d8 = (uint8_t *)dest; + uint64_t pattern = ((uint64_t)val << 32) | val; + + while (((uintptr_t)d8 & 7) % 8 != 0 && count > 0) { + *d8++ = (uint8_t)(val & 0xFF); + count--; + } + + size_t blocks = count / 128; + uint64_t *d64 = (uint64_t *)d8; + for (size_t i = 0; i < blocks; i++) { + *(d64++) = pattern; + *(d64++) = pattern; + *(d64++) = pattern; + *(d64++) = pattern; + *(d64++) = pattern; + *(d64++) = pattern; + *(d64++) = pattern; + *(d64++) = pattern; + *(d64++) = pattern; + *(d64++) = pattern; + *(d64++) = pattern; + *(d64++) = pattern; + *(d64++) = pattern; + *(d64++) = pattern; + *(d64++) = pattern; + *(d64++) = pattern; + } + + count %= 128; + if (count >= 8) { + for (size_t i = 0; i < count / 8; i++) { + *d64++ = pattern; + } + count %= 8; + } + d8 = (uint8_t *)d64; + if (count >= 4) { + *((uint32_t *)d8) = val; + d8 += 4; + count -= 4; + } + if (count >= 2) { + *((uint16_t *)d8) = ((val & 0xFF) << 8) | (val & 0xFF); + d8 += 2; + count -= 2; + } + if (count == 1) + *d8 = val & 0xFF; + + return dest; +} + +void* memset(void* dest, uint8_t byte, size_t count) { uint8_t *d8 = (uint8_t *)dest; - uint8_t byte = (uint8_t)(val & 0xFF); while (((uintptr_t)d8 & 7) && count > 0) { *d8++ = byte; diff --git a/shared/std/memory.h b/shared/std/memory.h index f8bb15b7..012859a5 100644 --- a/shared/std/memory.h +++ b/shared/std/memory.h @@ -5,7 +5,8 @@ extern "C" { #include "types.h" int memcmp(const void *s1, const void *s2, unsigned long count); -void* memset(void* dest, uint32_t val, size_t count); +void* memset(void* dest, uint8_t byte, size_t count); +void* memset32(void* dest, uint32_t val, size_t count); void* memcpy(void *dest, const void *src, uint64_t count); #ifdef __cplusplus diff --git a/shared/ui/draw/draw.c b/shared/ui/draw/draw.c index a986fd55..92d369fb 100644 --- a/shared/ui/draw/draw.c +++ b/shared/ui/draw/draw.c @@ -56,7 +56,7 @@ void mark_dirty(draw_ctx *ctx, uint32_t x, uint32_t y, uint32_t w, uint32_t h) { } void fb_clear(draw_ctx *ctx, uint32_t color) { - memset(ctx->fb, color, ctx->stride * ctx->height); + memset32(ctx->fb, color, ctx->stride * ctx->height); ctx->full_redraw = true; } @@ -73,10 +73,10 @@ void fb_draw_pixel(draw_ctx *ctx, uint32_t x, uint32_t y, color color){ void fb_fill_rect(draw_ctx *ctx, uint32_t x, uint32_t y, uint32_t width, uint32_t height, color color){ if (x + width >= ctx->width || y + height >= ctx->height) return; if (width == ctx->width && x == 0){ - memset(ctx->fb + (y * (ctx->width)) , color, ctx->stride * height); + memset32(ctx->fb + (y * (ctx->width)) , color, ctx->stride * height); } else { for (uint32_t dy = 0; dy < height; dy++) - memset(ctx->fb + ((y+dy) * (ctx->width)) + x, color, width*4); + memset32(ctx->fb + ((y+dy) * (ctx->width)) + x, color, width*4); } mark_dirty(ctx, x,y,width,height); } From c34d6c8aeeb420c22aadb42c8309e06a8a47a9b4 Mon Sep 17 00:00:00 2001 From: Diego Ferrari Date: Sun, 28 Sep 2025 00:00:00 +0000 Subject: [PATCH 20/23] [PR] minor PR fixes --- kernel/kernel.c | 5 ++--- kernel/networking/drivers/net_bus.cpp | 4 ++-- kernel/networking/network_dispatch.cpp | 4 ++-- run_virt | 1 - shared/std/allocator.cpp | 4 ++++ shared/std/string.c | 2 +- shared/std/string.h | 2 +- 7 files changed, 12 insertions(+), 10 deletions(-) diff --git a/kernel/kernel.c b/kernel/kernel.c index c8154157..9394bb2d 100644 --- a/kernel/kernel.c +++ b/kernel/kernel.c @@ -54,11 +54,10 @@ void kernel_main() { load_module(&disk_module); bool input_available = load_module(&input_module); - bool network_available = true; + bool network_available = false; if (BOARD_TYPE == 1){ //TODO: disabling networking until it is refactored to prevent memory issues - //network_available = false; - load_module(&net_module); + network_available = load_module(&net_module); load_module(&audio_module); diff --git a/kernel/networking/drivers/net_bus.cpp b/kernel/networking/drivers/net_bus.cpp index bc6ffb35..60666b9b 100644 --- a/kernel/networking/drivers/net_bus.cpp +++ b/kernel/networking/drivers/net_bus.cpp @@ -53,7 +53,7 @@ static void make_ifname(char* dst, size_t cap, const char* prefix){ else if (prefix && prefix[0]=='w'){ idx = g_wif_next++; } else { idx = g_net_next++; } size_t j=0; - if (prefix){ j = strcpy(dst, cap, prefix); } else { dst[0]='n'; dst[1]='i'; dst[2]='c'; dst[3]=0; j=3; } + if (prefix){ j = strncpy(dst, cap, prefix); } else { dst[0]='n'; dst[1]='i'; dst[2]='c'; dst[3]=0; j=3; } if (jifname, sizeof(e->ifname), if_prefix); const char* hw = d->hw_ifname(); - strcpy(e->hw_ifname, sizeof(e->hw_ifname), (hw && hw[0]) ? hw : "vnet"); + strncpy(e->hw_ifname, sizeof(e->hw_ifname), (hw && hw[0]) ? hw : "vnet"); kprintfv("[net-bus] added if=%s mac=%x:%x:%x:%x:%x:%x mtu=%u hdr=%u hw=%s irq_base=%u spd=%u dup=%u", e->ifname, e->mac[0],e->mac[1],e->mac[2],e->mac[3],e->mac[4],e->mac[5], diff --git a/kernel/networking/network_dispatch.cpp b/kernel/networking/network_dispatch.cpp index 38d03c33..11133fb3 100644 --- a/kernel/networking/network_dispatch.cpp +++ b/kernel/networking/network_dispatch.cpp @@ -252,8 +252,8 @@ bool NetworkDispatch::register_all_from_bus() { new ((void*)&c->tx) Queue(QUEUE_CAPACITY); new ((void*)&c->rx) Queue(QUEUE_CAPACITY); - strcpy(c->ifname_str, (int)sizeof(c->ifname_str), name); - strcpy(c->hwname_str, (int)sizeof(c->hwname_str), hw); + strncpy(c->ifname_str, (int)sizeof(c->ifname_str), name); + strncpy(c->hwname_str, (int)sizeof(c->hwname_str), hw); memcpy(c->mac_addr, macbuf, 6); c->mtu_val = m; c->hdr_sz = hs; diff --git a/run_virt b/run_virt index 5816dd1c..af264e64 100755 --- a/run_virt +++ b/run_virt @@ -73,5 +73,4 @@ $PRIVILEGE qemu-system-aarch64 \ -audiodev ${AUDIO_BACKEND},id=audio \ -d guest_errors \ #-netdev tap,id=net1,ifname=tap1,script=no,downscript=no,vnet_hdr=off \ - #-device virtio-net-pci,netdev=net1,mac=52:54:00:12:34:57 $ARGS diff --git a/shared/std/allocator.cpp b/shared/std/allocator.cpp index 229964fd..346ae0c6 100644 --- a/shared/std/allocator.cpp +++ b/shared/std/allocator.cpp @@ -14,15 +14,19 @@ void* operator new[](size_t size) { return (void*)malloc(size); } +//TODO: properly implement these void operator delete(void* ptr) noexcept { free(ptr, 0); } + void operator delete[](void* ptr) noexcept { free(ptr, 0); } + void operator delete(void* ptr, size_t size) noexcept { free(ptr, size); } + void operator delete[](void* ptr, size_t size) noexcept { free(ptr, size); } \ No newline at end of file diff --git a/shared/std/string.c b/shared/std/string.c index 231e92a9..15560fc5 100644 --- a/shared/std/string.c +++ b/shared/std/string.c @@ -462,7 +462,7 @@ const char* seek_to(const char *string, char character){ return string; } -size_t strcpy(char* dst, size_t cap, const char* src){ +size_t strncpy(char* dst, size_t cap, const char* src){ size_t i=0; if (!dst || !src || cap==0) return 0; while (i Date: Sun, 28 Sep 2025 14:48:08 +0200 Subject: [PATCH 21/23] net: removed legacy methods --- kernel/networking/network.cpp | 8 -------- kernel/networking/network.h | 2 -- 2 files changed, 10 deletions(-) diff --git a/kernel/networking/network.cpp b/kernel/networking/network.cpp index 04946089..52c4f25b 100644 --- a/kernel/networking/network.cpp +++ b/kernel/networking/network.cpp @@ -10,14 +10,6 @@ bool network_init() { return dispatch->init(); } -void network_handle_download_interrupt() { - if (dispatch) dispatch->handle_rx_irq(0);//legacy -} - -void network_handle_upload_interrupt() { - if (dispatch) dispatch->handle_tx_irq(0); //legacy -} - void network_handle_download_interrupt_nic(uint16_t nic_id) { if (dispatch) dispatch->handle_rx_irq((size_t)nic_id); } diff --git a/kernel/networking/network.h b/kernel/networking/network.h index 8fc5fb62..b7e82b6c 100644 --- a/kernel/networking/network.h +++ b/kernel/networking/network.h @@ -16,8 +16,6 @@ void network_net_set_pid(uint16_t pid); uint16_t network_net_get_pid(); bool network_init(); -void network_handle_download_interrupt(); -void network_handle_upload_interrupt(); void network_handle_download_interrupt_nic(uint16_t nic_id); void network_handle_upload_interrupt_nic(uint16_t nic_id); int network_net_task_entry(int argc, char* argv[]); From 9e9646c9d4af3cb9c01c313318da78b5fb8a28d8 Mon Sep 17 00:00:00 2001 From: CodeAnarchist <144830359+CodeAnarchist@users.noreply.github.com> Date: Mon, 29 Sep 2025 16:55:37 +0200 Subject: [PATCH 22/23] Update README.md --- README.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index afaa60b9..be76bf4c 100644 --- a/README.md +++ b/README.md @@ -77,6 +77,11 @@ The Raspberry Pi emulation has the following limitations: ## Networking -The system has basic networking support. Currently, it performs DHCP discovery and request to receive an IP address on the local network, is capable of responding to Ping and ARP, and can connect to a server running on ports 8080 and 80, though it currently does nothing noteworthy. +The system provides medium level networking support. At startup, it scans for available network cards, loads the matching driver if present and creates a logical L2 interface for each device; a loopback interface is also added for both IPv4 and IPv6, though the current loopback implementation is partial and rejects all localhost packets. IPv4 networking is fully implemented, while IPv6 support is limited to interface structures and it cannot perform real communication. +Once interfaces and dispatcher are initialized, the system starts ARP, DHCP, DNS and SNTP processes. At the moment, SNTP sets the unix time and the time zone is configured manually since DHCP options 100 and 101 are not always included. +The stack supports UDP and TCP sockets, and an HTTP socket is implemented on top of TCP. ICMP is also supported with the system able to respond to ping requests. DNS resolution can be called directly by applications and is also used by sockets. +An embedded HTTP server is included and listens on port 80, serving a minimal page. Also discovery mechanism is available: the system probes the local network via UDP broadcast on port 8080, and when a responder replies it connects via HTTP on port 80, though it currently does nothing noteworthy. An implementation of the server can be found at the [RedactedOS Firmware Server Repository](https://github.com/differrari/RedactedOS_firmware_server/tree/main) + + From fa28670e5d2f9632160c638a7ad8dac5bab872ba Mon Sep 17 00:00:00 2001 From: CodeAnarchist <144830359+CodeAnarchist@users.noreply.github.com> Date: Mon, 29 Sep 2025 16:56:56 +0200 Subject: [PATCH 23/23] Update README.md --- README.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/README.md b/README.md index be76bf4c..9c7d671f 100644 --- a/README.md +++ b/README.md @@ -82,6 +82,3 @@ Once interfaces and dispatcher are initialized, the system starts ARP, DHCP, DNS The stack supports UDP and TCP sockets, and an HTTP socket is implemented on top of TCP. ICMP is also supported with the system able to respond to ping requests. DNS resolution can be called directly by applications and is also used by sockets. An embedded HTTP server is included and listens on port 80, serving a minimal page. Also discovery mechanism is available: the system probes the local network via UDP broadcast on port 8080, and when a responder replies it connects via HTTP on port 80, though it currently does nothing noteworthy. An implementation of the server can be found at the [RedactedOS Firmware Server Repository](https://github.com/differrari/RedactedOS_firmware_server/tree/main) - - -