45 |
45 |
#include <linux/if_tun.h>
|
46 |
46 |
#endif
|
47 |
47 |
|
|
48 |
#if defined(CONFIG_SLIRP)
|
|
49 |
#include "libslirp.h"
|
|
50 |
#endif
|
|
51 |
|
48 |
52 |
#ifdef _WIN32
|
49 |
53 |
#include <sys/timeb.h>
|
50 |
54 |
#include <windows.h>
|
... | ... | |
750 |
754 |
#endif
|
751 |
755 |
|
752 |
756 |
/***********************************************************/
|
753 |
|
/* Linux network device redirector */
|
|
757 |
/* Linux network device redirectors */
|
754 |
758 |
|
755 |
|
#ifdef _WIN32
|
|
759 |
void hex_dump(FILE *f, const uint8_t *buf, int size)
|
|
760 |
{
|
|
761 |
int len, i, j, c;
|
|
762 |
|
|
763 |
for(i=0;i<size;i+=16) {
|
|
764 |
len = size - i;
|
|
765 |
if (len > 16)
|
|
766 |
len = 16;
|
|
767 |
fprintf(f, "%08x ", i);
|
|
768 |
for(j=0;j<16;j++) {
|
|
769 |
if (j < len)
|
|
770 |
fprintf(f, " %02x", buf[i+j]);
|
|
771 |
else
|
|
772 |
fprintf(f, " ");
|
|
773 |
}
|
|
774 |
fprintf(f, " ");
|
|
775 |
for(j=0;j<len;j++) {
|
|
776 |
c = buf[i+j];
|
|
777 |
if (c < ' ' || c > '~')
|
|
778 |
c = '.';
|
|
779 |
fprintf(f, "%c", c);
|
|
780 |
}
|
|
781 |
fprintf(f, "\n");
|
|
782 |
}
|
|
783 |
}
|
|
784 |
|
|
785 |
void qemu_send_packet(NetDriverState *nd, const uint8_t *buf, int size)
|
|
786 |
{
|
|
787 |
nd->send_packet(nd, buf, size);
|
|
788 |
}
|
756 |
789 |
|
757 |
|
static int net_init(void)
|
|
790 |
void qemu_add_read_packet(NetDriverState *nd, IOCanRWHandler *fd_can_read,
|
|
791 |
IOReadHandler *fd_read, void *opaque)
|
758 |
792 |
{
|
|
793 |
nd->add_read_packet(nd, fd_can_read, fd_read, opaque);
|
|
794 |
}
|
|
795 |
|
|
796 |
/* dummy network adapter */
|
|
797 |
|
|
798 |
static void dummy_send_packet(NetDriverState *nd, const uint8_t *buf, int size)
|
|
799 |
{
|
|
800 |
}
|
|
801 |
|
|
802 |
static void dummy_add_read_packet(NetDriverState *nd,
|
|
803 |
IOCanRWHandler *fd_can_read,
|
|
804 |
IOReadHandler *fd_read, void *opaque)
|
|
805 |
{
|
|
806 |
}
|
|
807 |
|
|
808 |
static int net_dummy_init(NetDriverState *nd)
|
|
809 |
{
|
|
810 |
nd->send_packet = dummy_send_packet;
|
|
811 |
nd->add_read_packet = dummy_add_read_packet;
|
|
812 |
pstrcpy(nd->ifname, sizeof(nd->ifname), "dummy");
|
759 |
813 |
return 0;
|
760 |
814 |
}
|
761 |
815 |
|
762 |
|
void net_send_packet(NetDriverState *nd, const uint8_t *buf, int size)
|
|
816 |
#if defined(CONFIG_SLIRP)
|
|
817 |
|
|
818 |
/* slirp network adapter */
|
|
819 |
|
|
820 |
static void *slirp_fd_opaque;
|
|
821 |
static IOCanRWHandler *slirp_fd_can_read;
|
|
822 |
static IOReadHandler *slirp_fd_read;
|
|
823 |
static int slirp_inited;
|
|
824 |
|
|
825 |
int slirp_can_output(void)
|
|
826 |
{
|
|
827 |
return slirp_fd_can_read(slirp_fd_opaque);
|
|
828 |
}
|
|
829 |
|
|
830 |
void slirp_output(const uint8_t *pkt, int pkt_len)
|
763 |
831 |
{
|
|
832 |
#if 0
|
|
833 |
printf("output:\n");
|
|
834 |
hex_dump(stdout, pkt, pkt_len);
|
|
835 |
#endif
|
|
836 |
slirp_fd_read(slirp_fd_opaque, pkt, pkt_len);
|
764 |
837 |
}
|
765 |
838 |
|
766 |
|
#else
|
|
839 |
static void slirp_send_packet(NetDriverState *nd, const uint8_t *buf, int size)
|
|
840 |
{
|
|
841 |
#if 0
|
|
842 |
printf("input:\n");
|
|
843 |
hex_dump(stdout, buf, size);
|
|
844 |
#endif
|
|
845 |
slirp_input(buf, size);
|
|
846 |
}
|
|
847 |
|
|
848 |
static void slirp_add_read_packet(NetDriverState *nd,
|
|
849 |
IOCanRWHandler *fd_can_read,
|
|
850 |
IOReadHandler *fd_read, void *opaque)
|
|
851 |
{
|
|
852 |
slirp_fd_opaque = opaque;
|
|
853 |
slirp_fd_can_read = fd_can_read;
|
|
854 |
slirp_fd_read = fd_read;
|
|
855 |
}
|
|
856 |
|
|
857 |
static int net_slirp_init(NetDriverState *nd)
|
|
858 |
{
|
|
859 |
if (!slirp_inited) {
|
|
860 |
slirp_inited = 1;
|
|
861 |
slirp_init();
|
|
862 |
}
|
|
863 |
nd->send_packet = slirp_send_packet;
|
|
864 |
nd->add_read_packet = slirp_add_read_packet;
|
|
865 |
pstrcpy(nd->ifname, sizeof(nd->ifname), "slirp");
|
|
866 |
return 0;
|
|
867 |
}
|
|
868 |
|
|
869 |
#endif /* CONFIG_SLIRP */
|
|
870 |
|
|
871 |
#if !defined(_WIN32)
|
767 |
872 |
|
768 |
873 |
static int tun_open(char *ifname, int ifname_size)
|
769 |
874 |
{
|
... | ... | |
790 |
895 |
return fd;
|
791 |
896 |
}
|
792 |
897 |
|
793 |
|
static int net_init(void)
|
|
898 |
static void tun_send_packet(NetDriverState *nd, const uint8_t *buf, int size)
|
|
899 |
{
|
|
900 |
write(nd->fd, buf, size);
|
|
901 |
}
|
|
902 |
|
|
903 |
static void tun_add_read_packet(NetDriverState *nd,
|
|
904 |
IOCanRWHandler *fd_can_read,
|
|
905 |
IOReadHandler *fd_read, void *opaque)
|
794 |
906 |
{
|
795 |
|
int pid, status, launch_script, i;
|
796 |
|
NetDriverState *nd;
|
797 |
|
char *args[MAX_NICS + 2];
|
|
907 |
qemu_add_fd_read_handler(nd->fd, fd_can_read, fd_read, opaque);
|
|
908 |
}
|
|
909 |
|
|
910 |
static int net_tun_init(NetDriverState *nd)
|
|
911 |
{
|
|
912 |
int pid, status;
|
|
913 |
char *args[3];
|
798 |
914 |
char **parg;
|
799 |
915 |
|
800 |
|
launch_script = 0;
|
801 |
|
for(i = 0; i < nb_nics; i++) {
|
802 |
|
nd = &nd_table[i];
|
803 |
|
if (nd->fd < 0) {
|
804 |
|
nd->fd = tun_open(nd->ifname, sizeof(nd->ifname));
|
805 |
|
if (nd->fd >= 0)
|
806 |
|
launch_script = 1;
|
807 |
|
}
|
808 |
|
}
|
|
916 |
nd->fd = tun_open(nd->ifname, sizeof(nd->ifname));
|
|
917 |
if (nd->fd < 0)
|
|
918 |
return -1;
|
809 |
919 |
|
810 |
|
if (launch_script) {
|
811 |
|
/* try to launch network init script */
|
812 |
|
pid = fork();
|
813 |
|
if (pid >= 0) {
|
814 |
|
if (pid == 0) {
|
815 |
|
parg = args;
|
816 |
|
*parg++ = network_script;
|
817 |
|
for(i = 0; i < nb_nics; i++) {
|
818 |
|
nd = &nd_table[i];
|
819 |
|
if (nd->fd >= 0) {
|
820 |
|
*parg++ = nd->ifname;
|
821 |
|
}
|
822 |
|
}
|
823 |
|
*parg++ = NULL;
|
824 |
|
execv(network_script, args);
|
825 |
|
exit(1);
|
826 |
|
}
|
827 |
|
while (waitpid(pid, &status, 0) != pid);
|
828 |
|
if (!WIFEXITED(status) ||
|
829 |
|
WEXITSTATUS(status) != 0) {
|
830 |
|
fprintf(stderr, "%s: could not launch network script\n",
|
831 |
|
network_script);
|
832 |
|
}
|
|
920 |
/* try to launch network init script */
|
|
921 |
pid = fork();
|
|
922 |
if (pid >= 0) {
|
|
923 |
if (pid == 0) {
|
|
924 |
parg = args;
|
|
925 |
*parg++ = network_script;
|
|
926 |
*parg++ = nd->ifname;
|
|
927 |
*parg++ = NULL;
|
|
928 |
execv(network_script, args);
|
|
929 |
exit(1);
|
|
930 |
}
|
|
931 |
while (waitpid(pid, &status, 0) != pid);
|
|
932 |
if (!WIFEXITED(status) ||
|
|
933 |
WEXITSTATUS(status) != 0) {
|
|
934 |
fprintf(stderr, "%s: could not launch network script\n",
|
|
935 |
network_script);
|
833 |
936 |
}
|
834 |
937 |
}
|
|
938 |
nd->send_packet = tun_send_packet;
|
|
939 |
nd->add_read_packet = tun_add_read_packet;
|
835 |
940 |
return 0;
|
836 |
941 |
}
|
837 |
942 |
|
838 |
|
void net_send_packet(NetDriverState *nd, const uint8_t *buf, int size)
|
|
943 |
static int net_fd_init(NetDriverState *nd, int fd)
|
839 |
944 |
{
|
840 |
|
#ifdef DEBUG_NE2000
|
841 |
|
printf("NE2000: sending packet size=%d\n", size);
|
842 |
|
#endif
|
843 |
|
write(nd->fd, buf, size);
|
|
945 |
nd->fd = fd;
|
|
946 |
nd->send_packet = tun_send_packet;
|
|
947 |
nd->add_read_packet = tun_add_read_packet;
|
|
948 |
pstrcpy(nd->ifname, sizeof(nd->ifname), "tunfd");
|
|
949 |
return 0;
|
844 |
950 |
}
|
845 |
951 |
|
846 |
|
#endif
|
|
952 |
#endif /* !_WIN32 */
|
847 |
953 |
|
848 |
954 |
/***********************************************************/
|
849 |
955 |
/* dumb display */
|
... | ... | |
1597 |
1703 |
}
|
1598 |
1704 |
}
|
1599 |
1705 |
}
|
|
1706 |
|
|
1707 |
#if defined(CONFIG_SLIRP)
|
|
1708 |
/* XXX: merge with poll() */
|
|
1709 |
if (slirp_inited) {
|
|
1710 |
fd_set rfds, wfds, xfds;
|
|
1711 |
int nfds;
|
|
1712 |
struct timeval tv;
|
|
1713 |
|
|
1714 |
nfds = -1;
|
|
1715 |
FD_ZERO(&rfds);
|
|
1716 |
FD_ZERO(&wfds);
|
|
1717 |
FD_ZERO(&xfds);
|
|
1718 |
slirp_select_fill(&nfds, &rfds, &wfds, &xfds);
|
|
1719 |
tv.tv_sec = 0;
|
|
1720 |
tv.tv_usec = 0;
|
|
1721 |
ret = select(nfds + 1, &rfds, &wfds, &xfds, &tv);
|
|
1722 |
if (ret >= 0) {
|
|
1723 |
slirp_select_poll(&rfds, &wfds, &xfds);
|
|
1724 |
}
|
|
1725 |
}
|
|
1726 |
#endif
|
|
1727 |
|
1600 |
1728 |
#endif
|
1601 |
1729 |
|
1602 |
1730 |
if (vm_running) {
|
... | ... | |
1636 |
1764 |
"-nographic disable graphical output and redirect serial I/Os to console\n"
|
1637 |
1765 |
"\n"
|
1638 |
1766 |
"Network options:\n"
|
1639 |
|
"-n script set network init script [default=%s]\n"
|
1640 |
|
"-nics n simulate 'n' network interfaces [default=1]\n"
|
|
1767 |
"-nics n simulate 'n' network cards [default=1]\n"
|
1641 |
1768 |
"-macaddr addr set the mac address of the first interface\n"
|
1642 |
|
"-tun-fd fd0[,...] use these fds as already opened tap/tun interfaces\n"
|
|
1769 |
"-n script set tap/tun network init script [default=%s]\n"
|
|
1770 |
"-tun-fd fd use this fd as already opened tap/tun interface\n"
|
|
1771 |
#ifdef CONFIG_SLIRP
|
|
1772 |
"-user-net use user mode network stack [default if no tap/tun script]\n"
|
|
1773 |
#endif
|
|
1774 |
"-dummy-net use dummy network stack\n"
|
1643 |
1775 |
"\n"
|
1644 |
1776 |
"Linux boot specific:\n"
|
1645 |
1777 |
"-kernel bzImage use 'bzImage' as kernel image\n"
|
... | ... | |
1695 |
1827 |
{ "no-code-copy", 0, NULL, 0 },
|
1696 |
1828 |
{ "nics", 1, NULL, 0 },
|
1697 |
1829 |
{ "macaddr", 1, NULL, 0 },
|
|
1830 |
{ "user-net", 1, NULL, 0 },
|
|
1831 |
{ "dummy-net", 1, NULL, 0 },
|
1698 |
1832 |
{ NULL, 0, NULL, 0 },
|
1699 |
1833 |
};
|
1700 |
1834 |
|
... | ... | |
1707 |
1841 |
|
1708 |
1842 |
#endif
|
1709 |
1843 |
|
|
1844 |
#define NET_IF_TUN 0
|
|
1845 |
#define NET_IF_USER 1
|
|
1846 |
#define NET_IF_DUMMY 2
|
|
1847 |
|
1710 |
1848 |
int main(int argc, char **argv)
|
1711 |
1849 |
{
|
1712 |
1850 |
#ifdef CONFIG_GDBSTUB
|
... | ... | |
1722 |
1860 |
int cyls, heads, secs;
|
1723 |
1861 |
int start_emulation = 1;
|
1724 |
1862 |
uint8_t macaddr[6];
|
1725 |
|
|
|
1863 |
int net_if_type, nb_tun_fds, tun_fds[MAX_NICS];
|
|
1864 |
|
1726 |
1865 |
#if !defined(CONFIG_SOFTMMU)
|
1727 |
1866 |
/* we never want that malloc() uses mmap() */
|
1728 |
1867 |
mallopt(M_MMAP_THRESHOLD, 4096 * 1024);
|
... | ... | |
1746 |
1885 |
has_cdrom = 1;
|
1747 |
1886 |
cyls = heads = secs = 0;
|
1748 |
1887 |
|
|
1888 |
nb_tun_fds = 0;
|
|
1889 |
net_if_type = -1;
|
1749 |
1890 |
nb_nics = 1;
|
1750 |
1891 |
/* default mac address of the first network interface */
|
1751 |
1892 |
macaddr[0] = 0x52;
|
... | ... | |
1754 |
1895 |
macaddr[3] = 0x12;
|
1755 |
1896 |
macaddr[4] = 0x34;
|
1756 |
1897 |
macaddr[5] = 0x56;
|
1757 |
|
|
1758 |
|
for(i = 0; i < MAX_NICS; i++)
|
1759 |
|
nd_table[i].fd = -1;
|
1760 |
|
|
|
1898 |
|
|
1899 |
|
1761 |
1900 |
for(;;) {
|
1762 |
1901 |
c = getopt_long_only(argc, argv, "hm:d:n:sp:L:S", long_options, &long_index);
|
1763 |
1902 |
if (c == -1)
|
... | ... | |
1809 |
1948 |
{
|
1810 |
1949 |
const char *p;
|
1811 |
1950 |
int fd;
|
1812 |
|
p = optarg;
|
1813 |
|
nb_nics = 0;
|
1814 |
|
for(;;) {
|
1815 |
|
fd = strtol(p, (char **)&p, 0);
|
1816 |
|
nd_table[nb_nics].fd = fd;
|
1817 |
|
snprintf(nd_table[nb_nics].ifname,
|
1818 |
|
sizeof(nd_table[nb_nics].ifname),
|
1819 |
|
"fd%d", nb_nics);
|
1820 |
|
nb_nics++;
|
1821 |
|
if (*p == ',') {
|
1822 |
|
p++;
|
1823 |
|
} else if (*p != '\0') {
|
1824 |
|
fprintf(stderr, "qemu: invalid fd for network interface %d\n", nb_nics);
|
|
1951 |
if (nb_tun_fds < MAX_NICS) {
|
|
1952 |
fd = strtol(optarg, (char **)&p, 0);
|
|
1953 |
if (*p != '\0') {
|
|
1954 |
fprintf(stderr, "qemu: invalid fd for network interface %d\n", nb_tun_fds);
|
1825 |
1955 |
exit(1);
|
1826 |
|
} else {
|
1827 |
|
break;
|
1828 |
1956 |
}
|
|
1957 |
tun_fds[nb_tun_fds++] = fd;
|
1829 |
1958 |
}
|
1830 |
1959 |
}
|
1831 |
1960 |
break;
|
... | ... | |
1885 |
2014 |
}
|
1886 |
2015 |
}
|
1887 |
2016 |
break;
|
|
2017 |
case 18:
|
|
2018 |
net_if_type = NET_IF_USER;
|
|
2019 |
break;
|
|
2020 |
case 19:
|
|
2021 |
net_if_type = NET_IF_DUMMY;
|
|
2022 |
break;
|
1888 |
2023 |
}
|
1889 |
2024 |
break;
|
1890 |
2025 |
case 'h':
|
... | ... | |
1965 |
2100 |
#endif
|
1966 |
2101 |
|
1967 |
2102 |
/* init host network redirectors */
|
1968 |
|
for(i = 0; i < MAX_NICS; i++) {
|
|
2103 |
if (net_if_type == -1) {
|
|
2104 |
net_if_type = NET_IF_TUN;
|
|
2105 |
#if defined(CONFIG_SLIRP)
|
|
2106 |
if (access(network_script, R_OK) < 0) {
|
|
2107 |
net_if_type = NET_IF_USER;
|
|
2108 |
}
|
|
2109 |
#endif
|
|
2110 |
}
|
|
2111 |
|
|
2112 |
for(i = 0; i < nb_nics; i++) {
|
1969 |
2113 |
NetDriverState *nd = &nd_table[i];
|
|
2114 |
nd->index = i;
|
1970 |
2115 |
/* init virtual mac address */
|
1971 |
2116 |
nd->macaddr[0] = macaddr[0];
|
1972 |
2117 |
nd->macaddr[1] = macaddr[1];
|
... | ... | |
1974 |
2119 |
nd->macaddr[3] = macaddr[3];
|
1975 |
2120 |
nd->macaddr[4] = macaddr[4];
|
1976 |
2121 |
nd->macaddr[5] = macaddr[5] + i;
|
|
2122 |
switch(net_if_type) {
|
|
2123 |
#if defined(CONFIG_SLIRP)
|
|
2124 |
case NET_IF_USER:
|
|
2125 |
net_slirp_init(nd);
|
|
2126 |
break;
|
|
2127 |
#endif
|
|
2128 |
#if !defined(_WIN32)
|
|
2129 |
case NET_IF_TUN:
|
|
2130 |
if (i < nb_tun_fds) {
|
|
2131 |
net_fd_init(nd, tun_fds[i]);
|
|
2132 |
} else {
|
|
2133 |
net_tun_init(nd);
|
|
2134 |
}
|
|
2135 |
break;
|
|
2136 |
#endif
|
|
2137 |
case NET_IF_DUMMY:
|
|
2138 |
default:
|
|
2139 |
net_dummy_init(nd);
|
|
2140 |
break;
|
|
2141 |
}
|
1977 |
2142 |
}
|
1978 |
|
net_init();
|
1979 |
2143 |
|
1980 |
2144 |
/* init the memory */
|
1981 |
2145 |
phys_ram_size = ram_size + vga_ram_size;
|
... | ... | |
2058 |
2222 |
}
|
2059 |
2223 |
if (fd_filename[i] != '\0') {
|
2060 |
2224 |
if (bdrv_open(fd_table[i], fd_filename[i], snapshot) < 0) {
|
2061 |
|
fprintf(stderr, "qemu: could not open floppy disk image '%s\n",
|
|
2225 |
fprintf(stderr, "qemu: could not open floppy disk image '%s'\n",
|
2062 |
2226 |
fd_filename[i]);
|
2063 |
2227 |
exit(1);
|
2064 |
2228 |
}
|