net: initial raw socket implementation
This commit is contained in:
parent
27229eefc4
commit
edc06e5f0c
@ -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);
|
||||
|
22
base/usr/include/kernel/net/eth.h
Normal file
22
base/usr/include/kernel/net/eth.h
Normal 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;
|
||||
};
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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
58
kernel/net/eth.c
Normal 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);
|
||||
}
|
@ -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) {
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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) {
|
||||
|
Loading…
Reference in New Issue
Block a user