15d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner/*
25d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * QEMU System Emulator
35d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner *
45d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * Copyright (c) 2003-2008 Fabrice Bellard
55d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner *
65d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * Permission is hereby granted, free of charge, to any person obtaining a copy
75d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * of this software and associated documentation files (the "Software"), to deal
85d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * in the Software without restriction, including without limitation the rights
95d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * copies of the Software, and to permit persons to whom the Software is
115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * furnished to do so, subject to the following conditions:
125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner *
135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * The above copyright notice and this permission notice shall be included in
145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * all copies or substantial portions of the Software.
155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner *
165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * THE SOFTWARE.
235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner */
245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <unistd.h>
255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <fcntl.h>
265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <signal.h>
275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <time.h>
285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <errno.h>
295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <sys/time.h>
305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <zlib.h>
315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
322c538c86c15d597cc875dc926e4e39285c5625dfDavid 'Digit' Turner/* Needed early for CONFIG_BSD etc. */
335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include "config-host.h"
345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#ifndef _WIN32
365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <sys/times.h>
375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <sys/wait.h>
385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <termios.h>
395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <sys/mman.h>
405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <sys/ioctl.h>
415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <sys/resource.h>
425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <sys/socket.h>
435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <netinet/in.h>
445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <net/if.h>
455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#ifdef __NetBSD__
465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <net/if_tap.h>
475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#endif
485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#ifdef __linux__
495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <linux/if_tun.h>
505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#endif
515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <arpa/inet.h>
525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <dirent.h>
535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <netdb.h>
545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <sys/select.h>
552c538c86c15d597cc875dc926e4e39285c5625dfDavid 'Digit' Turner#ifdef CONFIG_BSD
565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <sys/stat.h>
575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#if defined(__FreeBSD__) || defined(__DragonFly__)
585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <libutil.h>
595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#else
605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <util.h>
615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#endif
625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#elif defined (__GLIBC__) && defined (__FreeBSD_kernel__)
635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <freebsd/stdlib.h>
645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#else
655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#ifdef __linux__
665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <pty.h>
675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <malloc.h>
685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <linux/rtc.h>
695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner/* For the benefit of older linux systems which don't supply it,
715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner   we use a local copy of hpet.h. */
725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner/* #include <linux/hpet.h> */
735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include "hpet.h"
745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <linux/ppdev.h>
765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <linux/parport.h>
775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#endif
785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#ifdef __sun__
795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <sys/stat.h>
805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <sys/ethernet.h>
815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <sys/sockio.h>
825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <netinet/arp.h>
835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <netinet/in.h>
845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <netinet/in_systm.h>
855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <netinet/ip.h>
865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <netinet/ip_icmp.h> // must come after ip.h
875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <netinet/udp.h>
885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <netinet/tcp.h>
895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <net/if.h>
905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <syslog.h>
915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <stropts.h>
925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#endif
935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#endif
945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#endif
955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#if defined(__OpenBSD__)
975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <util.h>
985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#endif
995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#if defined(CONFIG_VDE)
1015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <libvdeplug.h>
1025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#endif
1035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#ifdef _WIN32
1055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <windows.h>
1065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <malloc.h>
1075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <sys/timeb.h>
1085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include <mmsystem.h>
1095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define getopt_long_only getopt_long
1105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define memalign(align, size) malloc(size)
1115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#endif
1125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include "qemu-common.h"
1145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include "net.h"
1155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include "monitor.h"
1165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include "sysemu.h"
1175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include "qemu-timer.h"
1185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include "qemu-char.h"
1195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include "audio/audio.h"
1205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include "qemu_socket.h"
1215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include "qemu-log.h"
1225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#if defined(CONFIG_SLIRP)
1245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#include "libslirp.h"
1255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#endif
1265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic VLANState *first_vlan;
1295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner/***********************************************************/
1315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner/* network device redirectors */
1325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#if defined(DEBUG_NET) || defined(DEBUG_SLIRP)
1345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void hex_dump(FILE *f, const uint8_t *buf, int size)
1355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
1365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int len, i, j, c;
1375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    for(i=0;i<size;i+=16) {
1395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        len = size - i;
1405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (len > 16)
1415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            len = 16;
1425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        fprintf(f, "%08x ", i);
1435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        for(j=0;j<16;j++) {
1445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            if (j < len)
1455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                fprintf(f, " %02x", buf[i+j]);
1465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            else
1475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                fprintf(f, "   ");
1485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
1495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        fprintf(f, " ");
1505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        for(j=0;j<len;j++) {
1515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            c = buf[i+j];
1525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            if (c < ' ' || c > '~')
1535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                c = '.';
1545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            fprintf(f, "%c", c);
1555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
1565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        fprintf(f, "\n");
1575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
1585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
1595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#endif
1605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int parse_macaddr(uint8_t *macaddr, const char *p)
1625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
1635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int i;
1645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    char *last_char;
1655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    long int offset;
1665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    errno = 0;
1685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    offset = strtol(p, &last_char, 0);
1695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (0 == errno && '\0' == *last_char &&
1705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            offset >= 0 && offset <= 0xFFFFFF) {
1715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        macaddr[3] = (offset & 0xFF0000) >> 16;
1725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        macaddr[4] = (offset & 0xFF00) >> 8;
1735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        macaddr[5] = offset & 0xFF;
1745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return 0;
1755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    } else {
1765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        for(i = 0; i < 6; i++) {
1775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            macaddr[i] = strtol(p, (char **)&p, 16);
1785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            if (i == 5) {
1795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                if (*p != '\0')
1805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                    return -1;
1815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            } else {
1825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                if (*p != ':' && *p != '-')
1835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                    return -1;
1845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                p++;
1855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            }
1865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
1875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return 0;
1885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
1895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return -1;
1915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
1925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int get_str_sep(char *buf, int buf_size, const char **pp, int sep)
1945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
1955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    const char *p, *p1;
1965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int len;
1975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    p = *pp;
1985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    p1 = strchr(p, sep);
1995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (!p1)
2005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return -1;
2015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    len = p1 - p;
2025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    p1++;
2035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (buf_size > 0) {
2045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (len > buf_size - 1)
2055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            len = buf_size - 1;
2065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        memcpy(buf, p, len);
2075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        buf[len] = '\0';
2085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
2095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    *pp = p1;
2105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return 0;
2115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
2125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerint parse_host_src_port(struct sockaddr_in *haddr,
2145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                        struct sockaddr_in *saddr,
2155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                        const char *input_str)
2165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
2175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    char *str = strdup(input_str);
2185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    char *host_str = str;
2195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    char *src_str;
2205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    const char *src_str2;
2215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    char *ptr;
2225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    /*
2245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner     * Chop off any extra arguments at the end of the string which
2255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner     * would start with a comma, then fill in the src port information
2265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner     * if it was provided else use the "any address" and "any port".
2275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner     */
2285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if ((ptr = strchr(str,',')))
2295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        *ptr = '\0';
2305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if ((src_str = strchr(input_str,'@'))) {
2325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        *src_str = '\0';
2335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        src_str++;
2345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
2355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (parse_host_port(haddr, host_str) < 0)
2375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        goto fail;
2385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    src_str2 = src_str;
2405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (!src_str || *src_str == '\0')
2415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        src_str2 = ":0";
2425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (parse_host_port(saddr, src_str2) < 0)
2445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        goto fail;
2455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    free(str);
2475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return(0);
2485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerfail:
2505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    free(str);
2515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return -1;
2525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
2535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerint parse_host_port(struct sockaddr_in *saddr, const char *str)
2555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
2565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    char buf[512];
2575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    struct hostent *he;
2585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    const char *p, *r;
2595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int port;
2605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    p = str;
2625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (get_str_sep(buf, sizeof(buf), &p, ':') < 0)
2635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return -1;
2645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    saddr->sin_family = AF_INET;
2655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (buf[0] == '\0') {
2665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        saddr->sin_addr.s_addr = 0;
2675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    } else {
2685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (qemu_isdigit(buf[0])) {
2695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            if (!inet_aton(buf, &saddr->sin_addr))
2705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                return -1;
2715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        } else {
2725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            if ((he = gethostbyname(buf)) == NULL)
2735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                return - 1;
2745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            saddr->sin_addr = *(struct in_addr *)he->h_addr;
2755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
2765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
2775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    port = strtol(p, (char **)&r, 0);
2785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (r == p)
2795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return -1;
2805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    saddr->sin_port = htons(port);
2815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return 0;
2825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
2835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#if !defined(_WIN32) && 0
2855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int parse_unix_path(struct sockaddr_un *uaddr, const char *str)
2865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
2875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    const char *p;
2885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int len;
2895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    len = MIN(108, strlen(str));
2915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    p = strchr(str, ',');
2925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (p)
2935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	len = MIN(len, p - str);
2945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    memset(uaddr, 0, sizeof(*uaddr));
2965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
2975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    uaddr->sun_family = AF_UNIX;
2985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    memcpy(uaddr->sun_path, str, len);
2995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return 0;
3015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
3025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#endif
3035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid qemu_format_nic_info_str(VLANClientState *vc, uint8_t macaddr[6])
3055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
3065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    snprintf(vc->info_str, sizeof(vc->info_str),
3075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner             "model=%s,macaddr=%02x:%02x:%02x:%02x:%02x:%02x",
3085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner             vc->model,
3095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner             macaddr[0], macaddr[1], macaddr[2],
3105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner             macaddr[3], macaddr[4], macaddr[5]);
3115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
3125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic char *assign_name(VLANClientState *vc1, const char *model)
3145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
3155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    VLANState *vlan;
3165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    char buf[256];
3175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int id = 0;
3185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    for (vlan = first_vlan; vlan; vlan = vlan->next) {
3205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        VLANClientState *vc;
3215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        for (vc = vlan->first_client; vc; vc = vc->next)
3235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            if (vc != vc1 && strcmp(vc->model, model) == 0)
3245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                id++;
3255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
3265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    snprintf(buf, sizeof(buf), "%s.%d", model, id);
3285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return strdup(buf);
3305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
3315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' TurnerVLANClientState *qemu_new_vlan_client(VLANState *vlan,
3335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                                      const char *model,
3345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                                      const char *name,
3355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                                      NetCanReceive *can_receive,
3365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                                      NetReceive *receive,
3375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                                      NetReceiveIOV *receive_iov,
3385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                                      NetCleanup *cleanup,
3395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                                      void *opaque)
3405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
3415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    VLANClientState *vc, **pvc;
3425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    vc = qemu_mallocz(sizeof(VLANClientState));
3435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    vc->model = strdup(model);
3445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (name)
3455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        vc->name = strdup(name);
3465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    else
3475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        vc->name = assign_name(vc, model);
3485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    vc->can_receive = can_receive;
3495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    vc->receive = receive;
3505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    vc->receive_iov = receive_iov;
3515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    vc->cleanup = cleanup;
3525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    vc->opaque = opaque;
3535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    vc->vlan = vlan;
3545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    vc->next = NULL;
3565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    pvc = &vlan->first_client;
3575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    while (*pvc != NULL)
3585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        pvc = &(*pvc)->next;
3595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    *pvc = vc;
3605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return vc;
3615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
3625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid qemu_del_vlan_client(VLANClientState *vc)
3645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
3655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    VLANClientState **pvc = &vc->vlan->first_client;
3665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    while (*pvc != NULL)
3685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (*pvc == vc) {
3695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            *pvc = vc->next;
3705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            if (vc->cleanup) {
3715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                vc->cleanup(vc);
3725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            }
3735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            free(vc->name);
3745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            free(vc->model);
3755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            qemu_free(vc);
3765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            break;
3775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        } else
3785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            pvc = &(*pvc)->next;
3795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
3805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' TurnerVLANClientState *qemu_find_vlan_client(VLANState *vlan, void *opaque)
3825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
3835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    VLANClientState **pvc = &vlan->first_client;
3845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    while (*pvc != NULL)
3865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if ((*pvc)->opaque == opaque)
3875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            return *pvc;
3885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        else
3895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            pvc = &(*pvc)->next;
3905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return NULL;
3925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
3935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerint qemu_can_send_packet(VLANClientState *sender)
3955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
3965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    VLANState *vlan = sender->vlan;
3975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    VLANClientState *vc;
3985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
3995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    for (vc = vlan->first_client; vc != NULL; vc = vc->next) {
4005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (vc == sender) {
4015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            continue;
4025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
4035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
4045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        /* no can_receive() handler, they can always receive */
4055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (!vc->can_receive || vc->can_receive(vc)) {
4065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            return 1;
4075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
4085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
4095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return 0;
4105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
4115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
4125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int
4135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerqemu_deliver_packet(VLANClientState *sender, const uint8_t *buf, int size)
4145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
4155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    VLANClientState *vc;
4165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int ret = -1;
4175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
4185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    sender->vlan->delivering = 1;
4195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
4205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    for (vc = sender->vlan->first_client; vc != NULL; vc = vc->next) {
4215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        ssize_t len;
4225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
4235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (vc == sender) {
4245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            continue;
4255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
4265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
4275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (vc->link_down) {
4285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            ret = size;
4295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            continue;
4305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
4315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
4325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        len = vc->receive(vc, buf, size);
4335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
4345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        ret = (ret >= 0) ? ret : len;
4355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
4365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
4375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    sender->vlan->delivering = 0;
4385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
4395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return ret;
4405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
4415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
4425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid qemu_flush_queued_packets(VLANClientState *vc)
4435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
4445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    VLANPacket *packet;
4455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
4465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    while ((packet = vc->vlan->send_queue) != NULL) {
4475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        int ret;
4485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
4495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        vc->vlan->send_queue = packet->next;
4505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
4515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        ret = qemu_deliver_packet(packet->sender, packet->data, packet->size);
4525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (ret == 0 && packet->sent_cb != NULL) {
4535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            packet->next = vc->vlan->send_queue;
4545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            vc->vlan->send_queue = packet;
4555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            break;
4565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
4575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
4585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (packet->sent_cb)
4595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            packet->sent_cb(packet->sender);
4605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
4615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        qemu_free(packet);
4625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
4635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
4645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
4655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void qemu_enqueue_packet(VLANClientState *sender,
4665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                                const uint8_t *buf, int size,
4675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                                NetPacketSent *sent_cb)
4685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
4695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    VLANPacket *packet;
4705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
4715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    packet = qemu_malloc(sizeof(VLANPacket) + size);
4725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    packet->next = sender->vlan->send_queue;
4735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    packet->sender = sender;
4745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    packet->size = size;
4755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    packet->sent_cb = sent_cb;
4765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    memcpy(packet->data, buf, size);
4775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    sender->vlan->send_queue = packet;
4785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
4795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
4805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerssize_t qemu_send_packet_async(VLANClientState *sender,
4815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                               const uint8_t *buf, int size,
4825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                               NetPacketSent *sent_cb)
4835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
4845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int ret;
4855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
4865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (sender->link_down) {
4875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return size;
4885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
4895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
4905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#ifdef DEBUG_NET
4915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    printf("vlan %d send:\n", sender->vlan->id);
4925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    hex_dump(stdout, buf, size);
4935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#endif
4945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
4955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (sender->vlan->delivering) {
4965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        qemu_enqueue_packet(sender, buf, size, NULL);
4975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return size;
4985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
4995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
5005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    ret = qemu_deliver_packet(sender, buf, size);
5015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (ret == 0 && sent_cb != NULL) {
5025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        qemu_enqueue_packet(sender, buf, size, sent_cb);
5035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return 0;
5045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
5055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
5065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qemu_flush_queued_packets(sender);
5075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
5085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return ret;
5095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
5105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
5115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid qemu_send_packet(VLANClientState *vc, const uint8_t *buf, int size)
5125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
5135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qemu_send_packet_async(vc, buf, size, NULL);
5145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
5155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
5165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic ssize_t vc_sendv_compat(VLANClientState *vc, const struct iovec *iov,
5175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                               int iovcnt)
5185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
5195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    uint8_t buffer[4096];
5205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    size_t offset = 0;
5215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int i;
5225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
5235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    for (i = 0; i < iovcnt; i++) {
5245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        size_t len;
5255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
5265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        len = MIN(sizeof(buffer) - offset, iov[i].iov_len);
5275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        memcpy(buffer + offset, iov[i].iov_base, len);
5285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        offset += len;
5295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
5305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
5315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return vc->receive(vc, buffer, offset);
5325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
5335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
5345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic ssize_t calc_iov_length(const struct iovec *iov, int iovcnt)
5355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
5365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    size_t offset = 0;
5375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int i;
5385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
5395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    for (i = 0; i < iovcnt; i++)
5405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        offset += iov[i].iov_len;
5415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return offset;
5425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
5435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
5445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int qemu_deliver_packet_iov(VLANClientState *sender,
5455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                                   const struct iovec *iov, int iovcnt)
5465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
5475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    VLANClientState *vc;
5485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int ret = -1;
5495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
5505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    sender->vlan->delivering = 1;
5515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
5525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    for (vc = sender->vlan->first_client; vc != NULL; vc = vc->next) {
5535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        ssize_t len;
5545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
5555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (vc == sender) {
5565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            continue;
5575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
5585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
5595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (vc->link_down) {
5605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            ret = calc_iov_length(iov, iovcnt);
5615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            continue;
5625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
5635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
5645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (vc->receive_iov) {
5655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            len = vc->receive_iov(vc, iov, iovcnt);
5665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        } else {
5675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            len = vc_sendv_compat(vc, iov, iovcnt);
5685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
5695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
5705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        ret = (ret >= 0) ? ret : len;
5715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
5725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
5735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    sender->vlan->delivering = 0;
5745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
5755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return ret;
5765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
5775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
5785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic ssize_t qemu_enqueue_packet_iov(VLANClientState *sender,
5795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                                       const struct iovec *iov, int iovcnt,
5805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                                       NetPacketSent *sent_cb)
5815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
5825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    VLANPacket *packet;
5835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    size_t max_len = 0;
5845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int i;
5855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
5865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    max_len = calc_iov_length(iov, iovcnt);
5875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
5885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    packet = qemu_malloc(sizeof(VLANPacket) + max_len);
5895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    packet->next = sender->vlan->send_queue;
5905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    packet->sender = sender;
5915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    packet->sent_cb = sent_cb;
5925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    packet->size = 0;
5935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
5945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    for (i = 0; i < iovcnt; i++) {
5955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        size_t len = iov[i].iov_len;
5965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
5975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        memcpy(packet->data + packet->size, iov[i].iov_base, len);
5985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        packet->size += len;
5995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
6005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
6015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    sender->vlan->send_queue = packet;
6025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
6035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return packet->size;
6045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
6055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
6065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerssize_t qemu_sendv_packet_async(VLANClientState *sender,
6075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                                const struct iovec *iov, int iovcnt,
6085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                                NetPacketSent *sent_cb)
6095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
6105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int ret;
6115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
6125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (sender->link_down) {
6135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return calc_iov_length(iov, iovcnt);
6145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
6155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
6165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (sender->vlan->delivering) {
6175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return qemu_enqueue_packet_iov(sender, iov, iovcnt, NULL);
6185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
6195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
6205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    ret = qemu_deliver_packet_iov(sender, iov, iovcnt);
6215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (ret == 0 && sent_cb != NULL) {
6225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        qemu_enqueue_packet_iov(sender, iov, iovcnt, sent_cb);
6235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return 0;
6245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
6255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
6265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qemu_flush_queued_packets(sender);
6275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
6285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return ret;
6295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
6305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
6315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerssize_t
6325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerqemu_sendv_packet(VLANClientState *vc, const struct iovec *iov, int iovcnt)
6335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
6345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return qemu_sendv_packet_async(vc, iov, iovcnt, NULL);
6355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
6365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
6375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void config_error(Monitor *mon, const char *fmt, ...)
6385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
6395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    va_list ap;
6405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
6415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    va_start(ap, fmt);
6425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (mon) {
6435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        monitor_vprintf(mon, fmt, ap);
6445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    } else {
6455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        fprintf(stderr, "qemu: ");
6465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        vfprintf(stderr, fmt, ap);
6475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        exit(1);
6485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
6495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    va_end(ap);
6505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
6515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
6525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#if defined(CONFIG_SLIRP)
6535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
6545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner/* slirp network adapter */
6555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
6565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstruct slirp_config_str {
6575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    struct slirp_config_str *next;
6585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    const char *str;
6595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner};
6605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
6615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int slirp_inited;
6625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic struct slirp_config_str *slirp_redirs;
6635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#ifndef _WIN32
6645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic const char *slirp_smb_export;
6655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#endif
6665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic VLANClientState *slirp_vc;
6675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
6685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#ifndef _WIN32
6695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void slirp_smb(const char *exported_dir);
6705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#endif
6715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void slirp_redirection(Monitor *mon, const char *redir_str);
6725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
6735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerint slirp_can_output(void)
6745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
6755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return !slirp_vc || qemu_can_send_packet(slirp_vc);
6765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
6775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
6785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid slirp_output(const uint8_t *pkt, int pkt_len)
6795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
6805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#ifdef DEBUG_SLIRP
6815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    printf("slirp output:\n");
6825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    hex_dump(stdout, pkt, pkt_len);
6835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#endif
6845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (!slirp_vc)
6855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return;
6865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qemu_send_packet(slirp_vc, pkt, pkt_len);
6875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
6885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
6895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerint slirp_is_inited(void)
6905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
6915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return slirp_inited;
6925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
6935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
6945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic ssize_t slirp_receive(VLANClientState *vc, const uint8_t *buf, size_t size)
6955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
6965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#ifdef DEBUG_SLIRP
6975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    printf("slirp input:\n");
6985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    hex_dump(stdout, buf, size);
6995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#endif
7005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    slirp_input(buf, size);
7015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return size;
7025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
7035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
7045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int slirp_in_use;
7055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
7065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void net_slirp_cleanup(VLANClientState *vc)
7075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
7085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    slirp_in_use = 0;
7095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
7105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
7115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int net_slirp_init(VLANState *vlan, const char *model, const char *name,
7125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                          int restricted, const char *ip)
7135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
7145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (slirp_in_use) {
7155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        /* slirp only supports a single instance so far */
7165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return -1;
7175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
7185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (!slirp_inited) {
7195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        slirp_inited = 1;
7205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        slirp_init(restricted, ip);
7215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
7225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        while (slirp_redirs) {
7235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            struct slirp_config_str *config = slirp_redirs;
7245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
7255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            slirp_redirection(NULL, config->str);
7265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            slirp_redirs = config->next;
7275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            qemu_free(config);
7285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
7295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#ifndef _WIN32
7305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (slirp_smb_export) {
7315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            slirp_smb(slirp_smb_export);
7325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
7335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#endif
7345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
7355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
7365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    slirp_vc = qemu_new_vlan_client(vlan, model, name, NULL, slirp_receive,
7375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                                    NULL, net_slirp_cleanup, NULL);
7385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    slirp_vc->info_str[0] = '\0';
7395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    slirp_in_use = 1;
7405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return 0;
7415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
7425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
7435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void net_slirp_redir_print(void *opaque, int is_udp,
7445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                                  struct in_addr *laddr, u_int lport,
7455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                                  struct in_addr *faddr, u_int fport)
7465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
7475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    Monitor *mon = (Monitor *)opaque;
7485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    uint32_t h_addr;
7495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    uint32_t g_addr;
7505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    char buf[16];
7515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
7525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    h_addr = ntohl(faddr->s_addr);
7535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    g_addr = ntohl(laddr->s_addr);
7545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
7555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    monitor_printf(mon, "  %s |", is_udp ? "udp" : "tcp" );
7565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    snprintf(buf, 15, "%d.%d.%d.%d", (h_addr >> 24) & 0xff,
7575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                                     (h_addr >> 16) & 0xff,
7585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                                     (h_addr >> 8) & 0xff,
7595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                                     (h_addr) & 0xff);
7605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    monitor_printf(mon, " %15s |", buf);
7615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    monitor_printf(mon, " %5d |", fport);
7625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
7635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    snprintf(buf, 15, "%d.%d.%d.%d", (g_addr >> 24) & 0xff,
7645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                                     (g_addr >> 16) & 0xff,
7655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                                     (g_addr >> 8) & 0xff,
7665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                                     (g_addr) & 0xff);
7675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    monitor_printf(mon, " %15s |", buf);
7685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    monitor_printf(mon, " %5d\n", lport);
7695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
7705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
7715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
7725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void net_slirp_redir_list(Monitor *mon)
7735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
7745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (!mon)
7755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return;
7765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
7775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    monitor_printf(mon, " Prot |    Host Addr    | HPort |    Guest Addr   | GPort\n");
7785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    monitor_printf(mon, "      |                 |       |                 |      \n");
7795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    slirp_redir_loop(net_slirp_redir_print, mon);
7805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
7815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
7825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void net_slirp_redir_rm(Monitor *mon, const char *port_str)
7835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
7845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int host_port;
7855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    char buf[256] = "";
7865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    const char *p = port_str;
7875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int is_udp = 0;
7885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int n;
7895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
7905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (!mon)
7915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return;
7925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
7935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (!port_str || !port_str[0])
7945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        goto fail_syntax;
7955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
7965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    get_str_sep(buf, sizeof(buf), &p, ':');
7975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
7985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (!strcmp(buf, "tcp") || buf[0] == '\0') {
7995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        is_udp = 0;
8005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    } else if (!strcmp(buf, "udp")) {
8015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        is_udp = 1;
8025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    } else {
8035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        goto fail_syntax;
8045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
8055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
8065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    host_port = atoi(p);
8075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
8085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    n = slirp_redir_rm(is_udp, host_port);
8095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
8105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    monitor_printf(mon, "removed %d redirections to %s port %d\n", n,
8115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                        is_udp ? "udp" : "tcp", host_port);
8125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return;
8135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
8145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner fail_syntax:
8155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    monitor_printf(mon, "invalid format\n");
8165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
8175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
8185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void slirp_redirection(Monitor *mon, const char *redir_str)
8195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
8205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    struct in_addr guest_addr;
8215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int host_port, guest_port;
8225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    const char *p;
8235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    char buf[256], *r;
8245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int is_udp;
8255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
8265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    p = redir_str;
8275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) {
8285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        goto fail_syntax;
8295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
8305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (!strcmp(buf, "tcp") || buf[0] == '\0') {
8315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        is_udp = 0;
8325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    } else if (!strcmp(buf, "udp")) {
8335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        is_udp = 1;
8345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    } else {
8355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        goto fail_syntax;
8365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
8375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
8385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) {
8395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        goto fail_syntax;
8405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
8415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    host_port = strtol(buf, &r, 0);
8425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (r == buf) {
8435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        goto fail_syntax;
8445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
8455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
8465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) {
8475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        goto fail_syntax;
8485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
8495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (buf[0] == '\0') {
8505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        pstrcpy(buf, sizeof(buf), "10.0.2.15");
8515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
8525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (!inet_aton(buf, &guest_addr)) {
8535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        goto fail_syntax;
8545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
8555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
8565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    guest_port = strtol(p, &r, 0);
8575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (r == p) {
8585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        goto fail_syntax;
8595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
8605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
8615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (slirp_redir(is_udp, host_port, guest_addr, guest_port) < 0) {
8625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        config_error(mon, "could not set up redirection '%s'\n", redir_str);
8635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
8645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return;
8655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
8665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner fail_syntax:
8675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    config_error(mon, "invalid redirection format '%s'\n", redir_str);
8685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
8695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
8705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid net_slirp_redir(Monitor *mon, const char *redir_str, const char *redir_opt2)
8715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
8725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    struct slirp_config_str *config;
8735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
8745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (!slirp_inited) {
8755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (mon) {
8765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            monitor_printf(mon, "user mode network stack not in use\n");
8775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        } else {
8785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            config = qemu_malloc(sizeof(*config));
8795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            config->str = redir_str;
8805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            config->next = slirp_redirs;
8815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            slirp_redirs = config;
8825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
8835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return;
8845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
8855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
8865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (!strcmp(redir_str, "remove")) {
8875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        net_slirp_redir_rm(mon, redir_opt2);
8885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return;
8895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
8905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
8915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (!strcmp(redir_str, "list")) {
8925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        net_slirp_redir_list(mon);
8935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return;
8945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
8955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
8965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    slirp_redirection(mon, redir_str);
8975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
8985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
8995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#ifndef _WIN32
9005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
9015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic char smb_dir[1024];
9025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
9035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void erase_dir(char *dir_name)
9045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
9055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    DIR *d;
9065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    struct dirent *de;
9075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    char filename[1024];
9085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
9095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    /* erase all the files in the directory */
9105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if ((d = opendir(dir_name)) != NULL) {
9115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        for(;;) {
9125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            de = readdir(d);
9135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            if (!de)
9145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                break;
9155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            if (strcmp(de->d_name, ".") != 0 &&
9165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                strcmp(de->d_name, "..") != 0) {
9175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                snprintf(filename, sizeof(filename), "%s/%s",
9185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                         smb_dir, de->d_name);
9195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                if (unlink(filename) != 0)  /* is it a directory? */
9205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                    erase_dir(filename);
9215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            }
9225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
9235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        closedir(d);
9245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        rmdir(dir_name);
9255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
9265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
9275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
9285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner/* automatic user mode samba server configuration */
9295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void smb_exit(void)
9305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
9315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    erase_dir(smb_dir);
9325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
9335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
9345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void slirp_smb(const char *exported_dir)
9355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
9365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    char smb_conf[1024];
9375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    char smb_cmdline[1024];
9385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    FILE *f;
9395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
9405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    /* XXX: better tmp dir construction */
9415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    snprintf(smb_dir, sizeof(smb_dir), "/tmp/qemu-smb.%ld", (long)getpid());
9425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (mkdir(smb_dir, 0700) < 0) {
9435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        fprintf(stderr, "qemu: could not create samba server dir '%s'\n", smb_dir);
9445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        exit(1);
9455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
9465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    snprintf(smb_conf, sizeof(smb_conf), "%s/%s", smb_dir, "smb.conf");
9475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
9485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    f = fopen(smb_conf, "w");
9495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (!f) {
9505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        fprintf(stderr, "qemu: could not create samba server configuration file '%s'\n", smb_conf);
9515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        exit(1);
9525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
9535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    fprintf(f,
9545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            "[global]\n"
9555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            "private dir=%s\n"
9565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            "smb ports=0\n"
9575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            "socket address=127.0.0.1\n"
9585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            "pid directory=%s\n"
9595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            "lock directory=%s\n"
9605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            "log file=%s/log.smbd\n"
9615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            "smb passwd file=%s/smbpasswd\n"
9625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            "security = share\n"
9635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            "[qemu]\n"
9645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            "path=%s\n"
9655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            "read only=no\n"
9665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            "guest ok=yes\n",
9675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            smb_dir,
9685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            smb_dir,
9695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            smb_dir,
9705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            smb_dir,
9715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            smb_dir,
9725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            exported_dir
9735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            );
9745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    fclose(f);
9755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    atexit(smb_exit);
9765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
9775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    snprintf(smb_cmdline, sizeof(smb_cmdline), "%s -s %s",
9785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner             SMBD_COMMAND, smb_conf);
9795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
9805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    slirp_add_exec(0, smb_cmdline, 4, 139);
9815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
9825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
9835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner/* automatic user mode samba server configuration */
9845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid net_slirp_smb(const char *exported_dir)
9855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
9865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (slirp_smb_export) {
9875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        fprintf(stderr, "-smb given twice\n");
9885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        exit(1);
9895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
9905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    slirp_smb_export = exported_dir;
9915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (slirp_inited) {
9925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        slirp_smb(exported_dir);
9935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
9945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
9955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
9965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#endif /* !defined(_WIN32) */
9975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
9985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid do_info_slirp(Monitor *mon)
9995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
10005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    slirp_stats();
10015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
10025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
10035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstruct VMChannel {
10045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    CharDriverState *hd;
10055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int port;
10065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner};
10075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
10085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int vmchannel_can_read(void *opaque)
10095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
10105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    struct VMChannel *vmc = (struct VMChannel*)opaque;
10115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return slirp_socket_can_recv(4, vmc->port);
10125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
10135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
10145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void vmchannel_read(void *opaque, const uint8_t *buf, int size)
10155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
10165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    struct VMChannel *vmc = (struct VMChannel*)opaque;
10175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    slirp_socket_recv(4, vmc->port, buf, size);
10185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
10195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
10205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#endif /* CONFIG_SLIRP */
10215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
10225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#if !defined(_WIN32)
10235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
10245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnertypedef struct TAPState {
10255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    VLANClientState *vc;
10265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int fd;
10275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    char down_script[1024];
10285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    char down_script_arg[128];
10295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    uint8_t buf[4096];
10305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} TAPState;
10315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
10325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int launch_script(const char *setup_script, const char *ifname, int fd);
10335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
10345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic ssize_t tap_receive_iov(VLANClientState *vc, const struct iovec *iov,
10355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                               int iovcnt)
10365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
10375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    TAPState *s = vc->opaque;
10385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    ssize_t len;
10395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
10405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    do {
10415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        len = writev(s->fd, iov, iovcnt);
10425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    } while (len == -1 && (errno == EINTR || errno == EAGAIN));
10435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
10445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return len;
10455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
10465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
10475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic ssize_t tap_receive(VLANClientState *vc, const uint8_t *buf, size_t size)
10485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
10495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    TAPState *s = vc->opaque;
10505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    ssize_t len;
10515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
10525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    do {
10535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        len = write(s->fd, buf, size);
10545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    } while (len == -1 && (errno == EINTR || errno == EAGAIN));
10555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
10565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return len;
10575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
10585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
10595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int tap_can_send(void *opaque)
10605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
10615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    TAPState *s = opaque;
10625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
10635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return qemu_can_send_packet(s->vc);
10645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
10655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
10665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#ifdef __sun__
10675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic ssize_t tap_read_packet(int tapfd, uint8_t *buf, int maxlen)
10685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
10695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    struct strbuf sbuf;
10705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int f = 0;
10715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
10725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    sbuf.maxlen = maxlen;
10735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    sbuf.buf = (char *)buf;
10745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
10755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return getmsg(tapfd, NULL, &sbuf, &f) >= 0 ? sbuf.len : -1;
10765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
10775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#else
10785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic ssize_t tap_read_packet(int tapfd, uint8_t *buf, int maxlen)
10795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
10805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return read(tapfd, buf, maxlen);
10815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
10825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#endif
10835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
10845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void tap_send(void *opaque);
10855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
10865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void tap_send_completed(VLANClientState *vc)
10875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
10885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    TAPState *s = vc->opaque;
10895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
10905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qemu_set_fd_handler2(s->fd, tap_can_send, tap_send, NULL, s);
10915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
10925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
10935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void tap_send(void *opaque)
10945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
10955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    TAPState *s = opaque;
10965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int size;
10975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
10985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    do {
10995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        size = tap_read_packet(s->fd, s->buf, sizeof(s->buf));
11005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (size <= 0) {
11015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            break;
11025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
11035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
11045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        size = qemu_send_packet_async(s->vc, s->buf, size, tap_send_completed);
11055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (size == 0) {
11065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL);
11075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
11085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    } while (size > 0);
11095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
11105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
11115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void tap_cleanup(VLANClientState *vc)
11125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
11135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    TAPState *s = vc->opaque;
11145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
11155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (s->down_script[0])
11165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        launch_script(s->down_script, s->down_script_arg, s->fd);
11175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
11185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qemu_set_fd_handler(s->fd, NULL, NULL, NULL);
11195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    close(s->fd);
11205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qemu_free(s);
11215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
11225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
11235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner/* fd support */
11245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
11255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic TAPState *net_tap_fd_init(VLANState *vlan,
11265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                                 const char *model,
11275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                                 const char *name,
11285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                                 int fd)
11295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
11305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    TAPState *s;
11315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
11325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    s = qemu_mallocz(sizeof(TAPState));
11335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    s->fd = fd;
11345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    s->vc = qemu_new_vlan_client(vlan, model, name, NULL, tap_receive,
11355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                                 tap_receive_iov, tap_cleanup, s);
11365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qemu_set_fd_handler2(s->fd, tap_can_send, tap_send, NULL, s);
11375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    snprintf(s->vc->info_str, sizeof(s->vc->info_str), "fd=%d", fd);
11385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return s;
11395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
11405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
11412c538c86c15d597cc875dc926e4e39285c5625dfDavid 'Digit' Turner#if defined (CONFIG_BSD) || defined (__FreeBSD_kernel__)
11425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int tap_open(char *ifname, int ifname_size)
11435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
11445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int fd;
11455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    char *dev;
11465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    struct stat s;
11475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
11485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    TFR(fd = open("/dev/tap", O_RDWR));
11495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (fd < 0) {
11505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        fprintf(stderr, "warning: could not open /dev/tap: no virtual network emulation\n");
11515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return -1;
11525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
11535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
11545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    fstat(fd, &s);
11555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    dev = devname(s.st_rdev, S_IFCHR);
11565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    pstrcpy(ifname, ifname_size, dev);
11575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
11585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    fcntl(fd, F_SETFL, O_NONBLOCK);
11595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return fd;
11605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
11615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#elif defined(__sun__)
11625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define TUNNEWPPA       (('T'<<16) | 0x0001)
11635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner/*
11645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * Allocate TAP device, returns opened fd.
11655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner * Stores dev name in the first arg(must be large enough).
11665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner */
11675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int tap_alloc(char *dev, size_t dev_size)
11685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
11695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int tap_fd, if_fd, ppa = -1;
11705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    static int ip_fd = 0;
11715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    char *ptr;
11725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
11735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    static int arp_fd = 0;
11745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int ip_muxid, arp_muxid;
11755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    struct strioctl  strioc_if, strioc_ppa;
11765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int link_type = I_PLINK;;
11775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    struct lifreq ifr;
11785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    char actual_name[32] = "";
11795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
11805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    memset(&ifr, 0x0, sizeof(ifr));
11815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
11825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if( *dev ){
11835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner       ptr = dev;
11845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner       while( *ptr && !qemu_isdigit((int)*ptr) ) ptr++;
11855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner       ppa = atoi(ptr);
11865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
11875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
11885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    /* Check if IP device was opened */
11895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if( ip_fd )
11905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner       close(ip_fd);
11915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
11925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    TFR(ip_fd = open("/dev/udp", O_RDWR, 0));
11935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (ip_fd < 0) {
11945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner       syslog(LOG_ERR, "Can't open /dev/ip (actually /dev/udp)");
11955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner       return -1;
11965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
11975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
11985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    TFR(tap_fd = open("/dev/tap", O_RDWR, 0));
11995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (tap_fd < 0) {
12005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner       syslog(LOG_ERR, "Can't open /dev/tap");
12015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner       return -1;
12025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
12035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
12045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    /* Assign a new PPA and get its unit number. */
12055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    strioc_ppa.ic_cmd = TUNNEWPPA;
12065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    strioc_ppa.ic_timout = 0;
12075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    strioc_ppa.ic_len = sizeof(ppa);
12085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    strioc_ppa.ic_dp = (char *)&ppa;
12095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if ((ppa = ioctl (tap_fd, I_STR, &strioc_ppa)) < 0)
12105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner       syslog (LOG_ERR, "Can't assign new interface");
12115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
12125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    TFR(if_fd = open("/dev/tap", O_RDWR, 0));
12135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (if_fd < 0) {
12145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner       syslog(LOG_ERR, "Can't open /dev/tap (2)");
12155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner       return -1;
12165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
12175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if(ioctl(if_fd, I_PUSH, "ip") < 0){
12185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner       syslog(LOG_ERR, "Can't push IP module");
12195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner       return -1;
12205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
12215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
12225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (ioctl(if_fd, SIOCGLIFFLAGS, &ifr) < 0)
12235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	syslog(LOG_ERR, "Can't get flags\n");
12245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
12255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    snprintf (actual_name, 32, "tap%d", ppa);
12265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    pstrcpy(ifr.lifr_name, sizeof(ifr.lifr_name), actual_name);
12275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
12285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    ifr.lifr_ppa = ppa;
12295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    /* Assign ppa according to the unit number returned by tun device */
12305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
12315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (ioctl (if_fd, SIOCSLIFNAME, &ifr) < 0)
12325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        syslog (LOG_ERR, "Can't set PPA %d", ppa);
12335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (ioctl(if_fd, SIOCGLIFFLAGS, &ifr) <0)
12345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        syslog (LOG_ERR, "Can't get flags\n");
12355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    /* Push arp module to if_fd */
12365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (ioctl (if_fd, I_PUSH, "arp") < 0)
12375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        syslog (LOG_ERR, "Can't push ARP module (2)");
12385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
12395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    /* Push arp module to ip_fd */
12405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (ioctl (ip_fd, I_POP, NULL) < 0)
12415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        syslog (LOG_ERR, "I_POP failed\n");
12425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (ioctl (ip_fd, I_PUSH, "arp") < 0)
12435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        syslog (LOG_ERR, "Can't push ARP module (3)\n");
12445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    /* Open arp_fd */
12455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    TFR(arp_fd = open ("/dev/tap", O_RDWR, 0));
12465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (arp_fd < 0)
12475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner       syslog (LOG_ERR, "Can't open %s\n", "/dev/tap");
12485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
12495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    /* Set ifname to arp */
12505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    strioc_if.ic_cmd = SIOCSLIFNAME;
12515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    strioc_if.ic_timout = 0;
12525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    strioc_if.ic_len = sizeof(ifr);
12535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    strioc_if.ic_dp = (char *)&ifr;
12545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (ioctl(arp_fd, I_STR, &strioc_if) < 0){
12555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        syslog (LOG_ERR, "Can't set ifname to arp\n");
12565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
12575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
12585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if((ip_muxid = ioctl(ip_fd, I_LINK, if_fd)) < 0){
12595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner       syslog(LOG_ERR, "Can't link TAP device to IP");
12605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner       return -1;
12615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
12625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
12635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if ((arp_muxid = ioctl (ip_fd, link_type, arp_fd)) < 0)
12645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        syslog (LOG_ERR, "Can't link TAP device to ARP");
12655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
12665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    close (if_fd);
12675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
12685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    memset(&ifr, 0x0, sizeof(ifr));
12695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    pstrcpy(ifr.lifr_name, sizeof(ifr.lifr_name), actual_name);
12705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    ifr.lifr_ip_muxid  = ip_muxid;
12715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    ifr.lifr_arp_muxid = arp_muxid;
12725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
12735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (ioctl (ip_fd, SIOCSLIFMUXID, &ifr) < 0)
12745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    {
12755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner      ioctl (ip_fd, I_PUNLINK , arp_muxid);
12765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner      ioctl (ip_fd, I_PUNLINK, ip_muxid);
12775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner      syslog (LOG_ERR, "Can't set multiplexor id");
12785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
12795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
12805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    snprintf(dev, dev_size, "tap%d", ppa);
12815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return tap_fd;
12825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
12835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
12845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int tap_open(char *ifname, int ifname_size)
12855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
12865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    char  dev[10]="";
12875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int fd;
12885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if( (fd = tap_alloc(dev, sizeof(dev))) < 0 ){
12895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner       fprintf(stderr, "Cannot allocate TAP device\n");
12905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner       return -1;
12915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
12925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    pstrcpy(ifname, ifname_size, dev);
12935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    fcntl(fd, F_SETFL, O_NONBLOCK);
12945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return fd;
12955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
12965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#elif defined (_AIX)
12975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int tap_open(char *ifname, int ifname_size)
12985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
12995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    fprintf (stderr, "no tap on AIX\n");
13005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return -1;
13015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
13025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#else
13035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int tap_open(char *ifname, int ifname_size)
13045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
13055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    struct ifreq ifr;
13065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int fd, ret;
13075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
13085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    TFR(fd = open("/dev/net/tun", O_RDWR));
13095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (fd < 0) {
13105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        fprintf(stderr, "warning: could not open /dev/net/tun: no virtual network emulation\n");
13115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return -1;
13125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
13135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    memset(&ifr, 0, sizeof(ifr));
13145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
13155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (ifname[0] != '\0')
13165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        pstrcpy(ifr.ifr_name, IFNAMSIZ, ifname);
13175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    else
13185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        pstrcpy(ifr.ifr_name, IFNAMSIZ, "tap%d");
13195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    ret = ioctl(fd, TUNSETIFF, (void *) &ifr);
13205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (ret != 0) {
13215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        fprintf(stderr, "warning: could not configure /dev/net/tun: no virtual network emulation\n");
13225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        close(fd);
13235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return -1;
13245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
13255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    pstrcpy(ifname, ifname_size, ifr.ifr_name);
13265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    fcntl(fd, F_SETFL, O_NONBLOCK);
13275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return fd;
13285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
13295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#endif
13305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
13315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int launch_script(const char *setup_script, const char *ifname, int fd)
13325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
13335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    sigset_t oldmask, mask;
13345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int pid, status;
13355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    char *args[3];
13365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    char **parg;
13375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
13385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    sigemptyset(&mask);
13395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    sigaddset(&mask, SIGCHLD);
13405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    sigprocmask(SIG_BLOCK, &mask, &oldmask);
13415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
13425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    /* try to launch network script */
13435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    pid = fork();
13445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (pid == 0) {
13455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        int open_max = sysconf(_SC_OPEN_MAX), i;
13465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
13475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        for (i = 0; i < open_max; i++) {
13485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            if (i != STDIN_FILENO &&
13495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                i != STDOUT_FILENO &&
13505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                i != STDERR_FILENO &&
13515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                i != fd) {
13525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                close(i);
13535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            }
13545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
13555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        parg = args;
13565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        *parg++ = (char *)setup_script;
13575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        *parg++ = (char *)ifname;
13585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        *parg++ = NULL;
13595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        execv(setup_script, args);
13604a2c9dd7630ce51a660e1aa14e10bc6fbc4621c4Iliyan Malchev        exit(1);
13615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    } else if (pid > 0) {
13625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        while (waitpid(pid, &status, 0) != pid) {
13635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            /* loop */
13645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
13655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        sigprocmask(SIG_SETMASK, &oldmask, NULL);
13665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
13675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
13685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            return 0;
13695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
13705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
13715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    fprintf(stderr, "%s: could not launch network script\n", setup_script);
13725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return -1;
13735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
13745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
13755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int net_tap_init(VLANState *vlan, const char *model,
13765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                        const char *name, const char *ifname1,
13775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                        const char *setup_script, const char *down_script)
13785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
13795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    TAPState *s;
13805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int fd;
13815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    char ifname[128];
13825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
13835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (ifname1 != NULL)
13845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        pstrcpy(ifname, sizeof(ifname), ifname1);
13855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    else
13865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        ifname[0] = '\0';
13875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    TFR(fd = tap_open(ifname, sizeof(ifname)));
13885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (fd < 0)
13895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return -1;
13905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
13915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (!setup_script || !strcmp(setup_script, "no"))
13925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        setup_script = "";
13935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (setup_script[0] != '\0') {
13945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	if (launch_script(setup_script, ifname, fd))
13955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	    return -1;
13965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
13975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    s = net_tap_fd_init(vlan, model, name, fd);
13985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    snprintf(s->vc->info_str, sizeof(s->vc->info_str),
13995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner             "ifname=%s,script=%s,downscript=%s",
14005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner             ifname, setup_script, down_script);
14015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (down_script && strcmp(down_script, "no")) {
14025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        snprintf(s->down_script, sizeof(s->down_script), "%s", down_script);
14035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        snprintf(s->down_script_arg, sizeof(s->down_script_arg), "%s", ifname);
14045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
14055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return 0;
14065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
14075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
14085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#endif /* !_WIN32 */
14095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
14105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#if defined(CONFIG_VDE)
14115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnertypedef struct VDEState {
14125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    VLANClientState *vc;
14135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    VDECONN *vde;
14145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} VDEState;
14155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
14165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void vde_to_qemu(void *opaque)
14175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
14185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    VDEState *s = opaque;
14195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    uint8_t buf[4096];
14205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int size;
14215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
14225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    size = vde_recv(s->vde, (char *)buf, sizeof(buf), 0);
14235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (size > 0) {
14245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        qemu_send_packet(s->vc, buf, size);
14255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
14265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
14275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
14285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic ssize_t vde_receive(VLANClientState *vc, const uint8_t *buf, size_t size)
14295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
14305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    VDEState *s = vc->opaque;
14315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    ssize_t ret;
14325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
14335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    do {
14345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner      ret = vde_send(s->vde, (const char *)buf, size, 0);
14355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    } while (ret < 0 && errno == EINTR);
14365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
14375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return ret;
14385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
14395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
14405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void vde_cleanup(VLANClientState *vc)
14415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
14425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    VDEState *s = vc->opaque;
14435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qemu_set_fd_handler(vde_datafd(s->vde), NULL, NULL, NULL);
14445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    vde_close(s->vde);
14455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qemu_free(s);
14465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
14475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
14485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int net_vde_init(VLANState *vlan, const char *model,
14495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                        const char *name, const char *sock,
14505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                        int port, const char *group, int mode)
14515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
14525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    VDEState *s;
14535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    char *init_group = strlen(group) ? (char *)group : NULL;
14545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    char *init_sock = strlen(sock) ? (char *)sock : NULL;
14555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
14565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    struct vde_open_args args = {
14575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        .port = port,
14585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        .group = init_group,
14595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        .mode = mode,
14605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    };
14615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
14625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    s = qemu_mallocz(sizeof(VDEState));
14635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    s->vde = vde_open(init_sock, (char *)"QEMU", &args);
14645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (!s->vde){
14655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        free(s);
14665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return -1;
14675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
14685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    s->vc = qemu_new_vlan_client(vlan, model, name, NULL, vde_receive,
14695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                                 NULL, vde_cleanup, s);
14705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qemu_set_fd_handler(vde_datafd(s->vde), vde_to_qemu, NULL, s);
14715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    snprintf(s->vc->info_str, sizeof(s->vc->info_str), "sock=%s,fd=%d",
14725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner             sock, vde_datafd(s->vde));
14735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return 0;
14745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
14755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#endif
14765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
14775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner/* network connection */
14785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnertypedef struct NetSocketState {
14795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    VLANClientState *vc;
14805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int fd;
14815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int state; /* 0 = getting length, 1 = getting data */
14825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    unsigned int index;
14835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    unsigned int packet_len;
14845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    uint8_t buf[4096];
14855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    struct sockaddr_in dgram_dst; /* contains inet host and port destination iff connectionless (SOCK_DGRAM) */
14865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} NetSocketState;
14875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
14885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnertypedef struct NetSocketListenState {
14895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    VLANState *vlan;
14905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    char *model;
14915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    char *name;
14925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int fd;
14935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} NetSocketListenState;
14945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
14955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner/* XXX: we consider we can send the whole packet without blocking */
14965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic ssize_t net_socket_receive(VLANClientState *vc, const uint8_t *buf, size_t size)
14975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
14985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    NetSocketState *s = vc->opaque;
14995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    uint32_t len;
15005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    len = htonl(size);
15015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
15025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    send_all(s->fd, (const uint8_t *)&len, sizeof(len));
15035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return send_all(s->fd, buf, size);
15045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
15055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
15065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic ssize_t net_socket_receive_dgram(VLANClientState *vc, const uint8_t *buf, size_t size)
15075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
15085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    NetSocketState *s = vc->opaque;
15095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
15105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return sendto(s->fd, (const void *)buf, size, 0,
15115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                  (struct sockaddr *)&s->dgram_dst, sizeof(s->dgram_dst));
15125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
15135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
15145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void net_socket_send(void *opaque)
15155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
15165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    NetSocketState *s = opaque;
15175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int size, err;
15185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    unsigned l;
15195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    uint8_t buf1[4096];
15205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    const uint8_t *buf;
15215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
15225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    size = recv(s->fd, (void *)buf1, sizeof(buf1), 0);
15235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (size < 0) {
15245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        err = socket_error();
15255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (err != EWOULDBLOCK)
15265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            goto eoc;
15275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    } else if (size == 0) {
15285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        /* end of connection */
15295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    eoc:
15305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        qemu_set_fd_handler(s->fd, NULL, NULL, NULL);
15315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        closesocket(s->fd);
15325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return;
15335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
15345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    buf = buf1;
15355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    while (size > 0) {
15365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        /* reassemble a packet from the network */
15375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        switch(s->state) {
15385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        case 0:
15395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            l = 4 - s->index;
15405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            if (l > size)
15415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                l = size;
15425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            memcpy(s->buf + s->index, buf, l);
15435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            buf += l;
15445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            size -= l;
15455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            s->index += l;
15465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            if (s->index == 4) {
15475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                /* got length */
15485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                s->packet_len = ntohl(*(uint32_t *)s->buf);
15495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                s->index = 0;
15505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                s->state = 1;
15515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            }
15525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            break;
15535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        case 1:
15545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            l = s->packet_len - s->index;
15555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            if (l > size)
15565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                l = size;
15575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            if (s->index + l <= sizeof(s->buf)) {
15585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                memcpy(s->buf + s->index, buf, l);
15595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            } else {
15605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                fprintf(stderr, "serious error: oversized packet received,"
15615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                    "connection terminated.\n");
15625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                s->state = 0;
15635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                goto eoc;
15645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            }
15655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
15665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            s->index += l;
15675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            buf += l;
15685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            size -= l;
15695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            if (s->index >= s->packet_len) {
15705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                qemu_send_packet(s->vc, s->buf, s->packet_len);
15715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                s->index = 0;
15725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                s->state = 0;
15735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            }
15745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            break;
15755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
15765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
15775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
15785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
15795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void net_socket_send_dgram(void *opaque)
15805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
15815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    NetSocketState *s = opaque;
15825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int size;
15835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
15845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    size = recv(s->fd, (void *)s->buf, sizeof(s->buf), 0);
15855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (size < 0)
15865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return;
15875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (size == 0) {
15885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        /* end of connection */
15895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        qemu_set_fd_handler(s->fd, NULL, NULL, NULL);
15905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return;
15915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
15925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qemu_send_packet(s->vc, s->buf, size);
15935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
15945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
15955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int net_socket_mcast_create(struct sockaddr_in *mcastaddr)
15965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
15975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    struct ip_mreq imr;
15985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int fd;
15995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int val, ret;
16005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (!IN_MULTICAST(ntohl(mcastaddr->sin_addr.s_addr))) {
16015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	fprintf(stderr, "qemu: error: specified mcastaddr \"%s\" (0x%08x) does not contain a multicast address\n",
16025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		inet_ntoa(mcastaddr->sin_addr),
16035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                (int)ntohl(mcastaddr->sin_addr.s_addr));
16045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	return -1;
16055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
16065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
16075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    fd = socket(PF_INET, SOCK_DGRAM, 0);
16085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (fd < 0) {
16095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        perror("socket(PF_INET, SOCK_DGRAM)");
16105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return -1;
16115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
16125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
16135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    val = 1;
16145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    ret=setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
16155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                   (const char *)&val, sizeof(val));
16165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (ret < 0) {
16175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	perror("setsockopt(SOL_SOCKET, SO_REUSEADDR)");
16185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	goto fail;
16195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
16205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
16215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    ret = bind(fd, (struct sockaddr *)mcastaddr, sizeof(*mcastaddr));
16225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (ret < 0) {
16235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        perror("bind");
16245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        goto fail;
16255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
16265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
16275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    /* Add host to multicast group */
16285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    imr.imr_multiaddr = mcastaddr->sin_addr;
16295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    imr.imr_interface.s_addr = htonl(INADDR_ANY);
16305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
16315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    ret = setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
16325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                     (const char *)&imr, sizeof(struct ip_mreq));
16335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (ret < 0) {
16345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	perror("setsockopt(IP_ADD_MEMBERSHIP)");
16355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	goto fail;
16365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
16375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
16385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    /* Force mcast msgs to loopback (eg. several QEMUs in same host */
16395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    val = 1;
16405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    ret=setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP,
16415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                   (const char *)&val, sizeof(val));
16425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (ret < 0) {
16435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	perror("setsockopt(SOL_IP, IP_MULTICAST_LOOP)");
16445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	goto fail;
16455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
16465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
16475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    socket_set_nonblock(fd);
16485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return fd;
16495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerfail:
16505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (fd >= 0)
16515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        closesocket(fd);
16525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return -1;
16535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
16545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
16555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void net_socket_cleanup(VLANClientState *vc)
16565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
16575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    NetSocketState *s = vc->opaque;
16585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qemu_set_fd_handler(s->fd, NULL, NULL, NULL);
16595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    close(s->fd);
16605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qemu_free(s);
16615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
16625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
16635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic NetSocketState *net_socket_fd_init_dgram(VLANState *vlan,
16645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                                                const char *model,
16655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                                                const char *name,
16665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                                                int fd, int is_connected)
16675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
16685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    struct sockaddr_in saddr;
16695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int newfd;
16705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    socklen_t saddr_len;
16715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    NetSocketState *s;
16725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
16735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    /* fd passed: multicast: "learn" dgram_dst address from bound address and save it
16745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner     * Because this may be "shared" socket from a "master" process, datagrams would be recv()
16755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner     * by ONLY ONE process: we must "clone" this dgram socket --jjo
16765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner     */
16775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
16785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (is_connected) {
16795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	if (getsockname(fd, (struct sockaddr *) &saddr, &saddr_len) == 0) {
16805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	    /* must be bound */
16815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	    if (saddr.sin_addr.s_addr==0) {
16825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		fprintf(stderr, "qemu: error: init_dgram: fd=%d unbound, cannot setup multicast dst addr\n",
16835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner			fd);
16845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		return NULL;
16855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	    }
16865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	    /* clone dgram socket */
16875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	    newfd = net_socket_mcast_create(&saddr);
16885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	    if (newfd < 0) {
16895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		/* error already reported by net_socket_mcast_create() */
16905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		close(fd);
16915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		return NULL;
16925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	    }
16935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	    /* clone newfd to fd, close newfd */
16945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	    dup2(newfd, fd);
16955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	    close(newfd);
16965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
16975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	} else {
16985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	    fprintf(stderr, "qemu: error: init_dgram: fd=%d failed getsockname(): %s\n",
16995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner		    fd, strerror(errno));
17005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	    return NULL;
17015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	}
17025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
17035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
17045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    s = qemu_mallocz(sizeof(NetSocketState));
17055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    s->fd = fd;
17065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
17075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    s->vc = qemu_new_vlan_client(vlan, model, name, NULL, net_socket_receive_dgram,
17085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                                 NULL, net_socket_cleanup, s);
17095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qemu_set_fd_handler(s->fd, net_socket_send_dgram, NULL, s);
17105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
17115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    /* mcast: save bound address as dst */
17125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (is_connected) s->dgram_dst=saddr;
17135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
17145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    snprintf(s->vc->info_str, sizeof(s->vc->info_str),
17155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	    "socket: fd=%d (%s mcast=%s:%d)",
17165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	    fd, is_connected? "cloned" : "",
17175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	    inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));
17185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return s;
17195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
17205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
17215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void net_socket_connect(void *opaque)
17225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
17235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    NetSocketState *s = opaque;
17245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qemu_set_fd_handler(s->fd, net_socket_send, NULL, s);
17255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
17265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
17275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic NetSocketState *net_socket_fd_init_stream(VLANState *vlan,
17285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                                                 const char *model,
17295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                                                 const char *name,
17305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                                                 int fd, int is_connected)
17315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
17325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    NetSocketState *s;
17335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    s = qemu_mallocz(sizeof(NetSocketState));
17345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    s->fd = fd;
17355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    s->vc = qemu_new_vlan_client(vlan, model, name, NULL, net_socket_receive,
17365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                                 NULL, net_socket_cleanup, s);
17375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    snprintf(s->vc->info_str, sizeof(s->vc->info_str),
17385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner             "socket: fd=%d", fd);
17395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (is_connected) {
17405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        net_socket_connect(s);
17415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    } else {
17425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        qemu_set_fd_handler(s->fd, NULL, net_socket_connect, s);
17435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
17445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return s;
17455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
17465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
17475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic NetSocketState *net_socket_fd_init(VLANState *vlan,
17485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                                          const char *model, const char *name,
17495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                                          int fd, int is_connected)
17505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
17515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int so_type=-1, optlen=sizeof(so_type);
17525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
17535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if(getsockopt(fd, SOL_SOCKET, SO_TYPE, (char *)&so_type,
17545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        (socklen_t *)&optlen)< 0) {
17555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	fprintf(stderr, "qemu: error: getsockopt(SO_TYPE) for fd=%d failed\n", fd);
17565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	return NULL;
17575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
17585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    switch(so_type) {
17595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    case SOCK_DGRAM:
17605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return net_socket_fd_init_dgram(vlan, model, name, fd, is_connected);
17615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    case SOCK_STREAM:
17625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return net_socket_fd_init_stream(vlan, model, name, fd, is_connected);
17635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    default:
17645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        /* who knows ... this could be a eg. a pty, do warn and continue as stream */
17655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        fprintf(stderr, "qemu: warning: socket type=%d for fd=%d is not SOCK_DGRAM or SOCK_STREAM\n", so_type, fd);
17665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return net_socket_fd_init_stream(vlan, model, name, fd, is_connected);
17675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
17685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return NULL;
17695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
17705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
17715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void net_socket_accept(void *opaque)
17725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
17735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    NetSocketListenState *s = opaque;
17745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    NetSocketState *s1;
17755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    struct sockaddr_in saddr;
17765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    socklen_t len;
17775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int fd;
17785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
17795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    for(;;) {
17805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        len = sizeof(saddr);
17815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        fd = accept(s->fd, (struct sockaddr *)&saddr, &len);
17825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (fd < 0 && errno != EINTR) {
17835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            return;
17845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        } else if (fd >= 0) {
17855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            break;
17865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
17875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
17885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    s1 = net_socket_fd_init(s->vlan, s->model, s->name, fd, 1);
17895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (!s1) {
17905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        closesocket(fd);
17915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    } else {
17925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        snprintf(s1->vc->info_str, sizeof(s1->vc->info_str),
17935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                 "socket: connection from %s:%d",
17945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                 inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));
17955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
17965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
17975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
17985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int net_socket_listen_init(VLANState *vlan,
17995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                                  const char *model,
18005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                                  const char *name,
18015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                                  const char *host_str)
18025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
18035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    NetSocketListenState *s;
18045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int fd, val, ret;
18055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    struct sockaddr_in saddr;
18065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
18075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (parse_host_port(&saddr, host_str) < 0)
18085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return -1;
18095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
18105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    s = qemu_mallocz(sizeof(NetSocketListenState));
18115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
18125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    fd = socket(PF_INET, SOCK_STREAM, 0);
18135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (fd < 0) {
18145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        perror("socket");
18155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return -1;
18165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
18175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    socket_set_nonblock(fd);
18185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
18195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    /* allow fast reuse */
18205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    val = 1;
18215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const char *)&val, sizeof(val));
18225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
18235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    ret = bind(fd, (struct sockaddr *)&saddr, sizeof(saddr));
18245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (ret < 0) {
18255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        perror("bind");
18265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return -1;
18275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
18285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    ret = listen(fd, 0);
18295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (ret < 0) {
18305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        perror("listen");
18315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return -1;
18325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
18335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    s->vlan = vlan;
18345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    s->model = strdup(model);
18355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    s->name = name ? strdup(name) : NULL;
18365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    s->fd = fd;
18375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qemu_set_fd_handler(fd, net_socket_accept, NULL, s);
18385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return 0;
18395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
18405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
18415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int net_socket_connect_init(VLANState *vlan,
18425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                                   const char *model,
18435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                                   const char *name,
18445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                                   const char *host_str)
18455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
18465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    NetSocketState *s;
18475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int fd, connected, ret, err;
18485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    struct sockaddr_in saddr;
18495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
18505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (parse_host_port(&saddr, host_str) < 0)
18515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return -1;
18525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
18535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    fd = socket(PF_INET, SOCK_STREAM, 0);
18545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (fd < 0) {
18555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        perror("socket");
18565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return -1;
18575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
18585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    socket_set_nonblock(fd);
18595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
18605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    connected = 0;
18615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    for(;;) {
18625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        ret = connect(fd, (struct sockaddr *)&saddr, sizeof(saddr));
18635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (ret < 0) {
18645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            err = socket_error();
18655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            if (err == EINTR || err == EWOULDBLOCK) {
18665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            } else if (err == EINPROGRESS) {
18675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                break;
18685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#ifdef _WIN32
18695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            } else if (err == WSAEALREADY) {
18705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                break;
18715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#endif
18725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            } else {
18735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                perror("connect");
18745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                closesocket(fd);
18755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                return -1;
18765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            }
18775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        } else {
18785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            connected = 1;
18795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            break;
18805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
18815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
18825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    s = net_socket_fd_init(vlan, model, name, fd, connected);
18835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (!s)
18845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return -1;
18855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    snprintf(s->vc->info_str, sizeof(s->vc->info_str),
18865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner             "socket: connect to %s:%d",
18875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner             inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));
18885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return 0;
18895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
18905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
18915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int net_socket_mcast_init(VLANState *vlan,
18925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                                 const char *model,
18935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                                 const char *name,
18945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                                 const char *host_str)
18955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
18965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    NetSocketState *s;
18975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int fd;
18985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    struct sockaddr_in saddr;
18995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
19005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (parse_host_port(&saddr, host_str) < 0)
19015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return -1;
19025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
19035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
19045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    fd = net_socket_mcast_create(&saddr);
19055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (fd < 0)
19065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	return -1;
19075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
19085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    s = net_socket_fd_init(vlan, model, name, fd, 0);
19095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (!s)
19105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return -1;
19115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
19125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    s->dgram_dst = saddr;
19135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
19145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    snprintf(s->vc->info_str, sizeof(s->vc->info_str),
19155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner             "socket: mcast=%s:%d",
19165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner             inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));
19175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return 0;
19185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
19195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
19205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
19215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnertypedef struct DumpState {
19225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    VLANClientState *pcap_vc;
19235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int fd;
19245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int pcap_caplen;
19255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner} DumpState;
19265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
19275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#define PCAP_MAGIC 0xa1b2c3d4
19285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
19295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstruct pcap_file_hdr {
19305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    uint32_t magic;
19315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    uint16_t version_major;
19325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    uint16_t version_minor;
19335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int32_t thiszone;
19345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    uint32_t sigfigs;
19355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    uint32_t snaplen;
19365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    uint32_t linktype;
19375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner};
19385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
19395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstruct pcap_sf_pkthdr {
19405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    struct {
19415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        int32_t tv_sec;
19425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        int32_t tv_usec;
19435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    } ts;
19445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    uint32_t caplen;
19455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    uint32_t len;
19465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner};
19475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
19485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic ssize_t dump_receive(VLANClientState *vc, const uint8_t *buf, size_t size)
19495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
19505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    DumpState *s = vc->opaque;
19515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    struct pcap_sf_pkthdr hdr;
19525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int64_t ts;
19535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int caplen;
19545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
19555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    /* Early return in case of previous error. */
19565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (s->fd < 0) {
19575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return size;
19585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
19595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
1960a7fb77d6eca56e61e94f62e7deb4120b60b1e919David 'Digit' Turner    ts = muldiv64(qemu_get_clock(vm_clock), 1000000, get_ticks_per_sec());
19615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    caplen = size > s->pcap_caplen ? s->pcap_caplen : size;
19625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
19635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    hdr.ts.tv_sec = ts / 1000000;
19645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    hdr.ts.tv_usec = ts % 1000000;
19655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    hdr.caplen = caplen;
19665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    hdr.len = size;
19675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (write(s->fd, &hdr, sizeof(hdr)) != sizeof(hdr) ||
19685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        write(s->fd, buf, caplen) != caplen) {
19695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        qemu_log("-net dump write error - stop dump\n");
19705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        close(s->fd);
19715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        s->fd = -1;
19725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
19735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
19745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return size;
19755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
19765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
19775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic void net_dump_cleanup(VLANClientState *vc)
19785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
19795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    DumpState *s = vc->opaque;
19805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
19815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    close(s->fd);
19825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qemu_free(s);
19835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
19845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
19855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int net_dump_init(Monitor *mon, VLANState *vlan, const char *device,
19865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                         const char *name, const char *filename, int len)
19875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
19885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    struct pcap_file_hdr hdr;
19895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    DumpState *s;
19905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
19915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    s = qemu_malloc(sizeof(DumpState));
19925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
19935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    s->fd = open(filename, O_CREAT | O_WRONLY, 0644);
19945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (s->fd < 0) {
19955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        config_error(mon, "-net dump: can't open %s\n", filename);
19965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return -1;
19975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
19985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
19995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    s->pcap_caplen = len;
20005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
20015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    hdr.magic = PCAP_MAGIC;
20025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    hdr.version_major = 2;
20035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    hdr.version_minor = 4;
20045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    hdr.thiszone = 0;
20055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    hdr.sigfigs = 0;
20065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    hdr.snaplen = s->pcap_caplen;
20075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    hdr.linktype = 1;
20085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
20095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (write(s->fd, &hdr, sizeof(hdr)) < sizeof(hdr)) {
20105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        config_error(mon, "-net dump write error: %s\n", strerror(errno));
20115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        close(s->fd);
20125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        qemu_free(s);
20135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return -1;
20145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
20155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
20165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    s->pcap_vc = qemu_new_vlan_client(vlan, device, name, NULL, dump_receive, NULL,
20175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                                      net_dump_cleanup, s);
20185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    snprintf(s->pcap_vc->info_str, sizeof(s->pcap_vc->info_str),
20195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner             "dump to %s (len=%d)", filename, len);
20205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return 0;
20215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
20225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
20235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner/* find or alloc a new VLAN */
20245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' TurnerVLANState *qemu_find_vlan(int id)
20255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
20265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    VLANState **pvlan, *vlan;
20275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    for(vlan = first_vlan; vlan != NULL; vlan = vlan->next) {
20285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (vlan->id == id)
20295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            return vlan;
20305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
20315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    vlan = qemu_mallocz(sizeof(VLANState));
20325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    vlan->id = id;
20335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    vlan->next = NULL;
20345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    pvlan = &first_vlan;
20355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    while (*pvlan != NULL)
20365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        pvlan = &(*pvlan)->next;
20375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    *pvlan = vlan;
20385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return vlan;
20395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
20405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
20415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int nic_get_free_idx(void)
20425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
20435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int index;
20445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
20455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    for (index = 0; index < MAX_NICS; index++)
20465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (!nd_table[index].used)
20475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            return index;
20485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return -1;
20495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
20505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
20515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid qemu_check_nic_model(NICInfo *nd, const char *model)
20525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
20535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    const char *models[2];
20545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
20555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    models[0] = model;
20565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    models[1] = NULL;
20575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
20585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qemu_check_nic_model_list(nd, models, model);
20595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
20605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
20615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid qemu_check_nic_model_list(NICInfo *nd, const char * const *models,
20625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                               const char *default_model)
20635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
20645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int i, exit_status = 0;
20655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
20665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (!nd->model)
20675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        nd->model = strdup(default_model);
20685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
20695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (strcmp(nd->model, "?") != 0) {
20705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        for (i = 0 ; models[i]; i++)
20715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            if (strcmp(nd->model, models[i]) == 0)
20725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                return;
20735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
20745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        fprintf(stderr, "qemu: Unsupported NIC model: %s\n", nd->model);
20755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        exit_status = 1;
20765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
20775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
20785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    fprintf(stderr, "qemu: Supported NIC models: ");
20795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    for (i = 0 ; models[i]; i++)
20805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        fprintf(stderr, "%s%c", models[i], models[i+1] ? ',' : '\n');
20815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
20825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    exit(exit_status);
20835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
20845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
20855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerint net_client_init(Monitor *mon, const char *device, const char *p)
20865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
20875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    static const char * const fd_params[] = {
20885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        "vlan", "name", "fd", NULL
20895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    };
20905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    char buf[1024];
20915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int vlan_id, ret;
20925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    VLANState *vlan;
20935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    char *name = NULL;
20945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
20955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    vlan_id = 0;
20965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (get_param_value(buf, sizeof(buf), "vlan", p)) {
20975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        vlan_id = strtol(buf, NULL, 0);
20985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
20995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    vlan = qemu_find_vlan(vlan_id);
21005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
21015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (get_param_value(buf, sizeof(buf), "name", p)) {
21025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        name = qemu_strdup(buf);
21035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
21045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (!strcmp(device, "nic")) {
21055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        static const char * const nic_params[] = {
21065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            "vlan", "name", "macaddr", "model", NULL
21075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        };
21085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        NICInfo *nd;
21095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        uint8_t *macaddr;
21105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        int idx = nic_get_free_idx();
21115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
21125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (check_params(buf, sizeof(buf), nic_params, p) < 0) {
21135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            config_error(mon, "invalid parameter '%s' in '%s'\n", buf, p);
21145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            ret = -1;
21155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            goto out;
21165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
21175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (idx == -1 || nb_nics >= MAX_NICS) {
21185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            config_error(mon, "Too Many NICs\n");
21195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            ret = -1;
21205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            goto out;
21215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
21225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        nd = &nd_table[idx];
21235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        macaddr = nd->macaddr;
21245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        macaddr[0] = 0x52;
21255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        macaddr[1] = 0x54;
21265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        macaddr[2] = 0x00;
21275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        macaddr[3] = 0x12;
21285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        macaddr[4] = 0x34;
21295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        macaddr[5] = 0x56 + idx;
21305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
21315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (get_param_value(buf, sizeof(buf), "macaddr", p)) {
21325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            if (parse_macaddr(macaddr, buf) < 0) {
21335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                config_error(mon, "invalid syntax for ethernet address\n");
21345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                ret = -1;
21355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                goto out;
21365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            }
21375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
21385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (get_param_value(buf, sizeof(buf), "model", p)) {
21395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            nd->model = strdup(buf);
21405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
21415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        nd->vlan = vlan;
21425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        nd->name = name;
21435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        nd->used = 1;
21445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        name = NULL;
21455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        nb_nics++;
21465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        vlan->nb_guest_devs++;
21475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        ret = idx;
21485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    } else
21495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (!strcmp(device, "none")) {
21505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (*p != '\0') {
21515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            config_error(mon, "'none' takes no parameters\n");
21525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            ret = -1;
21535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            goto out;
21545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
21555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        /* does nothing. It is needed to signal that no network cards
21565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner           are wanted */
21575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        ret = 0;
21585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    } else
21595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#ifdef CONFIG_SLIRP
21605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (!strcmp(device, "user")) {
21615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        static const char * const slirp_params[] = {
21625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            "vlan", "name", "hostname", "restrict", "ip", NULL
21635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        };
21645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        int restricted = 0;
21655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        char *ip = NULL;
21665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
21675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (check_params(buf, sizeof(buf), slirp_params, p) < 0) {
21685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            config_error(mon, "invalid parameter '%s' in '%s'\n", buf, p);
21695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            ret = -1;
21705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            goto out;
21715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
21725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (get_param_value(buf, sizeof(buf), "hostname", p)) {
21735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            pstrcpy(slirp_hostname, sizeof(slirp_hostname), buf);
21745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
21755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (get_param_value(buf, sizeof(buf), "restrict", p)) {
21765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            restricted = (buf[0] == 'y') ? 1 : 0;
21775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
21785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (get_param_value(buf, sizeof(buf), "ip", p)) {
21795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            ip = qemu_strdup(buf);
21805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
21815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        vlan->nb_host_devs++;
21825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        ret = net_slirp_init(vlan, device, name, restricted, ip);
21835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        qemu_free(ip);
21845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    } else if (!strcmp(device, "channel")) {
21855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        long port;
21865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        char name[20], *devname;
21875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        struct VMChannel *vmc;
21885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
21895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        port = strtol(p, &devname, 10);
21905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        devname++;
21915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (port < 1 || port > 65535) {
21925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            config_error(mon, "vmchannel wrong port number\n");
21935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            ret = -1;
21945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            goto out;
21955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
21965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        vmc = malloc(sizeof(struct VMChannel));
21975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        snprintf(name, 20, "vmchannel%ld", port);
21985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        vmc->hd = qemu_chr_open(name, devname, NULL);
21995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (!vmc->hd) {
22005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            config_error(mon, "could not open vmchannel device '%s'\n",
22015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                         devname);
22025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            ret = -1;
22035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            goto out;
22045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
22055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        vmc->port = port;
22065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        slirp_add_exec(3, vmc->hd, 4, port);
22075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        qemu_chr_add_handlers(vmc->hd, vmchannel_can_read, vmchannel_read,
22085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                NULL, vmc);
22095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        ret = 0;
22105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    } else
22115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#endif
22125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#ifdef _WIN32
22135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (!strcmp(device, "tap")) {
22145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        static const char * const tap_params[] = {
22155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            "vlan", "name", "ifname", NULL
22165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        };
22175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        char ifname[64];
22185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
22195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (check_params(buf, sizeof(buf), tap_params, p) < 0) {
22205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            config_error(mon, "invalid parameter '%s' in '%s'\n", buf, p);
22215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            ret = -1;
22225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            goto out;
22235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
22245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (get_param_value(ifname, sizeof(ifname), "ifname", p) <= 0) {
22255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            config_error(mon, "tap: no interface name\n");
22265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            ret = -1;
22275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            goto out;
22285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
22295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        vlan->nb_host_devs++;
22305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        ret = tap_win32_init(vlan, device, name, ifname);
22315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    } else
22325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#elif defined (_AIX)
22335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#else
22345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (!strcmp(device, "tap")) {
22355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        char ifname[64], chkbuf[64];
22365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        char setup_script[1024], down_script[1024];
22375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        int fd;
22385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        vlan->nb_host_devs++;
22395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (get_param_value(buf, sizeof(buf), "fd", p) > 0) {
22405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            if (check_params(chkbuf, sizeof(chkbuf), fd_params, p) < 0) {
22415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                config_error(mon, "invalid parameter '%s' in '%s'\n", chkbuf, p);
22425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                ret = -1;
22435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                goto out;
22445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            }
22455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            fd = strtol(buf, NULL, 0);
22465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            fcntl(fd, F_SETFL, O_NONBLOCK);
22475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            net_tap_fd_init(vlan, device, name, fd);
22485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            ret = 0;
22495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        } else {
22505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            static const char * const tap_params[] = {
22515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                "vlan", "name", "ifname", "script", "downscript", NULL
22525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            };
22535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            if (check_params(chkbuf, sizeof(chkbuf), tap_params, p) < 0) {
22545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                config_error(mon, "invalid parameter '%s' in '%s'\n", chkbuf, p);
22555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                ret = -1;
22565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                goto out;
22575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            }
22585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            if (get_param_value(ifname, sizeof(ifname), "ifname", p) <= 0) {
22595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                ifname[0] = '\0';
22605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            }
22615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            if (get_param_value(setup_script, sizeof(setup_script), "script", p) == 0) {
22625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                pstrcpy(setup_script, sizeof(setup_script), DEFAULT_NETWORK_SCRIPT);
22635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            }
22645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            if (get_param_value(down_script, sizeof(down_script), "downscript", p) == 0) {
22655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                pstrcpy(down_script, sizeof(down_script), DEFAULT_NETWORK_DOWN_SCRIPT);
22665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            }
22675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            ret = net_tap_init(vlan, device, name, ifname, setup_script, down_script);
22685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
22695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    } else
22705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#endif
22715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (!strcmp(device, "socket")) {
22725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        char chkbuf[64];
22735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (get_param_value(buf, sizeof(buf), "fd", p) > 0) {
22745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            int fd;
22755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            if (check_params(chkbuf, sizeof(chkbuf), fd_params, p) < 0) {
22765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                config_error(mon, "invalid parameter '%s' in '%s'\n", chkbuf, p);
22775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                ret = -1;
22785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                goto out;
22795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            }
22805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            fd = strtol(buf, NULL, 0);
22815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            ret = -1;
22825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            if (net_socket_fd_init(vlan, device, name, fd, 1))
22835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                ret = 0;
22845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        } else if (get_param_value(buf, sizeof(buf), "listen", p) > 0) {
22855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            static const char * const listen_params[] = {
22865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                "vlan", "name", "listen", NULL
22875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            };
22885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            if (check_params(chkbuf, sizeof(chkbuf), listen_params, p) < 0) {
22895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                config_error(mon, "invalid parameter '%s' in '%s'\n", chkbuf, p);
22905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                ret = -1;
22915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                goto out;
22925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            }
22935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            ret = net_socket_listen_init(vlan, device, name, buf);
22945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        } else if (get_param_value(buf, sizeof(buf), "connect", p) > 0) {
22955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            static const char * const connect_params[] = {
22965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                "vlan", "name", "connect", NULL
22975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            };
22985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            if (check_params(chkbuf, sizeof(chkbuf), connect_params, p) < 0) {
22995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                config_error(mon, "invalid parameter '%s' in '%s'\n", chkbuf, p);
23005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                ret = -1;
23015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                goto out;
23025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            }
23035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            ret = net_socket_connect_init(vlan, device, name, buf);
23045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        } else if (get_param_value(buf, sizeof(buf), "mcast", p) > 0) {
23055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            static const char * const mcast_params[] = {
23065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                "vlan", "name", "mcast", NULL
23075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            };
23085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            if (check_params(chkbuf, sizeof(chkbuf), mcast_params, p) < 0) {
23095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                config_error(mon, "invalid parameter '%s' in '%s'\n", chkbuf, p);
23105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                ret = -1;
23115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                goto out;
23125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            }
23135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            ret = net_socket_mcast_init(vlan, device, name, buf);
23145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        } else {
23155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            config_error(mon, "Unknown socket options: %s\n", p);
23165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            ret = -1;
23175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            goto out;
23185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
23195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        vlan->nb_host_devs++;
23205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    } else
23215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#ifdef CONFIG_VDE
23225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (!strcmp(device, "vde")) {
23235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        static const char * const vde_params[] = {
23245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            "vlan", "name", "sock", "port", "group", "mode", NULL
23255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        };
23265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        char vde_sock[1024], vde_group[512];
23275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	int vde_port, vde_mode;
23285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
23295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (check_params(buf, sizeof(buf), vde_params, p) < 0) {
23305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            config_error(mon, "invalid parameter '%s' in '%s'\n", buf, p);
23315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            ret = -1;
23325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            goto out;
23335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
23345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        vlan->nb_host_devs++;
23355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (get_param_value(vde_sock, sizeof(vde_sock), "sock", p) <= 0) {
23365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	    vde_sock[0] = '\0';
23375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	}
23385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	if (get_param_value(buf, sizeof(buf), "port", p) > 0) {
23395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	    vde_port = strtol(buf, NULL, 10);
23405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	} else {
23415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	    vde_port = 0;
23425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	}
23435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	if (get_param_value(vde_group, sizeof(vde_group), "group", p) <= 0) {
23445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	    vde_group[0] = '\0';
23455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	}
23465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	if (get_param_value(buf, sizeof(buf), "mode", p) > 0) {
23475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	    vde_mode = strtol(buf, NULL, 8);
23485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	} else {
23495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	    vde_mode = 0700;
23505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	}
23515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner	ret = net_vde_init(vlan, device, name, vde_sock, vde_port, vde_group, vde_mode);
23525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    } else
23535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#endif
23545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (!strcmp(device, "dump")) {
23555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        int len = 65536;
23565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
23575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (get_param_value(buf, sizeof(buf), "len", p) > 0) {
23585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            len = strtol(buf, NULL, 0);
23595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
23605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (!get_param_value(buf, sizeof(buf), "file", p)) {
23615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            snprintf(buf, sizeof(buf), "qemu-vlan%d.pcap", vlan_id);
23625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
23635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        ret = net_dump_init(mon, vlan, device, name, buf, len);
23645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    } else {
23655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        config_error(mon, "Unknown network device: %s\n", device);
23665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        ret = -1;
23675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        goto out;
23685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
23695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (ret < 0) {
23705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        config_error(mon, "Could not initialize device '%s'\n", device);
23715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
23725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerout:
23735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qemu_free(name);
23745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return ret;
23755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
23765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
23775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid net_client_uninit(NICInfo *nd)
23785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
23795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    nd->vlan->nb_guest_devs--;
23805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    nb_nics--;
23815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    nd->used = 0;
23825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    free((void *)nd->model);
23835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
23845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
23855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerstatic int net_host_check_device(const char *device)
23865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
23875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    int i;
23885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    const char *valid_param_list[] = { "tap", "socket", "dump"
23895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#ifdef CONFIG_SLIRP
23905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                                       ,"user"
23915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#endif
23925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#ifdef CONFIG_VDE
23935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                                       ,"vde"
23945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner#endif
23955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    };
23965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    for (i = 0; i < sizeof(valid_param_list) / sizeof(char *); i++) {
23975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (!strncmp(valid_param_list[i], device,
23985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                     strlen(valid_param_list[i])))
23995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            return 1;
24005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
24015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
24025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return 0;
24035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
24045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
24055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid net_host_device_add(Monitor *mon, const char *device, const char *opts)
24065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
24075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (!net_host_check_device(device)) {
24085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        monitor_printf(mon, "invalid host network device %s\n", device);
24095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return;
24105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
24115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (net_client_init(mon, device, opts ? opts : "") < 0) {
24125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        monitor_printf(mon, "adding host network device %s failed\n", device);
24135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
24145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
24155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
24165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid net_host_device_remove(Monitor *mon, int vlan_id, const char *device)
24175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
24185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    VLANState *vlan;
24195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    VLANClientState *vc;
24205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
24215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    vlan = qemu_find_vlan(vlan_id);
24225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
24235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    for (vc = vlan->first_client; vc != NULL; vc = vc->next) {
24245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (!strcmp(vc->name, device)) {
24255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            break;
24265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
24275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
24285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
24295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (!vc) {
24305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        monitor_printf(mon, "can't find device %s\n", device);
24315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return;
24325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
24335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (!net_host_check_device(vc->model)) {
24345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        monitor_printf(mon, "invalid host network device %s\n", device);
24355d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return;
24365d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
24375d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    qemu_del_vlan_client(vc);
24385d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
24395d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
24405d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerint net_client_parse(const char *str)
24415d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
24425d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    const char *p;
24435d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    char *q;
24445d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    char device[64];
24455d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
24465d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    p = str;
24475d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    q = device;
24485d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    while (*p != '\0' && *p != ',') {
24495d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if ((q - device) < sizeof(device) - 1)
24505d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            *q++ = *p;
24515d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        p++;
24525d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
24535d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    *q = '\0';
24545d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (*p == ',')
24555d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        p++;
24565d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
24575d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return net_client_init(NULL, device, p);
24585d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
24595d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
24605d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid do_info_network(Monitor *mon)
24615d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
24625d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    VLANState *vlan;
24635d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    VLANClientState *vc;
24645d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
24655d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    for(vlan = first_vlan; vlan != NULL; vlan = vlan->next) {
24665d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        monitor_printf(mon, "VLAN %d devices:\n", vlan->id);
24675d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        for(vc = vlan->first_client; vc != NULL; vc = vc->next)
24685d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            monitor_printf(mon, "  %s: %s\n", vc->name, vc->info_str);
24695d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
24705d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
24715d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
24725d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerint do_set_link(Monitor *mon, const char *name, const char *up_or_down)
24735d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
24745d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    VLANState *vlan;
24755d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    VLANClientState *vc = NULL;
24765d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
24775d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    for (vlan = first_vlan; vlan != NULL; vlan = vlan->next)
24785d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        for (vc = vlan->first_client; vc != NULL; vc = vc->next)
24795d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            if (strcmp(vc->name, name) == 0)
24805d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                goto done;
24815d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnerdone:
24825d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
24835d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (!vc) {
24845d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        monitor_printf(mon, "could not find network device '%s'", name);
24855d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        return 0;
24865d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
24875d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
24885d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (strcmp(up_or_down, "up") == 0)
24895d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        vc->link_down = 0;
24905d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    else if (strcmp(up_or_down, "down") == 0)
24915d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        vc->link_down = 1;
24925d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    else
24935d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        monitor_printf(mon, "invalid link status '%s'; only 'up' or 'down' "
24945d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                       "valid\n", up_or_down);
24955d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
24965d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    if (vc->link_status_changed)
24975d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        vc->link_status_changed(vc);
24985d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
24995d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    return 1;
25005d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
25015d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
25025d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid net_cleanup(void)
25035d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
25045d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    VLANState *vlan;
25055d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
25065d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    /* close network clients */
25075d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    for(vlan = first_vlan; vlan != NULL; vlan = vlan->next) {
25085d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        VLANClientState *vc = vlan->first_client;
25095d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
25105d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        while (vc) {
25115d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            VLANClientState *next = vc->next;
25125d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
25135d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            qemu_del_vlan_client(vc);
25145d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
25155d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            vc = next;
25165d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        }
25175d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
25185d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
25195d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
25205d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turnervoid net_client_check(void)
25215d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner{
25225d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    VLANState *vlan;
25235d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner
25245d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    for(vlan = first_vlan; vlan != NULL; vlan = vlan->next) {
25255d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (vlan->nb_guest_devs == 0 && vlan->nb_host_devs == 0)
25265d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            continue;
25275d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (vlan->nb_guest_devs == 0)
25285d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            fprintf(stderr, "Warning: vlan %d with no nics\n", vlan->id);
25295d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner        if (vlan->nb_host_devs == 0)
25305d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner            fprintf(stderr,
25315d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                    "Warning: vlan %d is not connected to host network\n",
25325d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner                    vlan->id);
25335d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner    }
25345d8f37ad78fc66901af50c762029a501561f3b23David 'Digit' Turner}
2535