qemu/net/tap-solaris.c
<<
>>
Prefs
   1/*
   2 * QEMU System Emulator
   3 *
   4 * Copyright (c) 2003-2008 Fabrice Bellard
   5 *
   6 * Permission is hereby granted, free of charge, to any person obtaining a copy
   7 * of this software and associated documentation files (the "Software"), to deal
   8 * in the Software without restriction, including without limitation the rights
   9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10 * copies of the Software, and to permit persons to whom the Software is
  11 * furnished to do so, subject to the following conditions:
  12 *
  13 * The above copyright notice and this permission notice shall be included in
  14 * all copies or substantial portions of the Software.
  15 *
  16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  22 * THE SOFTWARE.
  23 */
  24
  25#include "net/tap.h"
  26#include "sysemu.h"
  27
  28#include <sys/stat.h>
  29#include <sys/ethernet.h>
  30#include <sys/sockio.h>
  31#include <netinet/arp.h>
  32#include <netinet/in.h>
  33#include <netinet/in_systm.h>
  34#include <netinet/ip.h>
  35#include <netinet/ip_icmp.h> // must come after ip.h
  36#include <netinet/udp.h>
  37#include <netinet/tcp.h>
  38#include <net/if.h>
  39#include <syslog.h>
  40#include <stropts.h>
  41#include "qemu-error.h"
  42
  43ssize_t tap_read_packet(int tapfd, uint8_t *buf, int maxlen)
  44{
  45    struct strbuf sbuf;
  46    int f = 0;
  47
  48    sbuf.maxlen = maxlen;
  49    sbuf.buf = (char *)buf;
  50
  51    return getmsg(tapfd, NULL, &sbuf, &f) >= 0 ? sbuf.len : -1;
  52}
  53
  54#define TUNNEWPPA       (('T'<<16) | 0x0001)
  55/*
  56 * Allocate TAP device, returns opened fd.
  57 * Stores dev name in the first arg(must be large enough).
  58 */
  59static int tap_alloc(char *dev, size_t dev_size)
  60{
  61    int tap_fd, if_fd, ppa = -1;
  62    static int ip_fd = 0;
  63    char *ptr;
  64
  65    static int arp_fd = 0;
  66    int ip_muxid, arp_muxid;
  67    struct strioctl  strioc_if, strioc_ppa;
  68    int link_type = I_PLINK;
  69    struct lifreq ifr;
  70    char actual_name[32] = "";
  71
  72    memset(&ifr, 0x0, sizeof(ifr));
  73
  74    if( *dev ){
  75       ptr = dev;
  76       while( *ptr && !qemu_isdigit((int)*ptr) ) ptr++;
  77       ppa = atoi(ptr);
  78    }
  79
  80    /* Check if IP device was opened */
  81    if( ip_fd )
  82       close(ip_fd);
  83
  84    TFR(ip_fd = open("/dev/udp", O_RDWR, 0));
  85    if (ip_fd < 0) {
  86       syslog(LOG_ERR, "Can't open /dev/ip (actually /dev/udp)");
  87       return -1;
  88    }
  89
  90    TFR(tap_fd = open("/dev/tap", O_RDWR, 0));
  91    if (tap_fd < 0) {
  92       syslog(LOG_ERR, "Can't open /dev/tap");
  93       return -1;
  94    }
  95
  96    /* Assign a new PPA and get its unit number. */
  97    strioc_ppa.ic_cmd = TUNNEWPPA;
  98    strioc_ppa.ic_timout = 0;
  99    strioc_ppa.ic_len = sizeof(ppa);
 100    strioc_ppa.ic_dp = (char *)&ppa;
 101    if ((ppa = ioctl (tap_fd, I_STR, &strioc_ppa)) < 0)
 102       syslog (LOG_ERR, "Can't assign new interface");
 103
 104    TFR(if_fd = open("/dev/tap", O_RDWR, 0));
 105    if (if_fd < 0) {
 106       syslog(LOG_ERR, "Can't open /dev/tap (2)");
 107       return -1;
 108    }
 109    if(ioctl(if_fd, I_PUSH, "ip") < 0){
 110       syslog(LOG_ERR, "Can't push IP module");
 111       return -1;
 112    }
 113
 114    if (ioctl(if_fd, SIOCGLIFFLAGS, &ifr) < 0)
 115        syslog(LOG_ERR, "Can't get flags\n");
 116
 117    snprintf (actual_name, 32, "tap%d", ppa);
 118    pstrcpy(ifr.lifr_name, sizeof(ifr.lifr_name), actual_name);
 119
 120    ifr.lifr_ppa = ppa;
 121    /* Assign ppa according to the unit number returned by tun device */
 122
 123    if (ioctl (if_fd, SIOCSLIFNAME, &ifr) < 0)
 124        syslog (LOG_ERR, "Can't set PPA %d", ppa);
 125    if (ioctl(if_fd, SIOCGLIFFLAGS, &ifr) <0)
 126        syslog (LOG_ERR, "Can't get flags\n");
 127    /* Push arp module to if_fd */
 128    if (ioctl (if_fd, I_PUSH, "arp") < 0)
 129        syslog (LOG_ERR, "Can't push ARP module (2)");
 130
 131    /* Push arp module to ip_fd */
 132    if (ioctl (ip_fd, I_POP, NULL) < 0)
 133        syslog (LOG_ERR, "I_POP failed\n");
 134    if (ioctl (ip_fd, I_PUSH, "arp") < 0)
 135        syslog (LOG_ERR, "Can't push ARP module (3)\n");
 136    /* Open arp_fd */
 137    TFR(arp_fd = open ("/dev/tap", O_RDWR, 0));
 138    if (arp_fd < 0)
 139       syslog (LOG_ERR, "Can't open %s\n", "/dev/tap");
 140
 141    /* Set ifname to arp */
 142    strioc_if.ic_cmd = SIOCSLIFNAME;
 143    strioc_if.ic_timout = 0;
 144    strioc_if.ic_len = sizeof(ifr);
 145    strioc_if.ic_dp = (char *)&ifr;
 146    if (ioctl(arp_fd, I_STR, &strioc_if) < 0){
 147        syslog (LOG_ERR, "Can't set ifname to arp\n");
 148    }
 149
 150    if((ip_muxid = ioctl(ip_fd, I_LINK, if_fd)) < 0){
 151       syslog(LOG_ERR, "Can't link TAP device to IP");
 152       return -1;
 153    }
 154
 155    if ((arp_muxid = ioctl (ip_fd, link_type, arp_fd)) < 0)
 156        syslog (LOG_ERR, "Can't link TAP device to ARP");
 157
 158    close (if_fd);
 159
 160    memset(&ifr, 0x0, sizeof(ifr));
 161    pstrcpy(ifr.lifr_name, sizeof(ifr.lifr_name), actual_name);
 162    ifr.lifr_ip_muxid  = ip_muxid;
 163    ifr.lifr_arp_muxid = arp_muxid;
 164
 165    if (ioctl (ip_fd, SIOCSLIFMUXID, &ifr) < 0)
 166    {
 167      ioctl (ip_fd, I_PUNLINK , arp_muxid);
 168      ioctl (ip_fd, I_PUNLINK, ip_muxid);
 169      syslog (LOG_ERR, "Can't set multiplexor id");
 170    }
 171
 172    snprintf(dev, dev_size, "tap%d", ppa);
 173    return tap_fd;
 174}
 175
 176int tap_open(char *ifname, int ifname_size, int *vnet_hdr, int vnet_hdr_required)
 177{
 178    char  dev[10]="";
 179    int fd;
 180    if( (fd = tap_alloc(dev, sizeof(dev))) < 0 ){
 181       fprintf(stderr, "Cannot allocate TAP device\n");
 182       return -1;
 183    }
 184    pstrcpy(ifname, ifname_size, dev);
 185    if (*vnet_hdr) {
 186        /* Solaris doesn't have IFF_VNET_HDR */
 187        *vnet_hdr = 0;
 188
 189        if (vnet_hdr_required && !*vnet_hdr) {
 190            error_report("vnet_hdr=1 requested, but no kernel "
 191                         "support for IFF_VNET_HDR available");
 192            close(fd);
 193            return -1;
 194        }
 195    }
 196    fcntl(fd, F_SETFL, O_NONBLOCK);
 197    return fd;
 198}
 199
 200int tap_set_sndbuf(int fd, const NetdevTapOptions *tap)
 201{
 202    return 0;
 203}
 204
 205int tap_probe_vnet_hdr(int fd)
 206{
 207    return 0;
 208}
 209
 210int tap_probe_has_ufo(int fd)
 211{
 212    return 0;
 213}
 214
 215int tap_probe_vnet_hdr_len(int fd, int len)
 216{
 217    return 0;
 218}
 219
 220void tap_fd_set_vnet_hdr_len(int fd, int len)
 221{
 222}
 223
 224void tap_fd_set_offload(int fd, int csum, int tso4,
 225                        int tso6, int ecn, int ufo)
 226{
 227}
 228