// 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 TRANS_VDE "vde"#define TRANS_VDE_LEN strlen(TRANS_VDE) #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 = -errno; goto raw_fd_cleanup; } sock.sll_family = AF_PACKET; sock.sll_protocol = htons(proto); sock.sll_ifindex = ifr.ifr_ifindex; if (bind(fd, (struct sockaddr *) &sock, sizeof(struct sockaddr_ll)) < 0) { err = -errno; goto raw_fd_cleanup; } return fd;raw_fd_cleanup: printk(UM_KERN_ERR "user_init_raw: init failed, error %d", err); if (fd >= 0) os_close_file(fd); return err;} static struct vector_fds *user_init_tap_fds(struct arglist *ifspec){ int fd = -1, i; char *iface; struct vector_fds *result = NULL; bool dynamic = false; char dynamic_ifname[IFNAMSIZ]; char *argv[] = {NULL, NULL, NULL, NULL}; iface = uml_vector_fetch_arg(ifspec, TOKEN_IFNAME); if (iface == NULL) { dynamic = true; iface = dynamic_ifname; srand(getpid()); } result = uml_kmalloc(sizeof(struct vector_fds), UM_GFP_KERNEL); if (result == NULL) { printk(UM_KERN_ERR "uml_tap: failed to allocate file descriptors\n"); goto tap_cleanup; } result->rx_fd = -1; result->tx_fd = -1; result->remote_addr = NULL; result->remote_addr_size = 0; /* TAP */ do { if (dynamic) { strcpy(iface, template); for (i = 0; i < strlen(iface); i++) { if (iface[i] == 'X') { iface[i] = padchar[rand() % strlen(padchar)]; } } } fd = create_tap_fd(iface); if ((fd < 0) && (!dynamic)) { printk(UM_KERN_ERR "uml_tap: failed to create tun interface\n"); goto tap_cleanup; } result->tx_fd = fd; result->rx_fd = fd; } while (fd < 0); argv[0] = uml_vector_fetch_arg(ifspec, TOKEN_SCRIPT); if (argv[0]) { argv[1] = iface; run_helper(NULL, NULL, argv); } return result;tap_cleanup: printk(UM_KERN_ERR "user_init_tap: init failed, error %d", fd); kfree(result); return NULL;} static struct vector_fds *user_init_hybrid_fds(struct arglist *ifspec){ char *iface; struct vector_fds *result = NULL; char *argv[] = {NULL, NULL, NULL, NULL}; iface = uml_vector_fetch_arg(ifspec, TOKEN_IFNAME); if (iface == NULL) { printk(UM_KERN_ERR "uml_tap: failed to parse interface spec\n"); goto hybrid_cleanup; } result = uml_kmalloc(sizeof(struct vector_fds), UM_GFP_KERNEL); if (result == NULL) { printk(UM_KERN_ERR "uml_tap: failed to allocate file descriptors\n"); goto hybrid_cleanup; } result->rx_fd = -1; result->tx_fd = -1; result->remote_addr = NULL; result->remote_addr_size = 0; /* TAP */ result->tx_fd = create_tap_fd(iface); if (result->tx_fd < 0) { printk(UM_KERN_ERR "uml_tap: failed to create tun interface: %i\n", result->tx_fd); goto hybrid_cleanup; } /* RAW */ result->rx_fd = create_raw_fd(iface, ETH_P_ALL, ETH_P_ALL); if (result->rx_fd == -1) { printk(UM_KERN_ERR "uml_tap: failed to create paired raw socket: %i\n", result->rx_fd); goto hybrid_cleanup; } argv[0] = uml_vector_fetch_arg(ifspec, TOKEN_SCRIPT); if (argv[0]) { argv[1] = iface; run_helper(NULL, NULL, argv); } return result;hybrid_cleanup: printk(UM_KERN_ERR "user_init_hybrid: init failed"); kfree(result); return NULL;} static struct vector_fds *user_init_unix_fds(struct arglist *ifspec, int id){ int fd = -1; int socktype; char *src, *dst; struct vector_fds *result = NULL; struct sockaddr_un *local_addr = NULL, *remote_addr = NULL; src = uml_vector_fetch_arg(ifspec, "src"); dst = uml_vector_fetch_arg(ifspec, "dst"); result = uml_kmalloc(sizeof(struct vector_fds), UM_GFP_KERNEL); if (result == NULL) { printk(UM_KERN_ERR "unix open:cannot allocate remote addr"); goto unix_cleanup; } remote_addr = uml_kmalloc(sizeof(struct sockaddr_un), UM_GFP_KERNEL); if (remote_addr == NULL) { printk(UM_KERN_ERR "unix open:cannot allocate remote addr"); goto unix_cleanup; } switch (id) { case ID_BESS: socktype = SOCK_SEQPACKET; if ((src != NULL) && (strlen(src) <= MAX_UN_LEN)) { local_addr = uml_kmalloc(sizeof(struct sockaddr_un), UM_GFP_KERNEL); if (local_addr == NULL) { printk(UM_KERN_ERR "bess open:cannot allocate local addr"); goto unix_cleanup; } local_addr->sun_family = AF_UNIX; memcpy(local_addr->sun_path, src, strlen(src) + 1); } if ((dst == NULL) || (strlen(dst) > MAX_UN_LEN)) goto unix_cleanup; remote_addr->sun_family = AF_UNIX; memcpy(remote_addr->sun_path, dst, strlen(dst) + 1); break; default: printk(KERN_ERR "Unsupported unix socket type\n"); return NULL; } fd = socket(AF_UNIX, socktype, 0); if (fd == -1) { printk(UM_KERN_ERR "unix open: could not open socket, error = %d", -errno ); goto unix_cleanup; } if (local_addr != NULL) { if (bind(fd, (struct sockaddr *) local_addr, sizeof(struct sockaddr_un))) { printk(UM_KERN_ERR UNIX_BIND_FAIL, errno); goto unix_cleanup; } } switch (id) { case ID_BESS: if (connect(fd, (const struct sockaddr *) remote_addr, sizeof(struct sockaddr_un)) < 0) { printk(UM_KERN_ERR "bess open:cannot connect to %s %i", remote_addr->sun_path, -errno); goto unix_cleanup; } break; } result->rx_fd = fd; result->tx_fd = fd; result->remote_addr_size = sizeof(struct sockaddr_un); result->remote_addr = remote_addr; return result;unix_cleanup: if (fd >= 0) os_close_file(fd); kfree(remote_addr); kfree(result); return NULL;} static int strtofd(const char *nptr){ long fd; char *endptr; if (nptr == NULL) return -1; errno = 0; fd = strtol(nptr, &endptr, 10); if (nptr == endptr || errno != 0 || *endptr != '\0' || fd < 0 || fd > INT_MAX) { return -1; } return fd;} static struct vector_fds *user_init_fd_fds(struct arglist *ifspec){ int fd = -1; char *fdarg = NULL; struct vector_fds *result = NULL; fdarg = uml_vector_fetch_arg(ifspec, "fd"); fd = strtofd(fdarg); if (fd == -1) { printk(UM_KERN_ERR "fd open: bad or missing fd argument"); goto fd_cleanup; } result = uml_kmalloc(sizeof(struct vector_fds), UM_GFP_KERNEL); if (result == NULL) { printk(UM_KERN_ERR "fd open: allocation failed"); goto fd_cleanup; } result->rx_fd = fd; result->tx_fd = fd; result->remote_addr_size = 0; result->remote_addr = NULL; return result; fd_cleanup: if (fd >= 0) os_close_file(fd); kfree(result); return NULL;} /* enough char to store an int type */#define ENOUGH(type) ((CHAR_BIT * sizeof(type) - 1) / 3 + 2)#define ENOUGH_OCTAL(type) ((CHAR_BIT * sizeof(type) + 2) / 3)/* vde_plug --descr xx --port2 xx --mod2 xx --group2 xx seqpacket://NN vnl (NULL) */#define VDE_MAX_ARGC 12#define VDE_SEQPACKET_HEAD "seqpacket://"#define VDE_SEQPACKET_HEAD_LEN (sizeof(VDE_SEQPACKET_HEAD) - 1)#define VDE_DEFAULT_DESCRIPTION "UML" static struct vector_fds *user_init_vde_fds(struct arglist *ifspec){ char seqpacketvnl[VDE_SEQPACKET_HEAD_LEN + ENOUGH(int) + 1]; char *argv[VDE_MAX_ARGC] = {"vde_plug"}; int argc = 1; int rv; int sv[2]; struct vector_fds *result = NULL; char *vnl = uml_vector_fetch_arg(ifspec,"vnl"); char *descr = uml_vector_fetch_arg(ifspec,"descr"); char *port = uml_vector_fetch_arg(ifspec,"port"); char *mode = uml_vector_fetch_arg(ifspec,"mode"); char *group = uml_vector_fetch_arg(ifspec,"group"); if (descr == NULL) descr = VDE_DEFAULT_DESCRIPTION; argv[argc++] = "--descr"; argv[argc++] = descr; if (port != NULL) { argv[argc++] = "--port2"; argv[argc++] = port; } if (mode != NULL) { argv[argc++] = "--mod2"; argv[argc++] = mode; } if (group != NULL) { argv[argc++] = "--group2"; argv[argc++] = group; } argv[argc++] = seqpacketvnl; argv[argc++] = vnl; argv[argc++] = NULL; rv = socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sv); if (rv < 0) { printk(UM_KERN_ERR "vde: seqpacket socketpair err %d", -errno); return NULL; } rv = os_set_exec_close(sv[0]); if (rv < 0) { printk(UM_KERN_ERR "vde: seqpacket socketpair cloexec err %d", -errno); goto vde_cleanup_sv; } snprintf(seqpacketvnl, sizeof(seqpacketvnl), VDE_SEQPACKET_HEAD "%d", sv[1]); run_helper(NULL, NULL, argv); close(sv[1]); result = uml_kmalloc(sizeof(struct vector_fds), UM_GFP_KERNEL); if (result == NULL) {Lines 1–500 of 941. Load more
// 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 TRANS_VDE "vde" #define TRANS_VDE_LEN strlen(TRANS_VDE) #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 = -errno; goto raw_fd_cleanup; } sock.sll_family = AF_PACKET; sock.sll_protocol = htons(proto); sock.sll_ifindex = ifr.ifr_ifindex; if (bind(fd, (struct sockaddr *) &sock, sizeof(struct sockaddr_ll)) < 0) { err = -errno; goto raw_fd_cleanup; } return fd; raw_fd_cleanup: printk(UM_KERN_ERR "user_init_raw: init failed, error %d", err); if (fd >= 0) os_close_file(fd); return err; } static struct vector_fds *user_init_tap_fds(struct arglist *ifspec) { int fd = -1, i; char *iface; struct vector_fds *result = NULL; bool dynamic = false; char dynamic_ifname[IFNAMSIZ]; char *argv[] = {NULL, NULL, NULL, NULL}; iface = uml_vector_fetch_arg(ifspec, TOKEN_IFNAME); if (iface == NULL) { dynamic = true; iface = dynamic_ifname; srand(getpid()); } result = uml_kmalloc(sizeof(struct vector_fds), UM_GFP_KERNEL); if (result == NULL) { printk(UM_KERN_ERR "uml_tap: failed to allocate file descriptors\n"); goto tap_cleanup; } result->rx_fd = -1; result->tx_fd = -1; result->remote_addr = NULL; result->remote_addr_size = 0; /* TAP */ do { if (dynamic) { strcpy(iface, template); for (i = 0; i < strlen(iface); i++) { if (iface[i] == 'X') { iface[i] = padchar[rand() % strlen(padchar)]; } } } fd = create_tap_fd(iface); if ((fd < 0) && (!dynamic)) { printk(UM_KERN_ERR "uml_tap: failed to create tun interface\n"); goto tap_cleanup; } result->tx_fd = fd; result->rx_fd = fd; } while (fd < 0); argv[0] = uml_vector_fetch_arg(ifspec, TOKEN_SCRIPT); if (argv[0]) { argv[1] = iface; run_helper(NULL, NULL, argv); } return result; tap_cleanup: printk(UM_KERN_ERR "user_init_tap: init failed, error %d", fd); kfree(result); return NULL; } static struct vector_fds *user_init_hybrid_fds(struct arglist *ifspec) { char *iface; struct vector_fds *result = NULL; char *argv[] = {NULL, NULL, NULL, NULL}; iface = uml_vector_fetch_arg(ifspec, TOKEN_IFNAME); if (iface == NULL) { printk(UM_KERN_ERR "uml_tap: failed to parse interface spec\n"); goto hybrid_cleanup; } result = uml_kmalloc(sizeof(struct vector_fds), UM_GFP_KERNEL); if (result == NULL) { printk(UM_KERN_ERR "uml_tap: failed to allocate file descriptors\n"); goto hybrid_cleanup; } result->rx_fd = -1; result->tx_fd = -1; result->remote_addr = NULL; result->remote_addr_size = 0; /* TAP */ result->tx_fd = create_tap_fd(iface); if (result->tx_fd < 0) { printk(UM_KERN_ERR "uml_tap: failed to create tun interface: %i\n", result->tx_fd); goto hybrid_cleanup; } /* RAW */ result->rx_fd = create_raw_fd(iface, ETH_P_ALL, ETH_P_ALL); if (result->rx_fd == -1) { printk(UM_KERN_ERR "uml_tap: failed to create paired raw socket: %i\n", result->rx_fd); goto hybrid_cleanup; } argv[0] = uml_vector_fetch_arg(ifspec, TOKEN_SCRIPT); if (argv[0]) { argv[1] = iface; run_helper(NULL, NULL, argv); } return result; hybrid_cleanup: printk(UM_KERN_ERR "user_init_hybrid: init failed"); kfree(result); return NULL; } static struct vector_fds *user_init_unix_fds(struct arglist *ifspec, int id) { int fd = -1; int socktype; char *src, *dst; struct vector_fds *result = NULL; struct sockaddr_un *local_addr = NULL, *remote_addr = NULL; src = uml_vector_fetch_arg(ifspec, "src"); dst = uml_vector_fetch_arg(ifspec, "dst"); result = uml_kmalloc(sizeof(struct vector_fds), UM_GFP_KERNEL); if (result == NULL) { printk(UM_KERN_ERR "unix open:cannot allocate remote addr"); goto unix_cleanup; } remote_addr = uml_kmalloc(sizeof(struct sockaddr_un), UM_GFP_KERNEL); if (remote_addr == NULL) { printk(UM_KERN_ERR "unix open:cannot allocate remote addr"); goto unix_cleanup; } switch (id) { case ID_BESS: socktype = SOCK_SEQPACKET; if ((src != NULL) && (strlen(src) <= MAX_UN_LEN)) { local_addr = uml_kmalloc(sizeof(struct sockaddr_un), UM_GFP_KERNEL); if (local_addr == NULL) { printk(UM_KERN_ERR "bess open:cannot allocate local addr"); goto unix_cleanup; } local_addr->sun_family = AF_UNIX; memcpy(local_addr->sun_path, src, strlen(src) + 1); } if ((dst == NULL) || (strlen(dst) > MAX_UN_LEN)) goto unix_cleanup; remote_addr->sun_family = AF_UNIX; memcpy(remote_addr->sun_path, dst, strlen(dst) + 1); break; default: printk(KERN_ERR "Unsupported unix socket type\n"); return NULL; } fd = socket(AF_UNIX, socktype, 0); if (fd == -1) { printk(UM_KERN_ERR "unix open: could not open socket, error = %d", -errno ); goto unix_cleanup; } if (local_addr != NULL) { if (bind(fd, (struct sockaddr *) local_addr, sizeof(struct sockaddr_un))) { printk(UM_KERN_ERR UNIX_BIND_FAIL, errno); goto unix_cleanup; } } switch (id) { case ID_BESS: if (connect(fd, (const struct sockaddr *) remote_addr, sizeof(struct sockaddr_un)) < 0) { printk(UM_KERN_ERR "bess open:cannot connect to %s %i", remote_addr->sun_path, -errno); goto unix_cleanup; } break; } result->rx_fd = fd; result->tx_fd = fd; result->remote_addr_size = sizeof(struct sockaddr_un); result->remote_addr = remote_addr; return result; unix_cleanup: if (fd >= 0) os_close_file(fd); kfree(remote_addr); kfree(result); return NULL; } static int strtofd(const char *nptr) { long fd; char *endptr; if (nptr == NULL) return -1; errno = 0; fd = strtol(nptr, &endptr, 10); if (nptr == endptr || errno != 0 || *endptr != '\0' || fd < 0 || fd > INT_MAX) { return -1; } return fd; } static struct vector_fds *user_init_fd_fds(struct arglist *ifspec) { int fd = -1; char *fdarg = NULL; struct vector_fds *result = NULL; fdarg = uml_vector_fetch_arg(ifspec, "fd"); fd = strtofd(fdarg); if (fd == -1) { printk(UM_KERN_ERR "fd open: bad or missing fd argument"); goto fd_cleanup; } result = uml_kmalloc(sizeof(struct vector_fds), UM_GFP_KERNEL); if (result == NULL) { printk(UM_KERN_ERR "fd open: allocation failed"); goto fd_cleanup; } result->rx_fd = fd; result->tx_fd = fd; result->remote_addr_size = 0; result->remote_addr = NULL; return result; fd_cleanup: if (fd >= 0) os_close_file(fd); kfree(result); return NULL; } /* enough char to store an int type */ #define ENOUGH(type) ((CHAR_BIT * sizeof(type) - 1) / 3 + 2) #define ENOUGH_OCTAL(type) ((CHAR_BIT * sizeof(type) + 2) / 3) /* vde_plug --descr xx --port2 xx --mod2 xx --group2 xx seqpacket://NN vnl (NULL) */ #define VDE_MAX_ARGC 12 #define VDE_SEQPACKET_HEAD "seqpacket://" #define VDE_SEQPACKET_HEAD_LEN (sizeof(VDE_SEQPACKET_HEAD) - 1) #define VDE_DEFAULT_DESCRIPTION "UML" static struct vector_fds *user_init_vde_fds(struct arglist *ifspec) { char seqpacketvnl[VDE_SEQPACKET_HEAD_LEN + ENOUGH(int) + 1]; char *argv[VDE_MAX_ARGC] = {"vde_plug"}; int argc = 1; int rv; int sv[2]; struct vector_fds *result = NULL; char *vnl = uml_vector_fetch_arg(ifspec,"vnl"); char *descr = uml_vector_fetch_arg(ifspec,"descr"); char *port = uml_vector_fetch_arg(ifspec,"port"); char *mode = uml_vector_fetch_arg(ifspec,"mode"); char *group = uml_vector_fetch_arg(ifspec,"group"); if (descr == NULL) descr = VDE_DEFAULT_DESCRIPTION; argv[argc++] = "--descr"; argv[argc++] = descr; if (port != NULL) { argv[argc++] = "--port2"; argv[argc++] = port; } if (mode != NULL) { argv[argc++] = "--mod2"; argv[argc++] = mode; } if (group != NULL) { argv[argc++] = "--group2"; argv[argc++] = group; } argv[argc++] = seqpacketvnl; argv[argc++] = vnl; argv[argc++] = NULL; rv = socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sv); if (rv < 0) { printk(UM_KERN_ERR "vde: seqpacket socketpair err %d", -errno); return NULL; } rv = os_set_exec_close(sv[0]); if (rv < 0) { printk(UM_KERN_ERR "vde: seqpacket socketpair cloexec err %d", -errno); goto vde_cleanup_sv; } snprintf(seqpacketvnl, sizeof(seqpacketvnl), VDE_SEQPACKET_HEAD "%d", sv[1]); run_helper(NULL, NULL, argv); close(sv[1]); result = uml_kmalloc(sizeof(struct vector_fds), UM_GFP_KERNEL); if (result == NULL) {