From d2cbe2e9e07029f6a4fa91204bf32c70210f3b11 Mon Sep 17 00:00:00 2001 From: Ivan Baravy Date: Wed, 14 Oct 2020 06:30:01 +0300 Subject: [PATCH] Many fixes to scheduler and especially network. Ping via tap0 works!! --- linux/thread.c | 15 ++-- makefile | 8 +- shell.c | 65 ++++++++++----- umka.asm | 64 ++++++++++++++- umka.h | 30 ++++++- umka_os.c | 29 ++++++- umka_ping.c | 219 +++++++++++++++++++++++++------------------------ vnet.c | 47 +++++++++-- vnet.h | 2 +- 9 files changed, 322 insertions(+), 157 deletions(-) diff --git a/linux/thread.c b/linux/thread.c index 5691597..58df339 100644 --- a/linux/thread.c +++ b/linux/thread.c @@ -2,11 +2,8 @@ #define __USE_GNU #include #include -#include -#include sigset_t mask; -struct itimerval timeout = {.it_value = {.tv_sec = 0, .tv_usec = 10000}}; void reset_procmask(void) { sigemptyset (&mask); @@ -14,11 +11,13 @@ void reset_procmask(void) { sigprocmask(SIG_UNBLOCK, &mask, NULL); } -int get_fake_if(ucontext_t *ctx) { - // we fake IF with id flag - return ctx->uc_mcontext.__gregs[REG_EFL] & (1 << 21); +void set_procmask(void) { + sigemptyset (&mask); + sigaddset (&mask, SIGPROF); + sigprocmask(SIG_BLOCK, &mask, NULL); } -void restart_timer(void) { - setitimer(ITIMER_PROF, &timeout, NULL); +int get_fake_if(ucontext_t *ctx) { + // we fake IF with id flag + return !(ctx->uc_mcontext.__gregs[REG_EFL] & (1 << 21)); } diff --git a/makefile b/makefile index 52832eb..d65d41f 100644 --- a/makefile +++ b/makefile @@ -11,7 +11,7 @@ CFLAGS_32=$(CFLAGS) -m32 LDFLAGS=-no-pie LDFLAGS_32=$(LDFLAGS) -m32 -all: umka_shell umka_fuse umka_os umka_ping umka.sym umka.prp umka.lst tags \ +all: umka_shell umka_fuse umka_os umka.sym umka.prp umka.lst tags \ covpreproc default.skn skin.skn covpreproc: covpreproc.c @@ -25,11 +25,7 @@ umka_fuse: umka_fuse.o umka.o trace.o trace_lbr.o vdisk.o pci.o thread.o $(CC) $(LDFLAGS_32) $^ -o $@ `pkg-config fuse3 --libs` umka_os: umka_os.o umka.o shell.o lodepng.o vdisk.o vnet.o trace.o trace_lbr.o \ - pci.o thread.o - $(CC) $(LDFLAGS_32) $^ -o $@ -static - -umka_ping: umka_ping.o umka.o shell.o lodepng.o vdisk.o vnet.o trace.o \ - trace_lbr.o pci.o thread.o + pci.o thread.o umka_ping.o $(CC) $(LDFLAGS_32) $^ -o $@ -static umka.o umka.fas: umka.asm diff --git a/shell.c b/shell.c index 2066835..a809f92 100644 --- a/shell.c +++ b/shell.c @@ -54,25 +54,6 @@ FILE *fin, *fout; -static net_device_t vnet = { - .device_type = NET_TYPE_ETH, - .mtu = 1514, - .name = "UMK0770", - - .unload = vnet_unload, - .reset = vnet_reset, - .transmit = vnet_transmit, - - .bytes_tx = 0, - .bytes_rx = 0, - .packets_tx = 0, - .packets_rx = 0, - - .link_state = ETH_LINK_FD + ETH_LINK_10M, - .hwacc = 0, - .mac = {0x80, 0x2b, 0xf9, 0x3b, 0x6c, 0xca}, - }; - char cur_dir[PATH_MAX] = "/"; const char *last_dir = cur_dir; bool cur_dir_changed = true; @@ -485,6 +466,18 @@ void shell_dump_appdata(int argc, char **argv) { a->wnd_clientbox.top, a->wnd_clientbox.width, a->wnd_clientbox.height); fprintf(fout, "priority: %u\n", a->priority); + + fprintf(fout, "in_schedule: prev"); + if (show_pointers) { + fprintf(fout, " %p", (void*)a->in_schedule.prev); + } + fprintf(fout, " (%u), next", + (appdata_t*)a->in_schedule.prev - kos_slot_base); + if (show_pointers) { + fprintf(fout, " %p", (void*)a->in_schedule.next); + } + fprintf(fout, " (%u)\n", + (appdata_t*)a->in_schedule.next - kos_slot_base); } void shell_dump_taskdata(int argc, char **argv) { @@ -493,8 +486,14 @@ void shell_dump_taskdata(int argc, char **argv) { if (argc > 1) { idx = strtol(argv[1], NULL, 0); } - taskdata_t *t = kos_task_base + idx; + taskdata_t *t = kos_task_data + idx; fprintf(fout, "event_mask: %" PRIx32 "\n", t->event_mask); + fprintf(fout, "pid: %" PRId32 "\n", t->pid); + fprintf(fout, "state: 0x%" PRIx8 "\n", t->state); + fprintf(fout, "wnd_number: %" PRIu8 "\n", t->wnd_number); + fprintf(fout, "counter_sum: %" PRIu32 "\n", t->counter_sum); + fprintf(fout, "counter_add: %" PRIu32 "\n", t->counter_add); + fprintf(fout, "cpu_usage: %" PRIu32 "\n", t->cpu_usage); } void shell_mouse_move(int argc, char **argv) { @@ -1047,6 +1046,28 @@ fs_enc_t parse_encoding(const char *str) { return enc; } +void shell_exec(int argc, char **argv) { + (void)argc; + f7080s7arg_t fX0 = {.sf = 7}; + f7080ret_t r; + int opt = 1; + fX0.u.f70.zero = 0; + fX0.u.f70.path = argv[opt++]; + fX0.flags = 0; + fX0.params = "test"; + + COVERAGE_ON(); + umka_sys_lfn(&fX0, &r, F70); + COVERAGE_OFF(); + if (r.status < 0) { + r.status = -r.status; + } else { + fprintf(fout, "pid: %" PRIu32 "\n", r.status); + r.status = 0; + } + print_f70_status(&r, 1); +} + void shell_ls(int argc, char **argv, const char *usage, f70or80_t f70or80) { int opt; optind = 1; @@ -1339,7 +1360,8 @@ void shell_stack_init(int argc, char **argv) { void shell_net_add_device(int argc, char **argv) { (void)argc; (void)argv; - int32_t dev_num = kos_net_add_device(&vnet); + net_device_t *vnet = vnet_init(42); // FIXME: tap & list like block devices + int32_t dev_num = kos_net_add_device(vnet); fprintf(fout, "device number: %" PRIi32 "\n", dev_num); } @@ -2128,6 +2150,7 @@ func_table_t funcs[] = { { "pci_set_path", shell_pci_set_path }, { "pci_get_path", shell_pci_get_path }, { "mouse_move", shell_mouse_move }, + { "exec", shell_exec }, { NULL, NULL }, }; diff --git a/umka.asm b/umka.asm index cb7f706..225040a 100644 --- a/umka.asm +++ b/umka.asm @@ -64,6 +64,8 @@ public scheduler_add_thread public new_sys_threads public osloop public set_mouse_data as 'kos_set_mouse_data' +public scheduler_current as 'kos_scheduler_current' +public eth_input as 'kos_eth_input' macro cli { pushfd @@ -346,6 +348,31 @@ proc kos_init c uses ebx esi edi ebp mov [BOOT.lfb], LFB_BASE call init_video + stdcall alloc_kernel_space, 0x50000 ; FIXME check size + mov [default_io_map], eax + + add eax, 0x2000 + mov [ipc_tmp], eax + mov ebx, 0x1000 + + add eax, 0x40000 + mov [proc_mem_map], eax + + add eax, 0x8000 + mov [proc_mem_pdir], eax + + add eax, ebx + mov [proc_mem_tab], eax + + add eax, ebx + mov [tmp_task_ptab], eax + + add eax, ebx + mov [ipc_pdir], eax + + add eax, ebx + mov [ipc_ptab], eax + stdcall kernel_alloc, (unpack.LZMA_BASE_SIZE+(unpack.LZMA_LIT_SIZE shl \ (unpack.lc+unpack.lp)))*4 mov [unpack.p], eax @@ -512,25 +539,58 @@ proc delay_ms ret endp +;public inject_packet as 'kos_inject_packet' +public umka_inject_packet +proc umka_inject_packet c uses ebx esi edi, _data, _size, _dev + mov ebx, [_dev] + mov ecx, [_size] + push ecx + add ecx, NET_BUFF.data + stdcall net_buff_alloc, ecx ; Allocate a buffer to put packet into + pop ecx + test eax, eax ; Test if we allocated succesfully + jz .abort + mov [eax + NET_BUFF.length], ecx + mov [eax + NET_BUFF.device], ebx + mov [eax + NET_BUFF.offset], NET_BUFF.data + + lea edi, [eax + NET_BUFF.data] ; Where we will copy too + mov esi, [_data] ; The buffer we will copy from + rep movsb + + push .abort + push eax ; buffer ptr for Eth_input + + jmp eth_input ; Send it to kernel +.abort: + ret +endp + extrn reset_procmask extrn get_fake_if extrn restart_timer public irq0 proc irq0 c, _signo, _info, _context + DEBUGF 2, "### irq0\n" pushfd + cli pushad + inc [timer_ticks] + call updatecputimes ccall reset_procmask ccall get_fake_if, [_context] test eax, eax - jz .done + jnz @f + DEBUGF 2, "### cli\n" + jmp .done +@@: mov bl, SCHEDULE_ANY_PRIORITY call find_next_task jz .done ; if there is only one running process call _do_change_task .done: - ccall restart_timer popad popfd ret diff --git a/umka.h b/umka.h index cbd20c5..dd4e698 100644 --- a/umka.h +++ b/umka.h @@ -160,7 +160,7 @@ typedef struct { } bdfe_t; typedef struct { - uint32_t status; + int32_t status; uint32_t count; } f7080ret_t; @@ -225,6 +225,24 @@ typedef struct { } u; } __attribute__((packed)) f7080s5arg_t; +typedef struct { + uint32_t sf; + uint32_t flags; + char *params; + uint32_t reserved1; + uint32_t reserved2; + union { + struct { + uint8_t zero; + const char *path; + } __attribute__((packed)) f70; + struct { + uint32_t path_encoding; + const char *path; + } f80; + } u; +} __attribute__((packed)) f7080s7arg_t; + #define KF_READONLY 0x01 #define KF_HIDDEN 0x02 #define KF_SYSTEM 0x04 @@ -318,6 +336,7 @@ struct net_device_t { uint32_t hwacc; // bitmask stating enabled HW accelerations (offload // engines) uint8_t mac[6]; + void *userdata; // not in kolibri, umka-specific }; // NET_DEVICE typedef struct { @@ -361,6 +380,8 @@ static inline void umka_mouse_move(int lbheld, int mbheld, int rbheld, kos_set_mouse_data(btn_state, xmoving, ymoving, vscroll, hscroll); } +void umka_inject_packet(void *data, size_t size, net_device_t *dev); + static inline void umka_new_sys_threads(uint32_t flags, void (*entry)(), void *stack) { __asm__ __inline__ __volatile__ ( "pushad;" @@ -549,6 +570,13 @@ _Static_assert(sizeof(taskdata_t) == 32, "must be 0x20 bytes long"); #define UMKA_FUSE 2u #define UMKA_OS 3u +#define MAX_PRIORITY 0 // highest, used for kernel tasks +#define USER_PRIORITY 1 // default +#define IDLE_PRIORITY 2 // lowest, only IDLE thread goes here +#define NR_SCHED_QUEUES 3 // MUST equal IDLE_PRIORYTY + 1 + +extern appdata_t *kos_scheduler_current[NR_SCHED_QUEUES]; + extern uint32_t umka_tool; extern uint32_t kos_current_task; extern appdata_t *kos_current_slot; diff --git a/umka_os.c b/umka_os.c index 1969558..d5135e1 100644 --- a/umka_os.c +++ b/umka_os.c @@ -13,6 +13,12 @@ #define MONITOR_THREAD_STACK_SIZE 0x100000 void monitor() { + __asm__ __inline__ __volatile__ ( + "pushfd;" + "btr dword ptr[esp], 21;" + "popfd" + : : : "memory"); + fprintf(stderr, "Start monitor thread\n"); // mkfifo("/tmp/umka.fifo.2u", 0644); // mkfifo("/tmp/umka.fifo.4u", 0644); @@ -25,7 +31,20 @@ void monitor() { run_test(fin, fout, 0); } +void restart_timer(void); +void umka_thread_ping(void); +void umka_thread_net_drv(void); + +struct itimerval timeout = {.it_value = {.tv_sec = 0, .tv_usec = 10000}, + .it_interval = {.tv_sec = 0, .tv_usec = 10000}}; + int main() { + __asm__ __inline__ __volatile__ ( + "pushfd;" + "btr dword ptr[esp], 21;" + "popfd" + : : : "memory"); + umka_tool = UMKA_OS; struct sigaction sa; @@ -51,9 +70,15 @@ int main() { kos_init(); kos_stack_init(); uint8_t *monitor_stack = malloc(MONITOR_THREAD_STACK_SIZE); - umka_new_sys_threads(1, monitor, monitor_stack + MONITOR_THREAD_STACK_SIZE); + umka_new_sys_threads(0, monitor, monitor_stack + MONITOR_THREAD_STACK_SIZE); - raise(SIGPROF); + uint8_t *net_drv_stack = malloc(MONITOR_THREAD_STACK_SIZE); + umka_new_sys_threads(0, umka_thread_net_drv, net_drv_stack + MONITOR_THREAD_STACK_SIZE); + + uint8_t *ping_stack = malloc(MONITOR_THREAD_STACK_SIZE); + umka_new_sys_threads(0, umka_thread_ping, ping_stack + MONITOR_THREAD_STACK_SIZE); + + setitimer(ITIMER_PROF, &timeout, NULL); osloop(); // doesn't return diff --git a/umka_ping.c b/umka_ping.c index 70b9a98..81c1bf1 100644 --- a/umka_ping.c +++ b/umka_ping.c @@ -16,66 +16,43 @@ along with this program. If not, see . */ +#include +#include #include #include #include +#include +#include +#include +#include +#include #include #include #include -#include +#include +#include +#include #include +#include +#include #include -#include #include "shell.h" #include "umka.h" #include "trace.h" #include "vnet.h" -// tap -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +uint8_t packet[4096] = {0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 'a','b', + 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', + 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', + 'y', 'z', '0', '1', '2', '3', '4', '5'}; -static net_device_t vnet = { - .device_type = NET_TYPE_ETH, - .mtu = 1514, - .name = "UMK0770", - - .unload = vnet_unload, - .reset = vnet_reset, - .transmit = vnet_transmit, - - .bytes_tx = 0, - .bytes_rx = 0, - .packets_tx = 0, - .packets_rx = 0, - - .link_state = ETH_LINK_FD + ETH_LINK_10M, - .hwacc = 0, - .mac = {0x80, 0x2b, 0xf9, 0x3b, 0x6c, 0xca}, - }; - -uint8_t packet[4096] = {8, 0, 0, 0, 0, 0, 0, 0, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5'}; - -int tap_alloc(char *dev) -{ +int tap_alloc(char *dev) { int flags = IFF_TAP | IFF_NO_PI; struct ifreq ifr; int fd, err; char *clonedev = "/dev/net/tun"; - if( (fd = open(clonedev , O_RDWR)) < 0 ) + if( (fd = open(clonedev , O_RDWR | O_NONBLOCK)) < 0 ) { perror("Opening /dev/net/tun"); return fd; @@ -102,74 +79,26 @@ int tap_alloc(char *dev) return fd; } -int main(int argc, char **argv) { - umka_tool = UMKA_SHELL; - const char *usage = \ - "usage: umka_shell [-c]\n" - " -c collect coverage"; - int opt; - while ((opt = getopt(argc, argv, "c")) != -1) { - switch (opt) { - case 'c': - coverage = 1; - break; - default: - puts(usage); - return 1; - } - } +int tapfd; +_Atomic int go_ping = 0; + +int umka_thread_ping(void) { + __asm__ __inline__ __volatile__ ( + "pushfd;" + "btr dword ptr[esp], 21;" + "popfd" + : : : "memory"); + + while (!go_ping) { /* wait until initialized */ } + fprintf(stderr, "[ping] tapfd is %i\n", tapfd); if (coverage) trace_begin(); - COVERAGE_ON(); - kos_init(); - COVERAGE_OFF(); - - kos_stack_init(); - char tapdev[IFNAMSIZ] = "tap0"; - int tapfd = tap_alloc(tapdev); - vnet_init(tapfd); - - kos_net_add_device(&vnet); - char devname[64]; - umka_sys_net_dev_reset(1); - for (size_t i = 0; i < umka_sys_net_get_dev_count(); i++) { -// umka_sys_net_dev_reset(i); - umka_sys_net_get_dev_name(i, devname); - uint32_t devtype = umka_sys_net_get_dev_type(i); - printf("device %i: %s %u\n", i, devname, devtype); - } - - f76ret_t r76; - r76 = umka_sys_net_ipv4_set_subnet(1, inet_addr("0.0.0.0")); - if (r76.eax == (uint32_t)-1) { - fprintf(stderr, "error\n"); - exit(1); - } - - r76 = umka_sys_net_ipv4_set_gw(1, inet_addr("192.168.1.1")); - if (r76.eax == (uint32_t)-1) { - fprintf(stderr, "error\n"); - exit(1); - } - - r76 = umka_sys_net_ipv4_set_dns(1, inet_addr("217.10.36.5")); - if (r76.eax == (uint32_t)-1) { - fprintf(stderr, "error\n"); - exit(1); - } - - r76 = umka_sys_net_ipv4_set_addr(1, inet_addr("192.168.1.27")); - if (r76.eax == (uint32_t)-1) { - fprintf(stderr, "error\n"); - exit(1); - } - f75ret_t r75; - r75 = umka_sys_net_open_socket(AF_INET4, SOCK_RAW, IPPROTO_ICMP); + r75 = umka_sys_net_open_socket(AF_INET4, SOCK_STREAM, IPPROTO_TCP); if (r75.errorcode == (uint32_t)-1) { - fprintf(stderr, "error\n"); + fprintf(stderr, "[ping] error\n"); exit(1); } uint32_t sockfd = r75.value; @@ -177,7 +106,8 @@ int main(int argc, char **argv) { // uint32_t addr = inet_addr("127.0.0.1"); // uint32_t addr = inet_addr("192.243.108.5"); uint32_t addr = inet_addr("10.50.0.1"); - uint16_t port = 0; +// uint32_t addr = inet_addr("192.168.1.30"); + uint16_t port = 5000; struct sockaddr_in sa; memset(&sa, 0, sizeof(sa)); @@ -187,18 +117,93 @@ int main(int argc, char **argv) { r75 = umka_sys_net_connect(sockfd, &sa, sizeof(struct sockaddr_in)); if (r75.errorcode == (uint32_t)-1) { - fprintf(stderr, "error %u\n", r75.errorcode); + fprintf(stderr, "[ping] error %u\n", r75.errorcode); exit(1); } - r75 = umka_sys_net_send(sockfd, packet, 64, 0); + r75 = umka_sys_net_send(sockfd, packet, 128, 0); if (r75.errorcode == (uint32_t)-1) { - fprintf(stderr, "error %u\n", r75.errorcode); + fprintf(stderr, "[ping] error %u\n", r75.errorcode); exit(1); } if (coverage) trace_end(); + while (true) {} + return 0; } + +uint8_t buffer[2*1024]; +int plen = 0; + +void umka_thread_net_drv(void) { + __asm__ __inline__ __volatile__ ( + "pushfd;" + "btr dword ptr[esp], 21;" + "popfd" + : : : "memory"); + + fprintf(stderr, "[net_drv] starting\n"); + char tapdev[IFNAMSIZ] = "tap0"; + tapfd = tap_alloc(tapdev); + net_device_t *vnet = vnet_init(tapfd); + kos_net_add_device(vnet); + umka_sys_net_dev_reset(1); + + char devname[64]; + for (size_t i = 0; i < umka_sys_net_get_dev_count(); i++) { +// umka_sys_net_dev_reset(i); + umka_sys_net_get_dev_name(i, devname); + uint32_t devtype = umka_sys_net_get_dev_type(i); + printf("[net_drv] device %i: %s %u\n", i, devname, devtype); + } + + f76ret_t r76; + r76 = umka_sys_net_ipv4_set_subnet(1, inet_addr("255.255.255.0")); + if (r76.eax == (uint32_t)-1) { + fprintf(stderr, "[net_drv] error\n"); + exit(1); + } + +// r76 = umka_sys_net_ipv4_set_gw(1, inet_addr("192.168.1.1")); + r76 = umka_sys_net_ipv4_set_gw(1, inet_addr("10.50.0.1")); + if (r76.eax == (uint32_t)-1) { + fprintf(stderr, "error\n"); + exit(1); + } + + r76 = umka_sys_net_ipv4_set_dns(1, inet_addr("217.10.36.5")); + if (r76.eax == (uint32_t)-1) { + fprintf(stderr, "[net_drv] error\n"); + exit(1); + } + + r76 = umka_sys_net_ipv4_set_addr(1, inet_addr("10.50.0.2")); + if (r76.eax == (uint32_t)-1) { + fprintf(stderr, "[net_drv] error\n"); + exit(1); + } + + go_ping = 1; + + while(true) + { + plen = read(tapfd, buffer, 2*1024); + if (plen > 0) { + fprintf(stderr, "[net_drv] read %i bytes\n", plen); + for (int i = 0; i < plen; i++) { + fprintf(stderr, " %2.2x", buffer[i]); + } + fprintf(stderr, "\n"); + umka_inject_packet(buffer, plen, vnet); + } else if(plen == -1 && (errno == EAGAIN || errno == EINTR)) { + continue; + } else { + perror("[net_drv] reading data"); + exit(1); + } + } + +} diff --git a/vnet.c b/vnet.c index 581a0df..1d8e967 100644 --- a/vnet.c +++ b/vnet.c @@ -6,18 +6,39 @@ #include #include "umka.h" #include "trace.h" - -int tapfd; +#include "vnet.h" typedef struct { int fd; -} vnet_t; +} vnet_userdata_t; + +net_device_t *vnet_init(int fd) { +// printf("vnet_init\n"); + vnet_userdata_t *u = (vnet_userdata_t*)malloc(sizeof(vnet_userdata_t)); + u->fd = fd; + + net_device_t *vnet = (net_device_t*)malloc(sizeof(net_device_t)); + *vnet = (net_device_t){ + .device_type = NET_TYPE_ETH, + .mtu = 1514, + .name = "UMK0770", + + .unload = vnet_unload, + .reset = vnet_reset, + .transmit = vnet_transmit, + + .bytes_tx = 0, + .bytes_rx = 0, + .packets_tx = 0, + .packets_rx = 0, + + .link_state = ETH_LINK_FD + ETH_LINK_10M, + .hwacc = 0, + .mac = {0x80, 0x2b, 0xf9, 0x3b, 0x6c, 0xca}, + + .userdata = u, + }; -void *vnet_init(int fd) { - printf("vnet_init\n"); - vnet_t *vnet = (vnet_t*)malloc(sizeof(vnet_t)); - *vnet = (vnet_t){.fd = fd,}; - tapfd = fd; return vnet; } @@ -44,9 +65,17 @@ static void dump_net_buff(net_buff_t *buf) { __attribute__((__stdcall__)) int vnet_transmit(net_buff_t *buf) { + net_device_t *vnet; + __asm__ __inline__ __volatile__ ( + "nop" + : "=b"(vnet) + : + : "memory"); + + vnet_userdata_t *u = vnet->userdata; printf("vnet_transmit: %d bytes\n", buf->length); dump_net_buff(buf); - write(tapfd, buf->data, buf->length); + write(u->fd, buf->data, buf->length); buf->length = 0; COVERAGE_OFF(); COVERAGE_ON(); diff --git a/vnet.h b/vnet.h index e8f74c9..ff51eff 100644 --- a/vnet.h +++ b/vnet.h @@ -5,7 +5,7 @@ #include #include "umka.h" -void *vnet_init(int fd); +net_device_t *vnet_init(int fd); __attribute__((__stdcall__)) void vnet_unload(void);