From 64ce1ee2149b6c378210f6706f26969c0b4d118b Mon Sep 17 00:00:00 2001 From: Ivan Baravy Date: Thu, 7 May 2020 00:33:32 +0300 Subject: [PATCH] umka_shell: Add sf74 commands. --- kolibri.h | 61 ++++++- makefile | 5 +- syscalls.h | 123 ++++++++++++++ test/021_#i40_all.t | 1 + test/022_#net_#f74_all.t | 38 +++++ umka.asm | 15 +- umka_shell.c | 340 +++++++++++++++++++++++++++++++++------ vnet.c | 36 +++++ vnet.h | 19 +++ 9 files changed, 585 insertions(+), 53 deletions(-) create mode 100644 test/021_#i40_all.t create mode 100644 test/022_#net_#f74_all.t create mode 100644 vnet.c create mode 100644 vnet.h diff --git a/kolibri.h b/kolibri.h index e965b92..6d327e5 100644 --- a/kolibri.h +++ b/kolibri.h @@ -239,6 +239,36 @@ typedef struct { uint32_t eax; } pushad_t; +#define NET_TYPE_ETH 1 +#define NET_TYPE_SLIP 2 + +// Link state +#define ETH_LINK_DOWN 0x0 // Link is down +#define ETH_LINK_UNKNOWN 0x1 // There could be an active link +#define ETH_LINK_FD 0x2 // full duplex flag +#define ETH_LINK_10M 0x4 // 10 mbit +#define ETH_LINK_100M 0x8 // 100 mbit +#define ETH_LINK_1G 0xc // gigabit + +typedef struct { + uint32_t device_type; // type field + uint32_t mtu; // Maximal Transmission Unit + char *name; // ptr to 0 terminated string + + void *unload; // ptrs to driver functions + void *reset; + void *transmit; + + uint64_t bytes_tx; // statistics, updated by the driver + uint64_t bytes_rx; + uint32_t packets_tx; + uint32_t packets_rx; + + uint32_t link_state; // link state (0 = no link) + uint32_t hwacc; // bitmask stating enabled HW accelerations (offload + // engines) +} net_device_t; // NET_DEVICE + void kos_init(void); void i40(void); uint32_t kos_time_to_epoch(uint32_t *time); @@ -254,7 +284,36 @@ void ext_user_functions(void); void fat_user_functions(void); void ntfs_user_functions(void); -void kos_enable_acpi(void); +static inline void kos_enable_acpi() { + __asm__ __inline__ __volatile__ ( + "pushad;" + "call enable_acpi;" + "popad" + : + : + : "memory", "cc"); +} + +static inline void kos_stack_init() { + __asm__ __inline__ __volatile__ ( + "pushad;" + "call stack_init;" + "popad" + : + : + : "memory", "cc"); +} + +static inline int32_t kos_net_add_device(net_device_t *dev) { + int32_t dev_num; + __asm__ __inline__ __volatile__ ( + "call net_add_device" + : "=a"(dev_num) + : "b"(dev) + : "ecx", "edx", "esi", "edi", "memory", "cc"); + + return dev_num; +} void coverage_begin(void); void coverage_end(void); diff --git a/makefile b/makefile index 6dadb1d..41ed7f1 100644 --- a/makefile +++ b/makefile @@ -11,7 +11,7 @@ all: umka_shell umka_fuse umka.sym umka.prp umka.lst tags tools/mkdirrange tools covpreproc: covpreproc.c $(CC) $(CFLAGS) $(LDFLAGS) $^ -o $@ -umka_shell: umka_shell.o umka.o trace.o trace_lbr.o vdisk.o lodepng.o pci.o +umka_shell: umka_shell.o umka.o trace.o trace_lbr.o vdisk.o vnet.o lodepng.o pci.o $(CC) $(LDFLAGS_32) $^ -o $@ -static umka_fuse: umka_fuse.o umka.o trace.o trace_lbr.o vdisk.o pci.o @@ -53,6 +53,9 @@ trace_lbr.o: trace_lbr.c trace_lbr.h kolibri.h vdisk.o: vdisk.c $(CC) $(CFLAGS_32) -c $< +vnet.o: vnet.c + $(CC) $(CFLAGS_32) -c $< + umka_shell.o: umka_shell.c kolibri.h trace.h syscalls.h $(CC) $(CFLAGS_32) -c $< diff --git a/syscalls.h b/syscalls.h index b31e2f1..55598da 100644 --- a/syscalls.h +++ b/syscalls.h @@ -417,4 +417,127 @@ static inline void umka_sys_blit_bitmap(int operation, int background, : "memory"); } +static inline uint32_t umka_sys_net_get_dev_count() { + uint32_t count; + __asm__ __inline__ __volatile__ ( + "call i40" + : "=a"(count) + : "a"(74), + "b"(255) + : "memory"); + return count; +} + +static inline int32_t umka_sys_net_get_dev_type(uint8_t dev_num) { + int32_t type; + __asm__ __inline__ __volatile__ ( + "call i40" + : "=a"(type) + : "a"(74), + "b"((dev_num << 8) + 0) + : "memory"); + return type; +} + +static inline int32_t umka_sys_net_get_dev_name(uint8_t dev_num, char *name) { + int32_t status; + __asm__ __inline__ __volatile__ ( + "call i40" + : "=a"(status) + : "a"(74), + "b"((dev_num << 8) + 1), + "c"(name) + : "memory"); + return status; +} + +static inline int32_t umka_sys_net_dev_reset(uint8_t dev_num) { + int32_t status; + __asm__ __inline__ __volatile__ ( + "call i40" + : "=a"(status) + : "a"(74), + "b"((dev_num << 8) + 2) + : "memory"); + return status; +} + +static inline int32_t umka_sys_net_dev_stop(uint8_t dev_num) { + int32_t status; + __asm__ __inline__ __volatile__ ( + "call i40" + : "=a"(status) + : "a"(74), + "b"((dev_num << 8) + 3) + : "memory"); + return status; +} + +static inline intptr_t umka_sys_net_get_dev(uint8_t dev_num) { + intptr_t dev; + __asm__ __inline__ __volatile__ ( + "call i40" + : "=a"(dev) + : "a"(74), + "b"((dev_num << 8) + 4) + : "memory"); + return dev; +} + +static inline uint32_t umka_sys_net_get_packet_tx_count(uint8_t dev_num) { + uint32_t count; + __asm__ __inline__ __volatile__ ( + "call i40" + : "=a"(count) + : "a"(74), + "b"((dev_num << 8) + 6) + : "memory"); + return count; +} + +static inline uint32_t umka_sys_net_get_packet_rx_count(uint8_t dev_num) { + uint32_t count; + __asm__ __inline__ __volatile__ ( + "call i40" + : "=a"(count) + : "a"(74), + "b"((dev_num << 8) + 7) + : "memory"); + return count; +} + +static inline uint32_t umka_sys_net_get_byte_tx_count(uint8_t dev_num) { + uint32_t count; + __asm__ __inline__ __volatile__ ( + "call i40" + : "=a"(count) + : "a"(74), + "b"((dev_num << 8) + 8) + : "memory"); + return count; +} + +static inline uint32_t umka_sys_net_get_byte_rx_count(uint8_t dev_num) { + uint32_t count; + __asm__ __inline__ __volatile__ ( + "call i40" + : "=a"(count) + : "a"(74), + "b"((dev_num << 8) + 9) + : "memory"); + return count; +} + +static inline uint32_t umka_sys_net_get_link_status(uint8_t dev_num) { + uint32_t status; + __asm__ __inline__ __volatile__ ( + "call i40" + : "=a"(status) + : "a"(74), + "b"((dev_num << 8) + 10) + : "memory"); + return status; +} + + #endif diff --git a/test/021_#i40_all.t b/test/021_#i40_all.t new file mode 100644 index 0000000..fb9b6b9 --- /dev/null +++ b/test/021_#i40_all.t @@ -0,0 +1 @@ +i40 18 16 diff --git a/test/022_#net_#f74_all.t b/test/022_#net_#f74_all.t new file mode 100644 index 0000000..b40e980 --- /dev/null +++ b/test/022_#net_#f74_all.t @@ -0,0 +1,38 @@ +net_get_dev_count +stack_init +net_get_dev_count +net_add_device +net_get_dev_count +net_add_device +net_get_dev_count +net_add_device +net_get_dev_count +net_get_dev_type 0 +net_get_dev_type 1 +net_get_dev_type 2 +net_get_dev_name 0 +net_get_dev_name 1 +net_get_dev_name 2 +net_dev_stop 0 +net_dev_stop 1 +net_dev_reset 0 +net_dev_reset 1 +net_get_dev 0 +net_get_dev 1 +net_get_packet_tx_count 0 +net_get_packet_tx_count 1 +net_get_packet_tx_count 2 +net_get_packet_rx_count 0 +net_get_packet_rx_count 1 +net_get_packet_rx_count 2 + +net_get_byte_tx_count 0 +net_get_byte_tx_count 1 +net_get_byte_tx_count 2 +net_get_byte_rx_count 0 +net_get_byte_rx_count 1 +net_get_byte_rx_count 2 + +net_get_link_status 0 +net_get_link_status 1 +net_get_link_status 2 diff --git a/umka.asm b/umka.asm index 2fd7d6f..44a2489 100644 --- a/umka.asm +++ b/umka.asm @@ -26,11 +26,14 @@ public win_stack_addr as 'kos_win_stack' public win_pos_addr as 'kos_win_pos' public lfb_base_addr as 'kos_lfb_base' -public enable_acpi as 'kos_enable_acpi' +public enable_acpi public acpi_ssdt_cnt as 'kos_acpi_ssdt_cnt' public kos_acpi_ssdt_base public kos_acpi_ssdt_size +public stack_init +public net_add_device + cli equ nop iretd equ retd @@ -115,7 +118,9 @@ include 'core/string.inc' include 'core/malloc.inc' include 'core/heap.inc' include 'core/dll.inc' +new_sys_threads equ __pew_pew include 'core/taskman.inc' +restore new_sys_threads include 'core/timers.inc' include 'core/clipboard.inc' include 'core/syscall.inc' @@ -254,10 +259,6 @@ proc kos_init c uses ebx esi edi ebp endp extrn pci_read -;uint32_t pci_read(uint32_t bus, uint32_t dev, uint32_t fun, uint32_t offset, size_t len) { -; IN: ah=bus,device+func=bh,register address=bl -; number of bytes to read (1,2,4) coded into AL, bits 0-1 -; (0 - byte, 1 - word, 2 - dword) proc pci_read_reg uses ebx esi edi mov ecx, eax and ecx, 3 @@ -299,6 +300,10 @@ proc map_io_mem _base, _size, _flags ret endp +new_sys_threads: + xor eax, eax + ret + change_task: mov [REDRAW_BACKGROUND], 0 ret diff --git a/umka_shell.c b/umka_shell.c index ea7bb78..d2c8dee 100644 --- a/umka_shell.c +++ b/umka_shell.c @@ -31,6 +31,7 @@ #include #include #include "vdisk.h" +#include "vnet.h" #include "kolibri.h" #include "syscalls.h" #include "trace.h" @@ -56,6 +57,25 @@ diskfunc_t vdisk_functions = { .flush = NULL, .adjust_cache_size = NULL, }; + +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 = 0, // link state (0 = no link) + .hwacc = 0, + }; + char cur_dir[PATH_MAX] = "/"; const char *last_dir = cur_dir; bool cur_dir_changed = true; @@ -1042,58 +1062,286 @@ void shell_acpi_enable(int argc, char **argv) { COVERAGE_OFF(); } +void shell_stack_init(int argc, char **argv) { + (void)argc; + (void)argv; + kos_stack_init(); +} + +void shell_net_add_device(int argc, char **argv) { + (void)argc; + (void)argv; + int32_t dev_num = kos_net_add_device(&vnet); + printf("device number: %" PRIi32 "\n", dev_num); +} + +void shell_net_get_dev_count(int argc, char **argv) { + (void)argc; + (void)argv; + uint32_t count = umka_sys_net_get_dev_count(); + printf("active network devices: %u\n", count); +} + +void shell_net_get_dev_type(int argc, char **argv) { + const char *usage = \ + "usage: net_get_dev_type \n" + " dev_num device number as returned by net_add_device"; + if (argc != 2) { + puts(usage); + return; + } + uint8_t dev_num = strtoul(argv[1], NULL, 0); + int32_t dev_type = umka_sys_net_get_dev_type(dev_num); + printf("status: %s\n", dev_type == -1 ? "fail" : "ok"); + if (dev_type != -1) { + printf("type of network device #%" PRIu8 ": %i\n", dev_num, dev_type); + } +} + +void shell_net_get_dev_name(int argc, char **argv) { + const char *usage = \ + "usage: net_get_dev_name \n" + " dev_num device number as returned by net_add_device"; + if (argc != 2) { + puts(usage); + return; + } + char dev_name[64]; + uint8_t dev_num = strtoul(argv[1], NULL, 0); + int32_t status = umka_sys_net_get_dev_name(dev_num, dev_name); + printf("status: %s\n", status == -1 ? "fail" : "ok"); + if (status != -1) { + printf("name of network device #%" PRIu8 ": %s\n", dev_num, dev_name); + } +} + +void shell_net_dev_reset(int argc, char **argv) { + const char *usage = \ + "usage: net_dev_reset \n" + " dev_num device number as returned by net_add_device"; + if (argc != 2) { + puts(usage); + return; + } + uint8_t dev_num = strtoul(argv[1], NULL, 0); + int32_t status = umka_sys_net_dev_reset(dev_num); + printf("status: %s\n", status == -1 ? "fail" : "ok"); +} + +void shell_net_dev_stop(int argc, char **argv) { + const char *usage = \ + "usage: net_dev_stop \n" + " dev_num device number as returned by net_add_device"; + if (argc != 2) { + puts(usage); + return; + } + uint8_t dev_num = strtoul(argv[1], NULL, 0); + int32_t status = umka_sys_net_dev_stop(dev_num); + printf("status: %s\n", status == -1 ? "fail" : "ok"); +} + +void shell_net_get_dev(int argc, char **argv) { + const char *usage = \ + "usage: net_get_dev \n" + " dev_num device number as returned by net_add_device"; + if (argc != 2) { + puts(usage); + return; + } + uint8_t dev_num = strtoul(argv[1], NULL, 0); + intptr_t dev = umka_sys_net_get_dev(dev_num); + printf("status: %s\n", dev == -1 ? "fail" : "ok"); + if (dev != -1) { + printf("address of net dev #%" PRIu8 ": 0x%x\n", dev_num, dev); + } +} + +void shell_net_get_packet_tx_count(int argc, char **argv) { + const char *usage = \ + "usage: net_get_packet_tx_count \n" + " dev_num device number as returned by net_add_device"; + if (argc != 2) { + puts(usage); + return; + } + uint8_t dev_num = strtoul(argv[1], NULL, 0); + uint32_t count = umka_sys_net_get_packet_tx_count(dev_num); + printf("status: %s\n", count == UINT32_MAX ? "fail" : "ok"); + if (count != UINT32_MAX) { + printf("packet tx count of net dev #%" PRIu8 ": %" PRIu32 "\n", + dev_num, count); + } +} + +void shell_net_get_packet_rx_count(int argc, char **argv) { + const char *usage = \ + "usage: net_get_packet_rx_count \n" + " dev_num device number as returned by net_add_device"; + if (argc != 2) { + puts(usage); + return; + } + uint8_t dev_num = strtoul(argv[1], NULL, 0); + uint32_t count = umka_sys_net_get_packet_rx_count(dev_num); + printf("status: %s\n", count == UINT32_MAX ? "fail" : "ok"); + if (count != UINT32_MAX) { + printf("packet rx count of net dev #%" PRIu8 ": %" PRIu32 "\n", + dev_num, count); + } +} + +void shell_net_get_byte_tx_count(int argc, char **argv) { + const char *usage = \ + "usage: net_get_byte_tx_count \n" + " dev_num device number as returned by net_add_device"; + if (argc != 2) { + puts(usage); + return; + } + uint8_t dev_num = strtoul(argv[1], NULL, 0); + uint32_t count = umka_sys_net_get_byte_tx_count(dev_num); + printf("status: %s\n", count == UINT32_MAX ? "fail" : "ok"); + if (count != UINT32_MAX) { + printf("byte tx count of net dev #%" PRIu8 ": %" PRIu32 "\n", + dev_num, count); + } +} + +void shell_net_get_byte_rx_count(int argc, char **argv) { + const char *usage = \ + "usage: net_get_byte_rx_count \n" + " dev_num device number as returned by net_add_device"; + if (argc != 2) { + puts(usage); + return; + } + uint8_t dev_num = strtoul(argv[1], NULL, 0); + uint32_t count = umka_sys_net_get_byte_rx_count(dev_num); + printf("status: %s\n", count == UINT32_MAX ? "fail" : "ok"); + if (count != UINT32_MAX) { + printf("byte rx count of net dev #%" PRIu8 ": %" PRIu32 "\n", + dev_num, count); + } +} + +void print_link_status_names(uint32_t status) { + switch (status & 0x3) { + case ETH_LINK_DOWN: + printf("ETH_LINK_DOWN"); + break; + case ETH_LINK_UNKNOWN: + printf("ETH_LINK_UNKNOWN"); + break; + case ETH_LINK_FD: + printf("ETH_LINK_FD"); + break; + default: + printf("ERROR"); + break; + } + + switch(status & ~3u) { + case ETH_LINK_1G: + printf(" + ETH_LINK_1G"); + break; + case ETH_LINK_100M: + printf(" + ETH_LINK_100M"); + break; + case ETH_LINK_10M: + printf(" + ETH_LINK_10M"); + break; + default: + printf(" + UNKNOWN"); + break; + } +} + +void shell_net_get_link_status(int argc, char **argv) { + const char *usage = \ + "usage: net_get_link_status \n" + " dev_num device number as returned by net_add_device"; + if (argc != 2) { + puts(usage); + return; + } + uint8_t dev_num = strtoul(argv[1], NULL, 0); + uint32_t status = umka_sys_net_get_byte_rx_count(dev_num); + printf("status: %s\n", status == UINT32_MAX ? "fail" : "ok"); + if (status != UINT32_MAX) { + printf("link status of net dev #%" PRIu8 ": %" PRIu32 " ", + dev_num, status); + print_link_status_names(status); + putchar('\n'); + } +} + + typedef struct { char *name; void (*func) (int, char **); } func_table_t; func_table_t funcs[] = { - { "i40", shell_i40 }, - { "disk_add", shell_disk_add }, - { "disk_del", shell_disk_del }, - { "ls70", shell_ls70 }, - { "ls80", shell_ls80 }, - { "stat70", shell_stat70 }, - { "stat80", shell_stat80 }, - { "read70", shell_read70 }, - { "read80", shell_read80 }, - { "pwd", shell_pwd }, - { "cd", shell_cd }, - { "set_cwd", shell_cd }, - { "draw_window", shell_draw_window }, - { "set_pixel", shell_set_pixel }, - { "write_text", shell_write_text }, - { "put_image", shell_put_image }, - { "button", shell_button }, - { "process_info", shell_process_info }, - { "window_redraw", shell_window_redraw }, - { "draw_rect", shell_draw_rect }, - { "get_screen_size", shell_get_screen_size }, - { "draw_line", shell_draw_line }, - { "display_number", shell_display_number }, - { "set_button_style", shell_set_button_style }, - { "set_window_colors", shell_set_window_colors }, - { "get_window_colors", shell_get_window_colors }, - { "get_skin_height", shell_get_skin_height }, - { "get_screen_area", shell_get_screen_area }, - { "set_screen_area", shell_set_screen_area }, - { "get_skin_margins", shell_get_skin_margins }, - { "set_skin", shell_set_skin }, - { "get_font_smoothing", shell_get_font_smoothing }, - { "set_font_smoothing", shell_set_font_smoothing }, - { "get_font_size", shell_get_font_size }, - { "set_font_size", shell_set_font_size }, - { "put_image_palette", shell_put_image_palette }, - { "move_window", shell_move_window }, - { "set_window_caption", shell_set_window_caption }, - { "blit_bitmap", shell_blit_bitmap }, - { "scrot", shell_scrot }, - { "dump_win_stack", shell_dump_win_stack }, - { "dump_win_pos", shell_dump_win_pos }, - { "acpi_enable", shell_acpi_enable }, - { "acpi_preload_table", shell_acpi_preload_table }, - { NULL, NULL }, - }; + { "i40", shell_i40 }, + { "disk_add", shell_disk_add }, + { "disk_del", shell_disk_del }, + { "ls70", shell_ls70 }, + { "ls80", shell_ls80 }, + { "stat70", shell_stat70 }, + { "stat80", shell_stat80 }, + { "read70", shell_read70 }, + { "read80", shell_read80 }, + { "pwd", shell_pwd }, + { "cd", shell_cd }, + { "set_cwd", shell_cd }, + { "draw_window", shell_draw_window }, + { "set_pixel", shell_set_pixel }, + { "write_text", shell_write_text }, + { "put_image", shell_put_image }, + { "button", shell_button }, + { "process_info", shell_process_info }, + { "window_redraw", shell_window_redraw }, + { "draw_rect", shell_draw_rect }, + { "get_screen_size", shell_get_screen_size }, + { "draw_line", shell_draw_line }, + { "display_number", shell_display_number }, + { "set_button_style", shell_set_button_style }, + { "set_window_colors", shell_set_window_colors }, + { "get_window_colors", shell_get_window_colors }, + { "get_skin_height", shell_get_skin_height }, + { "get_screen_area", shell_get_screen_area }, + { "set_screen_area", shell_set_screen_area }, + { "get_skin_margins", shell_get_skin_margins }, + { "set_skin", shell_set_skin }, + { "get_font_smoothing", shell_get_font_smoothing }, + { "set_font_smoothing", shell_set_font_smoothing }, + { "get_font_size", shell_get_font_size }, + { "set_font_size", shell_set_font_size }, + { "put_image_palette", shell_put_image_palette }, + { "move_window", shell_move_window }, + { "set_window_caption", shell_set_window_caption }, + { "blit_bitmap", shell_blit_bitmap }, + { "scrot", shell_scrot }, + { "dump_win_stack", shell_dump_win_stack }, + { "dump_win_pos", shell_dump_win_pos }, + { "acpi_enable", shell_acpi_enable }, + { "acpi_preload_table", shell_acpi_preload_table }, + { "stack_init", shell_stack_init }, + { "net_add_device", shell_net_add_device }, + { "net_get_dev_count", shell_net_get_dev_count }, + { "net_get_dev_type", shell_net_get_dev_type }, + { "net_get_dev_name", shell_net_get_dev_name }, + { "net_dev_reset", shell_net_dev_reset }, + { "net_dev_stop", shell_net_dev_stop }, + { "net_get_dev", shell_net_get_dev }, + { "net_get_packet_tx_count", shell_net_get_packet_tx_count }, + { "net_get_packet_rx_count", shell_net_get_packet_rx_count }, + { "net_get_byte_tx_count", shell_net_get_byte_tx_count }, + { "net_get_byte_rx_count", shell_net_get_byte_rx_count }, + { "net_get_link_status", shell_net_get_link_status }, + { NULL, NULL }, +}; void *run_test(const char *infile_name) { FILE *infile, *outfile; diff --git a/vnet.c b/vnet.c new file mode 100644 index 0000000..32f979d --- /dev/null +++ b/vnet.c @@ -0,0 +1,36 @@ +#include +#include +#include +#include +#include +#include "kolibri.h" +#include "trace.h" + +typedef struct { + unsigned x; +} vnet_t; + +void *vnet_init() { + vnet_t *vnet = (vnet_t*)malloc(sizeof(vnet_t)); + *vnet = (vnet_t){.x = 0,}; + return vnet; +} + +__attribute__((__stdcall__)) +void vnet_unload() { + COVERAGE_OFF(); + COVERAGE_ON(); +} + +__attribute__((__stdcall__)) +void vnet_reset() { + COVERAGE_OFF(); + COVERAGE_ON(); +} + +__attribute__((__stdcall__)) +void vnet_transmit() { + COVERAGE_OFF(); + COVERAGE_ON(); +} + diff --git a/vnet.h b/vnet.h new file mode 100644 index 0000000..9a202dd --- /dev/null +++ b/vnet.h @@ -0,0 +1,19 @@ +#ifndef VNET_H_INCLUDED +#define VNET_H_INCLUDED + +#include +#include +#include "kolibri.h" + +void *vnet_init(void); + +__attribute__((__stdcall__)) +void vnet_unload(void); + +__attribute__((__stdcall__)) +void vnet_reset(void); + +__attribute__((__stdcall__)) +void vnet_transmit(void); + +#endif // VNET_H_INCLUDED