/* SPDX-License-Identifier: GPL-2.0-or-later UMKa - User-Mode KolibriOS developer tools vnet - virtual network card, tap interface Copyright (C) 2023 Ivan Baravy */ #include #include #include #include #include #include #include #include #include #include "trace.h" #include "vnet.h" #define TAP_DEV "/dev/net/tun" #define UMKA_TAP_NAME "umka%d" static STDCALL void vnet_unload_tap(void) { COVERAGE_ON(); COVERAGE_OFF(); } static STDCALL void vnet_reset_tap(void) { COVERAGE_ON(); COVERAGE_OFF(); } static STDCALL int vnet_transmit_tap(net_buff_t *buf) { struct vnet *net; __asm__ __inline__ __volatile__ ( "" : "=b"(net) : : "memory"); ssize_t written = write(net->fdout, buf->data, buf->length); (void)written; buf->length = 0; COVERAGE_OFF(); COVERAGE_ON(); return 0; } struct vnet * vnet_init_tap(void) { struct ifreq ifr = {.ifr_name = UMKA_TAP_NAME, .ifr_flags = IFF_TAP | IFF_NO_PI}; int fd, err; if( (fd = open(TAP_DEV, O_RDWR)) < 0 ) { perror("Opening " TAP_DEV ); return NULL; } if( (err = ioctl(fd, TUNSETIFF, &ifr)) < 0 ) { perror("ioctl(TUNSETIFF)"); close(fd); return NULL; } ifr.ifr_hwaddr.sa_family = ARPHRD_ETHER; memcpy(ifr.ifr_hwaddr.sa_data, (char[]){0x00, 0x11, 0x00, 0x00, 0x00, 0x00}, 6); if( (err = ioctl(fd, SIOCSIFHWADDR, &ifr)) < 0 ) { perror("ioctl(SIOCSIFHWADDR)"); close(fd); return NULL; } struct sockaddr_in sai; sai.sin_family = AF_INET; sai.sin_port = 0; sai.sin_addr.s_addr = inet_addr("10.50.0.1"); memcpy(&ifr.ifr_addr, &sai, sizeof(struct sockaddr)); int sockfd = socket(AF_INET, SOCK_DGRAM, 0); if ( (err = ioctl(sockfd, SIOCSIFADDR, &ifr)) < 0 ) { perror("ioctl(SIOCSIFADDR)"); close(fd); return NULL; } sai.sin_addr.s_addr = inet_addr("255.255.255.0"); memcpy(&ifr.ifr_netmask, &sai, sizeof(struct sockaddr)); if ((err = ioctl(sockfd, SIOCSIFNETMASK, &ifr)) < 0) { perror("ioctl(SIOCSIFNETMASK)"); close(fd); return NULL; } if ((err = ioctl(sockfd, SIOCGIFFLAGS, &ifr)) < 0) { perror("ioctl(SIOCGIFFLAGS)"); close(fd); return NULL; } ifr.ifr_flags |= IFF_UP | IFF_RUNNING; ifr.ifr_flags &= ~(IFF_BROADCAST | IFF_LOWER_UP); if ((err = ioctl(sockfd, SIOCSIFFLAGS, &ifr)) < 0) { perror("ioctl(SIOCSIFFLAGS)"); close(fd); return NULL; } struct vnet *vnet = malloc(sizeof(struct vnet)); vnet->eth.net.device_type = NET_TYPE_ETH; vnet->eth.net.mtu = 1514; char *devname = malloc(8); sprintf(devname, "UMKTAP%d", 0); // FIXME: support more devices vnet->eth.net.name = devname; vnet->eth.net.unload = vnet_unload_tap; vnet->eth.net.reset = vnet_reset_tap; vnet->eth.net.transmit = vnet_transmit_tap; vnet->fdin = fd; vnet->fdout = fd; vnet->input_processed = 1; memcpy(vnet->eth.mac, (uint8_t[]){0x80, 0x2b, 0xf9, 0x3b, 0x6c, 0xca}, sizeof(vnet->eth.mac)); return vnet; }