162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
462306a36Sopenharmony_ci */
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#include <stdbool.h>
762306a36Sopenharmony_ci#include <stdio.h>
862306a36Sopenharmony_ci#include <unistd.h>
962306a36Sopenharmony_ci#include <stdarg.h>
1062306a36Sopenharmony_ci#include <errno.h>
1162306a36Sopenharmony_ci#include <stddef.h>
1262306a36Sopenharmony_ci#include <string.h>
1362306a36Sopenharmony_ci#include <sys/ioctl.h>
1462306a36Sopenharmony_ci#include <net/if.h>
1562306a36Sopenharmony_ci#include <linux/if_tun.h>
1662306a36Sopenharmony_ci#include <arpa/inet.h>
1762306a36Sopenharmony_ci#include <sys/types.h>
1862306a36Sopenharmony_ci#include <sys/stat.h>
1962306a36Sopenharmony_ci#include <fcntl.h>
2062306a36Sopenharmony_ci#include <sys/socket.h>
2162306a36Sopenharmony_ci#include <sys/un.h>
2262306a36Sopenharmony_ci#include <netinet/ip.h>
2362306a36Sopenharmony_ci#include <linux/if_ether.h>
2462306a36Sopenharmony_ci#include <linux/if_packet.h>
2562306a36Sopenharmony_ci#include <sys/wait.h>
2662306a36Sopenharmony_ci#include <sys/uio.h>
2762306a36Sopenharmony_ci#include <linux/virtio_net.h>
2862306a36Sopenharmony_ci#include <netdb.h>
2962306a36Sopenharmony_ci#include <stdlib.h>
3062306a36Sopenharmony_ci#include <os.h>
3162306a36Sopenharmony_ci#include <limits.h>
3262306a36Sopenharmony_ci#include <um_malloc.h>
3362306a36Sopenharmony_ci#include "vector_user.h"
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci#define ID_GRE 0
3662306a36Sopenharmony_ci#define ID_L2TPV3 1
3762306a36Sopenharmony_ci#define ID_BESS 2
3862306a36Sopenharmony_ci#define ID_MAX 2
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci#define TOKEN_IFNAME "ifname"
4162306a36Sopenharmony_ci#define TOKEN_SCRIPT "ifup"
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci#define TRANS_RAW "raw"
4462306a36Sopenharmony_ci#define TRANS_RAW_LEN strlen(TRANS_RAW)
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci#define TRANS_FD "fd"
4762306a36Sopenharmony_ci#define TRANS_FD_LEN strlen(TRANS_FD)
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci#define VNET_HDR_FAIL "could not enable vnet headers on fd %d"
5062306a36Sopenharmony_ci#define TUN_GET_F_FAIL "tapraw: TUNGETFEATURES failed: %s"
5162306a36Sopenharmony_ci#define L2TPV3_BIND_FAIL "l2tpv3_open : could not bind socket err=%i"
5262306a36Sopenharmony_ci#define UNIX_BIND_FAIL "unix_open : could not bind socket err=%i"
5362306a36Sopenharmony_ci#define BPF_ATTACH_FAIL "Failed to attach filter size %d prog %px to %d, err %d\n"
5462306a36Sopenharmony_ci#define BPF_DETACH_FAIL "Failed to detach filter size %d prog %px to %d, err %d\n"
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci#define MAX_UN_LEN 107
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_cistatic const char padchar[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
5962306a36Sopenharmony_cistatic const char *template = "tapXXXXXX";
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci/* This is very ugly and brute force lookup, but it is done
6262306a36Sopenharmony_ci * only once at initialization so not worth doing hashes or
6362306a36Sopenharmony_ci * anything more intelligent
6462306a36Sopenharmony_ci */
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_cichar *uml_vector_fetch_arg(struct arglist *ifspec, char *token)
6762306a36Sopenharmony_ci{
6862306a36Sopenharmony_ci	int i;
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci	for (i = 0; i < ifspec->numargs; i++) {
7162306a36Sopenharmony_ci		if (strcmp(ifspec->tokens[i], token) == 0)
7262306a36Sopenharmony_ci			return ifspec->values[i];
7362306a36Sopenharmony_ci	}
7462306a36Sopenharmony_ci	return NULL;
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci}
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_cistruct arglist *uml_parse_vector_ifspec(char *arg)
7962306a36Sopenharmony_ci{
8062306a36Sopenharmony_ci	struct arglist *result;
8162306a36Sopenharmony_ci	int pos, len;
8262306a36Sopenharmony_ci	bool parsing_token = true, next_starts = true;
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci	if (arg == NULL)
8562306a36Sopenharmony_ci		return NULL;
8662306a36Sopenharmony_ci	result = uml_kmalloc(sizeof(struct arglist), UM_GFP_KERNEL);
8762306a36Sopenharmony_ci	if (result == NULL)
8862306a36Sopenharmony_ci		return NULL;
8962306a36Sopenharmony_ci	result->numargs = 0;
9062306a36Sopenharmony_ci	len = strlen(arg);
9162306a36Sopenharmony_ci	for (pos = 0; pos < len; pos++) {
9262306a36Sopenharmony_ci		if (next_starts) {
9362306a36Sopenharmony_ci			if (parsing_token) {
9462306a36Sopenharmony_ci				result->tokens[result->numargs] = arg + pos;
9562306a36Sopenharmony_ci			} else {
9662306a36Sopenharmony_ci				result->values[result->numargs] = arg + pos;
9762306a36Sopenharmony_ci				result->numargs++;
9862306a36Sopenharmony_ci			}
9962306a36Sopenharmony_ci			next_starts = false;
10062306a36Sopenharmony_ci		}
10162306a36Sopenharmony_ci		if (*(arg + pos) == '=') {
10262306a36Sopenharmony_ci			if (parsing_token)
10362306a36Sopenharmony_ci				parsing_token = false;
10462306a36Sopenharmony_ci			else
10562306a36Sopenharmony_ci				goto cleanup;
10662306a36Sopenharmony_ci			next_starts = true;
10762306a36Sopenharmony_ci			(*(arg + pos)) = '\0';
10862306a36Sopenharmony_ci		}
10962306a36Sopenharmony_ci		if (*(arg + pos) == ',') {
11062306a36Sopenharmony_ci			parsing_token = true;
11162306a36Sopenharmony_ci			next_starts = true;
11262306a36Sopenharmony_ci			(*(arg + pos)) = '\0';
11362306a36Sopenharmony_ci		}
11462306a36Sopenharmony_ci	}
11562306a36Sopenharmony_ci	return result;
11662306a36Sopenharmony_cicleanup:
11762306a36Sopenharmony_ci	printk(UM_KERN_ERR "vector_setup - Couldn't parse '%s'\n", arg);
11862306a36Sopenharmony_ci	kfree(result);
11962306a36Sopenharmony_ci	return NULL;
12062306a36Sopenharmony_ci}
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci/*
12362306a36Sopenharmony_ci * Socket/FD configuration functions. These return an structure
12462306a36Sopenharmony_ci * of rx and tx descriptors to cover cases where these are not
12562306a36Sopenharmony_ci * the same (f.e. read via raw socket and write via tap).
12662306a36Sopenharmony_ci */
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci#define PATH_NET_TUN "/dev/net/tun"
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_cistatic int create_tap_fd(char *iface)
13262306a36Sopenharmony_ci{
13362306a36Sopenharmony_ci	struct ifreq ifr;
13462306a36Sopenharmony_ci	int fd = -1;
13562306a36Sopenharmony_ci	int err = -ENOMEM, offload;
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci	fd = open(PATH_NET_TUN, O_RDWR);
13862306a36Sopenharmony_ci	if (fd < 0) {
13962306a36Sopenharmony_ci		printk(UM_KERN_ERR "uml_tap: failed to open tun device\n");
14062306a36Sopenharmony_ci		goto tap_fd_cleanup;
14162306a36Sopenharmony_ci	}
14262306a36Sopenharmony_ci	memset(&ifr, 0, sizeof(ifr));
14362306a36Sopenharmony_ci	ifr.ifr_flags = IFF_TAP | IFF_NO_PI | IFF_VNET_HDR;
14462306a36Sopenharmony_ci	strscpy(ifr.ifr_name, iface, sizeof(ifr.ifr_name));
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci	err = ioctl(fd, TUNSETIFF, (void *) &ifr);
14762306a36Sopenharmony_ci	if (err != 0) {
14862306a36Sopenharmony_ci		printk(UM_KERN_ERR "uml_tap: failed to select tap interface\n");
14962306a36Sopenharmony_ci		goto tap_fd_cleanup;
15062306a36Sopenharmony_ci	}
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci	offload = TUN_F_CSUM | TUN_F_TSO4 | TUN_F_TSO6;
15362306a36Sopenharmony_ci	ioctl(fd, TUNSETOFFLOAD, offload);
15462306a36Sopenharmony_ci	return fd;
15562306a36Sopenharmony_citap_fd_cleanup:
15662306a36Sopenharmony_ci	if (fd >= 0)
15762306a36Sopenharmony_ci		os_close_file(fd);
15862306a36Sopenharmony_ci	return err;
15962306a36Sopenharmony_ci}
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_cistatic int create_raw_fd(char *iface, int flags, int proto)
16262306a36Sopenharmony_ci{
16362306a36Sopenharmony_ci	struct ifreq ifr;
16462306a36Sopenharmony_ci	int fd = -1;
16562306a36Sopenharmony_ci	struct sockaddr_ll sock;
16662306a36Sopenharmony_ci	int err = -ENOMEM;
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci	fd = socket(AF_PACKET, SOCK_RAW, flags);
16962306a36Sopenharmony_ci	if (fd == -1) {
17062306a36Sopenharmony_ci		err = -errno;
17162306a36Sopenharmony_ci		goto raw_fd_cleanup;
17262306a36Sopenharmony_ci	}
17362306a36Sopenharmony_ci	memset(&ifr, 0, sizeof(ifr));
17462306a36Sopenharmony_ci	strscpy(ifr.ifr_name, iface, sizeof(ifr.ifr_name));
17562306a36Sopenharmony_ci	if (ioctl(fd, SIOCGIFINDEX, (void *) &ifr) < 0) {
17662306a36Sopenharmony_ci		err = -errno;
17762306a36Sopenharmony_ci		goto raw_fd_cleanup;
17862306a36Sopenharmony_ci	}
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci	sock.sll_family = AF_PACKET;
18162306a36Sopenharmony_ci	sock.sll_protocol = htons(proto);
18262306a36Sopenharmony_ci	sock.sll_ifindex = ifr.ifr_ifindex;
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci	if (bind(fd,
18562306a36Sopenharmony_ci		(struct sockaddr *) &sock, sizeof(struct sockaddr_ll)) < 0) {
18662306a36Sopenharmony_ci		err = -errno;
18762306a36Sopenharmony_ci		goto raw_fd_cleanup;
18862306a36Sopenharmony_ci	}
18962306a36Sopenharmony_ci	return fd;
19062306a36Sopenharmony_ciraw_fd_cleanup:
19162306a36Sopenharmony_ci	printk(UM_KERN_ERR "user_init_raw: init failed, error %d", err);
19262306a36Sopenharmony_ci	if (fd >= 0)
19362306a36Sopenharmony_ci		os_close_file(fd);
19462306a36Sopenharmony_ci	return err;
19562306a36Sopenharmony_ci}
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_cistatic struct vector_fds *user_init_tap_fds(struct arglist *ifspec)
19962306a36Sopenharmony_ci{
20062306a36Sopenharmony_ci	int fd = -1, i;
20162306a36Sopenharmony_ci	char *iface;
20262306a36Sopenharmony_ci	struct vector_fds *result = NULL;
20362306a36Sopenharmony_ci	bool dynamic = false;
20462306a36Sopenharmony_ci	char dynamic_ifname[IFNAMSIZ];
20562306a36Sopenharmony_ci	char *argv[] = {NULL, NULL, NULL, NULL};
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci	iface = uml_vector_fetch_arg(ifspec, TOKEN_IFNAME);
20862306a36Sopenharmony_ci	if (iface == NULL) {
20962306a36Sopenharmony_ci		dynamic = true;
21062306a36Sopenharmony_ci		iface = dynamic_ifname;
21162306a36Sopenharmony_ci		srand(getpid());
21262306a36Sopenharmony_ci	}
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci	result = uml_kmalloc(sizeof(struct vector_fds), UM_GFP_KERNEL);
21562306a36Sopenharmony_ci	if (result == NULL) {
21662306a36Sopenharmony_ci		printk(UM_KERN_ERR "uml_tap: failed to allocate file descriptors\n");
21762306a36Sopenharmony_ci		goto tap_cleanup;
21862306a36Sopenharmony_ci	}
21962306a36Sopenharmony_ci	result->rx_fd = -1;
22062306a36Sopenharmony_ci	result->tx_fd = -1;
22162306a36Sopenharmony_ci	result->remote_addr = NULL;
22262306a36Sopenharmony_ci	result->remote_addr_size = 0;
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_ci	/* TAP */
22562306a36Sopenharmony_ci	do {
22662306a36Sopenharmony_ci		if (dynamic) {
22762306a36Sopenharmony_ci			strcpy(iface, template);
22862306a36Sopenharmony_ci			for (i = 0; i < strlen(iface); i++) {
22962306a36Sopenharmony_ci				if (iface[i] == 'X') {
23062306a36Sopenharmony_ci					iface[i] = padchar[rand() % strlen(padchar)];
23162306a36Sopenharmony_ci				}
23262306a36Sopenharmony_ci			}
23362306a36Sopenharmony_ci		}
23462306a36Sopenharmony_ci		fd = create_tap_fd(iface);
23562306a36Sopenharmony_ci		if ((fd < 0) && (!dynamic)) {
23662306a36Sopenharmony_ci			printk(UM_KERN_ERR "uml_tap: failed to create tun interface\n");
23762306a36Sopenharmony_ci			goto tap_cleanup;
23862306a36Sopenharmony_ci		}
23962306a36Sopenharmony_ci		result->tx_fd = fd;
24062306a36Sopenharmony_ci		result->rx_fd = fd;
24162306a36Sopenharmony_ci	} while (fd < 0);
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ci	argv[0] = uml_vector_fetch_arg(ifspec, TOKEN_SCRIPT);
24462306a36Sopenharmony_ci	if (argv[0]) {
24562306a36Sopenharmony_ci		argv[1] = iface;
24662306a36Sopenharmony_ci		run_helper(NULL, NULL, argv);
24762306a36Sopenharmony_ci	}
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci	return result;
25062306a36Sopenharmony_citap_cleanup:
25162306a36Sopenharmony_ci	printk(UM_KERN_ERR "user_init_tap: init failed, error %d", fd);
25262306a36Sopenharmony_ci	kfree(result);
25362306a36Sopenharmony_ci	return NULL;
25462306a36Sopenharmony_ci}
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_cistatic struct vector_fds *user_init_hybrid_fds(struct arglist *ifspec)
25762306a36Sopenharmony_ci{
25862306a36Sopenharmony_ci	char *iface;
25962306a36Sopenharmony_ci	struct vector_fds *result = NULL;
26062306a36Sopenharmony_ci	char *argv[] = {NULL, NULL, NULL, NULL};
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci	iface = uml_vector_fetch_arg(ifspec, TOKEN_IFNAME);
26362306a36Sopenharmony_ci	if (iface == NULL) {
26462306a36Sopenharmony_ci		printk(UM_KERN_ERR "uml_tap: failed to parse interface spec\n");
26562306a36Sopenharmony_ci		goto hybrid_cleanup;
26662306a36Sopenharmony_ci	}
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci	result = uml_kmalloc(sizeof(struct vector_fds), UM_GFP_KERNEL);
26962306a36Sopenharmony_ci	if (result == NULL) {
27062306a36Sopenharmony_ci		printk(UM_KERN_ERR "uml_tap: failed to allocate file descriptors\n");
27162306a36Sopenharmony_ci		goto hybrid_cleanup;
27262306a36Sopenharmony_ci	}
27362306a36Sopenharmony_ci	result->rx_fd = -1;
27462306a36Sopenharmony_ci	result->tx_fd = -1;
27562306a36Sopenharmony_ci	result->remote_addr = NULL;
27662306a36Sopenharmony_ci	result->remote_addr_size = 0;
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci	/* TAP */
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_ci	result->tx_fd = create_tap_fd(iface);
28162306a36Sopenharmony_ci	if (result->tx_fd < 0) {
28262306a36Sopenharmony_ci		printk(UM_KERN_ERR "uml_tap: failed to create tun interface: %i\n", result->tx_fd);
28362306a36Sopenharmony_ci		goto hybrid_cleanup;
28462306a36Sopenharmony_ci	}
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_ci	/* RAW */
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ci	result->rx_fd = create_raw_fd(iface, ETH_P_ALL, ETH_P_ALL);
28962306a36Sopenharmony_ci	if (result->rx_fd == -1) {
29062306a36Sopenharmony_ci		printk(UM_KERN_ERR
29162306a36Sopenharmony_ci			"uml_tap: failed to create paired raw socket: %i\n", result->rx_fd);
29262306a36Sopenharmony_ci		goto hybrid_cleanup;
29362306a36Sopenharmony_ci	}
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ci	argv[0] = uml_vector_fetch_arg(ifspec, TOKEN_SCRIPT);
29662306a36Sopenharmony_ci	if (argv[0]) {
29762306a36Sopenharmony_ci		argv[1] = iface;
29862306a36Sopenharmony_ci		run_helper(NULL, NULL, argv);
29962306a36Sopenharmony_ci	}
30062306a36Sopenharmony_ci	return result;
30162306a36Sopenharmony_cihybrid_cleanup:
30262306a36Sopenharmony_ci	printk(UM_KERN_ERR "user_init_hybrid: init failed");
30362306a36Sopenharmony_ci	kfree(result);
30462306a36Sopenharmony_ci	return NULL;
30562306a36Sopenharmony_ci}
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_cistatic struct vector_fds *user_init_unix_fds(struct arglist *ifspec, int id)
30862306a36Sopenharmony_ci{
30962306a36Sopenharmony_ci	int fd = -1;
31062306a36Sopenharmony_ci	int socktype;
31162306a36Sopenharmony_ci	char *src, *dst;
31262306a36Sopenharmony_ci	struct vector_fds *result = NULL;
31362306a36Sopenharmony_ci	struct sockaddr_un *local_addr = NULL, *remote_addr = NULL;
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci	src = uml_vector_fetch_arg(ifspec, "src");
31662306a36Sopenharmony_ci	dst = uml_vector_fetch_arg(ifspec, "dst");
31762306a36Sopenharmony_ci	result = uml_kmalloc(sizeof(struct vector_fds), UM_GFP_KERNEL);
31862306a36Sopenharmony_ci	if (result == NULL) {
31962306a36Sopenharmony_ci		printk(UM_KERN_ERR "unix open:cannot allocate remote addr");
32062306a36Sopenharmony_ci		goto unix_cleanup;
32162306a36Sopenharmony_ci	}
32262306a36Sopenharmony_ci	remote_addr = uml_kmalloc(sizeof(struct sockaddr_un), UM_GFP_KERNEL);
32362306a36Sopenharmony_ci	if (remote_addr == NULL) {
32462306a36Sopenharmony_ci		printk(UM_KERN_ERR "unix open:cannot allocate remote addr");
32562306a36Sopenharmony_ci		goto unix_cleanup;
32662306a36Sopenharmony_ci	}
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci	switch (id) {
32962306a36Sopenharmony_ci	case ID_BESS:
33062306a36Sopenharmony_ci		socktype = SOCK_SEQPACKET;
33162306a36Sopenharmony_ci		if ((src != NULL) && (strlen(src) <= MAX_UN_LEN)) {
33262306a36Sopenharmony_ci			local_addr = uml_kmalloc(sizeof(struct sockaddr_un), UM_GFP_KERNEL);
33362306a36Sopenharmony_ci			if (local_addr == NULL) {
33462306a36Sopenharmony_ci				printk(UM_KERN_ERR "bess open:cannot allocate local addr");
33562306a36Sopenharmony_ci				goto unix_cleanup;
33662306a36Sopenharmony_ci			}
33762306a36Sopenharmony_ci			local_addr->sun_family = AF_UNIX;
33862306a36Sopenharmony_ci			memcpy(local_addr->sun_path, src, strlen(src) + 1);
33962306a36Sopenharmony_ci		}
34062306a36Sopenharmony_ci		if ((dst == NULL) || (strlen(dst) > MAX_UN_LEN))
34162306a36Sopenharmony_ci			goto unix_cleanup;
34262306a36Sopenharmony_ci		remote_addr->sun_family = AF_UNIX;
34362306a36Sopenharmony_ci		memcpy(remote_addr->sun_path, dst, strlen(dst) + 1);
34462306a36Sopenharmony_ci		break;
34562306a36Sopenharmony_ci	default:
34662306a36Sopenharmony_ci		printk(KERN_ERR "Unsupported unix socket type\n");
34762306a36Sopenharmony_ci		return NULL;
34862306a36Sopenharmony_ci	}
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ci	fd = socket(AF_UNIX, socktype, 0);
35162306a36Sopenharmony_ci	if (fd == -1) {
35262306a36Sopenharmony_ci		printk(UM_KERN_ERR
35362306a36Sopenharmony_ci			"unix open: could not open socket, error = %d",
35462306a36Sopenharmony_ci			-errno
35562306a36Sopenharmony_ci		);
35662306a36Sopenharmony_ci		goto unix_cleanup;
35762306a36Sopenharmony_ci	}
35862306a36Sopenharmony_ci	if (local_addr != NULL) {
35962306a36Sopenharmony_ci		if (bind(fd, (struct sockaddr *) local_addr, sizeof(struct sockaddr_un))) {
36062306a36Sopenharmony_ci			printk(UM_KERN_ERR UNIX_BIND_FAIL, errno);
36162306a36Sopenharmony_ci			goto unix_cleanup;
36262306a36Sopenharmony_ci		}
36362306a36Sopenharmony_ci	}
36462306a36Sopenharmony_ci	switch (id) {
36562306a36Sopenharmony_ci	case ID_BESS:
36662306a36Sopenharmony_ci		if (connect(fd, (const struct sockaddr *) remote_addr, sizeof(struct sockaddr_un)) < 0) {
36762306a36Sopenharmony_ci			printk(UM_KERN_ERR "bess open:cannot connect to %s %i", remote_addr->sun_path, -errno);
36862306a36Sopenharmony_ci			goto unix_cleanup;
36962306a36Sopenharmony_ci		}
37062306a36Sopenharmony_ci		break;
37162306a36Sopenharmony_ci	}
37262306a36Sopenharmony_ci	result->rx_fd = fd;
37362306a36Sopenharmony_ci	result->tx_fd = fd;
37462306a36Sopenharmony_ci	result->remote_addr_size = sizeof(struct sockaddr_un);
37562306a36Sopenharmony_ci	result->remote_addr = remote_addr;
37662306a36Sopenharmony_ci	return result;
37762306a36Sopenharmony_ciunix_cleanup:
37862306a36Sopenharmony_ci	if (fd >= 0)
37962306a36Sopenharmony_ci		os_close_file(fd);
38062306a36Sopenharmony_ci	kfree(remote_addr);
38162306a36Sopenharmony_ci	kfree(result);
38262306a36Sopenharmony_ci	return NULL;
38362306a36Sopenharmony_ci}
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_cistatic int strtofd(const char *nptr)
38662306a36Sopenharmony_ci{
38762306a36Sopenharmony_ci	long fd;
38862306a36Sopenharmony_ci	char *endptr;
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_ci	if (nptr == NULL)
39162306a36Sopenharmony_ci		return -1;
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_ci	errno = 0;
39462306a36Sopenharmony_ci	fd = strtol(nptr, &endptr, 10);
39562306a36Sopenharmony_ci	if (nptr == endptr ||
39662306a36Sopenharmony_ci		errno != 0 ||
39762306a36Sopenharmony_ci		*endptr != '\0' ||
39862306a36Sopenharmony_ci		fd < 0 ||
39962306a36Sopenharmony_ci		fd > INT_MAX) {
40062306a36Sopenharmony_ci		return -1;
40162306a36Sopenharmony_ci	}
40262306a36Sopenharmony_ci	return fd;
40362306a36Sopenharmony_ci}
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_cistatic struct vector_fds *user_init_fd_fds(struct arglist *ifspec)
40662306a36Sopenharmony_ci{
40762306a36Sopenharmony_ci	int fd = -1;
40862306a36Sopenharmony_ci	char *fdarg = NULL;
40962306a36Sopenharmony_ci	struct vector_fds *result = NULL;
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_ci	fdarg = uml_vector_fetch_arg(ifspec, "fd");
41262306a36Sopenharmony_ci	fd = strtofd(fdarg);
41362306a36Sopenharmony_ci	if (fd == -1) {
41462306a36Sopenharmony_ci		printk(UM_KERN_ERR "fd open: bad or missing fd argument");
41562306a36Sopenharmony_ci		goto fd_cleanup;
41662306a36Sopenharmony_ci	}
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_ci	result = uml_kmalloc(sizeof(struct vector_fds), UM_GFP_KERNEL);
41962306a36Sopenharmony_ci	if (result == NULL) {
42062306a36Sopenharmony_ci		printk(UM_KERN_ERR "fd open: allocation failed");
42162306a36Sopenharmony_ci		goto fd_cleanup;
42262306a36Sopenharmony_ci	}
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_ci	result->rx_fd = fd;
42562306a36Sopenharmony_ci	result->tx_fd = fd;
42662306a36Sopenharmony_ci	result->remote_addr_size = 0;
42762306a36Sopenharmony_ci	result->remote_addr = NULL;
42862306a36Sopenharmony_ci	return result;
42962306a36Sopenharmony_ci
43062306a36Sopenharmony_cifd_cleanup:
43162306a36Sopenharmony_ci	if (fd >= 0)
43262306a36Sopenharmony_ci		os_close_file(fd);
43362306a36Sopenharmony_ci	kfree(result);
43462306a36Sopenharmony_ci	return NULL;
43562306a36Sopenharmony_ci}
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_cistatic struct vector_fds *user_init_raw_fds(struct arglist *ifspec)
43862306a36Sopenharmony_ci{
43962306a36Sopenharmony_ci	int rxfd = -1, txfd = -1;
44062306a36Sopenharmony_ci	int err = -ENOMEM;
44162306a36Sopenharmony_ci	char *iface;
44262306a36Sopenharmony_ci	struct vector_fds *result = NULL;
44362306a36Sopenharmony_ci	char *argv[] = {NULL, NULL, NULL, NULL};
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_ci	iface = uml_vector_fetch_arg(ifspec, TOKEN_IFNAME);
44662306a36Sopenharmony_ci	if (iface == NULL)
44762306a36Sopenharmony_ci		goto raw_cleanup;
44862306a36Sopenharmony_ci
44962306a36Sopenharmony_ci	rxfd = create_raw_fd(iface, ETH_P_ALL, ETH_P_ALL);
45062306a36Sopenharmony_ci	if (rxfd == -1) {
45162306a36Sopenharmony_ci		err = -errno;
45262306a36Sopenharmony_ci		goto raw_cleanup;
45362306a36Sopenharmony_ci	}
45462306a36Sopenharmony_ci	txfd = create_raw_fd(iface, 0, ETH_P_IP); /* Turn off RX on this fd */
45562306a36Sopenharmony_ci	if (txfd == -1) {
45662306a36Sopenharmony_ci		err = -errno;
45762306a36Sopenharmony_ci		goto raw_cleanup;
45862306a36Sopenharmony_ci	}
45962306a36Sopenharmony_ci	result = uml_kmalloc(sizeof(struct vector_fds), UM_GFP_KERNEL);
46062306a36Sopenharmony_ci	if (result != NULL) {
46162306a36Sopenharmony_ci		result->rx_fd = rxfd;
46262306a36Sopenharmony_ci		result->tx_fd = txfd;
46362306a36Sopenharmony_ci		result->remote_addr = NULL;
46462306a36Sopenharmony_ci		result->remote_addr_size = 0;
46562306a36Sopenharmony_ci	}
46662306a36Sopenharmony_ci	argv[0] = uml_vector_fetch_arg(ifspec, TOKEN_SCRIPT);
46762306a36Sopenharmony_ci	if (argv[0]) {
46862306a36Sopenharmony_ci		argv[1] = iface;
46962306a36Sopenharmony_ci		run_helper(NULL, NULL, argv);
47062306a36Sopenharmony_ci	}
47162306a36Sopenharmony_ci	return result;
47262306a36Sopenharmony_ciraw_cleanup:
47362306a36Sopenharmony_ci	printk(UM_KERN_ERR "user_init_raw: init failed, error %d", err);
47462306a36Sopenharmony_ci	kfree(result);
47562306a36Sopenharmony_ci	return NULL;
47662306a36Sopenharmony_ci}
47762306a36Sopenharmony_ci
47862306a36Sopenharmony_ci
47962306a36Sopenharmony_cibool uml_raw_enable_qdisc_bypass(int fd)
48062306a36Sopenharmony_ci{
48162306a36Sopenharmony_ci	int optval = 1;
48262306a36Sopenharmony_ci
48362306a36Sopenharmony_ci	if (setsockopt(fd,
48462306a36Sopenharmony_ci		SOL_PACKET, PACKET_QDISC_BYPASS,
48562306a36Sopenharmony_ci		&optval, sizeof(optval)) != 0) {
48662306a36Sopenharmony_ci		return false;
48762306a36Sopenharmony_ci	}
48862306a36Sopenharmony_ci	return true;
48962306a36Sopenharmony_ci}
49062306a36Sopenharmony_ci
49162306a36Sopenharmony_cibool uml_raw_enable_vnet_headers(int fd)
49262306a36Sopenharmony_ci{
49362306a36Sopenharmony_ci	int optval = 1;
49462306a36Sopenharmony_ci
49562306a36Sopenharmony_ci	if (setsockopt(fd,
49662306a36Sopenharmony_ci		SOL_PACKET, PACKET_VNET_HDR,
49762306a36Sopenharmony_ci		&optval, sizeof(optval)) != 0) {
49862306a36Sopenharmony_ci		printk(UM_KERN_INFO VNET_HDR_FAIL, fd);
49962306a36Sopenharmony_ci		return false;
50062306a36Sopenharmony_ci	}
50162306a36Sopenharmony_ci	return true;
50262306a36Sopenharmony_ci}
50362306a36Sopenharmony_cibool uml_tap_enable_vnet_headers(int fd)
50462306a36Sopenharmony_ci{
50562306a36Sopenharmony_ci	unsigned int features;
50662306a36Sopenharmony_ci	int len = sizeof(struct virtio_net_hdr);
50762306a36Sopenharmony_ci
50862306a36Sopenharmony_ci	if (ioctl(fd, TUNGETFEATURES, &features) == -1) {
50962306a36Sopenharmony_ci		printk(UM_KERN_INFO TUN_GET_F_FAIL, strerror(errno));
51062306a36Sopenharmony_ci		return false;
51162306a36Sopenharmony_ci	}
51262306a36Sopenharmony_ci	if ((features & IFF_VNET_HDR) == 0) {
51362306a36Sopenharmony_ci		printk(UM_KERN_INFO "tapraw: No VNET HEADER support");
51462306a36Sopenharmony_ci		return false;
51562306a36Sopenharmony_ci	}
51662306a36Sopenharmony_ci	ioctl(fd, TUNSETVNETHDRSZ, &len);
51762306a36Sopenharmony_ci	return true;
51862306a36Sopenharmony_ci}
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_cistatic struct vector_fds *user_init_socket_fds(struct arglist *ifspec, int id)
52162306a36Sopenharmony_ci{
52262306a36Sopenharmony_ci	int err = -ENOMEM;
52362306a36Sopenharmony_ci	int fd = -1, gairet;
52462306a36Sopenharmony_ci	struct addrinfo srchints;
52562306a36Sopenharmony_ci	struct addrinfo dsthints;
52662306a36Sopenharmony_ci	bool v6, udp;
52762306a36Sopenharmony_ci	char *value;
52862306a36Sopenharmony_ci	char *src, *dst, *srcport, *dstport;
52962306a36Sopenharmony_ci	struct addrinfo *gairesult = NULL;
53062306a36Sopenharmony_ci	struct vector_fds *result = NULL;
53162306a36Sopenharmony_ci
53262306a36Sopenharmony_ci
53362306a36Sopenharmony_ci	value = uml_vector_fetch_arg(ifspec, "v6");
53462306a36Sopenharmony_ci	v6 = false;
53562306a36Sopenharmony_ci	udp = false;
53662306a36Sopenharmony_ci	if (value != NULL) {
53762306a36Sopenharmony_ci		if (strtol((const char *) value, NULL, 10) > 0)
53862306a36Sopenharmony_ci			v6 = true;
53962306a36Sopenharmony_ci	}
54062306a36Sopenharmony_ci
54162306a36Sopenharmony_ci	value = uml_vector_fetch_arg(ifspec, "udp");
54262306a36Sopenharmony_ci	if (value != NULL) {
54362306a36Sopenharmony_ci		if (strtol((const char *) value, NULL, 10) > 0)
54462306a36Sopenharmony_ci			udp = true;
54562306a36Sopenharmony_ci	}
54662306a36Sopenharmony_ci	src = uml_vector_fetch_arg(ifspec, "src");
54762306a36Sopenharmony_ci	dst = uml_vector_fetch_arg(ifspec, "dst");
54862306a36Sopenharmony_ci	srcport = uml_vector_fetch_arg(ifspec, "srcport");
54962306a36Sopenharmony_ci	dstport = uml_vector_fetch_arg(ifspec, "dstport");
55062306a36Sopenharmony_ci
55162306a36Sopenharmony_ci	memset(&dsthints, 0, sizeof(dsthints));
55262306a36Sopenharmony_ci
55362306a36Sopenharmony_ci	if (v6)
55462306a36Sopenharmony_ci		dsthints.ai_family = AF_INET6;
55562306a36Sopenharmony_ci	else
55662306a36Sopenharmony_ci		dsthints.ai_family = AF_INET;
55762306a36Sopenharmony_ci
55862306a36Sopenharmony_ci	switch (id) {
55962306a36Sopenharmony_ci	case ID_GRE:
56062306a36Sopenharmony_ci		dsthints.ai_socktype = SOCK_RAW;
56162306a36Sopenharmony_ci		dsthints.ai_protocol = IPPROTO_GRE;
56262306a36Sopenharmony_ci		break;
56362306a36Sopenharmony_ci	case ID_L2TPV3:
56462306a36Sopenharmony_ci		if (udp) {
56562306a36Sopenharmony_ci			dsthints.ai_socktype = SOCK_DGRAM;
56662306a36Sopenharmony_ci			dsthints.ai_protocol = 0;
56762306a36Sopenharmony_ci		} else {
56862306a36Sopenharmony_ci			dsthints.ai_socktype = SOCK_RAW;
56962306a36Sopenharmony_ci			dsthints.ai_protocol = IPPROTO_L2TP;
57062306a36Sopenharmony_ci		}
57162306a36Sopenharmony_ci		break;
57262306a36Sopenharmony_ci	default:
57362306a36Sopenharmony_ci		printk(KERN_ERR "Unsupported socket type\n");
57462306a36Sopenharmony_ci		return NULL;
57562306a36Sopenharmony_ci	}
57662306a36Sopenharmony_ci	memcpy(&srchints, &dsthints, sizeof(struct addrinfo));
57762306a36Sopenharmony_ci
57862306a36Sopenharmony_ci	gairet = getaddrinfo(src, srcport, &dsthints, &gairesult);
57962306a36Sopenharmony_ci	if ((gairet != 0) || (gairesult == NULL)) {
58062306a36Sopenharmony_ci		printk(UM_KERN_ERR
58162306a36Sopenharmony_ci			"socket_open : could not resolve src, error = %s",
58262306a36Sopenharmony_ci			gai_strerror(gairet)
58362306a36Sopenharmony_ci		);
58462306a36Sopenharmony_ci		return NULL;
58562306a36Sopenharmony_ci	}
58662306a36Sopenharmony_ci	fd = socket(gairesult->ai_family,
58762306a36Sopenharmony_ci		gairesult->ai_socktype, gairesult->ai_protocol);
58862306a36Sopenharmony_ci	if (fd == -1) {
58962306a36Sopenharmony_ci		printk(UM_KERN_ERR
59062306a36Sopenharmony_ci			"socket_open : could not open socket, error = %d",
59162306a36Sopenharmony_ci			-errno
59262306a36Sopenharmony_ci		);
59362306a36Sopenharmony_ci		goto cleanup;
59462306a36Sopenharmony_ci	}
59562306a36Sopenharmony_ci	if (bind(fd,
59662306a36Sopenharmony_ci		(struct sockaddr *) gairesult->ai_addr,
59762306a36Sopenharmony_ci		gairesult->ai_addrlen)) {
59862306a36Sopenharmony_ci		printk(UM_KERN_ERR L2TPV3_BIND_FAIL, errno);
59962306a36Sopenharmony_ci		goto cleanup;
60062306a36Sopenharmony_ci	}
60162306a36Sopenharmony_ci
60262306a36Sopenharmony_ci	if (gairesult != NULL)
60362306a36Sopenharmony_ci		freeaddrinfo(gairesult);
60462306a36Sopenharmony_ci
60562306a36Sopenharmony_ci	gairesult = NULL;
60662306a36Sopenharmony_ci
60762306a36Sopenharmony_ci	gairet = getaddrinfo(dst, dstport, &dsthints, &gairesult);
60862306a36Sopenharmony_ci	if ((gairet != 0) || (gairesult == NULL)) {
60962306a36Sopenharmony_ci		printk(UM_KERN_ERR
61062306a36Sopenharmony_ci			"socket_open : could not resolve dst, error = %s",
61162306a36Sopenharmony_ci			gai_strerror(gairet)
61262306a36Sopenharmony_ci		);
61362306a36Sopenharmony_ci		return NULL;
61462306a36Sopenharmony_ci	}
61562306a36Sopenharmony_ci
61662306a36Sopenharmony_ci	result = uml_kmalloc(sizeof(struct vector_fds), UM_GFP_KERNEL);
61762306a36Sopenharmony_ci	if (result != NULL) {
61862306a36Sopenharmony_ci		result->rx_fd = fd;
61962306a36Sopenharmony_ci		result->tx_fd = fd;
62062306a36Sopenharmony_ci		result->remote_addr = uml_kmalloc(
62162306a36Sopenharmony_ci			gairesult->ai_addrlen, UM_GFP_KERNEL);
62262306a36Sopenharmony_ci		if (result->remote_addr == NULL)
62362306a36Sopenharmony_ci			goto cleanup;
62462306a36Sopenharmony_ci		result->remote_addr_size = gairesult->ai_addrlen;
62562306a36Sopenharmony_ci		memcpy(
62662306a36Sopenharmony_ci			result->remote_addr,
62762306a36Sopenharmony_ci			gairesult->ai_addr,
62862306a36Sopenharmony_ci			gairesult->ai_addrlen
62962306a36Sopenharmony_ci		);
63062306a36Sopenharmony_ci	}
63162306a36Sopenharmony_ci	freeaddrinfo(gairesult);
63262306a36Sopenharmony_ci	return result;
63362306a36Sopenharmony_cicleanup:
63462306a36Sopenharmony_ci	if (gairesult != NULL)
63562306a36Sopenharmony_ci		freeaddrinfo(gairesult);
63662306a36Sopenharmony_ci	printk(UM_KERN_ERR "user_init_socket: init failed, error %d", err);
63762306a36Sopenharmony_ci	if (fd >= 0)
63862306a36Sopenharmony_ci		os_close_file(fd);
63962306a36Sopenharmony_ci	if (result != NULL) {
64062306a36Sopenharmony_ci		kfree(result->remote_addr);
64162306a36Sopenharmony_ci		kfree(result);
64262306a36Sopenharmony_ci	}
64362306a36Sopenharmony_ci	return NULL;
64462306a36Sopenharmony_ci}
64562306a36Sopenharmony_ci
64662306a36Sopenharmony_cistruct vector_fds *uml_vector_user_open(
64762306a36Sopenharmony_ci	int unit,
64862306a36Sopenharmony_ci	struct arglist *parsed
64962306a36Sopenharmony_ci)
65062306a36Sopenharmony_ci{
65162306a36Sopenharmony_ci	char *transport;
65262306a36Sopenharmony_ci
65362306a36Sopenharmony_ci	if (parsed == NULL) {
65462306a36Sopenharmony_ci		printk(UM_KERN_ERR "no parsed config for unit %d\n", unit);
65562306a36Sopenharmony_ci		return NULL;
65662306a36Sopenharmony_ci	}
65762306a36Sopenharmony_ci	transport = uml_vector_fetch_arg(parsed, "transport");
65862306a36Sopenharmony_ci	if (transport == NULL) {
65962306a36Sopenharmony_ci		printk(UM_KERN_ERR "missing transport for unit %d\n", unit);
66062306a36Sopenharmony_ci		return NULL;
66162306a36Sopenharmony_ci	}
66262306a36Sopenharmony_ci	if (strncmp(transport, TRANS_RAW, TRANS_RAW_LEN) == 0)
66362306a36Sopenharmony_ci		return user_init_raw_fds(parsed);
66462306a36Sopenharmony_ci	if (strncmp(transport, TRANS_HYBRID, TRANS_HYBRID_LEN) == 0)
66562306a36Sopenharmony_ci		return user_init_hybrid_fds(parsed);
66662306a36Sopenharmony_ci	if (strncmp(transport, TRANS_TAP, TRANS_TAP_LEN) == 0)
66762306a36Sopenharmony_ci		return user_init_tap_fds(parsed);
66862306a36Sopenharmony_ci	if (strncmp(transport, TRANS_GRE, TRANS_GRE_LEN) == 0)
66962306a36Sopenharmony_ci		return user_init_socket_fds(parsed, ID_GRE);
67062306a36Sopenharmony_ci	if (strncmp(transport, TRANS_L2TPV3, TRANS_L2TPV3_LEN) == 0)
67162306a36Sopenharmony_ci		return user_init_socket_fds(parsed, ID_L2TPV3);
67262306a36Sopenharmony_ci	if (strncmp(transport, TRANS_BESS, TRANS_BESS_LEN) == 0)
67362306a36Sopenharmony_ci		return user_init_unix_fds(parsed, ID_BESS);
67462306a36Sopenharmony_ci	if (strncmp(transport, TRANS_FD, TRANS_FD_LEN) == 0)
67562306a36Sopenharmony_ci		return user_init_fd_fds(parsed);
67662306a36Sopenharmony_ci	return NULL;
67762306a36Sopenharmony_ci}
67862306a36Sopenharmony_ci
67962306a36Sopenharmony_ci
68062306a36Sopenharmony_ciint uml_vector_sendmsg(int fd, void *hdr, int flags)
68162306a36Sopenharmony_ci{
68262306a36Sopenharmony_ci	int n;
68362306a36Sopenharmony_ci
68462306a36Sopenharmony_ci	CATCH_EINTR(n = sendmsg(fd, (struct msghdr *) hdr,  flags));
68562306a36Sopenharmony_ci	if ((n < 0) && (errno == EAGAIN))
68662306a36Sopenharmony_ci		return 0;
68762306a36Sopenharmony_ci	if (n >= 0)
68862306a36Sopenharmony_ci		return n;
68962306a36Sopenharmony_ci	else
69062306a36Sopenharmony_ci		return -errno;
69162306a36Sopenharmony_ci}
69262306a36Sopenharmony_ci
69362306a36Sopenharmony_ciint uml_vector_recvmsg(int fd, void *hdr, int flags)
69462306a36Sopenharmony_ci{
69562306a36Sopenharmony_ci	int n;
69662306a36Sopenharmony_ci	struct msghdr *msg = (struct msghdr *) hdr;
69762306a36Sopenharmony_ci
69862306a36Sopenharmony_ci	CATCH_EINTR(n = readv(fd, msg->msg_iov, msg->msg_iovlen));
69962306a36Sopenharmony_ci	if ((n < 0) && (errno == EAGAIN))
70062306a36Sopenharmony_ci		return 0;
70162306a36Sopenharmony_ci	if (n >= 0)
70262306a36Sopenharmony_ci		return n;
70362306a36Sopenharmony_ci	else
70462306a36Sopenharmony_ci		return -errno;
70562306a36Sopenharmony_ci}
70662306a36Sopenharmony_ci
70762306a36Sopenharmony_ciint uml_vector_writev(int fd, void *hdr, int iovcount)
70862306a36Sopenharmony_ci{
70962306a36Sopenharmony_ci	int n;
71062306a36Sopenharmony_ci
71162306a36Sopenharmony_ci	CATCH_EINTR(n = writev(fd, (struct iovec *) hdr,  iovcount));
71262306a36Sopenharmony_ci	if ((n < 0) && ((errno == EAGAIN) || (errno == ENOBUFS)))
71362306a36Sopenharmony_ci		return 0;
71462306a36Sopenharmony_ci	if (n >= 0)
71562306a36Sopenharmony_ci		return n;
71662306a36Sopenharmony_ci	else
71762306a36Sopenharmony_ci		return -errno;
71862306a36Sopenharmony_ci}
71962306a36Sopenharmony_ci
72062306a36Sopenharmony_ciint uml_vector_sendmmsg(
72162306a36Sopenharmony_ci	int fd,
72262306a36Sopenharmony_ci	void *msgvec,
72362306a36Sopenharmony_ci	unsigned int vlen,
72462306a36Sopenharmony_ci	unsigned int flags)
72562306a36Sopenharmony_ci{
72662306a36Sopenharmony_ci	int n;
72762306a36Sopenharmony_ci
72862306a36Sopenharmony_ci	CATCH_EINTR(n = sendmmsg(fd, (struct mmsghdr *) msgvec, vlen, flags));
72962306a36Sopenharmony_ci	if ((n < 0) && ((errno == EAGAIN) || (errno == ENOBUFS)))
73062306a36Sopenharmony_ci		return 0;
73162306a36Sopenharmony_ci	if (n >= 0)
73262306a36Sopenharmony_ci		return n;
73362306a36Sopenharmony_ci	else
73462306a36Sopenharmony_ci		return -errno;
73562306a36Sopenharmony_ci}
73662306a36Sopenharmony_ci
73762306a36Sopenharmony_ciint uml_vector_recvmmsg(
73862306a36Sopenharmony_ci	int fd,
73962306a36Sopenharmony_ci	void *msgvec,
74062306a36Sopenharmony_ci	unsigned int vlen,
74162306a36Sopenharmony_ci	unsigned int flags)
74262306a36Sopenharmony_ci{
74362306a36Sopenharmony_ci	int n;
74462306a36Sopenharmony_ci
74562306a36Sopenharmony_ci	CATCH_EINTR(
74662306a36Sopenharmony_ci		n = recvmmsg(fd, (struct mmsghdr *) msgvec, vlen, flags, 0));
74762306a36Sopenharmony_ci	if ((n < 0) && (errno == EAGAIN))
74862306a36Sopenharmony_ci		return 0;
74962306a36Sopenharmony_ci	if (n >= 0)
75062306a36Sopenharmony_ci		return n;
75162306a36Sopenharmony_ci	else
75262306a36Sopenharmony_ci		return -errno;
75362306a36Sopenharmony_ci}
75462306a36Sopenharmony_ciint uml_vector_attach_bpf(int fd, void *bpf)
75562306a36Sopenharmony_ci{
75662306a36Sopenharmony_ci	struct sock_fprog *prog = bpf;
75762306a36Sopenharmony_ci
75862306a36Sopenharmony_ci	int err = setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, bpf, sizeof(struct sock_fprog));
75962306a36Sopenharmony_ci
76062306a36Sopenharmony_ci	if (err < 0)
76162306a36Sopenharmony_ci		printk(KERN_ERR BPF_ATTACH_FAIL, prog->len, prog->filter, fd, -errno);
76262306a36Sopenharmony_ci	return err;
76362306a36Sopenharmony_ci}
76462306a36Sopenharmony_ci
76562306a36Sopenharmony_ciint uml_vector_detach_bpf(int fd, void *bpf)
76662306a36Sopenharmony_ci{
76762306a36Sopenharmony_ci	struct sock_fprog *prog = bpf;
76862306a36Sopenharmony_ci
76962306a36Sopenharmony_ci	int err = setsockopt(fd, SOL_SOCKET, SO_DETACH_FILTER, bpf, sizeof(struct sock_fprog));
77062306a36Sopenharmony_ci	if (err < 0)
77162306a36Sopenharmony_ci		printk(KERN_ERR BPF_DETACH_FAIL, prog->len, prog->filter, fd, -errno);
77262306a36Sopenharmony_ci	return err;
77362306a36Sopenharmony_ci}
77462306a36Sopenharmony_civoid *uml_vector_default_bpf(const void *mac)
77562306a36Sopenharmony_ci{
77662306a36Sopenharmony_ci	struct sock_filter *bpf;
77762306a36Sopenharmony_ci	uint32_t *mac1 = (uint32_t *)(mac + 2);
77862306a36Sopenharmony_ci	uint16_t *mac2 = (uint16_t *) mac;
77962306a36Sopenharmony_ci	struct sock_fprog *bpf_prog;
78062306a36Sopenharmony_ci
78162306a36Sopenharmony_ci	bpf_prog = uml_kmalloc(sizeof(struct sock_fprog), UM_GFP_KERNEL);
78262306a36Sopenharmony_ci	if (bpf_prog) {
78362306a36Sopenharmony_ci		bpf_prog->len = DEFAULT_BPF_LEN;
78462306a36Sopenharmony_ci		bpf_prog->filter = NULL;
78562306a36Sopenharmony_ci	} else {
78662306a36Sopenharmony_ci		return NULL;
78762306a36Sopenharmony_ci	}
78862306a36Sopenharmony_ci	bpf = uml_kmalloc(
78962306a36Sopenharmony_ci		sizeof(struct sock_filter) * DEFAULT_BPF_LEN, UM_GFP_KERNEL);
79062306a36Sopenharmony_ci	if (bpf) {
79162306a36Sopenharmony_ci		bpf_prog->filter = bpf;
79262306a36Sopenharmony_ci		/* ld	[8] */
79362306a36Sopenharmony_ci		bpf[0] = (struct sock_filter){ 0x20, 0, 0, 0x00000008 };
79462306a36Sopenharmony_ci		/* jeq	#0xMAC[2-6] jt 2 jf 5*/
79562306a36Sopenharmony_ci		bpf[1] = (struct sock_filter){ 0x15, 0, 3, ntohl(*mac1)};
79662306a36Sopenharmony_ci		/* ldh	[6] */
79762306a36Sopenharmony_ci		bpf[2] = (struct sock_filter){ 0x28, 0, 0, 0x00000006 };
79862306a36Sopenharmony_ci		/* jeq	#0xMAC[0-1] jt 4 jf 5 */
79962306a36Sopenharmony_ci		bpf[3] = (struct sock_filter){ 0x15, 0, 1, ntohs(*mac2)};
80062306a36Sopenharmony_ci		/* ret	#0 */
80162306a36Sopenharmony_ci		bpf[4] = (struct sock_filter){ 0x6, 0, 0, 0x00000000 };
80262306a36Sopenharmony_ci		/* ret	#0x40000 */
80362306a36Sopenharmony_ci		bpf[5] = (struct sock_filter){ 0x6, 0, 0, 0x00040000 };
80462306a36Sopenharmony_ci	} else {
80562306a36Sopenharmony_ci		kfree(bpf_prog);
80662306a36Sopenharmony_ci		bpf_prog = NULL;
80762306a36Sopenharmony_ci	}
80862306a36Sopenharmony_ci	return bpf_prog;
80962306a36Sopenharmony_ci}
81062306a36Sopenharmony_ci
81162306a36Sopenharmony_ci/* Note - this function requires a valid mac being passed as an arg */
81262306a36Sopenharmony_ci
81362306a36Sopenharmony_civoid *uml_vector_user_bpf(char *filename)
81462306a36Sopenharmony_ci{
81562306a36Sopenharmony_ci	struct sock_filter *bpf;
81662306a36Sopenharmony_ci	struct sock_fprog *bpf_prog;
81762306a36Sopenharmony_ci	struct stat statbuf;
81862306a36Sopenharmony_ci	int res, ffd = -1;
81962306a36Sopenharmony_ci
82062306a36Sopenharmony_ci	if (filename == NULL)
82162306a36Sopenharmony_ci		return NULL;
82262306a36Sopenharmony_ci
82362306a36Sopenharmony_ci	if (stat(filename, &statbuf) < 0) {
82462306a36Sopenharmony_ci		printk(KERN_ERR "Error %d reading bpf file", -errno);
82562306a36Sopenharmony_ci		return false;
82662306a36Sopenharmony_ci	}
82762306a36Sopenharmony_ci	bpf_prog = uml_kmalloc(sizeof(struct sock_fprog), UM_GFP_KERNEL);
82862306a36Sopenharmony_ci	if (bpf_prog == NULL) {
82962306a36Sopenharmony_ci		printk(KERN_ERR "Failed to allocate bpf prog buffer");
83062306a36Sopenharmony_ci		return NULL;
83162306a36Sopenharmony_ci	}
83262306a36Sopenharmony_ci	bpf_prog->len = statbuf.st_size / sizeof(struct sock_filter);
83362306a36Sopenharmony_ci	bpf_prog->filter = NULL;
83462306a36Sopenharmony_ci	ffd = os_open_file(filename, of_read(OPENFLAGS()), 0);
83562306a36Sopenharmony_ci	if (ffd < 0) {
83662306a36Sopenharmony_ci		printk(KERN_ERR "Error %d opening bpf file", -errno);
83762306a36Sopenharmony_ci		goto bpf_failed;
83862306a36Sopenharmony_ci	}
83962306a36Sopenharmony_ci	bpf = uml_kmalloc(statbuf.st_size, UM_GFP_KERNEL);
84062306a36Sopenharmony_ci	if (bpf == NULL) {
84162306a36Sopenharmony_ci		printk(KERN_ERR "Failed to allocate bpf buffer");
84262306a36Sopenharmony_ci		goto bpf_failed;
84362306a36Sopenharmony_ci	}
84462306a36Sopenharmony_ci	bpf_prog->filter = bpf;
84562306a36Sopenharmony_ci	res = os_read_file(ffd, bpf, statbuf.st_size);
84662306a36Sopenharmony_ci	if (res < statbuf.st_size) {
84762306a36Sopenharmony_ci		printk(KERN_ERR "Failed to read bpf program %s, error %d", filename, res);
84862306a36Sopenharmony_ci		kfree(bpf);
84962306a36Sopenharmony_ci		goto bpf_failed;
85062306a36Sopenharmony_ci	}
85162306a36Sopenharmony_ci	os_close_file(ffd);
85262306a36Sopenharmony_ci	return bpf_prog;
85362306a36Sopenharmony_cibpf_failed:
85462306a36Sopenharmony_ci	if (ffd > 0)
85562306a36Sopenharmony_ci		os_close_file(ffd);
85662306a36Sopenharmony_ci	kfree(bpf_prog);
85762306a36Sopenharmony_ci	return NULL;
85862306a36Sopenharmony_ci}
859