| 40 |
#include <sys/socket.h> |
#include <sys/socket.h> |
| 41 |
#include <netinet/in.h> |
#include <netinet/in.h> |
| 42 |
#include <dirent.h> |
#include <dirent.h> |
| 43 |
|
#include <netdb.h> |
| 44 |
#ifdef _BSD |
#ifdef _BSD |
| 45 |
#include <sys/stat.h> |
#include <sys/stat.h> |
| 46 |
#ifndef __APPLE__ |
#ifndef __APPLE__ |
| 123 |
int64_t ticks_per_sec; |
int64_t ticks_per_sec; |
| 124 |
int boot_device = 'c'; |
int boot_device = 'c'; |
| 125 |
int ram_size; |
int ram_size; |
|
static char network_script[1024]; |
|
| 126 |
int pit_min_timer_count = 0; |
int pit_min_timer_count = 0; |
| 127 |
int nb_nics; |
int nb_nics; |
| 128 |
NetDriverState nd_table[MAX_NICS]; |
NICInfo nd_table[MAX_NICS]; |
| 129 |
QEMUTimer *gui_timer; |
QEMUTimer *gui_timer; |
| 130 |
int vm_running; |
int vm_running; |
| 131 |
#ifdef HAS_AUDIO |
#ifdef HAS_AUDIO |
| 155 |
int usb_enabled = 0; |
int usb_enabled = 0; |
| 156 |
USBPort *vm_usb_ports[MAX_VM_USB_PORTS]; |
USBPort *vm_usb_ports[MAX_VM_USB_PORTS]; |
| 157 |
USBDevice *vm_usb_hub; |
USBDevice *vm_usb_hub; |
| 158 |
|
static VLANState *first_vlan; |
| 159 |
|
|
| 160 |
/***********************************************************/ |
/***********************************************************/ |
| 161 |
/* x86 ISA bus support */ |
/* x86 ISA bus support */ |
| 1077 |
|
|
| 1078 |
typedef struct { |
typedef struct { |
| 1079 |
int fd_in, fd_out; |
int fd_in, fd_out; |
|
/* for nographic stdio only */ |
|
| 1080 |
IOCanRWHandler *fd_can_read; |
IOCanRWHandler *fd_can_read; |
| 1081 |
IOReadHandler *fd_read; |
IOReadHandler *fd_read; |
| 1082 |
void *fd_opaque; |
void *fd_opaque; |
| 1083 |
|
int max_size; |
| 1084 |
} FDCharDriver; |
} FDCharDriver; |
| 1085 |
|
|
| 1086 |
#define STDIO_MAX_CLIENTS 2 |
#define STDIO_MAX_CLIENTS 2 |
| 1114 |
return unix_write(s->fd_out, buf, len); |
return unix_write(s->fd_out, buf, len); |
| 1115 |
} |
} |
| 1116 |
|
|
| 1117 |
|
static int fd_chr_read_poll(void *opaque) |
| 1118 |
|
{ |
| 1119 |
|
CharDriverState *chr = opaque; |
| 1120 |
|
FDCharDriver *s = chr->opaque; |
| 1121 |
|
|
| 1122 |
|
s->max_size = s->fd_can_read(s->fd_opaque); |
| 1123 |
|
return s->max_size; |
| 1124 |
|
} |
| 1125 |
|
|
| 1126 |
|
static void fd_chr_read(void *opaque) |
| 1127 |
|
{ |
| 1128 |
|
CharDriverState *chr = opaque; |
| 1129 |
|
FDCharDriver *s = chr->opaque; |
| 1130 |
|
int size, len; |
| 1131 |
|
uint8_t buf[1024]; |
| 1132 |
|
|
| 1133 |
|
len = sizeof(buf); |
| 1134 |
|
if (len > s->max_size) |
| 1135 |
|
len = s->max_size; |
| 1136 |
|
if (len == 0) |
| 1137 |
|
return; |
| 1138 |
|
size = read(s->fd_in, buf, len); |
| 1139 |
|
if (size > 0) { |
| 1140 |
|
s->fd_read(s->fd_opaque, buf, size); |
| 1141 |
|
} |
| 1142 |
|
} |
| 1143 |
|
|
| 1144 |
static void fd_chr_add_read_handler(CharDriverState *chr, |
static void fd_chr_add_read_handler(CharDriverState *chr, |
| 1145 |
IOCanRWHandler *fd_can_read, |
IOCanRWHandler *fd_can_read, |
| 1146 |
IOReadHandler *fd_read, void *opaque) |
IOReadHandler *fd_read, void *opaque) |
| 1148 |
FDCharDriver *s = chr->opaque; |
FDCharDriver *s = chr->opaque; |
| 1149 |
|
|
| 1150 |
if (s->fd_in >= 0) { |
if (s->fd_in >= 0) { |
| 1151 |
|
s->fd_can_read = fd_can_read; |
| 1152 |
|
s->fd_read = fd_read; |
| 1153 |
|
s->fd_opaque = opaque; |
| 1154 |
if (nographic && s->fd_in == 0) { |
if (nographic && s->fd_in == 0) { |
|
s->fd_can_read = fd_can_read; |
|
|
s->fd_read = fd_read; |
|
|
s->fd_opaque = opaque; |
|
| 1155 |
} else { |
} else { |
| 1156 |
qemu_add_fd_read_handler(s->fd_in, fd_can_read, fd_read, opaque); |
qemu_set_fd_handler2(s->fd_in, fd_chr_read_poll, |
| 1157 |
|
fd_chr_read, NULL, chr); |
| 1158 |
} |
} |
| 1159 |
} |
} |
| 1160 |
} |
} |
| 1290 |
} |
} |
| 1291 |
} |
} |
| 1292 |
|
|
| 1293 |
static int stdio_can_read(void *opaque) |
static int stdio_read_poll(void *opaque) |
| 1294 |
{ |
{ |
| 1295 |
CharDriverState *chr; |
CharDriverState *chr; |
| 1296 |
FDCharDriver *s; |
FDCharDriver *s; |
| 1313 |
} |
} |
| 1314 |
} |
} |
| 1315 |
|
|
| 1316 |
static void stdio_read(void *opaque, const uint8_t *buf, int size) |
static void stdio_read(void *opaque) |
| 1317 |
{ |
{ |
| 1318 |
int i; |
int size; |
| 1319 |
for(i = 0; i < size; i++) |
uint8_t buf[1]; |
| 1320 |
stdio_received_byte(buf[i]); |
|
| 1321 |
|
size = read(0, buf, 1); |
| 1322 |
|
if (size > 0) |
| 1323 |
|
stdio_received_byte(buf[0]); |
| 1324 |
} |
} |
| 1325 |
|
|
| 1326 |
/* init terminal so that we can grab keys */ |
/* init terminal so that we can grab keys */ |
| 1369 |
return NULL; |
return NULL; |
| 1370 |
chr = qemu_chr_open_fd(0, 1); |
chr = qemu_chr_open_fd(0, 1); |
| 1371 |
if (stdio_nb_clients == 0) |
if (stdio_nb_clients == 0) |
| 1372 |
qemu_add_fd_read_handler(0, stdio_can_read, stdio_read, NULL); |
qemu_set_fd_handler2(0, stdio_read_poll, stdio_read, NULL, NULL); |
| 1373 |
client_index = stdio_nb_clients; |
client_index = stdio_nb_clients; |
| 1374 |
} else { |
} else { |
| 1375 |
if (stdio_nb_clients != 0) |
if (stdio_nb_clients != 0) |
| 1635 |
} |
} |
| 1636 |
|
|
| 1637 |
/***********************************************************/ |
/***********************************************************/ |
| 1638 |
/* Linux network device redirectors */ |
/* network device redirectors */ |
| 1639 |
|
|
| 1640 |
void hex_dump(FILE *f, const uint8_t *buf, int size) |
void hex_dump(FILE *f, const uint8_t *buf, int size) |
| 1641 |
{ |
{ |
| 1663 |
} |
} |
| 1664 |
} |
} |
| 1665 |
|
|
| 1666 |
void qemu_send_packet(NetDriverState *nd, const uint8_t *buf, int size) |
static int parse_macaddr(uint8_t *macaddr, const char *p) |
| 1667 |
{ |
{ |
| 1668 |
nd->send_packet(nd, buf, size); |
int i; |
| 1669 |
|
for(i = 0; i < 6; i++) { |
| 1670 |
|
macaddr[i] = strtol(p, (char **)&p, 16); |
| 1671 |
|
if (i == 5) { |
| 1672 |
|
if (*p != '\0') |
| 1673 |
|
return -1; |
| 1674 |
|
} else { |
| 1675 |
|
if (*p != ':') |
| 1676 |
|
return -1; |
| 1677 |
|
p++; |
| 1678 |
|
} |
| 1679 |
|
} |
| 1680 |
|
return 0; |
| 1681 |
} |
} |
| 1682 |
|
|
| 1683 |
void qemu_add_read_packet(NetDriverState *nd, IOCanRWHandler *fd_can_read, |
static int get_str_sep(char *buf, int buf_size, const char **pp, int sep) |
|
IOReadHandler *fd_read, void *opaque) |
|
| 1684 |
{ |
{ |
| 1685 |
nd->add_read_packet(nd, fd_can_read, fd_read, opaque); |
const char *p, *p1; |
| 1686 |
|
int len; |
| 1687 |
|
p = *pp; |
| 1688 |
|
p1 = strchr(p, sep); |
| 1689 |
|
if (!p1) |
| 1690 |
|
return -1; |
| 1691 |
|
len = p1 - p; |
| 1692 |
|
p1++; |
| 1693 |
|
if (buf_size > 0) { |
| 1694 |
|
if (len > buf_size - 1) |
| 1695 |
|
len = buf_size - 1; |
| 1696 |
|
memcpy(buf, p, len); |
| 1697 |
|
buf[len] = '\0'; |
| 1698 |
|
} |
| 1699 |
|
*pp = p1; |
| 1700 |
|
return 0; |
| 1701 |
} |
} |
| 1702 |
|
|
| 1703 |
/* dummy network adapter */ |
int parse_host_port(struct sockaddr_in *saddr, const char *str) |
|
|
|
|
static void dummy_send_packet(NetDriverState *nd, const uint8_t *buf, int size) |
|
| 1704 |
{ |
{ |
| 1705 |
|
char buf[512]; |
| 1706 |
|
struct hostent *he; |
| 1707 |
|
const char *p, *r; |
| 1708 |
|
int port; |
| 1709 |
|
|
| 1710 |
|
p = str; |
| 1711 |
|
if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) |
| 1712 |
|
return -1; |
| 1713 |
|
saddr->sin_family = AF_INET; |
| 1714 |
|
if (buf[0] == '\0') { |
| 1715 |
|
saddr->sin_addr.s_addr = 0; |
| 1716 |
|
} else { |
| 1717 |
|
if (isdigit(buf[0])) { |
| 1718 |
|
if (!inet_aton(buf, &saddr->sin_addr)) |
| 1719 |
|
return -1; |
| 1720 |
|
} else { |
| 1721 |
|
#ifdef _WIN32 |
| 1722 |
|
return -1; |
| 1723 |
|
#else |
| 1724 |
|
if ((he = gethostbyname(buf)) == NULL) |
| 1725 |
|
return - 1; |
| 1726 |
|
saddr->sin_addr = *(struct in_addr *)he->h_addr; |
| 1727 |
|
#endif |
| 1728 |
|
} |
| 1729 |
|
} |
| 1730 |
|
port = strtol(p, (char **)&r, 0); |
| 1731 |
|
if (r == p) |
| 1732 |
|
return -1; |
| 1733 |
|
saddr->sin_port = htons(port); |
| 1734 |
|
return 0; |
| 1735 |
} |
} |
| 1736 |
|
|
| 1737 |
static void dummy_add_read_packet(NetDriverState *nd, |
/* find or alloc a new VLAN */ |
| 1738 |
IOCanRWHandler *fd_can_read, |
VLANState *qemu_find_vlan(int id) |
|
IOReadHandler *fd_read, void *opaque) |
|
| 1739 |
{ |
{ |
| 1740 |
|
VLANState **pvlan, *vlan; |
| 1741 |
|
for(vlan = first_vlan; vlan != NULL; vlan = vlan->next) { |
| 1742 |
|
if (vlan->id == id) |
| 1743 |
|
return vlan; |
| 1744 |
|
} |
| 1745 |
|
vlan = qemu_mallocz(sizeof(VLANState)); |
| 1746 |
|
if (!vlan) |
| 1747 |
|
return NULL; |
| 1748 |
|
vlan->id = id; |
| 1749 |
|
vlan->next = NULL; |
| 1750 |
|
pvlan = &first_vlan; |
| 1751 |
|
while (*pvlan != NULL) |
| 1752 |
|
pvlan = &(*pvlan)->next; |
| 1753 |
|
*pvlan = vlan; |
| 1754 |
|
return vlan; |
| 1755 |
|
} |
| 1756 |
|
|
| 1757 |
|
VLANClientState *qemu_new_vlan_client(VLANState *vlan, |
| 1758 |
|
IOReadHandler *fd_read, void *opaque) |
| 1759 |
|
{ |
| 1760 |
|
VLANClientState *vc, **pvc; |
| 1761 |
|
vc = qemu_mallocz(sizeof(VLANClientState)); |
| 1762 |
|
if (!vc) |
| 1763 |
|
return NULL; |
| 1764 |
|
vc->fd_read = fd_read; |
| 1765 |
|
vc->opaque = opaque; |
| 1766 |
|
vc->vlan = vlan; |
| 1767 |
|
|
| 1768 |
|
vc->next = NULL; |
| 1769 |
|
pvc = &vlan->first_client; |
| 1770 |
|
while (*pvc != NULL) |
| 1771 |
|
pvc = &(*pvc)->next; |
| 1772 |
|
*pvc = vc; |
| 1773 |
|
return vc; |
| 1774 |
} |
} |
| 1775 |
|
|
| 1776 |
static int net_dummy_init(NetDriverState *nd) |
void qemu_send_packet(VLANClientState *vc1, const uint8_t *buf, int size) |
| 1777 |
{ |
{ |
| 1778 |
nd->send_packet = dummy_send_packet; |
VLANState *vlan = vc1->vlan; |
| 1779 |
nd->add_read_packet = dummy_add_read_packet; |
VLANClientState *vc; |
| 1780 |
pstrcpy(nd->ifname, sizeof(nd->ifname), "dummy"); |
|
| 1781 |
return 0; |
#if 0 |
| 1782 |
|
printf("vlan %d send:\n", vlan->id); |
| 1783 |
|
hex_dump(stdout, buf, size); |
| 1784 |
|
#endif |
| 1785 |
|
for(vc = vlan->first_client; vc != NULL; vc = vc->next) { |
| 1786 |
|
if (vc != vc1) { |
| 1787 |
|
vc->fd_read(vc->opaque, buf, size); |
| 1788 |
|
} |
| 1789 |
|
} |
| 1790 |
} |
} |
| 1791 |
|
|
| 1792 |
#if defined(CONFIG_SLIRP) |
#if defined(CONFIG_SLIRP) |
| 1793 |
|
|
| 1794 |
/* slirp network adapter */ |
/* slirp network adapter */ |
| 1795 |
|
|
|
static void *slirp_fd_opaque; |
|
|
static IOCanRWHandler *slirp_fd_can_read; |
|
|
static IOReadHandler *slirp_fd_read; |
|
| 1796 |
static int slirp_inited; |
static int slirp_inited; |
| 1797 |
|
static VLANClientState *slirp_vc; |
| 1798 |
|
|
| 1799 |
int slirp_can_output(void) |
int slirp_can_output(void) |
| 1800 |
{ |
{ |
| 1801 |
return slirp_fd_can_read(slirp_fd_opaque); |
return 1; |
| 1802 |
} |
} |
| 1803 |
|
|
| 1804 |
void slirp_output(const uint8_t *pkt, int pkt_len) |
void slirp_output(const uint8_t *pkt, int pkt_len) |
| 1805 |
{ |
{ |
| 1806 |
#if 0 |
#if 0 |
| 1807 |
printf("output:\n"); |
printf("slirp output:\n"); |
| 1808 |
hex_dump(stdout, pkt, pkt_len); |
hex_dump(stdout, pkt, pkt_len); |
| 1809 |
#endif |
#endif |
| 1810 |
slirp_fd_read(slirp_fd_opaque, pkt, pkt_len); |
qemu_send_packet(slirp_vc, pkt, pkt_len); |
| 1811 |
} |
} |
| 1812 |
|
|
| 1813 |
static void slirp_send_packet(NetDriverState *nd, const uint8_t *buf, int size) |
static void slirp_receive(void *opaque, const uint8_t *buf, int size) |
| 1814 |
{ |
{ |
| 1815 |
#if 0 |
#if 0 |
| 1816 |
printf("input:\n"); |
printf("slirp input:\n"); |
| 1817 |
hex_dump(stdout, buf, size); |
hex_dump(stdout, buf, size); |
| 1818 |
#endif |
#endif |
| 1819 |
slirp_input(buf, size); |
slirp_input(buf, size); |
| 1820 |
} |
} |
| 1821 |
|
|
| 1822 |
static void slirp_add_read_packet(NetDriverState *nd, |
static int net_slirp_init(VLANState *vlan) |
|
IOCanRWHandler *fd_can_read, |
|
|
IOReadHandler *fd_read, void *opaque) |
|
|
{ |
|
|
slirp_fd_opaque = opaque; |
|
|
slirp_fd_can_read = fd_can_read; |
|
|
slirp_fd_read = fd_read; |
|
|
} |
|
|
|
|
|
static int net_slirp_init(NetDriverState *nd) |
|
| 1823 |
{ |
{ |
| 1824 |
if (!slirp_inited) { |
if (!slirp_inited) { |
| 1825 |
slirp_inited = 1; |
slirp_inited = 1; |
| 1826 |
slirp_init(); |
slirp_init(); |
| 1827 |
} |
} |
| 1828 |
nd->send_packet = slirp_send_packet; |
slirp_vc = qemu_new_vlan_client(vlan, |
| 1829 |
nd->add_read_packet = slirp_add_read_packet; |
slirp_receive, NULL); |
| 1830 |
pstrcpy(nd->ifname, sizeof(nd->ifname), "slirp"); |
snprintf(slirp_vc->info_str, sizeof(slirp_vc->info_str), "user redirector"); |
|
return 0; |
|
|
} |
|
|
|
|
|
static int get_str_sep(char *buf, int buf_size, const char **pp, int sep) |
|
|
{ |
|
|
const char *p, *p1; |
|
|
int len; |
|
|
p = *pp; |
|
|
p1 = strchr(p, sep); |
|
|
if (!p1) |
|
|
return -1; |
|
|
len = p1 - p; |
|
|
p1++; |
|
|
if (buf_size > 0) { |
|
|
if (len > buf_size - 1) |
|
|
len = buf_size - 1; |
|
|
memcpy(buf, p, len); |
|
|
buf[len] = '\0'; |
|
|
} |
|
|
*pp = p1; |
|
| 1831 |
return 0; |
return 0; |
| 1832 |
} |
} |
| 1833 |
|
|
| 1970 |
#endif /* CONFIG_SLIRP */ |
#endif /* CONFIG_SLIRP */ |
| 1971 |
|
|
| 1972 |
#if !defined(_WIN32) |
#if !defined(_WIN32) |
| 1973 |
|
|
| 1974 |
|
typedef struct TAPState { |
| 1975 |
|
VLANClientState *vc; |
| 1976 |
|
int fd; |
| 1977 |
|
} TAPState; |
| 1978 |
|
|
| 1979 |
|
static void tap_receive(void *opaque, const uint8_t *buf, int size) |
| 1980 |
|
{ |
| 1981 |
|
TAPState *s = opaque; |
| 1982 |
|
int ret; |
| 1983 |
|
for(;;) { |
| 1984 |
|
ret = write(s->fd, buf, size); |
| 1985 |
|
if (ret < 0 && (errno == EINTR || errno == EAGAIN)) { |
| 1986 |
|
} else { |
| 1987 |
|
break; |
| 1988 |
|
} |
| 1989 |
|
} |
| 1990 |
|
} |
| 1991 |
|
|
| 1992 |
|
static void tap_send(void *opaque) |
| 1993 |
|
{ |
| 1994 |
|
TAPState *s = opaque; |
| 1995 |
|
uint8_t buf[4096]; |
| 1996 |
|
int size; |
| 1997 |
|
|
| 1998 |
|
size = read(s->fd, buf, sizeof(buf)); |
| 1999 |
|
if (size > 0) { |
| 2000 |
|
qemu_send_packet(s->vc, buf, size); |
| 2001 |
|
} |
| 2002 |
|
} |
| 2003 |
|
|
| 2004 |
|
/* fd support */ |
| 2005 |
|
|
| 2006 |
|
static TAPState *net_tap_fd_init(VLANState *vlan, int fd) |
| 2007 |
|
{ |
| 2008 |
|
TAPState *s; |
| 2009 |
|
|
| 2010 |
|
s = qemu_mallocz(sizeof(TAPState)); |
| 2011 |
|
if (!s) |
| 2012 |
|
return NULL; |
| 2013 |
|
s->fd = fd; |
| 2014 |
|
s->vc = qemu_new_vlan_client(vlan, tap_receive, s); |
| 2015 |
|
qemu_set_fd_handler(s->fd, tap_send, NULL, s); |
| 2016 |
|
snprintf(s->vc->info_str, sizeof(s->vc->info_str), "tap: fd=%d", fd); |
| 2017 |
|
return s; |
| 2018 |
|
} |
| 2019 |
|
|
| 2020 |
#ifdef _BSD |
#ifdef _BSD |
| 2021 |
static int tun_open(char *ifname, int ifname_size) |
static int tap_open(char *ifname, int ifname_size) |
| 2022 |
{ |
{ |
| 2023 |
int fd; |
int fd; |
| 2024 |
char *dev; |
char *dev; |
| 2038 |
return fd; |
return fd; |
| 2039 |
} |
} |
| 2040 |
#else |
#else |
| 2041 |
static int tun_open(char *ifname, int ifname_size) |
static int tap_open(char *ifname, int ifname_size) |
| 2042 |
{ |
{ |
| 2043 |
struct ifreq ifr; |
struct ifreq ifr; |
| 2044 |
int fd, ret; |
int fd, ret; |
| 2050 |
} |
} |
| 2051 |
memset(&ifr, 0, sizeof(ifr)); |
memset(&ifr, 0, sizeof(ifr)); |
| 2052 |
ifr.ifr_flags = IFF_TAP | IFF_NO_PI; |
ifr.ifr_flags = IFF_TAP | IFF_NO_PI; |
| 2053 |
pstrcpy(ifr.ifr_name, IFNAMSIZ, "tun%d"); |
if (ifname[0] != '\0') |
| 2054 |
|
pstrcpy(ifr.ifr_name, IFNAMSIZ, ifname); |
| 2055 |
|
else |
| 2056 |
|
pstrcpy(ifr.ifr_name, IFNAMSIZ, "tap%d"); |
| 2057 |
ret = ioctl(fd, TUNSETIFF, (void *) &ifr); |
ret = ioctl(fd, TUNSETIFF, (void *) &ifr); |
| 2058 |
if (ret != 0) { |
if (ret != 0) { |
| 2059 |
fprintf(stderr, "warning: could not configure /dev/net/tun: no virtual network emulation\n"); |
fprintf(stderr, "warning: could not configure /dev/net/tun: no virtual network emulation\n"); |
| 2060 |
close(fd); |
close(fd); |
| 2061 |
return -1; |
return -1; |
| 2062 |
} |
} |
|
printf("Connected to host network interface: %s\n", ifr.ifr_name); |
|
| 2063 |
pstrcpy(ifname, ifname_size, ifr.ifr_name); |
pstrcpy(ifname, ifname_size, ifr.ifr_name); |
| 2064 |
fcntl(fd, F_SETFL, O_NONBLOCK); |
fcntl(fd, F_SETFL, O_NONBLOCK); |
| 2065 |
return fd; |
return fd; |
| 2066 |
} |
} |
| 2067 |
#endif |
#endif |
| 2068 |
|
|
| 2069 |
static void tun_send_packet(NetDriverState *nd, const uint8_t *buf, int size) |
static int net_tap_init(VLANState *vlan, const char *ifname1, |
| 2070 |
|
const char *setup_script) |
| 2071 |
|
{ |
| 2072 |
|
TAPState *s; |
| 2073 |
|
int pid, status, fd; |
| 2074 |
|
char *args[3]; |
| 2075 |
|
char **parg; |
| 2076 |
|
char ifname[128]; |
| 2077 |
|
|
| 2078 |
|
if (ifname1 != NULL) |
| 2079 |
|
pstrcpy(ifname, sizeof(ifname), ifname1); |
| 2080 |
|
else |
| 2081 |
|
ifname[0] = '\0'; |
| 2082 |
|
fd = tap_open(ifname, sizeof(ifname)); |
| 2083 |
|
if (fd < 0) |
| 2084 |
|
return -1; |
| 2085 |
|
|
| 2086 |
|
if (!setup_script) |
| 2087 |
|
setup_script = ""; |
| 2088 |
|
if (setup_script[0] != '\0') { |
| 2089 |
|
/* try to launch network init script */ |
| 2090 |
|
pid = fork(); |
| 2091 |
|
if (pid >= 0) { |
| 2092 |
|
if (pid == 0) { |
| 2093 |
|
parg = args; |
| 2094 |
|
*parg++ = (char *)setup_script; |
| 2095 |
|
*parg++ = ifname; |
| 2096 |
|
*parg++ = NULL; |
| 2097 |
|
execv(setup_script, args); |
| 2098 |
|
exit(1); |
| 2099 |
|
} |
| 2100 |
|
while (waitpid(pid, &status, 0) != pid); |
| 2101 |
|
if (!WIFEXITED(status) || |
| 2102 |
|
WEXITSTATUS(status) != 0) { |
| 2103 |
|
fprintf(stderr, "%s: could not launch network script\n", |
| 2104 |
|
setup_script); |
| 2105 |
|
return -1; |
| 2106 |
|
} |
| 2107 |
|
} |
| 2108 |
|
} |
| 2109 |
|
s = net_tap_fd_init(vlan, fd); |
| 2110 |
|
if (!s) |
| 2111 |
|
return -1; |
| 2112 |
|
snprintf(s->vc->info_str, sizeof(s->vc->info_str), |
| 2113 |
|
"tap: ifname=%s setup_script=%s", ifname, setup_script); |
| 2114 |
|
return 0; |
| 2115 |
|
} |
| 2116 |
|
|
| 2117 |
|
/* network connection */ |
| 2118 |
|
typedef struct NetSocketState { |
| 2119 |
|
VLANClientState *vc; |
| 2120 |
|
int fd; |
| 2121 |
|
int state; /* 0 = getting length, 1 = getting data */ |
| 2122 |
|
int index; |
| 2123 |
|
int packet_len; |
| 2124 |
|
uint8_t buf[4096]; |
| 2125 |
|
} NetSocketState; |
| 2126 |
|
|
| 2127 |
|
typedef struct NetSocketListenState { |
| 2128 |
|
VLANState *vlan; |
| 2129 |
|
int fd; |
| 2130 |
|
} NetSocketListenState; |
| 2131 |
|
|
| 2132 |
|
/* XXX: we consider we can send the whole packet without blocking */ |
| 2133 |
|
static void net_socket_receive(void *opaque, const uint8_t *buf, int size) |
| 2134 |
{ |
{ |
| 2135 |
write(nd->fd, buf, size); |
NetSocketState *s = opaque; |
| 2136 |
|
uint32_t len; |
| 2137 |
|
len = htonl(size); |
| 2138 |
|
|
| 2139 |
|
unix_write(s->fd, (const uint8_t *)&len, sizeof(len)); |
| 2140 |
|
unix_write(s->fd, buf, size); |
| 2141 |
} |
} |
| 2142 |
|
|
| 2143 |
static void tun_add_read_packet(NetDriverState *nd, |
static void net_socket_send(void *opaque) |
|
IOCanRWHandler *fd_can_read, |
|
|
IOReadHandler *fd_read, void *opaque) |
|
| 2144 |
{ |
{ |
| 2145 |
qemu_add_fd_read_handler(nd->fd, fd_can_read, fd_read, opaque); |
NetSocketState *s = opaque; |
| 2146 |
|
int l, size; |
| 2147 |
|
uint8_t buf1[4096]; |
| 2148 |
|
const uint8_t *buf; |
| 2149 |
|
|
| 2150 |
|
size = read(s->fd, buf1, sizeof(buf1)); |
| 2151 |
|
if (size < 0) |
| 2152 |
|
return; |
| 2153 |
|
if (size == 0) { |
| 2154 |
|
/* end of connection */ |
| 2155 |
|
qemu_set_fd_handler(s->fd, NULL, NULL, NULL); |
| 2156 |
|
return; |
| 2157 |
|
} |
| 2158 |
|
buf = buf1; |
| 2159 |
|
while (size > 0) { |
| 2160 |
|
/* reassemble a packet from the network */ |
| 2161 |
|
switch(s->state) { |
| 2162 |
|
case 0: |
| 2163 |
|
l = 4 - s->index; |
| 2164 |
|
if (l > size) |
| 2165 |
|
l = size; |
| 2166 |
|
memcpy(s->buf + s->index, buf, l); |
| 2167 |
|
buf += l; |
| 2168 |
|
size -= l; |
| 2169 |
|
s->index += l; |
| 2170 |
|
if (s->index == 4) { |
| 2171 |
|
/* got length */ |
| 2172 |
|
s->packet_len = ntohl(*(uint32_t *)s->buf); |
| 2173 |
|
s->index = 0; |
| 2174 |
|
s->state = 1; |
| 2175 |
|
} |
| 2176 |
|
break; |
| 2177 |
|
case 1: |
| 2178 |
|
l = s->packet_len - s->index; |
| 2179 |
|
if (l > size) |
| 2180 |
|
l = size; |
| 2181 |
|
memcpy(s->buf + s->index, buf, l); |
| 2182 |
|
s->index += l; |
| 2183 |
|
buf += l; |
| 2184 |
|
size -= l; |
| 2185 |
|
if (s->index >= s->packet_len) { |
| 2186 |
|
qemu_send_packet(s->vc, s->buf, s->packet_len); |
| 2187 |
|
s->index = 0; |
| 2188 |
|
s->state = 0; |
| 2189 |
|
} |
| 2190 |
|
break; |
| 2191 |
|
} |
| 2192 |
|
} |
| 2193 |
} |
} |
| 2194 |
|
|
| 2195 |
static int net_tun_init(NetDriverState *nd) |
static void net_socket_connect(void *opaque) |
| 2196 |
{ |
{ |
| 2197 |
int pid, status; |
NetSocketState *s = opaque; |
| 2198 |
char *args[3]; |
qemu_set_fd_handler(s->fd, net_socket_send, NULL, s); |
| 2199 |
char **parg; |
} |
| 2200 |
|
|
| 2201 |
nd->fd = tun_open(nd->ifname, sizeof(nd->ifname)); |
static NetSocketState *net_socket_fd_init(VLANState *vlan, int fd, |
| 2202 |
if (nd->fd < 0) |
int is_connected) |
| 2203 |
return -1; |
{ |
| 2204 |
|
NetSocketState *s; |
| 2205 |
|
s = qemu_mallocz(sizeof(NetSocketState)); |
| 2206 |
|
if (!s) |
| 2207 |
|
return NULL; |
| 2208 |
|
s->fd = fd; |
| 2209 |
|
s->vc = qemu_new_vlan_client(vlan, |
| 2210 |
|
net_socket_receive, s); |
| 2211 |
|
snprintf(s->vc->info_str, sizeof(s->vc->info_str), |
| 2212 |
|
"socket: fd=%d", fd); |
| 2213 |
|
if (is_connected) { |
| 2214 |
|
net_socket_connect(s); |
| 2215 |
|
} else { |
| 2216 |
|
qemu_set_fd_handler(s->fd, NULL, net_socket_connect, s); |
| 2217 |
|
} |
| 2218 |
|
return s; |
| 2219 |
|
} |
| 2220 |
|
|
| 2221 |
/* try to launch network init script */ |
static void net_socket_accept(void *opaque) |
| 2222 |
pid = fork(); |
{ |
| 2223 |
if (pid >= 0) { |
NetSocketListenState *s = opaque; |
| 2224 |
if (pid == 0) { |
NetSocketState *s1; |
| 2225 |
parg = args; |
struct sockaddr_in saddr; |
| 2226 |
*parg++ = network_script; |
socklen_t len; |
| 2227 |
*parg++ = nd->ifname; |
int fd; |
| 2228 |
*parg++ = NULL; |
|
| 2229 |
execv(network_script, args); |
for(;;) { |
| 2230 |
exit(1); |
len = sizeof(saddr); |
| 2231 |
} |
fd = accept(s->fd, (struct sockaddr *)&saddr, &len); |
| 2232 |
while (waitpid(pid, &status, 0) != pid); |
if (fd < 0 && errno != EINTR) { |
| 2233 |
if (!WIFEXITED(status) || |
return; |
| 2234 |
WEXITSTATUS(status) != 0) { |
} else if (fd >= 0) { |
| 2235 |
fprintf(stderr, "%s: could not launch network script\n", |
break; |
|
network_script); |
|
| 2236 |
} |
} |
| 2237 |
} |
} |
| 2238 |
nd->send_packet = tun_send_packet; |
s1 = net_socket_fd_init(s->vlan, fd, 1); |
| 2239 |
nd->add_read_packet = tun_add_read_packet; |
if (!s1) { |
| 2240 |
|
close(fd); |
| 2241 |
|
} else { |
| 2242 |
|
snprintf(s1->vc->info_str, sizeof(s1->vc->info_str), |
| 2243 |
|
"socket: connection from %s:%d", |
| 2244 |
|
inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port)); |
| 2245 |
|
} |
| 2246 |
|
} |
| 2247 |
|
|
| 2248 |
|
static int net_socket_listen_init(VLANState *vlan, const char *host_str) |
| 2249 |
|
{ |
| 2250 |
|
NetSocketListenState *s; |
| 2251 |
|
int fd, val, ret; |
| 2252 |
|
struct sockaddr_in saddr; |
| 2253 |
|
|
| 2254 |
|
if (parse_host_port(&saddr, host_str) < 0) |
| 2255 |
|
return -1; |
| 2256 |
|
|
| 2257 |
|
s = qemu_mallocz(sizeof(NetSocketListenState)); |
| 2258 |
|
if (!s) |
| 2259 |
|
return -1; |
| 2260 |
|
|
| 2261 |
|
fd = socket(PF_INET, SOCK_STREAM, 0); |
| 2262 |
|
if (fd < 0) { |
| 2263 |
|
perror("socket"); |
| 2264 |
|
return -1; |
| 2265 |
|
} |
| 2266 |
|
fcntl(fd, F_SETFL, O_NONBLOCK); |
| 2267 |
|
|
| 2268 |
|
/* allow fast reuse */ |
| 2269 |
|
val = 1; |
| 2270 |
|
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)); |
| 2271 |
|
|
| 2272 |
|
ret = bind(fd, (struct sockaddr *)&saddr, sizeof(saddr)); |
| 2273 |
|
if (ret < 0) { |
| 2274 |
|
perror("bind"); |
| 2275 |
|
return -1; |
| 2276 |
|
} |
| 2277 |
|
ret = listen(fd, 0); |
| 2278 |
|
if (ret < 0) { |
| 2279 |
|
perror("listen"); |
| 2280 |
|
return -1; |
| 2281 |
|
} |
| 2282 |
|
s->vlan = vlan; |
| 2283 |
|
s->fd = fd; |
| 2284 |
|
qemu_set_fd_handler(fd, net_socket_accept, NULL, s); |
| 2285 |
return 0; |
return 0; |
| 2286 |
} |
} |
| 2287 |
|
|
| 2288 |
static int net_fd_init(NetDriverState *nd, int fd) |
static int net_socket_connect_init(VLANState *vlan, const char *host_str) |
| 2289 |
{ |
{ |
| 2290 |
nd->fd = fd; |
NetSocketState *s; |
| 2291 |
nd->send_packet = tun_send_packet; |
int fd, connected, ret; |
| 2292 |
nd->add_read_packet = tun_add_read_packet; |
struct sockaddr_in saddr; |
| 2293 |
pstrcpy(nd->ifname, sizeof(nd->ifname), "tunfd"); |
|
| 2294 |
|
if (parse_host_port(&saddr, host_str) < 0) |
| 2295 |
|
return -1; |
| 2296 |
|
|
| 2297 |
|
fd = socket(PF_INET, SOCK_STREAM, 0); |
| 2298 |
|
if (fd < 0) { |
| 2299 |
|
perror("socket"); |
| 2300 |
|
return -1; |
| 2301 |
|
} |
| 2302 |
|
fcntl(fd, F_SETFL, O_NONBLOCK); |
| 2303 |
|
|
| 2304 |
|
connected = 0; |
| 2305 |
|
for(;;) { |
| 2306 |
|
ret = connect(fd, (struct sockaddr *)&saddr, sizeof(saddr)); |
| 2307 |
|
if (ret < 0) { |
| 2308 |
|
if (errno == EINTR || errno == EAGAIN) { |
| 2309 |
|
} else if (errno == EINPROGRESS) { |
| 2310 |
|
break; |
| 2311 |
|
} else { |
| 2312 |
|
perror("connect"); |
| 2313 |
|
close(fd); |
| 2314 |
|
return -1; |
| 2315 |
|
} |
| 2316 |
|
} else { |
| 2317 |
|
connected = 1; |
| 2318 |
|
break; |
| 2319 |
|
} |
| 2320 |
|
} |
| 2321 |
|
s = net_socket_fd_init(vlan, fd, connected); |
| 2322 |
|
if (!s) |
| 2323 |
|
return -1; |
| 2324 |
|
snprintf(s->vc->info_str, sizeof(s->vc->info_str), |
| 2325 |
|
"socket: connect to %s:%d", |
| 2326 |
|
inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port)); |
| 2327 |
return 0; |
return 0; |
| 2328 |
} |
} |
| 2329 |
|
|
| 2330 |
#endif /* !_WIN32 */ |
#endif /* !_WIN32 */ |
| 2331 |
|
|
| 2332 |
|
static int get_param_value(char *buf, int buf_size, |
| 2333 |
|
const char *tag, const char *str) |
| 2334 |
|
{ |
| 2335 |
|
const char *p; |
| 2336 |
|
char *q; |
| 2337 |
|
char option[128]; |
| 2338 |
|
|
| 2339 |
|
p = str; |
| 2340 |
|
for(;;) { |
| 2341 |
|
q = option; |
| 2342 |
|
while (*p != '\0' && *p != '=') { |
| 2343 |
|
if ((q - option) < sizeof(option) - 1) |
| 2344 |
|
*q++ = *p; |
| 2345 |
|
p++; |
| 2346 |
|
} |
| 2347 |
|
*q = '\0'; |
| 2348 |
|
if (*p != '=') |
| 2349 |
|
break; |
| 2350 |
|
p++; |
| 2351 |
|
if (!strcmp(tag, option)) { |
| 2352 |
|
q = buf; |
| 2353 |
|
while (*p != '\0' && *p != ',') { |
| 2354 |
|
if ((q - buf) < buf_size - 1) |
| 2355 |
|
*q++ = *p; |
| 2356 |
|
p++; |
| 2357 |
|
} |
| 2358 |
|
*q = '\0'; |
| 2359 |
|
return q - buf; |
| 2360 |
|
} else { |
| 2361 |
|
while (*p != '\0' && *p != ',') { |
| 2362 |
|
p++; |
| 2363 |
|
} |
| 2364 |
|
} |
| 2365 |
|
if (*p != ',') |
| 2366 |
|
break; |
| 2367 |
|
p++; |
| 2368 |
|
} |
| 2369 |
|
return 0; |
| 2370 |
|
} |
| 2371 |
|
|
| 2372 |
|
int net_client_init(const char *str) |
| 2373 |
|
{ |
| 2374 |
|
const char *p; |
| 2375 |
|
char *q; |
| 2376 |
|
char device[64]; |
| 2377 |
|
char buf[1024]; |
| 2378 |
|
int vlan_id, ret; |
| 2379 |
|
VLANState *vlan; |
| 2380 |
|
|
| 2381 |
|
p = str; |
| 2382 |
|
q = device; |
| 2383 |
|
while (*p != '\0' && *p != ',') { |
| 2384 |
|
if ((q - device) < sizeof(device) - 1) |
| 2385 |
|
*q++ = *p; |
| 2386 |
|
p++; |
| 2387 |
|
} |
| 2388 |
|
*q = '\0'; |
| 2389 |
|
if (*p == ',') |
| 2390 |
|
p++; |
| 2391 |
|
vlan_id = 0; |
| 2392 |
|
if (get_param_value(buf, sizeof(buf), "vlan", p)) { |
| 2393 |
|
vlan_id = strtol(buf, NULL, 0); |
| 2394 |
|
} |
| 2395 |
|
vlan = qemu_find_vlan(vlan_id); |
| 2396 |
|
if (!vlan) { |
| 2397 |
|
fprintf(stderr, "Could not create vlan %d\n", vlan_id); |
| 2398 |
|
return -1; |
| 2399 |
|
} |
| 2400 |
|
if (!strcmp(device, "nic")) { |
| 2401 |
|
NICInfo *nd; |
| 2402 |
|
uint8_t *macaddr; |
| 2403 |
|
|
| 2404 |
|
if (nb_nics >= MAX_NICS) { |
| 2405 |
|
fprintf(stderr, "Too Many NICs\n"); |
| 2406 |
|
return -1; |
| 2407 |
|
} |
| 2408 |
|
nd = &nd_table[nb_nics]; |
| 2409 |
|
macaddr = nd->macaddr; |
| 2410 |
|
macaddr[0] = 0x52; |
| 2411 |
|
macaddr[1] = 0x54; |
| 2412 |
|
macaddr[2] = 0x00; |
| 2413 |
|
macaddr[3] = 0x12; |
| 2414 |
|
macaddr[4] = 0x34; |
| 2415 |
|
macaddr[5] = 0x56 + nb_nics; |
| 2416 |
|
|
| 2417 |
|
if (get_param_value(buf, sizeof(buf), "macaddr", p)) { |
| 2418 |
|
if (parse_macaddr(macaddr, buf) < 0) { |
| 2419 |
|
fprintf(stderr, "invalid syntax for ethernet address\n"); |
| 2420 |
|
return -1; |
| 2421 |
|
} |
| 2422 |
|
} |
| 2423 |
|
nd->vlan = vlan; |
| 2424 |
|
nb_nics++; |
| 2425 |
|
ret = 0; |
| 2426 |
|
} else |
| 2427 |
|
if (!strcmp(device, "none")) { |
| 2428 |
|
/* does nothing. It is needed to signal that no network cards |
| 2429 |
|
are wanted */ |
| 2430 |
|
ret = 0; |
| 2431 |
|
} else |
| 2432 |
|
#ifdef CONFIG_SLIRP |
| 2433 |
|
if (!strcmp(device, "user")) { |
| 2434 |
|
ret = net_slirp_init(vlan); |
| 2435 |
|
} else |
| 2436 |
|
#endif |
| 2437 |
|
#ifndef _WIN32 |
| 2438 |
|
if (!strcmp(device, "tap")) { |
| 2439 |
|
char ifname[64]; |
| 2440 |
|
char setup_script[1024]; |
| 2441 |
|
int fd; |
| 2442 |
|
if (get_param_value(buf, sizeof(buf), "fd", p) > 0) { |
| 2443 |
|
fd = strtol(buf, NULL, 0); |
| 2444 |
|
ret = -1; |
| 2445 |
|
if (net_tap_fd_init(vlan, fd)) |
| 2446 |
|
ret = 0; |
| 2447 |
|
} else { |
| 2448 |
|
get_param_value(ifname, sizeof(ifname), "ifname", p); |
| 2449 |
|
if (get_param_value(setup_script, sizeof(setup_script), "script", p) == 0) { |
| 2450 |
|
pstrcpy(setup_script, sizeof(setup_script), DEFAULT_NETWORK_SCRIPT); |
| 2451 |
|
} |
| 2452 |
|
ret = net_tap_init(vlan, ifname, setup_script); |
| 2453 |
|
} |
| 2454 |
|
} else |
| 2455 |
|
if (!strcmp(device, "socket")) { |
| 2456 |
|
if (get_param_value(buf, sizeof(buf), "fd", p) > 0) { |
| 2457 |
|
int fd; |
| 2458 |
|
fd = strtol(buf, NULL, 0); |
| 2459 |
|
ret = -1; |
| 2460 |
|
if (net_socket_fd_init(vlan, fd, 1)) |
| 2461 |
|
ret = 0; |
| 2462 |
|
} else if (get_param_value(buf, sizeof(buf), "listen", p) > 0) { |
| 2463 |
|
ret = net_socket_listen_init(vlan, buf); |
| 2464 |
|
} else if (get_param_value(buf, sizeof(buf), "connect", p) > 0) { |
| 2465 |
|
ret = net_socket_connect_init(vlan, buf); |
| 2466 |
|
} else { |
| 2467 |
|
fprintf(stderr, "Unknown socket options: %s\n", p); |
| 2468 |
|
return -1; |
| 2469 |
|
} |
| 2470 |
|
} else |
| 2471 |
|
#endif |
| 2472 |
|
{ |
| 2473 |
|
fprintf(stderr, "Unknown network device: %s\n", device); |
| 2474 |
|
return -1; |
| 2475 |
|
} |
| 2476 |
|
if (ret < 0) { |
| 2477 |
|
fprintf(stderr, "Could not initialize device '%s'\n", device); |
| 2478 |
|
} |
| 2479 |
|
|
| 2480 |
|
return ret; |
| 2481 |
|
} |
| 2482 |
|
|
| 2483 |
|
void do_info_network(void) |
| 2484 |
|
{ |
| 2485 |
|
VLANState *vlan; |
| 2486 |
|
VLANClientState *vc; |
| 2487 |
|
|
| 2488 |
|
for(vlan = first_vlan; vlan != NULL; vlan = vlan->next) { |
| 2489 |
|
term_printf("VLAN %d devices:\n", vlan->id); |
| 2490 |
|
for(vc = vlan->first_client; vc != NULL; vc = vc->next) |
| 2491 |
|
term_printf(" %s\n", vc->info_str); |
| 2492 |
|
} |
| 2493 |
|
} |
| 2494 |
|
|
| 2495 |
/***********************************************************/ |
/***********************************************************/ |
| 2496 |
/* USB devices */ |
/* USB devices */ |
| 2497 |
|
|
| 2690 |
|
|
| 2691 |
typedef struct IOHandlerRecord { |
typedef struct IOHandlerRecord { |
| 2692 |
int fd; |
int fd; |
| 2693 |
IOCanRWHandler *fd_can_read; |
IOCanRWHandler *fd_read_poll; |
| 2694 |
IOReadHandler *fd_read; |
IOHandler *fd_read; |
| 2695 |
|
IOHandler *fd_write; |
| 2696 |
void *opaque; |
void *opaque; |
| 2697 |
/* temporary data */ |
/* temporary data */ |
| 2698 |
struct pollfd *ufd; |
struct pollfd *ufd; |
|
int max_size; |
|
| 2699 |
struct IOHandlerRecord *next; |
struct IOHandlerRecord *next; |
| 2700 |
} IOHandlerRecord; |
} IOHandlerRecord; |
| 2701 |
|
|
| 2702 |
static IOHandlerRecord *first_io_handler; |
static IOHandlerRecord *first_io_handler; |
| 2703 |
|
|
| 2704 |
int qemu_add_fd_read_handler(int fd, IOCanRWHandler *fd_can_read, |
/* XXX: fd_read_poll should be suppressed, but an API change is |
| 2705 |
IOReadHandler *fd_read, void *opaque) |
necessary in the character devices to suppress fd_can_read(). */ |
| 2706 |
|
int qemu_set_fd_handler2(int fd, |
| 2707 |
|
IOCanRWHandler *fd_read_poll, |
| 2708 |
|
IOHandler *fd_read, |
| 2709 |
|
IOHandler *fd_write, |
| 2710 |
|
void *opaque) |
| 2711 |
{ |
{ |
| 2712 |
IOHandlerRecord *ioh; |
IOHandlerRecord **pioh, *ioh; |
| 2713 |
|
|
| 2714 |
ioh = qemu_mallocz(sizeof(IOHandlerRecord)); |
if (!fd_read && !fd_write) { |
| 2715 |
if (!ioh) |
pioh = &first_io_handler; |
| 2716 |
return -1; |
for(;;) { |
| 2717 |
ioh->fd = fd; |
ioh = *pioh; |
| 2718 |
ioh->fd_can_read = fd_can_read; |
if (ioh == NULL) |
| 2719 |
ioh->fd_read = fd_read; |
break; |
| 2720 |
ioh->opaque = opaque; |
if (ioh->fd == fd) { |
| 2721 |
ioh->next = first_io_handler; |
*pioh = ioh->next; |
| 2722 |
first_io_handler = ioh; |
break; |
| 2723 |
|
} |
| 2724 |
|
pioh = &ioh->next; |
| 2725 |
|
} |
| 2726 |
|
} else { |
| 2727 |
|
for(ioh = first_io_handler; ioh != NULL; ioh = ioh->next) { |
| 2728 |
|
if (ioh->fd == fd) |
| 2729 |
|
goto found; |
| 2730 |
|
} |
| 2731 |
|
ioh = qemu_mallocz(sizeof(IOHandlerRecord)); |
| 2732 |
|
if (!ioh) |
| 2733 |
|
return -1; |
| 2734 |
|
ioh->next = first_io_handler; |
| 2735 |
|
first_io_handler = ioh; |
| 2736 |
|
found: |
| 2737 |
|
ioh->fd = fd; |
| 2738 |
|
ioh->fd_read_poll = fd_read_poll; |
| 2739 |
|
ioh->fd_read = fd_read; |
| 2740 |
|
ioh->fd_write = fd_write; |
| 2741 |
|
ioh->opaque = opaque; |
| 2742 |
|
} |
| 2743 |
return 0; |
return 0; |
| 2744 |
} |
} |
| 2745 |
|
|
| 2746 |
void qemu_del_fd_read_handler(int fd) |
int qemu_set_fd_handler(int fd, |
| 2747 |
|
IOHandler *fd_read, |
| 2748 |
|
IOHandler *fd_write, |
| 2749 |
|
void *opaque) |
| 2750 |
{ |
{ |
| 2751 |
IOHandlerRecord **pioh, *ioh; |
return qemu_set_fd_handler2(fd, NULL, fd_read, fd_write, opaque); |
|
|
|
|
pioh = &first_io_handler; |
|
|
for(;;) { |
|
|
ioh = *pioh; |
|
|
if (ioh == NULL) |
|
|
break; |
|
|
if (ioh->fd == fd) { |
|
|
*pioh = ioh->next; |
|
|
break; |
|
|
} |
|
|
pioh = &ioh->next; |
|
|
} |
|
| 2752 |
} |
} |
| 2753 |
|
|
| 2754 |
/***********************************************************/ |
/***********************************************************/ |
| 3611 |
#ifndef _WIN32 |
#ifndef _WIN32 |
| 3612 |
struct pollfd ufds[MAX_IO_HANDLERS + 1], *pf; |
struct pollfd ufds[MAX_IO_HANDLERS + 1], *pf; |
| 3613 |
IOHandlerRecord *ioh, *ioh_next; |
IOHandlerRecord *ioh, *ioh_next; |
|
uint8_t buf[4096]; |
|
|
int n, max_size; |
|
| 3614 |
#endif |
#endif |
| 3615 |
int ret; |
int ret; |
| 3616 |
|
|
| 3622 |
/* XXX: separate device handlers from system ones */ |
/* XXX: separate device handlers from system ones */ |
| 3623 |
pf = ufds; |
pf = ufds; |
| 3624 |
for(ioh = first_io_handler; ioh != NULL; ioh = ioh->next) { |
for(ioh = first_io_handler; ioh != NULL; ioh = ioh->next) { |
| 3625 |
if (!ioh->fd_can_read) { |
pf->events = 0; |
| 3626 |
max_size = 0; |
pf->fd = ioh->fd; |
| 3627 |
pf->fd = ioh->fd; |
if (ioh->fd_read && |
| 3628 |
pf->events = POLLIN; |
(!ioh->fd_read_poll || |
| 3629 |
ioh->ufd = pf; |
ioh->fd_read_poll(ioh->opaque) != 0)) { |
| 3630 |
pf++; |
pf->events |= POLLIN; |
|
} else { |
|
|
max_size = ioh->fd_can_read(ioh->opaque); |
|
|
if (max_size > 0) { |
|
|
if (max_size > sizeof(buf)) |
|
|
max_size = sizeof(buf); |
|
|
pf->fd = ioh->fd; |
|
|
pf->events = POLLIN; |
|
|
ioh->ufd = pf; |
|
|
pf++; |
|
|
} else { |
|
|
ioh->ufd = NULL; |
|
|
} |
|
| 3631 |
} |
} |
| 3632 |
ioh->max_size = max_size; |
if (ioh->fd_write) { |
| 3633 |
|
pf->events |= POLLOUT; |
| 3634 |
|
} |
| 3635 |
|
ioh->ufd = pf; |
| 3636 |
|
pf++; |
| 3637 |
} |
} |
| 3638 |
|
|
| 3639 |
ret = poll(ufds, pf - ufds, timeout); |
ret = poll(ufds, pf - ufds, timeout); |
| 3642 |
for(ioh = first_io_handler; ioh != NULL; ioh = ioh_next) { |
for(ioh = first_io_handler; ioh != NULL; ioh = ioh_next) { |
| 3643 |
ioh_next = ioh->next; |
ioh_next = ioh->next; |
| 3644 |
pf = ioh->ufd; |
pf = ioh->ufd; |
| 3645 |
if (pf) { |
if (pf->revents & POLLIN) { |
| 3646 |
if (pf->revents & POLLIN) { |
ioh->fd_read(ioh->opaque); |
| 3647 |
if (ioh->max_size == 0) { |
} |
| 3648 |
/* just a read event */ |
if (pf->revents & POLLOUT) { |
| 3649 |
ioh->fd_read(ioh->opaque, NULL, 0); |
ioh->fd_write(ioh->opaque); |
|
} else { |
|
|
n = read(ioh->fd, buf, ioh->max_size); |
|
|
if (n >= 0) { |
|
|
ioh->fd_read(ioh->opaque, buf, n); |
|
|
} else if (errno != EAGAIN) { |
|
|
ioh->fd_read(ioh->opaque, NULL, -errno); |
|
|
} |
|
|
} |
|
|
} |
|
| 3650 |
} |
} |
| 3651 |
} |
} |
| 3652 |
} |
} |
| 3763 |
#endif |
#endif |
| 3764 |
"\n" |
"\n" |
| 3765 |
"Network options:\n" |
"Network options:\n" |
| 3766 |
"-nics n simulate 'n' network cards [default=1]\n" |
"-net nic[,vlan=n][,macaddr=addr]\n" |
| 3767 |
"-macaddr addr set the mac address of the first interface\n" |
" create a new Network Interface Card and connect it to VLAN 'n'\n" |
| 3768 |
"-n script set tap/tun network init script [default=%s]\n" |
#ifdef CONFIG_SLIRP |
| 3769 |
"-tun-fd fd use this fd as already opened tap/tun interface\n" |
"-net user[,vlan=n]\n" |
| 3770 |
|
" connect the user mode network stack to VLAN 'n'\n" |
| 3771 |
|
#endif |
| 3772 |
|
#ifndef _WIN32 |
| 3773 |
|
"-net tap[,vlan=n][,fd=h][,ifname=name][,script=file]\n" |
| 3774 |
|
" connect the host TAP network interface to VLAN 'n' and use\n" |
| 3775 |
|
" the network script 'file' (default=%s);\n" |
| 3776 |
|
" use 'fd=h' to connect to an already opened TAP interface\n" |
| 3777 |
|
"-net socket[,vlan=n][,fd=x][,listen=[host]:port][,connect=host:port]\n" |
| 3778 |
|
" connect the vlan 'n' to another VLAN using a socket connection\n" |
| 3779 |
|
#endif |
| 3780 |
|
"-net none use it alone to have zero network devices; if no -net option\n" |
| 3781 |
|
" is provided, the default is '-net nic -net user'\n" |
| 3782 |
|
"\n" |
| 3783 |
#ifdef CONFIG_SLIRP |
#ifdef CONFIG_SLIRP |
| 3784 |
"-user-net use user mode network stack [default if no tap/tun script]\n" |
"-tftp prefix allow tftp access to files starting with prefix [-net user]\n" |
|
"-tftp prefix allow tftp access to files starting with prefix [-user-net]\n" |
|
| 3785 |
#ifndef _WIN32 |
#ifndef _WIN32 |
| 3786 |
"-smb dir allow SMB access to files in 'dir' [-user-net]\n" |
"-smb dir allow SMB access to files in 'dir' [-net user]\n" |
| 3787 |
#endif |
#endif |
| 3788 |
"-redir [tcp|udp]:host-port:[guest-host]:guest-port\n" |
"-redir [tcp|udp]:host-port:[guest-host]:guest-port\n" |
| 3789 |
" redirect TCP or UDP connections from host to guest [-user-net]\n" |
" redirect TCP or UDP connections from host to guest [-net user]\n" |
| 3790 |
#endif |
#endif |
|
"-dummy-net use dummy network stack\n" |
|
| 3791 |
"\n" |
"\n" |
| 3792 |
"Linux boot specific:\n" |
"Linux boot specific:\n" |
| 3793 |
"-kernel bzImage use 'bzImage' as kernel image\n" |
"-kernel bzImage use 'bzImage' as kernel image\n" |
| 3831 |
"qemu-fast", |
"qemu-fast", |
| 3832 |
#endif |
#endif |
| 3833 |
DEFAULT_RAM_SIZE, |
DEFAULT_RAM_SIZE, |
| 3834 |
|
#ifndef _WIN32 |
| 3835 |
DEFAULT_NETWORK_SCRIPT, |
DEFAULT_NETWORK_SCRIPT, |
| 3836 |
|
#endif |
| 3837 |
DEFAULT_GDBSTUB_PORT, |
DEFAULT_GDBSTUB_PORT, |
| 3838 |
"/tmp/qemu.log"); |
"/tmp/qemu.log"); |
| 3839 |
#ifndef CONFIG_SOFTMMU |
#ifndef CONFIG_SOFTMMU |
| 3868 |
QEMU_OPTION_soundhw, |
QEMU_OPTION_soundhw, |
| 3869 |
#endif |
#endif |
| 3870 |
|
|
| 3871 |
QEMU_OPTION_nics, |
QEMU_OPTION_net, |
|
QEMU_OPTION_macaddr, |
|
|
QEMU_OPTION_n, |
|
|
QEMU_OPTION_tun_fd, |
|
|
QEMU_OPTION_user_net, |
|
| 3872 |
QEMU_OPTION_tftp, |
QEMU_OPTION_tftp, |
| 3873 |
QEMU_OPTION_smb, |
QEMU_OPTION_smb, |
| 3874 |
QEMU_OPTION_redir, |
QEMU_OPTION_redir, |
|
QEMU_OPTION_dummy_net, |
|
| 3875 |
|
|
| 3876 |
QEMU_OPTION_kernel, |
QEMU_OPTION_kernel, |
| 3877 |
QEMU_OPTION_append, |
QEMU_OPTION_append, |
| 3929 |
{ "soundhw", HAS_ARG, QEMU_OPTION_soundhw }, |
{ "soundhw", HAS_ARG, QEMU_OPTION_soundhw }, |
| 3930 |
#endif |
#endif |
| 3931 |
|
|
| 3932 |
{ "nics", HAS_ARG, QEMU_OPTION_nics}, |
{ "net", HAS_ARG, QEMU_OPTION_net}, |
|
{ "macaddr", HAS_ARG, QEMU_OPTION_macaddr}, |
|
|
{ "n", HAS_ARG, QEMU_OPTION_n }, |
|
|
{ "tun-fd", HAS_ARG, QEMU_OPTION_tun_fd }, |
|
| 3933 |
#ifdef CONFIG_SLIRP |
#ifdef CONFIG_SLIRP |
|
{ "user-net", 0, QEMU_OPTION_user_net }, |
|
| 3934 |
{ "tftp", HAS_ARG, QEMU_OPTION_tftp }, |
{ "tftp", HAS_ARG, QEMU_OPTION_tftp }, |
| 3935 |
#ifndef _WIN32 |
#ifndef _WIN32 |
| 3936 |
{ "smb", HAS_ARG, QEMU_OPTION_smb }, |
{ "smb", HAS_ARG, QEMU_OPTION_smb }, |
| 3937 |
#endif |
#endif |
| 3938 |
{ "redir", HAS_ARG, QEMU_OPTION_redir }, |
{ "redir", HAS_ARG, QEMU_OPTION_redir }, |
| 3939 |
#endif |
#endif |
|
{ "dummy-net", 0, QEMU_OPTION_dummy_net }, |
|
| 3940 |
|
|
| 3941 |
{ "kernel", HAS_ARG, QEMU_OPTION_kernel }, |
{ "kernel", HAS_ARG, QEMU_OPTION_kernel }, |
| 3942 |
{ "append", HAS_ARG, QEMU_OPTION_append }, |
{ "append", HAS_ARG, QEMU_OPTION_append }, |
| 4111 |
} |
} |
| 4112 |
#endif |
#endif |
| 4113 |
|
|
| 4114 |
#define NET_IF_TUN 0 |
#define MAX_NET_CLIENTS 32 |
|
#define NET_IF_USER 1 |
|
|
#define NET_IF_DUMMY 2 |
|
| 4115 |
|
|
| 4116 |
int main(int argc, char **argv) |
int main(int argc, char **argv) |
| 4117 |
{ |
{ |
| 4127 |
DisplayState *ds = &display_state; |
DisplayState *ds = &display_state; |
| 4128 |
int cyls, heads, secs, translation; |
int cyls, heads, secs, translation; |
| 4129 |
int start_emulation = 1; |
int start_emulation = 1; |
| 4130 |
uint8_t macaddr[6]; |
char net_clients[MAX_NET_CLIENTS][256]; |
| 4131 |
int net_if_type, nb_tun_fds, tun_fds[MAX_NICS]; |
int nb_net_clients; |
| 4132 |
int optind; |
int optind; |
| 4133 |
const char *r, *optarg; |
const char *r, *optarg; |
| 4134 |
CharDriverState *monitor_hd; |
CharDriverState *monitor_hd; |
| 4157 |
ram_size = DEFAULT_RAM_SIZE * 1024 * 1024; |
ram_size = DEFAULT_RAM_SIZE * 1024 * 1024; |
| 4158 |
vga_ram_size = VGA_RAM_SIZE; |
vga_ram_size = VGA_RAM_SIZE; |
| 4159 |
bios_size = BIOS_SIZE; |
bios_size = BIOS_SIZE; |
|
pstrcpy(network_script, sizeof(network_script), DEFAULT_NETWORK_SCRIPT); |
|
| 4160 |
#ifdef CONFIG_GDBSTUB |
#ifdef CONFIG_GDBSTUB |
| 4161 |
use_gdbstub = 0; |
use_gdbstub = 0; |
| 4162 |
gdbstub_port = DEFAULT_GDBSTUB_PORT; |
gdbstub_port = DEFAULT_GDBSTUB_PORT; |
| 4186 |
|
|
| 4187 |
usb_devices_index = 0; |
usb_devices_index = 0; |
| 4188 |
|
|
| 4189 |
nb_tun_fds = 0; |
nb_net_clients = 0; |
| 4190 |
net_if_type = -1; |
|
| 4191 |
nb_nics = 1; |
nb_nics = 0; |
| 4192 |
/* default mac address of the first network interface */ |
/* default mac address of the first network interface */ |
|
macaddr[0] = 0x52; |
|
|
macaddr[1] = 0x54; |
|
|
macaddr[2] = 0x00; |
|
|
macaddr[3] = 0x12; |
|
|
macaddr[4] = 0x34; |
|
|
macaddr[5] = 0x56; |
|
| 4193 |
|
|
| 4194 |
optind = 1; |
optind = 1; |
| 4195 |
for(;;) { |
for(;;) { |
| 4303 |
case QEMU_OPTION_append: |
case QEMU_OPTION_append: |
| 4304 |
kernel_cmdline = optarg; |
kernel_cmdline = optarg; |
| 4305 |
break; |
break; |
|
case QEMU_OPTION_tun_fd: |
|
|
{ |
|
|
const char *p; |
|
|
int fd; |
|
|
net_if_type = NET_IF_TUN; |
|
|
if (nb_tun_fds < MAX_NICS) { |
|
|
fd = strtol(optarg, (char **)&p, 0); |
|
|
if (*p != '\0') { |
|
|
fprintf(stderr, "qemu: invalid fd for network interface %d\n", nb_tun_fds); |
|
|
exit(1); |
|
|
} |
|
|
tun_fds[nb_tun_fds++] = fd; |
|
|
} |
|
|
} |
|
|
break; |
|
| 4306 |
case QEMU_OPTION_cdrom: |
case QEMU_OPTION_cdrom: |
| 4307 |
if (cdrom_index >= 0) { |
if (cdrom_index >= 0) { |
| 4308 |
hd_filename[cdrom_index] = optarg; |
hd_filename[cdrom_index] = optarg; |
| 4329 |
case QEMU_OPTION_no_code_copy: |
case QEMU_OPTION_no_code_copy: |
| 4330 |
code_copy_enabled = 0; |
code_copy_enabled = 0; |
| 4331 |
break; |
break; |
| 4332 |
case QEMU_OPTION_nics: |
case QEMU_OPTION_net: |
| 4333 |
nb_nics = atoi(optarg); |
if (nb_net_clients >= MAX_NET_CLIENTS) { |
| 4334 |
if (nb_nics < 0 || nb_nics > MAX_NICS) { |
fprintf(stderr, "qemu: too many network clients\n"); |
|
fprintf(stderr, "qemu: invalid number of network interfaces\n"); |
|
| 4335 |
exit(1); |
exit(1); |
| 4336 |
} |
} |
| 4337 |
break; |
pstrcpy(net_clients[nb_net_clients], |
| 4338 |
case QEMU_OPTION_macaddr: |
sizeof(net_clients[0]), |
| 4339 |
{ |
optarg); |
| 4340 |
const char *p; |
nb_net_clients++; |
|
int i; |
|
|
p = optarg; |
|
|
for(i = 0; i < 6; i++) { |
|
|
macaddr[i] = strtol(p, (char **)&p, 16); |
|
|
if (i == 5) { |
|
|
if (*p != '\0') |
|
|
goto macaddr_error; |
|
|
} else { |
|
|
if (*p != ':') { |
|
|
macaddr_error: |
|
|
fprintf(stderr, "qemu: invalid syntax for ethernet address\n"); |
|
|
exit(1); |
|
|
} |
|
|
p++; |
|
|
} |
|
|
} |
|
|
} |
|
| 4341 |
break; |
break; |
| 4342 |
#ifdef CONFIG_SLIRP |
#ifdef CONFIG_SLIRP |
| 4343 |
case QEMU_OPTION_tftp: |
case QEMU_OPTION_tftp: |
| 4348 |
net_slirp_smb(optarg); |
net_slirp_smb(optarg); |
| 4349 |
break; |
break; |
| 4350 |
#endif |
#endif |
|
case QEMU_OPTION_user_net: |
|
|
net_if_type = NET_IF_USER; |
|
|
break; |
|
| 4351 |
case QEMU_OPTION_redir: |
case QEMU_OPTION_redir: |
| 4352 |
net_slirp_redir(optarg); |
net_slirp_redir(optarg); |
| 4353 |
break; |
break; |
| 4354 |
#endif |
#endif |
|
case QEMU_OPTION_dummy_net: |
|
|
net_if_type = NET_IF_DUMMY; |
|
|
break; |
|
| 4355 |
#ifdef HAS_AUDIO |
#ifdef HAS_AUDIO |
| 4356 |
case QEMU_OPTION_enable_audio: |
case QEMU_OPTION_enable_audio: |
| 4357 |
audio_enabled = 1; |
audio_enabled = 1; |
| 4397 |
cpu_set_log(mask); |
cpu_set_log(mask); |
| 4398 |
} |
} |
| 4399 |
break; |
break; |
|
case QEMU_OPTION_n: |
|
|
pstrcpy(network_script, sizeof(network_script), optarg); |
|
|
break; |
|
| 4400 |
#ifdef CONFIG_GDBSTUB |
#ifdef CONFIG_GDBSTUB |
| 4401 |
case QEMU_OPTION_s: |
case QEMU_OPTION_s: |
| 4402 |
use_gdbstub = 1; |
use_gdbstub = 1; |
| 4540 |
#else |
#else |
| 4541 |
setvbuf(stdout, NULL, _IOLBF, 0); |
setvbuf(stdout, NULL, _IOLBF, 0); |
| 4542 |
#endif |
#endif |
| 4543 |
|
|
| 4544 |
/* init host network redirectors */ |
/* init network clients */ |
| 4545 |
if (net_if_type == -1) { |
if (nb_net_clients == 0) { |
| 4546 |
net_if_type = NET_IF_TUN; |
/* if no clients, we use a default config */ |
| 4547 |
#if defined(CONFIG_SLIRP) |
pstrcpy(net_clients[0], sizeof(net_clients[0]), |
| 4548 |
if (access(network_script, R_OK) < 0) { |
"nic"); |
| 4549 |
net_if_type = NET_IF_USER; |
pstrcpy(net_clients[1], sizeof(net_clients[0]), |
| 4550 |
} |
"user"); |
| 4551 |
#endif |
nb_net_clients = 2; |
| 4552 |
} |
} |
| 4553 |
|
|
| 4554 |
for(i = 0; i < nb_nics; i++) { |
for(i = 0;i < nb_net_clients; i++) { |
| 4555 |
NetDriverState *nd = &nd_table[i]; |
if (net_client_init(net_clients[i]) < 0) |
| 4556 |
nd->index = i; |
exit(1); |
|
/* init virtual mac address */ |
|
|
nd->macaddr[0] = macaddr[0]; |
|
|
nd->macaddr[1] = macaddr[1]; |
|
|
nd->macaddr[2] = macaddr[2]; |
|
|
nd->macaddr[3] = macaddr[3]; |
|
|
nd->macaddr[4] = macaddr[4]; |
|
|
nd->macaddr[5] = macaddr[5] + i; |
|
|
switch(net_if_type) { |
|
|
#if defined(CONFIG_SLIRP) |
|
|
case NET_IF_USER: |
|
|
net_slirp_init(nd); |
|
|
break; |
|
|
#endif |
|
|
#if !defined(_WIN32) |
|
|
case NET_IF_TUN: |
|
|
if (i < nb_tun_fds) { |
|
|
net_fd_init(nd, tun_fds[i]); |
|
|
} else { |
|
|
if (net_tun_init(nd) < 0) |
|
|
net_dummy_init(nd); |
|
|
} |
|
|
break; |
|
|
#endif |
|
|
case NET_IF_DUMMY: |
|
|
default: |
|
|
net_dummy_init(nd); |
|
|
break; |
|
|
} |
|
| 4557 |
} |
} |
| 4558 |
|
|
| 4559 |
/* init the memory */ |
/* init the memory */ |