// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
*/
#include <stdbool.h>
#include <stdio.h>
#include <unistd.h>
#include <stdarg.h>
#include <errno.h>
#include <stddef.h>
#include <string.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <linux/if_tun.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <netinet/ip.h>
#include <linux/if_ether.h>
#include <linux/if_packet.h>
#include <sys/wait.h>
#include <sys/uio.h>
#include <linux/virtio_net.h>
#include <netdb.h>
#include <stdlib.h>
#include <os.h>
#include <limits.h>
#include <um_malloc.h>
#include "vector_user.h"
#define ID_GRE 0
#define ID_L2TPV3 1
#define ID_BESS 2
#define ID_MAX 2
#define TOKEN_IFNAME "ifname"
#define TOKEN_SCRIPT "ifup"
#define TRANS_RAW "raw"
#define TRANS_RAW_LEN strlen(TRANS_RAW)
#define TRANS_FD "fd"
#define TRANS_FD_LEN strlen(TRANS_FD)
#define VNET_HDR_FAIL "could not enable vnet headers on fd %d"
#define TUN_GET_F_FAIL "tapraw: TUNGETFEATURES failed: %s"
#define L2TPV3_BIND_FAIL "l2tpv3_open : could not bind socket err=%i"
#define UNIX_BIND_FAIL "unix_open : could not bind socket err=%i"
#define BPF_ATTACH_FAIL "Failed to attach filter size %d prog %px to %d, err %d\n"
#define BPF_DETACH_FAIL "Failed to detach filter size %d prog %px to %d, err %d\n"
#define MAX_UN_LEN 107
static const char padchar[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
static const char *template = "tapXXXXXX";
/* This is very ugly and brute force lookup, but it is done
* only once at initialization so not worth doing hashes or
* anything more intelligent
*/
char *uml_vector_fetch_arg(struct arglist *ifspec, char *token)
{
int i;
for (i = 0; i < ifspec->numargs; i++) {
if (strcmp(ifspec->tokens[i], token) == 0)
return ifspec->values[i];
}
return NULL;
}
struct arglist *uml_parse_vector_ifspec(char *arg)
{
struct arglist *result;
int pos, len;
bool parsing_token = true, next_starts = true;
if (arg == NULL)
return NULL;
result = uml_kmalloc(sizeof(struct arglist), UM_GFP_KERNEL);
if (result == NULL)
return NULL;
result->numargs = 0;
len = strlen(arg);
for (pos = 0; pos < len; pos++) {
if (next_starts) {
if (parsing_token) {
result->tokens[result->numargs] = arg + pos;
} else {
result->values[result->numargs] = arg + pos;
result->numargs++;
}
next_starts = false;
}
if (*(arg + pos) == '=') {
if (parsing_token)
parsing_token = false;
else
goto cleanup;
next_starts = true;
(*(arg + pos)) = '\0';
}
if (*(arg + pos) == ',') {
parsing_token = true;
next_starts = true;
(*(arg + pos)) = '\0';
}
}
return result;
cleanup:
printk(UM_KERN_ERR "vector_setup - Couldn't parse '%s'\n", arg);
kfree(result);
return NULL;
}
/*
* Socket/FD configuration functions. These return an structure
* of rx and tx descriptors to cover cases where these are not
* the same (f.e. read via raw socket and write via tap).
*/
#define PATH_NET_TUN "/dev/net/tun"
static int create_tap_fd(char *iface)
{
struct ifreq ifr;
int fd = -1;
int err = -ENOMEM, offload;
fd = open(PATH_NET_TUN, O_RDWR);
if (fd < 0) {
printk(UM_KERN_ERR "uml_tap: failed to open tun device\n");
goto tap_fd_cleanup;
}
memset(&ifr, 0, sizeof(ifr));
ifr.ifr_flags = IFF_TAP | IFF_NO_PI | IFF_VNET_HDR;
strscpy(ifr.ifr_name, iface);
err = ioctl(fd, TUNSETIFF, (void *) &ifr);
if (err != 0) {
printk(UM_KERN_ERR "uml_tap: failed to select tap interface\n");
goto tap_fd_cleanup;
}
offload = TUN_F_CSUM | TUN_F_TSO4 | TUN_F_TSO6;
ioctl(fd, TUNSETOFFLOAD, offload);
return fd;
tap_fd_cleanup:
if (fd >= 0)
os_close_file(fd);
return err;
}
static int create_raw_fd(char *iface, int flags, int proto)
{
struct ifreq ifr;
int fd = -1;
struct sockaddr_ll sock;
int err = -ENOMEM;
fd = socket(AF_PACKET, SOCK_RAW, flags);
if (fd == -1) {
err = -errno;
goto raw_fd_cleanup;
}
memset(&ifr, 0, sizeof(ifr));
strscpy(ifr.ifr_name, iface);
if (ioctl(fd, SIOCGIFINDEX, (void *) &ifr) < 0) {
err =