linux/arch/um/drivers/vector_user.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
   3 * Licensed under the GPL
   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/types.h>
  20#include <sys/socket.h>
  21#include <net/ethernet.h>
  22#include <netinet/ip.h>
  23#include <netinet/ether.h>
  24#include <linux/if_ether.h>
  25#include <linux/if_packet.h>
  26#include <sys/socket.h>
  27#include <sys/wait.h>
  28#include <linux/virtio_net.h>
  29#include <netdb.h>
  30#include <stdlib.h>
  31#include <os.h>
  32#include <um_malloc.h>
  33#include "vector_user.h"
  34
  35#define ID_GRE 0
  36#define ID_L2TPV3 1
  37#define ID_MAX 1
  38
  39#define TOKEN_IFNAME "ifname"
  40
  41#define TRANS_RAW "raw"
  42#define TRANS_RAW_LEN strlen(TRANS_RAW)
  43
  44#define VNET_HDR_FAIL "could not enable vnet headers on fd %d"
  45#define TUN_GET_F_FAIL "tapraw: TUNGETFEATURES failed: %s"
  46#define L2TPV3_BIND_FAIL "l2tpv3_open : could not bind socket err=%i"
  47#define BPF_ATTACH_FAIL "Failed to attach filter size %d to %d, err %d\n"
  48
  49/* This is very ugly and brute force lookup, but it is done
  50 * only once at initialization so not worth doing hashes or
  51 * anything more intelligent
  52 */
  53
  54char *uml_vector_fetch_arg(struct arglist *ifspec, char *token)
  55{
  56        int i;
  57
  58        for (i = 0; i < ifspec->numargs; i++) {
  59                if (strcmp(ifspec->tokens[i], token) == 0)
  60                        return ifspec->values[i];
  61        }
  62        return NULL;
  63
  64}
  65
  66struct arglist *uml_parse_vector_ifspec(char *arg)
  67{
  68        struct arglist *result;
  69        int pos, len;
  70        bool parsing_token = true, next_starts = true;
  71
  72        if (arg == NULL)
  73                return NULL;
  74        result = uml_kmalloc(sizeof(struct arglist), UM_GFP_KERNEL);
  75        if (result == NULL)
  76                return NULL;
  77        result->numargs = 0;
  78        len = strlen(arg);
  79        for (pos = 0; pos < len; pos++) {
  80                if (next_starts) {
  81                        if (parsing_token) {
  82                                result->tokens[result->numargs] = arg + pos;
  83                        } else {
  84                                result->values[result->numargs] = arg + pos;
  85                                result->numargs++;
  86                        }
  87                        next_starts = false;
  88                }
  89                if (*(arg + pos) == '=') {
  90                        if (parsing_token)
  91                                parsing_token = false;
  92                        else
  93                                goto cleanup;
  94                        next_starts = true;
  95                        (*(arg + pos)) = '\0';
  96                }
  97                if (*(arg + pos) == ',') {
  98                        parsing_token = true;
  99                        next_starts = true;
 100                        (*(arg + pos)) = '\0';
 101                }
 102        }
 103        return result;
 104cleanup:
 105        printk(UM_KERN_ERR "vector_setup - Couldn't parse '%s'\n", arg);
 106        kfree(result);
 107        return NULL;
 108}
 109
 110/*
 111 * Socket/FD configuration functions. These return an structure
 112 * of rx and tx descriptors to cover cases where these are not
 113 * the same (f.e. read via raw socket and write via tap).
 114 */
 115
 116#define PATH_NET_TUN "/dev/net/tun"
 117
 118static struct vector_fds *user_init_tap_fds(struct arglist *ifspec)
 119{
 120        struct ifreq ifr;
 121        int fd = -1;
 122        struct sockaddr_ll sock;
 123        int err = -ENOMEM, offload;
 124        char *iface;
 125        struct vector_fds *result = NULL;
 126
 127        iface = uml_vector_fetch_arg(ifspec, TOKEN_IFNAME);
 128        if (iface == NULL) {
 129                printk(UM_KERN_ERR "uml_tap: failed to parse interface spec\n");
 130                goto tap_cleanup;
 131        }
 132
 133        result = uml_kmalloc(sizeof(struct vector_fds), UM_GFP_KERNEL);
 134        if (result == NULL) {
 135                printk(UM_KERN_ERR "uml_tap: failed to allocate file descriptors\n");
 136                goto tap_cleanup;
 137        }
 138        result->rx_fd = -1;
 139        result->tx_fd = -1;
 140        result->remote_addr = NULL;
 141        result->remote_addr_size = 0;
 142
 143        /* TAP */
 144
 145        fd = open(PATH_NET_TUN, O_RDWR);
 146        if (fd < 0) {
 147                printk(UM_KERN_ERR "uml_tap: failed to open tun device\n");
 148                goto tap_cleanup;
 149        }
 150        result->tx_fd = fd;
 151        memset(&ifr, 0, sizeof(ifr));
 152        ifr.ifr_flags = IFF_TAP | IFF_NO_PI | IFF_VNET_HDR;
 153        strncpy((char *)&ifr.ifr_name, iface, sizeof(ifr.ifr_name) - 1);
 154
 155        err = ioctl(fd, TUNSETIFF, (void *) &ifr);
 156        if (err != 0) {
 157                printk(UM_KERN_ERR "uml_tap: failed to select tap interface\n");
 158                goto tap_cleanup;
 159        }
 160
 161        offload = TUN_F_CSUM | TUN_F_TSO4 | TUN_F_TSO6;
 162        ioctl(fd, TUNSETOFFLOAD, offload);
 163
 164        /* RAW */
 165
 166        fd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
 167        if (fd == -1) {
 168                printk(UM_KERN_ERR
 169                        "uml_tap: failed to create socket: %i\n", -errno);
 170                goto tap_cleanup;
 171        }
 172        result->rx_fd = fd;
 173        memset(&ifr, 0, sizeof(ifr));
 174        strncpy((char *)&ifr.ifr_name, iface, sizeof(ifr.ifr_name) - 1);
 175        if (ioctl(fd, SIOCGIFINDEX, (void *) &ifr) < 0) {
 176                printk(UM_KERN_ERR
 177                        "uml_tap: failed to set interface: %i\n", -errno);
 178                goto tap_cleanup;
 179        }
 180
 181        sock.sll_family = AF_PACKET;
 182        sock.sll_protocol = htons(ETH_P_ALL);
 183        sock.sll_ifindex = ifr.ifr_ifindex;
 184
 185        if (bind(fd,
 186                (struct sockaddr *) &sock, sizeof(struct sockaddr_ll)) < 0) {
 187                printk(UM_KERN_ERR
 188                        "user_init_tap: failed to bind raw pair, err %d\n",
 189                                -errno);
 190                goto tap_cleanup;
 191        }
 192        return result;
 193tap_cleanup:
 194        printk(UM_KERN_ERR "user_init_tap: init failed, error %d", err);
 195        if (result != NULL) {
 196                if (result->rx_fd >= 0)
 197                        os_close_file(result->rx_fd);
 198                if (result->tx_fd >= 0)
 199                        os_close_file(result->tx_fd);
 200                kfree(result);
 201        }
 202        return NULL;
 203}
 204
 205
 206static struct vector_fds *user_init_raw_fds(struct arglist *ifspec)
 207{
 208        struct ifreq ifr;
 209        int rxfd = -1, txfd = -1;
 210        struct sockaddr_ll sock;
 211        int err = -ENOMEM;
 212        char *iface;
 213        struct vector_fds *result = NULL;
 214
 215        iface = uml_vector_fetch_arg(ifspec, TOKEN_IFNAME);
 216        if (iface == NULL)
 217                goto cleanup;
 218
 219        rxfd = socket(AF_PACKET, SOCK_RAW, ETH_P_ALL);
 220        if (rxfd == -1) {
 221                err = -errno;
 222                goto cleanup;
 223        }
 224        txfd = socket(AF_PACKET, SOCK_RAW, 0); /* Turn off RX on this fd */
 225        if (txfd == -1) {
 226                err = -errno;
 227                goto cleanup;
 228        }
 229        memset(&ifr, 0, sizeof(ifr));
 230        strncpy((char *)&ifr.ifr_name, iface, sizeof(ifr.ifr_name) - 1);
 231        if (ioctl(rxfd, SIOCGIFINDEX, (void *) &ifr) < 0) {
 232                err = -errno;
 233                goto cleanup;
 234        }
 235
 236        sock.sll_family = AF_PACKET;
 237        sock.sll_protocol = htons(ETH_P_ALL);
 238        sock.sll_ifindex = ifr.ifr_ifindex;
 239
 240        if (bind(rxfd,
 241                (struct sockaddr *) &sock, sizeof(struct sockaddr_ll)) < 0) {
 242                err = -errno;
 243                goto cleanup;
 244        }
 245
 246        sock.sll_family = AF_PACKET;
 247        sock.sll_protocol = htons(ETH_P_IP);
 248        sock.sll_ifindex = ifr.ifr_ifindex;
 249
 250        if (bind(txfd,
 251                (struct sockaddr *) &sock, sizeof(struct sockaddr_ll)) < 0) {
 252                err = -errno;
 253                goto cleanup;
 254        }
 255
 256        result = uml_kmalloc(sizeof(struct vector_fds), UM_GFP_KERNEL);
 257        if (result != NULL) {
 258                result->rx_fd = rxfd;
 259                result->tx_fd = txfd;
 260                result->remote_addr = NULL;
 261                result->remote_addr_size = 0;
 262        }
 263        return result;
 264cleanup:
 265        printk(UM_KERN_ERR "user_init_raw: init failed, error %d", err);
 266        if (rxfd >= 0)
 267                os_close_file(rxfd);
 268        if (txfd >= 0)
 269                os_close_file(txfd);
 270        if (result != NULL)
 271                kfree(result);
 272        return NULL;
 273}
 274
 275
 276bool uml_raw_enable_qdisc_bypass(int fd)
 277{
 278        int optval = 1;
 279
 280        if (setsockopt(fd,
 281                SOL_PACKET, PACKET_QDISC_BYPASS,
 282                &optval, sizeof(optval)) != 0) {
 283                return false;
 284        }
 285        return true;
 286}
 287
 288bool uml_raw_enable_vnet_headers(int fd)
 289{
 290        int optval = 1;
 291
 292        if (setsockopt(fd,
 293                SOL_PACKET, PACKET_VNET_HDR,
 294                &optval, sizeof(optval)) != 0) {
 295                printk(UM_KERN_INFO VNET_HDR_FAIL, fd);
 296                return false;
 297        }
 298        return true;
 299}
 300bool uml_tap_enable_vnet_headers(int fd)
 301{
 302        unsigned int features;
 303        int len = sizeof(struct virtio_net_hdr);
 304
 305        if (ioctl(fd, TUNGETFEATURES, &features) == -1) {
 306                printk(UM_KERN_INFO TUN_GET_F_FAIL, strerror(errno));
 307                return false;
 308        }
 309        if ((features & IFF_VNET_HDR) == 0) {
 310                printk(UM_KERN_INFO "tapraw: No VNET HEADER support");
 311                return false;
 312        }
 313        ioctl(fd, TUNSETVNETHDRSZ, &len);
 314        return true;
 315}
 316
 317static struct vector_fds *user_init_socket_fds(struct arglist *ifspec, int id)
 318{
 319        int err = -ENOMEM;
 320        int fd = -1, gairet;
 321        struct addrinfo srchints;
 322        struct addrinfo dsthints;
 323        bool v6, udp;
 324        char *value;
 325        char *src, *dst, *srcport, *dstport;
 326        struct addrinfo *gairesult = NULL;
 327        struct vector_fds *result = NULL;
 328
 329
 330        value = uml_vector_fetch_arg(ifspec, "v6");
 331        v6 = false;
 332        udp = false;
 333        if (value != NULL) {
 334                if (strtol((const char *) value, NULL, 10) > 0)
 335                        v6 = true;
 336        }
 337
 338        value = uml_vector_fetch_arg(ifspec, "udp");
 339        if (value != NULL) {
 340                if (strtol((const char *) value, NULL, 10) > 0)
 341                        udp = true;
 342        }
 343        src = uml_vector_fetch_arg(ifspec, "src");
 344        dst = uml_vector_fetch_arg(ifspec, "dst");
 345        srcport = uml_vector_fetch_arg(ifspec, "srcport");
 346        dstport = uml_vector_fetch_arg(ifspec, "dstport");
 347
 348        memset(&dsthints, 0, sizeof(dsthints));
 349
 350        if (v6)
 351                dsthints.ai_family = AF_INET6;
 352        else
 353                dsthints.ai_family = AF_INET;
 354
 355        switch (id) {
 356        case ID_GRE:
 357                dsthints.ai_socktype = SOCK_RAW;
 358                dsthints.ai_protocol = IPPROTO_GRE;
 359                break;
 360        case ID_L2TPV3:
 361                if (udp) {
 362                        dsthints.ai_socktype = SOCK_DGRAM;
 363                        dsthints.ai_protocol = 0;
 364                } else {
 365                        dsthints.ai_socktype = SOCK_RAW;
 366                        dsthints.ai_protocol = IPPROTO_L2TP;
 367                }
 368                break;
 369        default:
 370                printk(KERN_ERR "Unsupported socket type\n");
 371                return NULL;
 372        }
 373        memcpy(&srchints, &dsthints, sizeof(struct addrinfo));
 374
 375        gairet = getaddrinfo(src, srcport, &dsthints, &gairesult);
 376        if ((gairet != 0) || (gairesult == NULL)) {
 377                printk(UM_KERN_ERR
 378                        "socket_open : could not resolve src, error = %s",
 379                        gai_strerror(gairet)
 380                );
 381                return NULL;
 382        }
 383        fd = socket(gairesult->ai_family,
 384                gairesult->ai_socktype, gairesult->ai_protocol);
 385        if (fd == -1) {
 386                printk(UM_KERN_ERR
 387                        "socket_open : could not open socket, error = %d",
 388                        -errno
 389                );
 390                goto cleanup;
 391        }
 392        if (bind(fd,
 393                (struct sockaddr *) gairesult->ai_addr,
 394                gairesult->ai_addrlen)) {
 395                printk(UM_KERN_ERR L2TPV3_BIND_FAIL, errno);
 396                goto cleanup;
 397        }
 398
 399        if (gairesult != NULL)
 400                freeaddrinfo(gairesult);
 401
 402        gairesult = NULL;
 403
 404        gairet = getaddrinfo(dst, dstport, &dsthints, &gairesult);
 405        if ((gairet != 0) || (gairesult == NULL)) {
 406                printk(UM_KERN_ERR
 407                        "socket_open : could not resolve dst, error = %s",
 408                        gai_strerror(gairet)
 409                );
 410                return NULL;
 411        }
 412
 413        result = uml_kmalloc(sizeof(struct vector_fds), UM_GFP_KERNEL);
 414        if (result != NULL) {
 415                result->rx_fd = fd;
 416                result->tx_fd = fd;
 417                result->remote_addr = uml_kmalloc(
 418                        gairesult->ai_addrlen, UM_GFP_KERNEL);
 419                if (result->remote_addr == NULL)
 420                        goto cleanup;
 421                result->remote_addr_size = gairesult->ai_addrlen;
 422                memcpy(
 423                        result->remote_addr,
 424                        gairesult->ai_addr,
 425                        gairesult->ai_addrlen
 426                );
 427        }
 428        freeaddrinfo(gairesult);
 429        return result;
 430cleanup:
 431        if (gairesult != NULL)
 432                freeaddrinfo(gairesult);
 433        printk(UM_KERN_ERR "user_init_socket: init failed, error %d", err);
 434        if (fd >= 0)
 435                os_close_file(fd);
 436        if (result != NULL) {
 437                if (result->remote_addr != NULL)
 438                        kfree(result->remote_addr);
 439                kfree(result);
 440        }
 441        return NULL;
 442}
 443
 444struct vector_fds *uml_vector_user_open(
 445        int unit,
 446        struct arglist *parsed
 447)
 448{
 449        char *transport;
 450
 451        if (parsed == NULL) {
 452                printk(UM_KERN_ERR "no parsed config for unit %d\n", unit);
 453                return NULL;
 454        }
 455        transport = uml_vector_fetch_arg(parsed, "transport");
 456        if (transport == NULL) {
 457                printk(UM_KERN_ERR "missing transport for unit %d\n", unit);
 458                return NULL;
 459        }
 460        if (strncmp(transport, TRANS_RAW, TRANS_RAW_LEN) == 0)
 461                return user_init_raw_fds(parsed);
 462        if (strncmp(transport, TRANS_TAP, TRANS_TAP_LEN) == 0)
 463                return user_init_tap_fds(parsed);
 464        if (strncmp(transport, TRANS_GRE, TRANS_GRE_LEN) == 0)
 465                return user_init_socket_fds(parsed, ID_GRE);
 466        if (strncmp(transport, TRANS_L2TPV3, TRANS_L2TPV3_LEN) == 0)
 467                return user_init_socket_fds(parsed, ID_L2TPV3);
 468        return NULL;
 469}
 470
 471
 472int uml_vector_sendmsg(int fd, void *hdr, int flags)
 473{
 474        int n;
 475
 476        CATCH_EINTR(n = sendmsg(fd, (struct msghdr *) hdr,  flags));
 477        if ((n < 0) && (errno == EAGAIN))
 478                return 0;
 479        if (n >= 0)
 480                return n;
 481        else
 482                return -errno;
 483}
 484
 485int uml_vector_recvmsg(int fd, void *hdr, int flags)
 486{
 487        int n;
 488
 489        CATCH_EINTR(n = recvmsg(fd, (struct msghdr *) hdr,  flags));
 490        if ((n < 0) && (errno == EAGAIN))
 491                return 0;
 492        if (n >= 0)
 493                return n;
 494        else
 495                return -errno;
 496}
 497
 498int uml_vector_writev(int fd, void *hdr, int iovcount)
 499{
 500        int n;
 501
 502        CATCH_EINTR(n = writev(fd, (struct iovec *) hdr,  iovcount));
 503        if ((n < 0) && (errno == EAGAIN))
 504                return 0;
 505        if (n >= 0)
 506                return n;
 507        else
 508                return -errno;
 509}
 510
 511int uml_vector_sendmmsg(
 512        int fd,
 513        void *msgvec,
 514        unsigned int vlen,
 515        unsigned int flags)
 516{
 517        int n;
 518
 519        CATCH_EINTR(n = sendmmsg(fd, (struct mmsghdr *) msgvec, vlen, flags));
 520        if ((n < 0) && (errno == EAGAIN))
 521                return 0;
 522        if (n >= 0)
 523                return n;
 524        else
 525                return -errno;
 526}
 527
 528int uml_vector_recvmmsg(
 529        int fd,
 530        void *msgvec,
 531        unsigned int vlen,
 532        unsigned int flags)
 533{
 534        int n;
 535
 536        CATCH_EINTR(
 537                n = recvmmsg(fd, (struct mmsghdr *) msgvec, vlen, flags, 0));
 538        if ((n < 0) && (errno == EAGAIN))
 539                return 0;
 540        if (n >= 0)
 541                return n;
 542        else
 543                return -errno;
 544}
 545int uml_vector_attach_bpf(int fd, void *bpf, int bpf_len)
 546{
 547        int err = setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, bpf, bpf_len);
 548
 549        if (err < 0)
 550                printk(KERN_ERR BPF_ATTACH_FAIL, bpf_len, fd, -errno);
 551        return err;
 552}
 553
 554#define DEFAULT_BPF_LEN 6
 555
 556void *uml_vector_default_bpf(int fd, void *mac)
 557{
 558        struct sock_filter *bpf;
 559        uint32_t *mac1 = (uint32_t *)(mac + 2);
 560        uint16_t *mac2 = (uint16_t *) mac;
 561        struct sock_fprog bpf_prog = {
 562                .len = 6,
 563                .filter = NULL,
 564        };
 565
 566        bpf = uml_kmalloc(
 567                sizeof(struct sock_filter) * DEFAULT_BPF_LEN, UM_GFP_KERNEL);
 568        if (bpf != NULL) {
 569                bpf_prog.filter = bpf;
 570                /* ld   [8] */
 571                bpf[0] = (struct sock_filter){ 0x20, 0, 0, 0x00000008 };
 572                /* jeq  #0xMAC[2-6] jt 2 jf 5*/
 573                bpf[1] = (struct sock_filter){ 0x15, 0, 3, ntohl(*mac1)};
 574                /* ldh  [6] */
 575                bpf[2] = (struct sock_filter){ 0x28, 0, 0, 0x00000006 };
 576                /* jeq  #0xMAC[0-1] jt 4 jf 5 */
 577                bpf[3] = (struct sock_filter){ 0x15, 0, 1, ntohs(*mac2)};
 578                /* ret  #0 */
 579                bpf[4] = (struct sock_filter){ 0x6, 0, 0, 0x00000000 };
 580                /* ret  #0x40000 */
 581                bpf[5] = (struct sock_filter){ 0x6, 0, 0, 0x00040000 };
 582                if (uml_vector_attach_bpf(
 583                        fd, &bpf_prog, sizeof(struct sock_fprog)) < 0) {
 584                        kfree(bpf);
 585                        bpf = NULL;
 586                }
 587        }
 588        return bpf;
 589}
 590
 591