2021-10-22 09:36:03 +03:00
|
|
|
/**
|
|
|
|
* @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;
|
|
|
|
|
2021-10-25 12:27:08 +03:00
|
|
|
net_eth_handle((void*)buffer, node, size);
|
2021-10-22 09:36:03 +03:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|