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