linux/arch/um/drivers/vector_user.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
   4 */
   5
   6#include <stdio.h>
   7#include <unistd.h>
   8#include <stdarg.h>
   9#include <errno.h>
  10#include <stddef.h>
  11#include <string.h>
  12#include <sys/ioctl.h>
  13#include <net/if.h>
  14#include <linux/if_tun.h>
  15#include <arpa/inet.h>
  16#include <sys/types.h>
  17#include <sys/stat.h>
  18#include <fcntl.h>
  19#include <sys/socket.h>
  20#include <sys/un.h>
  21#include <netinet/ip.h>
  22#include <linux/if_ether.h>
  23#include <linux/if_packet.h>
  24#include <sys/wait.h>
  25#include <sys/uio.h>
  26#include <linux/virtio_net.h>
  27#include <netdb.h>
  28#include <stdlib.h>
  29#include <os.h>
  30#include <limits.h>
  31#include <um_malloc.h>
  32#include "vector_user.h"
  33
  34#define ID_GRE 0
  35#define ID_L2TPV3 1
  36#define ID_BESS 2
  37#define ID_MAX 2
  38
  39#define TOKEN_IFNAME "ifname"
  40#define TOKEN_SCRIPT "ifup"
  41
  42#define TRANS_RAW "raw"
  43#define TRANS_RAW_LEN strlen(TRANS_RAW)
  44
  45#define TRANS_FD "fd"
  46#define TRANS_FD_LEN strlen(TRANS_FD)
  47
  48#define VNET_HDR_FAIL "could not enable vnet headers on fd %d"
  49#define TUN_GET_F_FAIL "tapraw: TUNGETFEATURES failed: %s"
  50#define L2TPV3_BIND_FAIL "l2tpv3_open : could not bind socket err=%i"
  51#define UNIX_BIND_FAIL "unix_open : could not bind socket err=%i"
  52#define BPF_ATTACH_FAIL "Failed to attach filter size %d prog %px to %d, err %d\n"
  53#define BPF_DETACH_FAIL "Failed to detach filter size %d prog %px to %d, err %d\n"
  54
  55#define MAX_UN_LEN 107
  56
  57static const char padchar[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
  58static const char *template = "tapXXXXXX";
  59
  60/* This is very ugly and brute force lookup, but it is done
  61 * only once at initialization so not worth doing hashes or
  62 * anything more intelligent
  63 */
  64
  65char *uml_vector_fetch_arg(struct arglist *ifspec, char *token)
  66{
  67        int i;
  68
  69        for (i = 0; i < ifspec->numargs; i++) {
  70                if (strcmp(ifspec->tokens[i], token) == 0)
  71                        return ifspec->values[i];
  72        }
  73        return NULL;
  74
  75}
  76
  77struct arglist *uml_parse_vector_ifspec(char *arg)
  78{
  79        struct arglist *result;
  80        int pos, len;
  81        bool parsing_token = true, next_starts = true;
  82
  83        if (arg == NULL)
  84                return NULL;
  85        result = uml_kmalloc(sizeof(struct arglist), UM_GFP_KERNEL);
  86        if (result == NULL)
  87                return NULL;
  88        result->numargs = 0;
  89        len = strlen(arg);
  90        for (pos = 0; pos < len; pos++) {
  91                if (next_starts) {
  92                        if (parsing_token) {
  93                                result->tokens[result->numargs] = arg + pos;
  94                        } else {
  95                                result->values[result->numargs] = arg + pos;
  96                                result->numargs++;
  97                        }
  98                        next_starts = false;
  99                }
 100                if (*(arg + pos) == '=') {
 101                        if (parsing_token)
 102                                parsing_token = false;
 103                        else
 104                                goto cleanup;
 105                        next_starts = true;
 106                        (*(arg + pos)) = '\0';
 107                }
 108                if (*(arg + pos) == ',') {
 109                        parsing_token = true;
 110                        next_starts = true;
 111                        (*(arg + pos)) = '\0';
 112                }
 113        }
 114        return result;
 115cleanup:
 116        printk(UM_KERN_ERR "vector_setup - Couldn't parse '%s'\n", arg);
 117        kfree(result);
 118        return NULL;
 119}
 120
 121/*
 122 * Socket/FD configuration functions. These return an structure
 123 * of rx and tx descriptors to cover cases where these are not
 124 * the same (f.e. read via raw socket and write via tap).
 125 */
 126
 127#define PATH_NET_TUN "/dev/net/tun"
 128
 129
 130static int create_tap_fd(char *iface)
 131{
 132        struct ifreq ifr;
 133        int fd = -1;
 134        int err = -ENOMEM, offload;
 135
 136        fd = open(PATH_NET_TUN, O_RDWR);
 137        if (fd < 0) {
 138                printk(UM_KERN_ERR "uml_tap: failed to open tun device\n");
 139                goto tap_fd_cleanup;
 140        }
 141        memset(&ifr, 0, sizeof(ifr));
 142        ifr.ifr_flags = IFF_TAP | IFF_NO_PI | IFF_VNET_HDR;
 143        strncpy((char *)&ifr.ifr_name, iface, sizeof(ifr.ifr_name) - 1);
 144
 145        err = ioctl(fd, TUNSETIFF, (void *) &ifr);
 146        if (err != 0) {
 147                printk(UM_KERN_ERR "uml_tap: failed to select tap interface\n");
 148                goto tap_fd_cleanup;
 149        }
 150
 151        offload = TUN_F_CSUM | TUN_F_TSO4 | TUN_F_TSO6;
 152        ioctl(fd, TUNSETOFFLOAD, offload);
 153        return fd;
 154tap_fd_cleanup:
 155        if (fd >= 0)
 156                os_close_file(fd);
 157        return err;
 158}
 159
 160static int create_raw_fd(char *iface, int flags, int proto)
 161{
 162        struct ifreq ifr;
 163        int fd = -1;
 164        struct sockaddr_ll sock;
 165        int err = -ENOMEM;
 166
 167        fd = socket(AF_PACKET, SOCK_RAW, flags);
 168        if (fd == -1) {
 169                err = -errno;
 170                goto raw_fd_cleanup;
 171        }
 172        memset(&ifr, 0, sizeof(ifr));
 173        strncpy((char *)&ifr.ifr_name, iface, sizeof(ifr.ifr_name) - 1);
 174        if (ioctl(fd, SIOCGIFINDEX, (void *) &ifr) < 0) {
 175                err = -errno;
 176                goto raw_fd_cleanup;
 177        }
 178
 179        sock.sll_family = AF_PACKET;
 180        sock.sll_protocol = htons(proto);
 181        sock.sll_ifindex = ifr.ifr_ifindex;
 182
 183        if (bind(fd,
 184                (struct sockaddr *) &sock, sizeof(struct sockaddr_ll)) < 0) {
 185                err = -errno;
 186                goto raw_fd_cleanup;
 187        }
 188        return fd;
 189raw_fd_cleanup:
 190        printk(UM_KERN_ERR "user_init_raw: init failed, error %d", err);
 191        if (fd >= 0)
 192                os_close_file(fd);
 193        return err;
 194}
 195
 196
 197static struct vector_fds *user_init_tap_fds(struct arglist *ifspec)
 198{
 199        int fd = -1, i;
 200        char *iface;
 201        struct vector_fds *result = NULL;
 202        bool dynamic = false;
 203        char dynamic_ifname[IFNAMSIZ];
 204        char *argv[] = {NULL, NULL, NULL, NULL};
 205
 206        iface = uml_vector_fetch_arg(ifspec, TOKEN_IFNAME);
 207        if (iface == NULL) {
 208                dynamic = true;
 209                iface = dynamic_ifname;
 210                srand(getpid());
 211        }
 212
 213        result = uml_kmalloc(sizeof(struct vector_fds), UM_GFP_KERNEL);
 214        if (result == NULL) {
 215                printk(UM_KERN_ERR "uml_tap: failed to allocate file descriptors\n");
 216                goto tap_cleanup;
 217        }
 218        result->rx_fd = -1;
 219        result->tx_fd = -1;
 220        result->remote_addr = NULL;
 221        result->remote_addr_size = 0;
 222
 223        /* TAP */
 224        do {
 225                if (dynamic) {
 226                        strcpy(iface, template);
 227                        for (i = 0; i < strlen(iface); i++) {
 228                                if (iface[i] == 'X') {
 229                                        iface[i] = padchar[rand() % strlen(padchar)];
 230                                }
 231                        }
 232                }
 233                fd = create_tap_fd(iface);
 234                if ((fd < 0) && (!dynamic)) {
 235                        printk(UM_KERN_ERR "uml_tap: failed to create tun interface\n");
 236                        goto tap_cleanup;
 237                }
 238                result->tx_fd = fd;
 239                result->rx_fd = fd;
 240        } while (fd < 0);
 241
 242        argv[0] = uml_vector_fetch_arg(ifspec, TOKEN_SCRIPT);
 243        if (argv[0]) {
 244                argv[1] = iface;
 245                run_helper(NULL, NULL, argv);
 246        }
 247
 248        return result;
 249tap_cleanup:
 250        printk(UM_KERN_ERR "user_init_tap: init failed, error %d", fd);
 251        kfree(result);
 252        return NULL;
 253}
 254
 255static struct vector_fds *user_init_hybrid_fds(struct arglist *ifspec)
 256{
 257        char *iface;
 258        struct vector_fds *result = NULL;
 259        char *argv[] = {NULL, NULL, NULL, NULL};
 260
 261        iface = uml_vector_fetch_arg(ifspec, TOKEN_IFNAME);
 262        if (iface == NULL) {
 263                printk(UM_KERN_ERR "uml_tap: failed to parse interface spec\n");
 264                goto hybrid_cleanup;
 265        }
 266
 267        result = uml_kmalloc(sizeof(struct vector_fds), UM_GFP_KERNEL);
 268        if (result == NULL) {
 269                printk(UM_KERN_ERR "uml_tap: failed to allocate file descriptors\n");
 270                goto hybrid_cleanup;
 271        }
 272        result->rx_fd = -1;
 273        result->tx_fd = -1;
 274        result->remote_addr = NULL;
 275        result->remote_addr_size = 0;
 276
 277        /* TAP */
 278
 279        result->tx_fd = create_tap_fd(iface);
 280        if (result->tx_fd < 0) {
 281                printk(UM_KERN_ERR "uml_tap: failed to create tun interface: %i\n", result->tx_fd);
 282                goto hybrid_cleanup;
 283        }
 284
 285        /* RAW */
 286
 287        result->rx_fd = create_raw_fd(iface, ETH_P_ALL, ETH_P_ALL);
 288        if (result->rx_fd == -1) {
 289                printk(UM_KERN_ERR
 290                        "uml_tap: failed to create paired raw socket: %i\n", result->rx_fd);
 291                goto hybrid_cleanup;
 292        }
 293
 294        argv[0] = uml_vector_fetch_arg(ifspec, TOKEN_SCRIPT);
 295        if (argv[0]) {
 296                argv[1] = iface;
 297                run_helper(NULL, NULL, argv);
 298        }
 299        return result;
 300hybrid_cleanup:
 301        printk(UM_KERN_ERR "user_init_hybrid: init failed");
 302        kfree(result);
 303        return NULL;
 304}
 305
 306static struct vector_fds *user_init_unix_fds(struct arglist *ifspec, int id)
 307{
 308        int fd = -1;
 309        int socktype;
 310        char *src, *dst;
 311        struct vector_fds *result = NULL;
 312        struct sockaddr_un *local_addr = NULL, *remote_addr = NULL;
 313
 314        src = uml_vector_fetch_arg(ifspec, "src");
 315        dst = uml_vector_fetch_arg(ifspec, "dst");
 316        result = uml_kmalloc(sizeof(struct vector_fds), UM_GFP_KERNEL);
 317        if (result == NULL) {
 318                printk(UM_KERN_ERR "unix open:cannot allocate remote addr");
 319                goto unix_cleanup;
 320        }
 321        remote_addr = uml_kmalloc(sizeof(struct sockaddr_un), UM_GFP_KERNEL);
 322        if (remote_addr == NULL) {
 323                printk(UM_KERN_ERR "unix open:cannot allocate remote addr");
 324                goto unix_cleanup;
 325        }
 326
 327        switch (id) {
 328        case ID_BESS:
 329                socktype = SOCK_SEQPACKET;
 330                if ((src != NULL) && (strlen(src) <= MAX_UN_LEN)) {
 331                        local_addr = uml_kmalloc(sizeof(struct sockaddr_un), UM_GFP_KERNEL);
 332                        if (local_addr == NULL) {
 333                                printk(UM_KERN_ERR "bess open:cannot allocate local addr");
 334                                goto unix_cleanup;
 335                        }
 336                        local_addr->sun_family = AF_UNIX;
 337                        memcpy(local_addr->sun_path, src, strlen(src) + 1);
 338                }
 339                if ((dst == NULL) || (strlen(dst) > MAX_UN_LEN))
 340                        goto unix_cleanup;
 341                remote_addr->sun_family = AF_UNIX;
 342                memcpy(remote_addr->sun_path, dst, strlen(dst) + 1);
 343                break;
 344        default:
 345                printk(KERN_ERR "Unsupported unix socket type\n");
 346                return NULL;
 347        }
 348
 349        fd = socket(AF_UNIX, socktype, 0);
 350        if (fd == -1) {
 351                printk(UM_KERN_ERR
 352                        "unix open: could not open socket, error = %d",
 353                        -errno
 354                );
 355                goto unix_cleanup;
 356        }
 357        if (local_addr != NULL) {
 358                if (bind(fd, (struct sockaddr *) local_addr, sizeof(struct sockaddr_un))) {
 359                        printk(UM_KERN_ERR UNIX_BIND_FAIL, errno);
 360                        goto unix_cleanup;
 361                }
 362        }
 363        switch (id) {
 364        case ID_BESS:
 365                if (connect(fd, (const struct sockaddr *) remote_addr, sizeof(struct sockaddr_un)) < 0) {
 366                        printk(UM_KERN_ERR "bess open:cannot connect to %s %i", remote_addr->sun_path, -errno);
 367                        goto unix_cleanup;
 368                }
 369                break;
 370        }
 371        result->rx_fd = fd;
 372        result->tx_fd = fd;
 373        result->remote_addr_size = sizeof(struct sockaddr_un);
 374        result->remote_addr = remote_addr;
 375        return result;
 376unix_cleanup:
 377        if (fd >= 0)
 378                os_close_file(fd);
 379        kfree(remote_addr);
 380        kfree(result);
 381        return NULL;
 382}
 383
 384static int strtofd(const char *nptr)
 385{
 386        long fd;
 387        char *endptr;
 388
 389        if (nptr == NULL)
 390                return -1;
 391
 392        errno = 0;
 393        fd = strtol(nptr, &endptr, 10);
 394        if (nptr == endptr ||
 395                errno != 0 ||
 396                *endptr != '\0' ||
 397                fd < 0 ||
 398                fd > INT_MAX) {
 399                return -1;
 400        }
 401        return fd;
 402}
 403
 404static struct vector_fds *user_init_fd_fds(struct arglist *ifspec)
 405{
 406        int fd = -1;
 407        char *fdarg = NULL;
 408        struct vector_fds *result = NULL;
 409
 410        fdarg = uml_vector_fetch_arg(ifspec, "fd");
 411        fd = strtofd(fdarg);
 412        if (fd == -1) {
 413                printk(UM_KERN_ERR "fd open: bad or missing fd argument");
 414                goto fd_cleanup;
 415        }
 416
 417        result = uml_kmalloc(sizeof(struct vector_fds), UM_GFP_KERNEL);
 418        if (result == NULL) {
 419                printk(UM_KERN_ERR "fd open: allocation failed");
 420                goto fd_cleanup;
 421        }
 422
 423        result->rx_fd = fd;
 424        result->tx_fd = fd;
 425        result->remote_addr_size = 0;
 426        result->remote_addr = NULL;
 427        return result;
 428
 429fd_cleanup:
 430        if (fd >= 0)
 431                os_close_file(fd);
 432        kfree(result);
 433        return NULL;
 434}
 435
 436static struct vector_fds *user_init_raw_fds(struct arglist *ifspec)
 437{
 438        int rxfd = -1, txfd = -1;
 439        int err = -ENOMEM;
 440        char *iface;
 441        struct vector_fds *result = NULL;
 442        char *argv[] = {NULL, NULL, NULL, NULL};
 443
 444        iface = uml_vector_fetch_arg(ifspec, TOKEN_IFNAME);
 445        if (iface == NULL)
 446                goto raw_cleanup;
 447
 448        rxfd = create_raw_fd(iface, ETH_P_ALL, ETH_P_ALL);
 449        if (rxfd == -1) {
 450                err = -errno;
 451                goto raw_cleanup;
 452        }
 453        txfd = create_raw_fd(iface, 0, ETH_P_IP); /* Turn off RX on this fd */
 454        if (txfd == -1) {
 455                err = -errno;
 456                goto raw_cleanup;
 457        }
 458        result = uml_kmalloc(sizeof(struct vector_fds), UM_GFP_KERNEL);
 459        if (result != NULL) {
 460                result->rx_fd = rxfd;
 461                result->tx_fd = txfd;
 462                result->remote_addr = NULL;
 463                result->remote_addr_size = 0;
 464        }
 465        argv[0] = uml_vector_fetch_arg(ifspec, TOKEN_SCRIPT);
 466        if (argv[0]) {
 467                argv[1] = iface;
 468                run_helper(NULL, NULL, argv);
 469        }
 470        return result;
 471raw_cleanup:
 472        printk(UM_KERN_ERR "user_init_raw: init failed, error %d", err);
 473        kfree(result);
 474        return NULL;
 475}
 476
 477
 478bool uml_raw_enable_qdisc_bypass(int fd)
 479{
 480        int optval = 1;
 481
 482        if (setsockopt(fd,
 483                SOL_PACKET, PACKET_QDISC_BYPASS,
 484                &optval, sizeof(optval)) != 0) {
 485                return false;
 486        }
 487        return true;
 488}
 489
 490bool uml_raw_enable_vnet_headers(int fd)
 491{
 492        int optval = 1;
 493
 494        if (setsockopt(fd,
 495                SOL_PACKET, PACKET_VNET_HDR,
 496                &optval, sizeof(optval)) != 0) {
 497                printk(UM_KERN_INFO VNET_HDR_FAIL, fd);
 498                return false;
 499        }
 500        return true;
 501}
 502bool uml_tap_enable_vnet_headers(int fd)
 503{
 504        unsigned int features;
 505        int len = sizeof(struct virtio_net_hdr);
 506
 507        if (ioctl(fd, TUNGETFEATURES, &features) == -1) {
 508                printk(UM_KERN_INFO TUN_GET_F_FAIL, strerror(errno));
 509                return false;
 510        }
 511        if ((features & IFF_VNET_HDR) == 0) {
 512                printk(UM_KERN_INFO "tapraw: No VNET HEADER support");
 513                return false;
 514        }
 515        ioctl(fd, TUNSETVNETHDRSZ, &len);
 516        return true;
 517}
 518
 519static struct vector_fds *user_init_socket_fds(struct arglist *ifspec, int id)
 520{
 521        int err = -ENOMEM;
 522        int fd = -1, gairet;
 523        struct addrinfo srchints;
 524        struct addrinfo dsthints;
 525        bool v6, udp;
 526        char *value;
 527        char *src, *dst, *srcport, *dstport;
 528        struct addrinfo *gairesult = NULL;
 529        struct vector_fds *result = NULL;
 530
 531
 532        value = uml_vector_fetch_arg(ifspec, "v6");
 533        v6 = false;
 534        udp = false;
 535        if (value != NULL) {
 536                if (strtol((const char *) value, NULL, 10) > 0)
 537                        v6 = true;
 538        }
 539
 540        value = uml_vector_fetch_arg(ifspec, "udp");
 541        if (value != NULL) {
 542                if (strtol((const char *) value, NULL, 10) > 0)
 543                        udp = true;
 544        }
 545        src = uml_vector_fetch_arg(ifspec, "src");
 546        dst = uml_vector_fetch_arg(ifspec, "dst");
 547        srcport = uml_vector_fetch_arg(ifspec, "srcport");
 548        dstport = uml_vector_fetch_arg(ifspec, "dstport");
 549
 550        memset(&dsthints, 0, sizeof(dsthints));
 551
 552        if (v6)
 553                dsthints.ai_family = AF_INET6;
 554        else
 555                dsthints.ai_family = AF_INET;
 556
 557        switch (id) {
 558        case ID_GRE:
 559                dsthints.ai_socktype = SOCK_RAW;
 560                dsthints.ai_protocol = IPPROTO_GRE;
 561                break;
 562        case ID_L2TPV3:
 563                if (udp) {
 564                        dsthints.ai_socktype = SOCK_DGRAM;
 565                        dsthints.ai_protocol = 0;
 566                } else {
 567                        dsthints.ai_socktype = SOCK_RAW;
 568                        dsthints.ai_protocol = IPPROTO_L2TP;
 569                }
 570                break;
 571        default:
 572                printk(KERN_ERR "Unsupported socket type\n");
 573                return NULL;
 574        }
 575        memcpy(&srchints, &dsthints, sizeof(struct addrinfo));
 576
 577        gairet = getaddrinfo(src, srcport, &dsthints, &gairesult);
 578        if ((gairet != 0) || (gairesult == NULL)) {
 579                printk(UM_KERN_ERR
 580                        "socket_open : could not resolve src, error = %s",
 581                        gai_strerror(gairet)
 582                );
 583                return NULL;
 584        }
 585        fd = socket(gairesult->ai_family,
 586                gairesult->ai_socktype, gairesult->ai_protocol);
 587        if (fd == -1) {
 588                printk(UM_KERN_ERR
 589                        "socket_open : could not open socket, error = %d",
 590                        -errno
 591                );
 592                goto cleanup;
 593        }
 594        if (bind(fd,
 595                (struct sockaddr *) gairesult->ai_addr,
 596                gairesult->ai_addrlen)) {
 597                printk(UM_KERN_ERR L2TPV3_BIND_FAIL, errno);
 598                goto cleanup;
 599        }
 600
 601        if (gairesult != NULL)
 602                freeaddrinfo(gairesult);
 603
 604        gairesult = NULL;
 605
 606        gairet = getaddrinfo(dst, dstport, &dsthints, &gairesult);
 607        if ((gairet != 0) || (gairesult == NULL)) {
 608                printk(UM_KERN_ERR
 609                        "socket_open : could not resolve dst, error = %s",
 610                        gai_strerror(gairet)
 611                );
 612                return NULL;
 613        }
 614
 615        result = uml_kmalloc(sizeof(struct vector_fds), UM_GFP_KERNEL);
 616        if (result != NULL) {
 617                result->rx_fd = fd;
 618                result->tx_fd = fd;
 619                result->remote_addr = uml_kmalloc(
 620                        gairesult->ai_addrlen, UM_GFP_KERNEL);
 621                if (result->remote_addr == NULL)
 622                        goto cleanup;
 623                result->remote_addr_size = gairesult->ai_addrlen;
 624                memcpy(
 625                        result->remote_addr,
 626                        gairesult->ai_addr,
 627                        gairesult->ai_addrlen
 628                );
 629        }
 630        freeaddrinfo(gairesult);
 631        return result;
 632cleanup:
 633        if (gairesult != NULL)
 634                freeaddrinfo(gairesult);
 635        printk(UM_KERN_ERR "user_init_socket: init failed, error %d", err);
 636        if (fd >= 0)
 637                os_close_file(fd);
 638        if (result != NULL) {
 639                kfree(result->remote_addr);
 640                kfree(result);
 641        }
 642        return NULL;
 643}
 644
 645struct vector_fds *uml_vector_user_open(
 646        int unit,
 647        struct arglist *parsed
 648)
 649{
 650        char *transport;
 651
 652        if (parsed == NULL) {
 653                printk(UM_KERN_ERR "no parsed config for unit %d\n", unit);
 654                return NULL;
 655        }
 656        transport = uml_vector_fetch_arg(parsed, "transport");
 657        if (transport == NULL) {
 658                printk(UM_KERN_ERR "missing transport for unit %d\n", unit);
 659                return NULL;
 660        }
 661        if (strncmp(transport, TRANS_RAW, TRANS_RAW_LEN) == 0)
 662                return user_init_raw_fds(parsed);
 663        if (strncmp(transport, TRANS_HYBRID, TRANS_HYBRID_LEN) == 0)
 664                return user_init_hybrid_fds(parsed);
 665        if (strncmp(transport, TRANS_TAP, TRANS_TAP_LEN) == 0)
 666                return user_init_tap_fds(parsed);
 667        if (strncmp(transport, TRANS_GRE, TRANS_GRE_LEN) == 0)
 668                return user_init_socket_fds(parsed, ID_GRE);
 669        if (strncmp(transport, TRANS_L2TPV3, TRANS_L2TPV3_LEN) == 0)
 670                return user_init_socket_fds(parsed, ID_L2TPV3);
 671        if (strncmp(transport, TRANS_BESS, TRANS_BESS_LEN) == 0)
 672                return user_init_unix_fds(parsed, ID_BESS);
 673        if (strncmp(transport, TRANS_FD, TRANS_FD_LEN) == 0)
 674                return user_init_fd_fds(parsed);
 675        return NULL;
 676}
 677
 678
 679int uml_vector_sendmsg(int fd, void *hdr, int flags)
 680{
 681        int n;
 682
 683        CATCH_EINTR(n = sendmsg(fd, (struct msghdr *) hdr,  flags));
 684        if ((n < 0) && (errno == EAGAIN))
 685                return 0;
 686        if (n >= 0)
 687                return n;
 688        else
 689                return -errno;
 690}
 691
 692int uml_vector_recvmsg(int fd, void *hdr, int flags)
 693{
 694        int n;
 695        struct msghdr *msg = (struct msghdr *) hdr;
 696
 697        CATCH_EINTR(n = readv(fd, msg->msg_iov, msg->msg_iovlen));
 698        if ((n < 0) && (errno == EAGAIN))
 699                return 0;
 700        if (n >= 0)
 701                return n;
 702        else
 703                return -errno;
 704}
 705
 706int uml_vector_writev(int fd, void *hdr, int iovcount)
 707{
 708        int n;
 709
 710        CATCH_EINTR(n = writev(fd, (struct iovec *) hdr,  iovcount));
 711        if ((n < 0) && ((errno == EAGAIN) || (errno == ENOBUFS)))
 712                return 0;
 713        if (n >= 0)
 714                return n;
 715        else
 716                return -errno;
 717}
 718
 719int uml_vector_sendmmsg(
 720        int fd,
 721        void *msgvec,
 722        unsigned int vlen,
 723        unsigned int flags)
 724{
 725        int n;
 726
 727        CATCH_EINTR(n = sendmmsg(fd, (struct mmsghdr *) msgvec, vlen, flags));
 728        if ((n < 0) && ((errno == EAGAIN) || (errno == ENOBUFS)))
 729                return 0;
 730        if (n >= 0)
 731                return n;
 732        else
 733                return -errno;
 734}
 735
 736int uml_vector_recvmmsg(
 737        int fd,
 738        void *msgvec,
 739        unsigned int vlen,
 740        unsigned int flags)
 741{
 742        int n;
 743
 744        CATCH_EINTR(
 745                n = recvmmsg(fd, (struct mmsghdr *) msgvec, vlen, flags, 0));
 746        if ((n < 0) && (errno == EAGAIN))
 747                return 0;
 748        if (n >= 0)
 749                return n;
 750        else
 751                return -errno;
 752}
 753int uml_vector_attach_bpf(int fd, void *bpf)
 754{
 755        struct sock_fprog *prog = bpf;
 756
 757        int err = setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, bpf, sizeof(struct sock_fprog));
 758
 759        if (err < 0)
 760                printk(KERN_ERR BPF_ATTACH_FAIL, prog->len, prog->filter, fd, -errno);
 761        return err;
 762}
 763
 764int uml_vector_detach_bpf(int fd, void *bpf)
 765{
 766        struct sock_fprog *prog = bpf;
 767
 768        int err = setsockopt(fd, SOL_SOCKET, SO_DETACH_FILTER, bpf, sizeof(struct sock_fprog));
 769        if (err < 0)
 770                printk(KERN_ERR BPF_DETACH_FAIL, prog->len, prog->filter, fd, -errno);
 771        return err;
 772}
 773void *uml_vector_default_bpf(void *mac)
 774{
 775        struct sock_filter *bpf;
 776        uint32_t *mac1 = (uint32_t *)(mac + 2);
 777        uint16_t *mac2 = (uint16_t *) mac;
 778        struct sock_fprog *bpf_prog;
 779
 780        bpf_prog = uml_kmalloc(sizeof(struct sock_fprog), UM_GFP_KERNEL);
 781        if (bpf_prog) {
 782                bpf_prog->len = DEFAULT_BPF_LEN;
 783                bpf_prog->filter = NULL;
 784        } else {
 785                return NULL;
 786        }
 787        bpf = uml_kmalloc(
 788                sizeof(struct sock_filter) * DEFAULT_BPF_LEN, UM_GFP_KERNEL);
 789        if (bpf) {
 790                bpf_prog->filter = bpf;
 791                /* ld   [8] */
 792                bpf[0] = (struct sock_filter){ 0x20, 0, 0, 0x00000008 };
 793                /* jeq  #0xMAC[2-6] jt 2 jf 5*/
 794                bpf[1] = (struct sock_filter){ 0x15, 0, 3, ntohl(*mac1)};
 795                /* ldh  [6] */
 796                bpf[2] = (struct sock_filter){ 0x28, 0, 0, 0x00000006 };
 797                /* jeq  #0xMAC[0-1] jt 4 jf 5 */
 798                bpf[3] = (struct sock_filter){ 0x15, 0, 1, ntohs(*mac2)};
 799                /* ret  #0 */
 800                bpf[4] = (struct sock_filter){ 0x6, 0, 0, 0x00000000 };
 801                /* ret  #0x40000 */
 802                bpf[5] = (struct sock_filter){ 0x6, 0, 0, 0x00040000 };
 803        } else {
 804                kfree(bpf_prog);
 805                bpf_prog = NULL;
 806        }
 807        return bpf_prog;
 808}
 809
 810/* Note - this function requires a valid mac being passed as an arg */
 811
 812void *uml_vector_user_bpf(char *filename)
 813{
 814        struct sock_filter *bpf;
 815        struct sock_fprog *bpf_prog;
 816        struct stat statbuf;
 817        int res, ffd = -1;
 818
 819        if (filename == NULL)
 820                return NULL;
 821
 822        if (stat(filename, &statbuf) < 0) {
 823                printk(KERN_ERR "Error %d reading bpf file", -errno);
 824                return false;
 825        }
 826        bpf_prog = uml_kmalloc(sizeof(struct sock_fprog), UM_GFP_KERNEL);
 827        if (bpf_prog == NULL) {
 828                printk(KERN_ERR "Failed to allocate bpf prog buffer");
 829                return NULL;
 830        }
 831        bpf_prog->len = statbuf.st_size / sizeof(struct sock_filter);
 832        bpf_prog->filter = NULL;
 833        ffd = os_open_file(filename, of_read(OPENFLAGS()), 0);
 834        if (ffd < 0) {
 835                printk(KERN_ERR "Error %d opening bpf file", -errno);
 836                goto bpf_failed;
 837        }
 838        bpf = uml_kmalloc(statbuf.st_size, UM_GFP_KERNEL);
 839        if (bpf == NULL) {
 840                printk(KERN_ERR "Failed to allocate bpf buffer");
 841                goto bpf_failed;
 842        }
 843        bpf_prog->filter = bpf;
 844        res = os_read_file(ffd, bpf, statbuf.st_size);
 845        if (res < statbuf.st_size) {
 846                printk(KERN_ERR "Failed to read bpf program %s, error %d", filename, res);
 847                kfree(bpf);
 848                goto bpf_failed;
 849        }
 850        os_close_file(ffd);
 851        return bpf_prog;
 852bpf_failed:
 853        if (ffd > 0)
 854                os_close_file(ffd);
 855        kfree(bpf_prog);
 856        return NULL;
 857}
 858
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.