toaruos/kernel/net/loop.c

123 lines
3.1 KiB
C
Raw Normal View History

/**
* @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 <kernel/types.h>
#include <kernel/string.h>
#include <kernel/printf.h>
#include <kernel/vfs.h>
#include <kernel/spinlock.h>
#include <kernel/list.h>
#include <kernel/mod/net.h>
#include <kernel/net/netif.h>
#include <kernel/net/eth.h>
#include <errno.h>
#include <sys/socket.h>
#include <net/if.h>
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, size);
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;
}