From c520edb3eba963d9226a341d571f0cc50fd14a97 Mon Sep 17 00:00:00 2001 From: William Durand Date: Thu, 10 Feb 2022 21:58:43 +0100 Subject: [PATCH] kernel: add linux compatibility layer --- Makefile | 6 + Makefile-cfg.include | 2 + data/initrd/etc/hosts | 1 + data/initrd/etc/passwd | 1 + include/kernel/proc/descriptor.h | 8 + include/libc/sys/linux_compat.h | 95 +++++++++ include/libc/sys/socket.h | 5 +- include/libc/sys/syscall.h | 8 + src/kernel/arch/x86_64/Makefile.include | 3 +- src/kernel/arch/x86_64/asm/boot.asm | 23 ++ src/kernel/arch/x86_64/proc/process.c | 138 ++++++++++++ src/kernel/arch/x86_64/proc/process.h | 31 +++ src/kernel/net/ipv4.c | 9 + src/kernel/net/udp.c | 2 +- src/kernel/proc/descriptor.c | 33 ++- src/kernel/sys/k_read.c | 6 +- src/kernel/sys/k_recvfrom.c | 30 ++- src/kernel/sys/k_sendto.c | 87 ++++++-- src/kernel/sys/k_socket.c | 18 +- src/kernel/sys/k_syscall.c | 266 +++++++++++++++++++++++- src/kernel/sys/k_write.c | 15 +- src/userland/Makefile.include | 4 + 22 files changed, 742 insertions(+), 49 deletions(-) create mode 100644 data/initrd/etc/hosts create mode 100644 data/initrd/etc/passwd create mode 100644 include/libc/sys/linux_compat.h create mode 100644 src/kernel/arch/x86_64/proc/process.c create mode 100644 src/kernel/arch/x86_64/proc/process.h diff --git a/Makefile b/Makefile index 79b2e0884..d984b643f 100644 --- a/Makefile +++ b/Makefile @@ -160,6 +160,11 @@ ifeq ($(CONFIG_USE_FAKE_CLOCK), 1) libk_c_files += $(kernel_src_dir)/time/fake_clock.c endif +ifeq ($(CONFIG_LINUX_COMPAT), 1) + KERNEL_CONFIG += -DCONFIG_LINUX_COMPAT + LIBC_CONFIG += -DCONFIG_LINUX_COMPAT +endif + # This file exists in a Docker container because we copy it in `Dockerfile`. in_docker = $(wildcard /tmp/install-linux-deps) ifneq ($(in_docker),) @@ -432,6 +437,7 @@ what: ## display some information about the current configuration echo "OS_NAME : $(OS_NAME)" echo "ARCH : $(ARCH)" echo "" + echo "CONFIG_LINUX_COMPAT = $(CONFIG_LINUX_COMPAT)" echo "CONFIG_SEMIHOSTING = $(CONFIG_SEMIHOSTING)" echo "CONFIG_USE_DLMALLOC = $(CONFIG_USE_DLMALLOC)" echo "CONFIG_USE_FAKE_CLOCK = $(CONFIG_USE_FAKE_CLOCK)" diff --git a/Makefile-cfg.include b/Makefile-cfg.include index 9f7794b7c..ec370f177 100644 --- a/Makefile-cfg.include +++ b/Makefile-cfg.include @@ -6,6 +6,8 @@ LLVM_SUFFIX ?= # When set to 1, enable the Undefined Behavior SANitizer. UBSAN ?= +# When set to 1, enable Linux (binary) compatibility. +CONFIG_LINUX_COMPAT ?= # When set to 1, enable semi-hosting mode (QEMU, mainly). CONFIG_SEMIHOSTING ?= # When set to 1, use dlmalloc for malloc/free/realloc (instead of liballoc). diff --git a/data/initrd/etc/hosts b/data/initrd/etc/hosts new file mode 100644 index 000000000..988ed358d --- /dev/null +++ b/data/initrd/etc/hosts @@ -0,0 +1 @@ +140.82.121.4 github diff --git a/data/initrd/etc/passwd b/data/initrd/etc/passwd new file mode 100644 index 000000000..038b4bfad --- /dev/null +++ b/data/initrd/etc/passwd @@ -0,0 +1 @@ +root:x:0:0::/:none diff --git a/include/kernel/proc/descriptor.h b/include/kernel/proc/descriptor.h index 1fc452a1e..de27a62ce 100644 --- a/include/kernel/proc/descriptor.h +++ b/include/kernel/proc/descriptor.h @@ -2,9 +2,11 @@ #ifndef PROC_DESCRIPTOR_H #define PROC_DESCRIPTOR_H +#include #include #include #include +#include #include #define STDIN 0 @@ -23,6 +25,8 @@ typedef struct descriptor uint32_t type; uint32_t protocol; uint16_t port; + struct sockaddr_in addr; + socklen_t addr_len; } descriptor_t; /** @@ -82,4 +86,8 @@ int descriptor_udp_lookup(uint16_t port); */ bool is_protocol_supported(uint32_t type, uint32_t protocol); +void duplicate_descriptor(int oldfd, int newfd); + +int descriptor_raw_lookup(uint32_t protocol, in_addr_t src_addr); + #endif diff --git a/include/libc/sys/linux_compat.h b/include/libc/sys/linux_compat.h new file mode 100644 index 000000000..6712ffe2f --- /dev/null +++ b/include/libc/sys/linux_compat.h @@ -0,0 +1,95 @@ +// https://chromium.googlesource.com/chromiumos/docs/+/HEAD/constants/syscalls.md +#ifndef SYS_LINUX_COMPAT_H +#define SYS_LINUX_COMPAT_H + +#ifdef __x86_64__ + +#define SYSCALL_READ 0 +#define SYSCALL_WRITE 1 +#define SYSCALL_OPEN 2 +#define SYSCALL_CLOSE 3 +#define SYSCALL_FSTAT 5 +#define SYSCALL_LSEEK 8 +#define SYSCALL_BRK 12 +#define SYSCALL_IOCTL 16 +#define SYSCALL_WRITEV 20 +#define SYSCALL_DUP2 33 +#define SYSCALL_GETPID 39 +#define SYSCALL_SOCKET 41 +#define SYSCALL_SENDTO 44 +#define SYSCALL_RECVFROM 45 +#define SYSCALL_EXECV 49 +#define SYSCALL_EXIT 60 +#define SYSCALL_GETTIMEOFDAY 96 +#define SYSCALL_GETEUID 107 +#define SYSCALL_ARCH_PRCTL 158 +#define SYSCALL_REBOOT 169 +#define SYSCALL_SET_TID_ADDR 218 +#define SYSCALL_EXIT_GROUP 231 +#define SYSCALL_OPENAT 257 + +#elif __arm__ + +#define SYSCALL_EXIT 1 +#define SYSCALL_READ 3 +#define SYSCALL_WRITE 4 +#define SYSCALL_OPEN 5 +#define SYSCALL_CLOSE 6 +#define SYSCALL_EXECV 11 +#define SYSCALL_LSEEK 19 +#define SYSCALL_GETPID 20 +#define SYSCALL_BRK 45 +#define SYSCALL_GETEUID 49 +#define SYSCALL_IOCTL 54 +#define SYSCALL_DUP2 63 +#define SYSCALL_GETTIMEOFDAY 78 +#define SYSCALL_REBOOT 88 +#define SYSCALL_FSTAT 108 +#define SYSCALL_WRITEV 146 +#define SYSCALL_EXIT_GROUP 248 +#define SYSCALL_SET_TID_ADDR 256 +#define SYSCALL_SOCKET 281 +#define SYSCALL_SENDTO 290 +#define SYSCALL_RECVFROM 292 +#define SYSCALL_OPENAT 322 + +// Not available on AArch32: +// +// - SYSCALL_ARCH_PRCTL + +#elif __aarch64__ + +#define SYSCALL_IOCTL 29 +#define SYSCALL_OPENAT 56 +#define SYSCALL_CLOSE 57 +#define SYSCALL_LSEEK 62 +#define SYSCALL_READ 63 +#define SYSCALL_WRITE 64 +#define SYSCALL_WRITEV 66 +#define SYSCALL_FSTAT 80 +#define SYSCALL_EXIT 93 +#define SYSCALL_EXIT_GROUP 94 +#define SYSCALL_SET_TID_ADDR 96 +#define SYSCALL_REBOOT 142 +#define SYSCALL_GETTIMEOFDAY 169 +#define SYSCALL_GETPID 172 +#define SYSCALL_GETEUID 175 +#define SYSCALL_SOCKET 198 +#define SYSCALL_SENDTO 206 +#define SYSCALL_RECVFROM 207 +#define SYSCALL_BRK 214 +#define SYSCALL_EXECV 221 + +// Not available on AArch64: +// +// - SYSCALL_OPEN +// - SYSCALL_DUP2 +// - SYSCALL_ARCH_PRCTL + +#endif + +// Not available outside ArvernOS: +#define SYSCALL_TEST 348 +#define SYSCALL_GETHOSTBYNAME2 349 + +#endif diff --git a/include/libc/sys/socket.h b/include/libc/sys/socket.h index 1279a09dc..1172a639b 100644 --- a/include/libc/sys/socket.h +++ b/include/libc/sys/socket.h @@ -8,8 +8,11 @@ #define AF_INET 2 // Types #define SOCK_DGRAM 2 +#define SOCK_RAW 3 // Protocols -#define IPPROTO_UDP 17 +#define IPPROTO_IP 0 +#define IPPROTO_ICMP 1 +#define IPPROTO_UDP 17 typedef uint16_t sa_family_t; diff --git a/include/libc/sys/syscall.h b/include/libc/sys/syscall.h index 276f7fc41..c37818ba4 100644 --- a/include/libc/sys/syscall.h +++ b/include/libc/sys/syscall.h @@ -11,6 +11,12 @@ #include #include +#ifdef CONFIG_LINUX_COMPAT + +#include + +#else + #define SYSCALL_TEST 1 #define SYSCALL_WRITE 2 #define SYSCALL_READ 3 @@ -29,6 +35,8 @@ #define SYSCALL_EXIT 16 #define SYSCALL_OPENAT 17 +#endif // CONFIG_LINUX_COMPAT + #define SYSCALL_SET_ERRNO() \ if (retval < 0) { \ errno = -retval; \ diff --git a/src/kernel/arch/x86_64/Makefile.include b/src/kernel/arch/x86_64/Makefile.include index f9e963a14..00a74b36a 100644 --- a/src/kernel/arch/x86_64/Makefile.include +++ b/src/kernel/arch/x86_64/Makefile.include @@ -27,7 +27,7 @@ QEMU = qemu-system-x86_64 # Options for the different tools ############################################################################### -QEMU_OPTIONS += -m 512M +QEMU_OPTIONS += -m 512M -cpu IvyBridge QEMU_OPTIONS += -serial file:$(log_file) QEMU_OPTIONS += -netdev user,id=u1,ipv6=off,dhcpstart=10.0.2.20 QEMU_OPTIONS += -device rtl8139,netdev=u1 @@ -51,6 +51,7 @@ libk_c_files += $(wildcard $(arch_src)/drivers/*.c) libk_c_files += $(wildcard $(arch_src)/fs/dev/*.c) libk_c_files += $(wildcard $(arch_src)/fs/proc/*.c) libk_c_files += $(wildcard $(arch_src)/mmu/*.c) +libk_c_files += $(wildcard $(arch_src)/proc/*.c) libk_c_files += $(wildcard $(arch_src)/sys/*.c) libk_asm_files += $(wildcard $(arch_src)/asm/*.asm) libc_test_files += $(patsubst $(tests_dir)/%.c, %, $(shell find $(tests_dir)/libc -name '*.c')) diff --git a/src/kernel/arch/x86_64/asm/boot.asm b/src/kernel/arch/x86_64/asm/boot.asm index 545004b0c..120713fb3 100644 --- a/src/kernel/arch/x86_64/asm/boot.asm +++ b/src/kernel/arch/x86_64/asm/boot.asm @@ -28,11 +28,34 @@ start: ; load the 64-bit GDT lgdt [gdt64.pointer] + call enable_sse + + mov eax, cr4 + or eax, 1 << 16 + mov cr4, eax + jmp gdt64.kernel_code:long_mode_start ; Should not be reached. hlt +enable_sse: + mov eax, 0x1 ; check for SSE + cpuid + test edx, 1 << 25 + jz .no_sse ; after this, SSE can be enabled + mov eax, cr0 + and ax, 0xFFFB ; clear coprocessor emulation CR0.EM + or ax, 0x2 ; set coprocessor monitoring CR0.MP + mov cr0, eax + mov eax, cr4 + or ax, 3 << 9 ; set CR4.OSFXSR and CR4.OSXMMEXCPT at the same time + mov cr4, eax + ret + +.no_sse: + ret + ; ----------------------------------------------------------------------------- ; make sure the kernel was really loaded by a Multiboot compliant bootloader %define MULTIBOOT2_MAGIC_VALUE 0x36d76289 diff --git a/src/kernel/arch/x86_64/proc/process.c b/src/kernel/arch/x86_64/proc/process.c new file mode 100644 index 000000000..f1b5f2fd5 --- /dev/null +++ b/src/kernel/arch/x86_64/proc/process.c @@ -0,0 +1,138 @@ +#include "process.h" + +#include +#include +#include + +#define PUSH_TO_STACK(stack, type, value) \ + stack = (char*)stack - sizeof(type); \ + *((type*)stack) = value + +static process_t* current_process = NULL; + +process_t* process_create_root() +{ + current_process = (process_t*)malloc(sizeof(process_t)); + current_process->pid = 0; + + return current_process; +} + +process_t* process_get_current() +{ + return current_process; +} + +process_t* process_exec(uint8_t* image, const char* name, char* const argv[]) +{ + PROC_DEBUG("image=%p name=%s", image, name); + + if (current_process == NULL) { + current_process = process_create_root(); + } else { + elf_unload(current_process->elf); + free(current_process->elf); + // Free the current name as we'll update it right after. + free(current_process->name); + // Give a new PID to the current process. + current_process->pid++; + } + + // Load ELF in current process. + // TODO: Handle the case where the image isn't a valid/supported ELF. + elf_header_t* elf = elf_load(image); + current_process->elf = elf; + + // Set current process name. + current_process->name = strdup(name); + + memset(current_process->user_heap, 0, USER_HEAP_SIZE); + current_process->user_brk = (uintptr_t)current_process->user_heap; + + // Set up user stack. + memset(current_process->user_stack, 0, USER_STACK_SIZE); + + // User stack: + // + // +--------+ user_stack[0] + // | | + // | | + // ^ | | + // | | | + // sp --->| | user_stack[USER_STACK_TOP] + // | | + // | | + // | | + // | | + // buf --->| | user_stack[USER_STACK_BUF] + // | | | + // v | | + // | | + // | | + // +--------+ user_stack[USER_STACK_SIZE] + // + void* stack = (void*)¤t_process->user_stack[USER_STACK_TOP]; + char* buf = (char*)¤t_process->user_stack[USER_STACK_BUF]; + + size_t off = 0; + + // auxv + uint8_t rand_bytes[16] = { + 0xaa, 0xc0, 0xff, 0xee, 0xc0, 0xff, 0xee, 0xc0, + 0xff, 0xee, 0xc0, 0xff, 0xee, 0xc0, 0xff, 0xee, + }; + memcpy(&buf[off], rand_bytes, sizeof(rand_bytes)); + char* rand_ptr = &buf[off]; + off += sizeof(rand_bytes); + + // aux: AT_NULL + PUSH_TO_STACK(stack, uintptr_t, (uintptr_t)NULL); + PUSH_TO_STACK(stack, uintptr_t, (uintptr_t)NULL); + // aux: AT_RANDOM + PUSH_TO_STACK(stack, uintptr_t, (uintptr_t)rand_ptr); + PUSH_TO_STACK(stack, uint64_t, 25); + // aux: AT_PAGESZ + PUSH_TO_STACK(stack, uint64_t, 4096); + PUSH_TO_STACK(stack, uint64_t, 6); + // aux: AT_PHNUM + PUSH_TO_STACK(stack, uint64_t, elf->ph_num); + PUSH_TO_STACK(stack, uint64_t, 5); + // aux: AT_PHENT + PUSH_TO_STACK(stack, uint64_t, elf->ph_size); + PUSH_TO_STACK(stack, uint64_t, 4); + // aux: AT_PHDR + PUSH_TO_STACK(stack, uintptr_t, (uintptr_t)image + elf->ph_offset); + PUSH_TO_STACK(stack, uint64_t, 3); + + // envp + PUSH_TO_STACK(stack, uintptr_t, (uintptr_t)NULL); + + // We need both `argc` and `argv` so we start by retrieving `argc`. + uint64_t argc = 0; + while (argv[argc]) { + argc++; + } + + // argv + PUSH_TO_STACK(stack, uintptr_t, (uintptr_t)NULL); + + for (int i = argc - 1; i >= 0; i--) { + size_t len = strlen(argv[i]); + // Copy argv[i] to high address in initial process stack. + strncpy(&buf[off], argv[i], len + 1); + + // TODO: Check that we have enough space to write argv. + + // Add address of argv[i] to the stack. + PUSH_TO_STACK(stack, uintptr_t, (uintptr_t)&buf[off]); + + off += len + 1; + } + + // argc + PUSH_TO_STACK(stack, uint64_t, argc); + + current_process->user_rsp = (uintptr_t)stack; + + return current_process; +} diff --git a/src/kernel/arch/x86_64/proc/process.h b/src/kernel/arch/x86_64/proc/process.h new file mode 100644 index 000000000..f5a097cb2 --- /dev/null +++ b/src/kernel/arch/x86_64/proc/process.h @@ -0,0 +1,31 @@ +#ifndef PROC_PROCESS_H +#define PROC_PROCESS_H + +#include +#include + +#define USER_STACK_SIZE 0x30000 +#define USER_STACK_TOP 0x01000 +#define USER_STACK_BUF 0x02000 +#define USER_HEAP_SIZE 0x10000 + +typedef struct process +{ + pid_t pid; + char* name; + elf_header_t* elf; + uint64_t user_stack[USER_STACK_SIZE]; + uintptr_t user_rsp; + uint64_t user_heap[USER_HEAP_SIZE]; + uintptr_t user_brk; + // TODO: We should probably retain the file descriptors that are opened by + // the process so that we can close them. +} process_t; + +process_t* process_create_root(); + +process_t* process_exec(uint8_t* image, const char* name, char* const argv[]); + +process_t* process_get_current(); + +#endif diff --git a/src/kernel/net/ipv4.c b/src/kernel/net/ipv4.c index e2e309428..8fc342cea 100644 --- a/src/kernel/net/ipv4.c +++ b/src/kernel/net/ipv4.c @@ -5,9 +5,11 @@ #include #include #include +#include #include #include #include +#include ipv4_header_t ipv4_create_header(uint8_t src_ip[4], in_addr_t dst_addr, @@ -36,6 +38,13 @@ void ipv4_receive_packet(net_interface_t* interface, src_ip[3], interface->id); + int sockfd = descriptor_raw_lookup(header.proto, header.src_addr); + if (sockfd >= 0) { + // Handle SOCK_RAW. + write(sockfd, data, len); + return; + } + switch (header.proto) { case IPV4_PROTO_ICMP: icmpv4_receive_packet(interface, data, &header); diff --git a/src/kernel/net/udp.c b/src/kernel/net/udp.c index ccf9accca..9a3855049 100644 --- a/src/kernel/net/udp.c +++ b/src/kernel/net/udp.c @@ -34,7 +34,7 @@ void udp_receive_packet(net_interface_t* interface, int sockfd = descriptor_udp_lookup(udp_header.dst_port); NET_DEBUG("got sockfd=%d for dst_port=%d", sockfd, udp_header.dst_port); - if (sockfd > 0) { + if (sockfd >= 0) { write(sockfd, udp_data, udp_header.len - sizeof(udp_header_t)); return; } diff --git a/src/kernel/proc/descriptor.c b/src/kernel/proc/descriptor.c index 92297547d..8417d121e 100644 --- a/src/kernel/proc/descriptor.c +++ b/src/kernel/proc/descriptor.c @@ -1,7 +1,6 @@ #include #include -#include #define NB_SYSTEM_DESCRIPTORS 20 @@ -39,6 +38,12 @@ descriptor_t* get_descriptor(int id) return &descriptors[id]; } +void duplicate_descriptor(int oldfd, int newfd) +{ + memcpy(&descriptors[newfd], get_descriptor(oldfd), sizeof(descriptor_t)); + delete_descriptor(oldfd); +} + void delete_descriptor(int id) { if (id >= NB_SYSTEM_DESCRIPTORS) { @@ -71,6 +76,25 @@ int create_socket_descriptor(inode_t inode, return -1; } +int descriptor_raw_lookup(uint32_t protocol, in_addr_t src_addr) +{ + for (uint8_t fd = 0; fd < NB_SYSTEM_DESCRIPTORS; fd++) { + if (!descriptors[fd].used || descriptors[fd].type != SOCK_RAW || + descriptors[fd].protocol != protocol) { + continue; + } + + struct sockaddr_in sa = { 0 }; + memcpy(&sa, &descriptors[fd].addr, descriptors[fd].addr_len); + + if (sa.sin_addr.s_addr == src_addr) { + return fd; + } + } + + return -1; +} + int descriptor_udp_lookup(uint16_t port) { for (uint8_t fd = 3; fd < NB_SYSTEM_DESCRIPTORS; fd++) { @@ -89,10 +113,17 @@ bool is_protocol_supported(uint32_t type, uint32_t protocol) switch (type) { case SOCK_DGRAM: switch (protocol) { + case IPPROTO_IP: case IPPROTO_UDP: return true; } break; + + case SOCK_RAW: + switch (protocol) { + case IPPROTO_ICMP: + return true; + } } return false; diff --git a/src/kernel/sys/k_read.c b/src/kernel/sys/k_read.c index 7fb40c074..1b01ae765 100644 --- a/src/kernel/sys/k_read.c +++ b/src/kernel/sys/k_read.c @@ -12,8 +12,12 @@ ssize_t k_read(int fd, void* buf, size_t count) { + SYS_DEBUG("fd=%d", fd); + if (fd == STDIN_FILENO) { - unsigned char c = arch_getchar(false); + // TODO: This was changed to please `read(STDIN)` for Linux compat' but I + // am not sure that's what we want... + unsigned char c = arch_getchar(true); if (c) { ((uint8_t*)buf)[0] = c; diff --git a/src/kernel/sys/k_recvfrom.c b/src/kernel/sys/k_recvfrom.c index fd625a911..dd9e97230 100644 --- a/src/kernel/sys/k_recvfrom.c +++ b/src/kernel/sys/k_recvfrom.c @@ -5,6 +5,7 @@ #include #include #include +#include #include ssize_t k_recvfrom(int sockfd, @@ -14,15 +15,8 @@ ssize_t k_recvfrom(int sockfd, struct sockaddr* src_addr, socklen_t* addrlen) { - UNUSED(addrlen); - UNUSED(src_addr); UNUSED(flags); - if (sockfd < 3) { - SYS_DEBUG("invalid socket descriptor sd=%d", sockfd); - return -ENOTSOCK; - } - descriptor_t* desc = get_descriptor(sockfd); if (desc == NULL) { @@ -30,11 +24,27 @@ ssize_t k_recvfrom(int sockfd, return -EBADF; } - if (desc->domain != AF_INET || desc->type != SOCK_DGRAM || - !is_protocol_supported(desc->type, desc->protocol)) { - SYS_DEBUG("invalid sockfd=%d", sockfd); + if (desc->domain != AF_INET) { + SYS_DEBUG("invalid domain for sockfd=%d", sockfd); + return -EINVAL; + } + + switch (desc->type) { + case SOCK_DGRAM: + case SOCK_RAW: + break; + default: + SYS_DEBUG("invalid type for sockfd=%d", sockfd); + return -EINVAL; + } + + if (!is_protocol_supported(desc->type, desc->protocol)) { + SYS_DEBUG("unsupported protocol for sockfd=%d", sockfd); return -EINVAL; } + memcpy(src_addr, &desc->addr, desc->addr_len); + *addrlen = desc->addr_len; + return vfs_read(desc->inode, buf, len, 0); } diff --git a/src/kernel/sys/k_sendto.c b/src/kernel/sys/k_sendto.c index 824342efa..58698ebcd 100644 --- a/src/kernel/sys/k_sendto.c +++ b/src/kernel/sys/k_sendto.c @@ -17,10 +17,7 @@ ssize_t k_sendto(int sockfd, { UNUSED(flags); - if (sockfd < 3) { - SYS_DEBUG("invalid socket descriptor sd=%d", sockfd); - return -ENOTSOCK; - } + SYS_DEBUG("sockfd=%d buf=%p len=%d flags=%d", sockfd, buf, len, flags); descriptor_t* desc = get_descriptor(sockfd); @@ -29,27 +26,79 @@ ssize_t k_sendto(int sockfd, return -EBADF; } - if (desc->domain != AF_INET || desc->type != SOCK_DGRAM || - !is_protocol_supported(desc->type, desc->protocol)) { - SYS_DEBUG("invalid sockfd=%d", sockfd); + if (desc->domain != AF_INET) { + SYS_DEBUG("invalid domain for sockfd=%d", sockfd); + return -EINVAL; + } + + switch (desc->type) { + case SOCK_DGRAM: + case SOCK_RAW: + break; + default: + SYS_DEBUG("invalid type for sockfd=%d", sockfd); + return -EINVAL; + } + + if (!is_protocol_supported(desc->type, desc->protocol)) { + SYS_DEBUG("unsupported protocol for sockfd=%d", sockfd); return -EINVAL; } + SYS_DEBUG("descriptor: domain=%d type=%d protocol=%d", + desc->domain, + desc->type, + desc->protocol); + + memcpy(&desc->addr, dst_addr, addrlen); + desc->addr_len = addrlen; + net_interface_t* interface = net_get_interface(0); - struct sockaddr_in addr = { 0 }; - memcpy(&addr, dst_addr, addrlen); + switch (desc->type) { + case SOCK_DGRAM: + switch (desc->protocol) { + case IPPROTO_IP: + ipv4_send_packet(interface, + (struct sockaddr_in*)&desc->addr, + IPV4_PROTO_ICMP, + 0, + (uint8_t*)buf, + len); + return len; - switch (desc->protocol) { - case IPPROTO_UDP: - udp_send_packet( - interface, desc->port, interface->mac, &addr, (uint8_t*)buf, len); - break; - default: - // Indicate that something went wrong, even though the type and protocol - // are supported. - len = 0; + case IPPROTO_UDP: + udp_send_packet(interface, + desc->port, + interface->mac, + (struct sockaddr_in*)&desc->addr, + (uint8_t*)buf, + len); + return len; + + default: + // Indicate that something went wrong, even though the type and + // protocol are supported. + return 0; + } + + case SOCK_RAW: + switch (desc->protocol) { + case IPPROTO_ICMP: + ipv4_send_packet(interface, + (struct sockaddr_in*)&desc->addr, + IPV4_PROTO_ICMP, + 0, + (uint8_t*)buf, + len); + return len; + + default: + // Indicate that something went wrong, even though the type and + // protocol are supported. + return 0; + } } - return len; + return 0; } diff --git a/src/kernel/sys/k_socket.c b/src/kernel/sys/k_socket.c index 9e45aa30a..c8959d8e5 100644 --- a/src/kernel/sys/k_socket.c +++ b/src/kernel/sys/k_socket.c @@ -8,12 +8,18 @@ int k_socket(int domain, int type, int protocol) { + SYS_DEBUG("domain=%d type=%d protocol=%d", domain, type, protocol); + if (domain != AF_INET) { return -EAFNOSUPPORT; } - if (type != SOCK_DGRAM) { - return -ESOCKTNOSUPPORT; + switch (type) { + case SOCK_DGRAM: + case SOCK_RAW: + break; + default: + return -ESOCKTNOSUPPORT; } if (!is_protocol_supported(type, protocol)) { @@ -43,6 +49,12 @@ int k_socket(int domain, int type, int protocol) return -ENFILE; } - SYS_DEBUG("open sd=%d", sd); + SYS_DEBUG("open sd=%d inode=%p domain=%d type=%d protocol=%d", + sd, + inode, + domain, + type, + protocol); + return sd; } diff --git a/src/kernel/sys/k_syscall.c b/src/kernel/sys/k_syscall.c index b72663223..f11c58c2d 100644 --- a/src/kernel/sys/k_syscall.c +++ b/src/kernel/sys/k_syscall.c @@ -1,15 +1,230 @@ #include #include +#include +#include +#include +#include +#include +#include #include #include +#include