diff --git a/base/usr/include/kernel/net/netif.h b/base/usr/include/kernel/net/netif.h index d7e87f78..a13e1f94 100644 --- a/base/usr/include/kernel/net/netif.h +++ b/base/usr/include/kernel/net/netif.h @@ -10,6 +10,7 @@ int net_add_interface(const char * name, fs_node_t * deviceNode); fs_node_t * net_if_lookup(const char * name); +fs_node_t * net_if_route(uint32_t addr); typedef struct SockData { fs_node_t _fnode; diff --git a/kernel/net/ipv4.c b/kernel/net/ipv4.c index 9bb67611..2273c89f 100644 --- a/kernel/net/ipv4.c +++ b/kernel/net/ipv4.c @@ -31,7 +31,6 @@ #define DEFAULT_TCP_WINDOW_SIZE 65535 static int _debug __attribute__((unused)) = 0; -extern fs_node_t * net_if_any(void); static void ip_ntoa(const uint32_t src_addr, char * out) { snprintf(out, 16, "%d.%d.%d.%d", @@ -225,7 +224,7 @@ static long sock_icmp_send(sock_t * sock, const struct msghdr *msg, int flags) { } struct sockaddr_in * name = msg->msg_name; - fs_node_t * nic = net_if_any(); + fs_node_t * nic = net_if_route(name->sin_addr.s_addr); if (!nic) return -ENONET; size_t total_length = sizeof(struct ipv4_packet) + msg->msg_iov[0].iov_len; @@ -470,7 +469,7 @@ static long sock_udp_send(sock_t * sock, const struct msghdr *msg, int flags) { printf("udp: want to send to %s\n", dest); /* Routing: We need a device to send this on... */ - fs_node_t * nic = net_if_any(); + fs_node_t * nic = net_if_route(name->sin_addr.s_addr); if (!nic) return 0; size_t total_length = sizeof(struct ipv4_packet) + msg->msg_iov[0].iov_len + sizeof(struct udp_packet); @@ -582,7 +581,7 @@ static void sock_tcp_close(sock_t * sock) { spin_unlock(tcp_port_lock); size_t total_length = sizeof(struct ipv4_packet) + sizeof(struct tcp_header); - fs_node_t * nic = net_if_any(); + fs_node_t * nic = net_if_route(((struct sockaddr_in*)&sock->dest)->sin_addr.s_addr); if (!nic) return; struct ipv4_packet * response = malloc(total_length); @@ -719,7 +718,7 @@ static long sock_tcp_connect(sock_t * sock, const struct sockaddr *addr, socklen memcpy(&sock->dest, addr, addrlen); - fs_node_t * nic = net_if_any(); + fs_node_t * nic = net_if_route(dest->sin_addr.s_addr); if (!nic) return -ENONET; size_t total_length = sizeof(struct ipv4_packet) + sizeof(struct tcp_header); @@ -844,7 +843,7 @@ static long sock_tcp_send(sock_t * sock, const struct msghdr *msg, int flags) { size_t size_to_send = size_remaining > 1024 ? 1024 : size_remaining; size_t total_length = sizeof(struct ipv4_packet) + sizeof(struct tcp_header) + size_to_send; - fs_node_t * nic = net_if_any(); + fs_node_t * nic = net_if_route(((struct sockaddr_in*)&sock->dest)->sin_addr.s_addr); if (!nic) return -ENONET; struct ipv4_packet * response = malloc(total_length); diff --git a/kernel/net/loop.c b/kernel/net/loop.c new file mode 100644 index 00000000..179686f6 --- /dev/null +++ b/kernel/net/loop.c @@ -0,0 +1,122 @@ +/** + * @file kernel/net/loop.c + * @brief Loopback interface + * + * @copyright + * This file is part of ToaruOS and is released under the terms + * of the NCSA / University of Illinois License - see LICENSE.md + * Copyright (C) 2021 K. Lange + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +struct loop_nic { + struct EthernetDevice eth; + netif_counters_t counts; +}; + +static int ioctl_loop(fs_node_t * node, unsigned long request, void * argp) { + struct loop_nic * nic = node->device; + + switch (request) { + case SIOCGIFHWADDR: + return 1; + case SIOCGIFADDR: + if (nic->eth.ipv4_addr == 0) return -ENOENT; + memcpy(argp, &nic->eth.ipv4_addr, sizeof(nic->eth.ipv4_addr)); + return 0; + case SIOCSIFADDR: + memcpy(&nic->eth.ipv4_addr, argp, sizeof(nic->eth.ipv4_addr)); + return 0; + case SIOCGIFNETMASK: + if (nic->eth.ipv4_subnet == 0) return -ENOENT; + memcpy(argp, &nic->eth.ipv4_subnet, sizeof(nic->eth.ipv4_subnet)); + return 0; + case SIOCSIFNETMASK: + memcpy(&nic->eth.ipv4_subnet, argp, sizeof(nic->eth.ipv4_subnet)); + return 0; + case SIOCGIFGATEWAY: + if (nic->eth.ipv4_subnet == 0) return -ENOENT; + memcpy(argp, &nic->eth.ipv4_gateway, sizeof(nic->eth.ipv4_gateway)); + return 0; + case SIOCSIFGATEWAY: + memcpy(&nic->eth.ipv4_gateway, argp, sizeof(nic->eth.ipv4_gateway)); + net_arp_ask(nic->eth.ipv4_gateway, node); + return 0; + + case SIOCGIFADDR6: + return -ENOENT; + case SIOCSIFADDR6: + memcpy(&nic->eth.ipv6_addr, argp, sizeof(nic->eth.ipv6_addr)); + return 0; + + case SIOCGIFFLAGS: { + uint32_t * flags = argp; + *flags = IFF_RUNNING; + *flags |= IFF_UP; + *flags |= IFF_LOOPBACK; + return 0; + } + + case SIOCGIFMTU: { + uint32_t * mtu = argp; + *mtu = nic->eth.mtu; + return 0; + } + + case SIOCGIFCOUNTS: { + memcpy(argp, &nic->counts, sizeof(netif_counters_t)); + return 0; + } + + default: + return -EINVAL; + } +} + +static ssize_t write_loop(fs_node_t *node, off_t offset, size_t size, uint8_t *buffer) { + struct loop_nic * nic = node->device; + nic->counts.rx_count++; + nic->counts.tx_count++; + nic->counts.rx_bytes += size; + nic->counts.tx_bytes += size; + + net_eth_handle((void*)buffer, node); + return size; +} + +static void loop_init(struct loop_nic * nic) { + nic->eth.device_node = calloc(sizeof(fs_node_t),1); + snprintf(nic->eth.device_node->name, 100, "%s", nic->eth.if_name); + nic->eth.device_node->flags = FS_BLOCKDEVICE; + nic->eth.device_node->mask = 0666; + nic->eth.device_node->ioctl = ioctl_loop; + nic->eth.device_node->write = write_loop; + nic->eth.device_node->device = nic; + nic->eth.mtu = 65536; /* guess */ + + nic->eth.ipv4_addr = 0x0100007F; + nic->eth.ipv4_subnet = 0x000000FF; + + net_add_interface(nic->eth.if_name, nic->eth.device_node); +} + +fs_node_t * loopbook_install(void) { + struct loop_nic * nic = calloc(1,sizeof(struct loop_nic)); + snprintf(nic->eth.if_name, 31, "lo"); + loop_init(nic); + return nic->eth.device_node; + return 0; +} + diff --git a/kernel/net/netif.c b/kernel/net/netif.c index c1e872a0..d6db1f37 100644 --- a/kernel/net/netif.c +++ b/kernel/net/netif.c @@ -22,10 +22,13 @@ static hashmap_t * interfaces = NULL; extern list_t * net_raw_sockets_list; static fs_node_t * _if_first = NULL; +static fs_node_t * _if_loop = NULL; extern void ipv4_install(void); extern hashmap_t * net_arp_cache; +extern fs_node_t * loopbook_install(void); + void net_install(void) { /* Set up virtual devices */ map_vfs_directory("/dev/net"); @@ -33,6 +36,8 @@ void net_install(void) { net_raw_sockets_list = list_create("raw sockets", NULL); net_arp_cache = hashmap_create_int(10); ipv4_install(); + _if_loop = loopbook_install(); + _if_first = NULL; } /* kinda temporary for now */ @@ -55,3 +60,9 @@ fs_node_t * net_if_lookup(const char * name) { fs_node_t * net_if_any(void) { return _if_first; } + +fs_node_t * net_if_route(uint32_t addr) { + /* First off, let's do stupid stuff. */ + if (addr == 0x0100007F) return _if_loop; + return _if_first; +}