net: initial raw socket implementation

This commit is contained in:
K. Lange 2021-06-09 08:23:34 +09:00
parent 27229eefc4
commit edc06e5f0c
9 changed files with 324 additions and 20 deletions

View File

@ -238,7 +238,6 @@ static void time_diff(struct timeval *start, struct timeval *end, time_t *sec_di
extern char * _argv_0;
static int configure_interface(const char * if_name) {
#if 0
/* Open a raw socket. */
int sock = socket(AF_RAW, SOCK_RAW, 0);
if (!sock) {
@ -253,7 +252,6 @@ static int configure_interface(const char * if_name) {
}
/* Request the mac address */
#endif
char if_path[100];
snprintf(if_path, 100, "/dev/net/%s", if_name);
int netdev = open(if_path, O_RDWR);
@ -281,7 +279,7 @@ static int configure_interface(const char * if_name) {
fill(&thething, 8);
write(netdev, &thething, sizeof(struct payload));
send(sock, &thething, sizeof(struct payload), 0);
}
uint32_t yiaddr;
@ -299,19 +297,23 @@ static int configure_interface(const char * if_name) {
gettimeofday(&end, NULL);
time_diff(&start,&end,&sec_diff,&usec_diff);
if (sec_diff > 3) {
if (sec_diff > 0 || usec_diff > 500000) {
close(netdev);
return 1;
}
struct pollfd fds[1];
fds[0].fd = netdev;
fds[0].fd = sock;
fds[0].events = POLLIN;
int ret = poll(fds,1,2000);
if (ret <= 0) {
int ret = poll(fds,1,200);
if (ret == 0) {
continue;
}
ssize_t rsize = read(netdev, &buf, 8092);
if (ret < 0) {
fprintf(stderr, "poll: failed\n");
return 1;
}
ssize_t rsize = recv(sock, &buf, 8092, 0);
if (rsize <= 0) {
fprintf(stderr, "%s: %s: bad size? %zd\n", _argv_0, if_name, rsize);
@ -347,7 +349,7 @@ static int configure_interface(const char * if_name) {
55,2,3,6,255,0}
};
fill(&thething, 14);
write(netdev, &thething, sizeof(struct payload));
send(sock, &thething, sizeof(struct payload), 0);
stage = 2;
} else if (stage == 2) {
yiaddr = response->dhcp_header.yiaddr;
@ -391,6 +393,7 @@ static int configure_interface(const char * if_name) {
}
close(netdev);
close(sock);
return 0;
}
} while (1);

View File

@ -0,0 +1,22 @@
#pragma once
#include <kernel/vfs.h>
#include <kernel/mod/net.h>
void net_eth_handle(struct ethernet_packet * frame, fs_node_t * nic);
struct EthernetDevice {
char if_name[32];
uint8_t mac[6];
size_t mtu;
/* XXX: just to get things going */
uint32_t ipv4_addr;
uint32_t ipv4_subnet;
uint8_t ipv6_addr[16];
/* TODO: Address lists? */
fs_node_t * device_node;
};

View File

@ -1,5 +1,30 @@
#pragma once
#include <kernel/vfs.h>
#include <sys/socket.h>
#define htonl(l) ( (((l) & 0xFF) << 24) | (((l) & 0xFF00) << 8) | (((l) & 0xFF0000) >> 8) | (((l) & 0xFF000000) >> 24))
#define htons(s) ( (((s) & 0xFF) << 8) | (((s) & 0xFF00) >> 8) )
#define ntohl(l) htonl((l))
#define ntohs(s) htons((s))
int net_add_interface(const char * name, fs_node_t * deviceNode);
fs_node_t * net_if_lookup(const char * name);
typedef struct SockData {
fs_node_t _fnode;
spin_lock_t alert_lock;
spin_lock_t rx_lock;
list_t * alert_wait;
list_t * rx_wait;
list_t * rx_queue;
long (*sock_recv)(struct SockData * sock, struct msghdr * msg, int flags);
long (*sock_send)(struct SockData * sock, const struct msghdr *msg, int flags);
void (*sock_close)(struct SockData * sock);
} sock_t;
void net_sock_alert(sock_t * sock);
void net_sock_add(sock_t * sock, void * frame);
void * net_sock_get(sock_t * sock);
sock_t * net_sock_create(void);

View File

@ -22,6 +22,8 @@ _Begin_C_Header
#define SO_KEEPALIVE 1
#define SO_REUSEADDR 2
#define SO_BINDTODEVICE 3
struct hostent {
char *h_name; /* official name of host */
char **h_aliases; /* alias list */
@ -30,8 +32,6 @@ struct hostent {
char **h_addr_list; /* list of addresses */
};
extern struct hostent * gethostbyname(const char * name);
typedef size_t socklen_t;
struct sockaddr {
@ -84,6 +84,9 @@ struct sockaddr_storage {
typedef uint32_t in_addr_t;
typedef uint16_t in_port_t;
#ifndef _KERNEL_
extern struct hostent * gethostbyname(const char * name);
extern ssize_t recv(int sockfd, void *buf, size_t len, int flags);
extern ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen);
extern ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);
@ -110,6 +113,7 @@ extern int setsockopt(int sockfd, int level, int optname, const void *optval, so
extern int connect(int sockfd, const struct sockaddr * addr, socklen_t addrlen);
extern int shutdown(int sockfd, int how);
#endif
#define IFF_UP 0x0001
#define IFF_BROADCAST 0x0002

View File

@ -56,6 +56,7 @@ struct e1000_nic {
spin_lock_t net_queue_lock;
spin_lock_t alert_lock;
spin_lock_t tx_lock;
list_t * net_queue;
list_t * rx_wait;
list_t * alert_wait;
@ -247,6 +248,7 @@ static int irq_handler(struct regs *r) {
}
static void send_packet(struct e1000_nic * device, uint8_t* payload, size_t payload_size) {
spin_lock(device->tx_lock);
device->tx_index = read_command(device, E1000_REG_TXDESCTAIL);
memcpy(device->tx_virt[device->tx_index], payload, payload_size);
@ -256,6 +258,7 @@ static void send_packet(struct e1000_nic * device, uint8_t* payload, size_t payl
device->tx_index = (device->tx_index + 1) % E1000_NUM_TX_DESC;
write_command(device, E1000_REG_TXDESCTAIL, device->tx_index);
spin_unlock(device->tx_lock);
}
static void init_rx(struct e1000_nic * device) {
@ -354,6 +357,12 @@ static int ioctl_e1000(fs_node_t * node, unsigned long request, void * argp) {
}
}
static void write_packet(fs_node_t * node, uint8_t * buffer, size_t len) {
struct e1000_nic * nic = node->device;
/* write packet */
send_packet(nic, buffer, len);
}
static ssize_t write_e1000(fs_node_t *node, off_t offset, size_t size, uint8_t *buffer) {
struct e1000_nic * nic = node->device;
/* write packet */
@ -520,7 +529,11 @@ static void e1000_init(void * data) {
net_add_interface(nic->if_name, nic->device_node);
switch_task(0);
/* Now wait for packets */
while (1) {
struct ethernet_packet * packet = dequeue_packet(nic);
net_eth_handle(packet, nic->device_node);
}
}
static void find_e1000(uint32_t device, uint16_t vendorid, uint16_t deviceid, void * found) {

58
kernel/net/eth.c Normal file
View File

@ -0,0 +1,58 @@
#include <kernel/types.h>
#include <kernel/string.h>
#include <kernel/printf.h>
#include <kernel/process.h>
#include <kernel/pipe.h>
#include <kernel/list.h>
#include <kernel/spinlock.h>
#include <kernel/vfs.h>
#include <kernel/mod/net.h>
#include <kernel/net/netif.h>
#include <kernel/net/eth.h>
#include <errno.h>
#include <sys/socket.h>
struct ethernet_packet {
uint8_t destination[6];
uint8_t source[6];
uint16_t type;
uint8_t payload[];
} __attribute__((packed)) __attribute__((aligned(2)));
#define ETHERNET_TYPE_IPV4 0x0800
#define ETHERNET_TYPE_ARP 0x0806
#define BROADCAST_MAC {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}
extern spin_lock_t net_raw_sockets_lock;
extern list_t * net_raw_sockets_list;
extern void net_sock_add(sock_t * sock, void * frame);
extern void net_ipv4_handle(void * packet, fs_node_t * nic);
void net_eth_handle(struct ethernet_packet * frame, fs_node_t * nic) {
spin_lock(net_raw_sockets_lock);
foreach(node, net_raw_sockets_list) {
sock_t * sock = node->value;
if (!sock->_fnode.device || sock->_fnode.device == nic) {
net_sock_add(sock, frame);
}
}
spin_unlock(net_raw_sockets_lock);
struct EthernetDevice * nic_eth = nic->device;
if (!memcmp(frame->destination, nic_eth->mac, 6) || !memcmp(frame->destination, (uint8_t[])BROADCAST_MAC, 6)) {
/* Now pass the frame to the appropriate handler... */
switch (ntohs(frame->type)) {
case ETHERNET_TYPE_ARP:
printf("net: eth: %s: rx arp packet\n", nic->name);
break;
case ETHERNET_TYPE_IPV4:
printf("net: eth: %s: rx ipv4 packet\n", nic->name);
net_ipv4_handle(&frame->payload, nic);
break;
}
}
free(frame);
}

View File

@ -14,6 +14,34 @@
#include <sys/socket.h>
struct ipv4_packet {
uint8_t version_ihl;
uint8_t dscp_ecn;
uint16_t length;
uint16_t ident;
uint16_t flags_fragment;
uint8_t ttl;
uint8_t protocol;
uint16_t checksum;
uint32_t source;
uint32_t destination;
uint8_t payload[];
} __attribute__ ((packed)) __attribute__((aligned(2)));
#define IPV4_PROT_UDP 17
#define IPV4_PROT_TCP 6
void net_ipv4_handle(struct ipv4_packet * packet, fs_node_t * nic) {
switch (packet->protocol) {
case IPV4_PROT_UDP:
printf("net: ipv4: %s: udp packet\n", nic->name);
break;
case IPV4_PROT_TCP:
printf("net: ipv4: %s: tcp packet\n", nic->name);
break;
}
}
long net_ipv4_socket(int type, int protocol) {
/* Ignore protocol, make socket for 'type' only... */
switch (type) {

View File

@ -22,6 +22,7 @@
static hashmap_t * interfaces = NULL;
void net_install(void) {
/* Set up virtual devices */
map_vfs_directory("/dev/net");
interfaces = hashmap_create(10);
}
@ -36,3 +37,7 @@ int net_add_interface(const char * name, fs_node_t * deviceNode) {
return 0;
}
fs_node_t * net_if_lookup(const char * name) {
return hashmap_get(interfaces, name);
}

View File

@ -12,9 +12,12 @@
#include <kernel/types.h>
#include <kernel/string.h>
#include <kernel/printf.h>
#include <kernel/list.h>
#include <kernel/syscall.h>
#include <kernel/vfs.h>
#include <kernel/net/netif.h>
#include <sys/socket.h>
/**
@ -24,6 +27,116 @@
*/
extern long net_ipv4_socket(int,int);
void net_sock_alert(sock_t * sock) {
spin_lock(sock->alert_lock);
while (sock->alert_wait->head) {
node_t * node = list_dequeue(sock->alert_wait);
process_t * p = node->value;
free(node);
spin_unlock(sock->alert_lock);
process_alert_node(p, (fs_node_t*)sock);
spin_lock(sock->alert_lock);
}
spin_unlock(sock->alert_lock);
}
void net_sock_add(sock_t * sock, void * frame) {
spin_lock(sock->rx_lock);
char * bleh = malloc(8092);
memcpy(bleh, frame, 8092);
list_insert(sock->rx_queue, bleh);
wakeup_queue(sock->rx_wait);
net_sock_alert(sock);
spin_unlock(sock->rx_lock);
}
void * net_sock_get(sock_t * sock) {
while (!sock->rx_queue->length) {
sleep_on(sock->rx_wait);
}
spin_lock(sock->rx_lock);
node_t * n = list_dequeue(sock->rx_queue);
void* value = n->value;
free(n);
spin_unlock(sock->rx_lock);
return value;
}
int sock_generic_check(fs_node_t *node) {
sock_t * sock = (sock_t*)node;
return sock->rx_queue->length ? 0 : 1;
}
int sock_generic_wait(fs_node_t *node, void * process) {
sock_t * sock = (sock_t*)node;
spin_lock(sock->alert_lock);
if (!list_find(sock->alert_wait, process)) {
list_insert(sock->alert_wait, process);
}
list_insert(((process_t *)process)->node_waits, sock);
spin_unlock(sock->alert_lock);
return 0;
}
void sock_generic_close(fs_node_t *node) {
sock_t * sock = (sock_t*)node;
sock->sock_close(sock);
printf("net: socket closed\n");
}
sock_t * net_sock_create(void) {
sock_t * sock = calloc(sizeof(struct SockData),1);
sock->_fnode.flags = FS_PIPE; /* uh, FS_SOCKET? */
sock->_fnode.mask = 0600;
sock->_fnode.device = NULL;
sock->_fnode.selectcheck = sock_generic_check;
sock->_fnode.selectwait = sock_generic_wait;
sock->_fnode.close = sock_generic_close;
sock->alert_wait = list_create("socket alert wait", sock);
sock->rx_wait = list_create("socket rx wait", sock);
sock->rx_queue = list_create("socket rx queue", sock);
open_fs((fs_node_t*)sock,0);
return sock;
}
spin_lock_t net_raw_sockets_lock = {0};
list_t * net_raw_sockets_list = NULL;
static long sock_raw_recv(sock_t * sock, struct msghdr * msg, int flags) {
if (!sock->_fnode.device) return -EINVAL;
if (msg->msg_iovlen > 1) {
printf("net: todo: can't recv multiple iovs\n");
return -ENOTSUP;
}
if (msg->msg_iovlen == 0) return 0;
if (msg->msg_iov[0].iov_len != 8092) return -EINVAL;
void * data = net_sock_get(sock);
memcpy(msg->msg_iov[0].iov_base, data, 8092);
free(data);
return 8092;
}
static long sock_raw_send(sock_t * sock, const struct msghdr *msg, int flags) {
if (!sock->_fnode.device) return -EINVAL;
if (msg->msg_iovlen > 1) {
printf("net: todo: can't send multiple iovs\n");
return -ENOTSUP;
}
if (msg->msg_iovlen == 0) return 0;
return write_fs(sock->_fnode.device, 0, msg->msg_iov[0].iov_len, msg->msg_iov[0].iov_base);
}
static void sock_raw_close(sock_t * sock) {
spin_lock(net_raw_sockets_lock);
list_delete(net_raw_sockets_list, list_find(net_raw_sockets_list, sock));
spin_unlock(net_raw_sockets_lock);
/* free stuff ? */
}
/**
* Raw sockets
*/
@ -31,13 +144,17 @@ long net_raw_socket(int type, int protocol) {
if (type != SOCK_RAW) return -EINVAL;
/* Make a new raw socket? */
fs_node_t * sock = calloc(sizeof(fs_node_t),1);
sock->flags = FS_PIPE; /* uh, FS_SOCKET? */
sock->mask = 0600;
//sock->read = sock_raw_read;
//sock->write = sock_raw_write;
sock_t * sock = net_sock_create();
sock->sock_recv = sock_raw_recv;
sock->sock_send = sock_raw_send;
sock->sock_close = sock_raw_close;
int fd = process_append_fd((process_t *)this_core->current_process, sock);
spin_lock(net_raw_sockets_lock);
if (!net_raw_sockets_list) net_raw_sockets_list = list_create("raw sockets", NULL);
list_insert(net_raw_sockets_list, sock);
spin_unlock(net_raw_sockets_lock);
int fd = process_append_fd((process_t *)this_core->current_process, (fs_node_t *)sock);
return fd;
}
@ -52,7 +169,30 @@ long net_socket(int domain, int type, int protocol) {
}
}
long net_so_socket(struct SockData * sock, int optname, const void *optval, socklen_t optlen) {
switch (optname) {
case SO_BINDTODEVICE: {
if (optlen < 1 || optlen > 32 || ((const char*)optval)[optlen-1] != 0) return -EINVAL;
fs_node_t * netif = net_if_lookup((const char*)optval);
if (!netif) return -ENOENT;
sock->_fnode.device = netif;
return 0;
}
default:
return -ENOPROTOOPT;
}
}
long net_setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen) {
if (!FD_CHECK(sockfd)) return -EBADF;
PTR_VALIDATE(optval);
sock_t * node = (sock_t*)FD_ENTRY(sockfd);
switch (level) {
case SOL_SOCKET:
return net_so_socket(node,optname,optval,optlen);
default:
return -ENOPROTOOPT;
}
return -EINVAL;
}
@ -77,11 +217,17 @@ long net_connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen) {
}
long net_recv(int sockfd, struct msghdr * msg, int flags) {
return -EINVAL;
if (!FD_CHECK(sockfd)) return -EBADF;
PTR_VALIDATE(msg);
sock_t * node = (sock_t*)FD_ENTRY(sockfd);
return node->sock_recv(node,msg,flags);
}
long net_send(int sockfd, const struct msghdr * msg, int flags) {
return -EINVAL;
if (!FD_CHECK(sockfd)) return -EBADF;
PTR_VALIDATE(msg);
sock_t * node = (sock_t*)FD_ENTRY(sockfd);
return node->sock_send(node,msg,flags);
}
long net_shutdown(int sockfd, int how) {