X-Git-Url: http://git.maemo.org/git/?a=blobdiff_plain;f=net.c;h=31ee95a4ff3daea30adb99a55ae8b80c0d7ef702;hb=72b675caacfc6f2fde17e6b51a668c0d5409a8f7;hp=c6b196fb935936cc8dd508087a206e625bcf4d42;hpb=8e4416af458b5fdfc81950005e358de02511eb9f;p=qemu diff --git a/net.c b/net.c index c6b196f..31ee95a 100644 --- a/net.c +++ b/net.c @@ -118,6 +118,7 @@ #include "qemu-char.h" #include "audio/audio.h" #include "qemu_socket.h" +#include "qemu-log.h" #if defined(CONFIG_SLIRP) #include "libslirp.h" @@ -402,22 +403,46 @@ int qemu_can_send_packet(VLANClientState *vc1) return 0; } -void qemu_send_packet(VLANClientState *vc1, const uint8_t *buf, int size) +static void +qemu_deliver_packet(VLANClientState *sender, const uint8_t *buf, int size) { - VLANState *vlan = vc1->vlan; VLANClientState *vc; - if (vc1->link_down) + for (vc = sender->vlan->first_client; vc != NULL; vc = vc->next) { + if (vc != sender && !vc->link_down) { + vc->fd_read(vc->opaque, buf, size); + } + } +} + +void qemu_send_packet(VLANClientState *vc, const uint8_t *buf, int size) +{ + VLANState *vlan = vc->vlan; + VLANPacket *packet; + + if (vc->link_down) return; #ifdef DEBUG_NET printf("vlan %d send:\n", vlan->id); hex_dump(stdout, buf, size); #endif - for(vc = vlan->first_client; vc != NULL; vc = vc->next) { - if (vc != vc1 && !vc->link_down) { - vc->fd_read(vc->opaque, buf, size); + if (vlan->delivering) { + packet = qemu_malloc(sizeof(VLANPacket) + size); + packet->next = vlan->send_queue; + packet->sender = vc; + packet->size = size; + memcpy(packet->data, buf, size); + vlan->send_queue = packet; + } else { + vlan->delivering = 1; + qemu_deliver_packet(vc, buf, size); + while ((packet = vlan->send_queue) != NULL) { + qemu_deliver_packet(packet->sender, packet->data, packet->size); + vlan->send_queue = packet->next; + qemu_free(packet); } + vlan->delivering = 0; } } @@ -519,23 +544,35 @@ static void slirp_receive(void *opaque, const uint8_t *buf, int size) slirp_input(buf, size); } +static int slirp_in_use; + +static void net_slirp_cleanup(VLANClientState *vc) +{ + slirp_in_use = 0; +} + static int net_slirp_init(VLANState *vlan, const char *model, const char *name) { + if (slirp_in_use) { + /* slirp only supports a single instance so far */ + return -1; + } if (!slirp_inited) { slirp_inited = 1; slirp_init(slirp_restrict, slirp_ip); } slirp_vc = qemu_new_vlan_client(vlan, model, name, - slirp_receive, NULL, NULL, NULL); + slirp_receive, NULL, net_slirp_cleanup, NULL); slirp_vc->info_str[0] = '\0'; + slirp_in_use = 1; return 0; } -void net_slirp_redir(const char *redir_str) +void net_slirp_redir(Monitor *mon, const char *redir_str) { int is_udp; char buf[256], *r; - const char *p; + const char *p, *errmsg; struct in_addr guest_addr; int host_port, guest_port; @@ -546,41 +583,48 @@ void net_slirp_redir(const char *redir_str) p = redir_str; if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) - goto fail; - if (!strcmp(buf, "tcp")) { + goto fail_syntax; + if (!strcmp(buf, "tcp") || buf[0] == '\0') { is_udp = 0; } else if (!strcmp(buf, "udp")) { is_udp = 1; } else { - goto fail; + goto fail_syntax; } if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) - goto fail; + goto fail_syntax; host_port = strtol(buf, &r, 0); if (r == buf) - goto fail; + goto fail_syntax; if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) - goto fail; + goto fail_syntax; if (buf[0] == '\0') { pstrcpy(buf, sizeof(buf), "10.0.2.15"); } if (!inet_aton(buf, &guest_addr)) - goto fail; + goto fail_syntax; guest_port = strtol(p, &r, 0); if (r == p) - goto fail; + goto fail_syntax; if (slirp_redir(is_udp, host_port, guest_addr, guest_port) < 0) { - fprintf(stderr, "qemu: could not set up redirection\n"); - exit(1); + errmsg = "could not set up redirection\n"; + goto fail; } return; + + fail_syntax: + errmsg = "invalid redirection format\n"; fail: - fprintf(stderr, "qemu: syntax: -redir [tcp|udp]:host-port:[guest-host]:guest-port\n"); - exit(1); + if (mon) { + monitor_printf(mon, "%s", errmsg); + } else { + fprintf(stderr, "qemu: %s", errmsg); + exit(1); + } } #ifndef _WIN32 @@ -1059,7 +1103,7 @@ static void vde_to_qemu(void *opaque) uint8_t buf[4096]; int size; - size = vde_recv(s->vde, buf, sizeof(buf), 0); + size = vde_recv(s->vde, (char *)buf, sizeof(buf), 0); if (size > 0) { qemu_send_packet(s->vc, buf, size); } @@ -1070,7 +1114,7 @@ static void vde_from_qemu(void *opaque, const uint8_t *buf, int size) VDEState *s = opaque; int ret; for(;;) { - ret = vde_send(s->vde, buf, size, 0); + ret = vde_send(s->vde, (const char *)buf, size, 0); if (ret < 0 && errno == EINTR) { } else { break; @@ -1101,7 +1145,7 @@ static int net_vde_init(VLANState *vlan, const char *model, }; s = qemu_mallocz(sizeof(VDEState)); - s->vde = vde_open(init_sock, "QEMU", &args); + s->vde = vde_open(init_sock, (char *)"QEMU", &args); if (!s->vde){ free(s); return -1; @@ -1558,6 +1602,106 @@ static int net_socket_mcast_init(VLANState *vlan, } +typedef struct DumpState { + VLANClientState *pcap_vc; + int fd; + int pcap_caplen; +} DumpState; + +#define PCAP_MAGIC 0xa1b2c3d4 + +struct pcap_file_hdr { + uint32_t magic; + uint16_t version_major; + uint16_t version_minor; + int32_t thiszone; + uint32_t sigfigs; + uint32_t snaplen; + uint32_t linktype; +}; + +struct pcap_sf_pkthdr { + struct { + int32_t tv_sec; + int32_t tv_usec; + } ts; + uint32_t caplen; + uint32_t len; +}; + +static void dump_receive(void *opaque, const uint8_t *buf, int size) +{ + DumpState *s = opaque; + struct pcap_sf_pkthdr hdr; + int64_t ts; + int caplen; + + /* Early return in case of previous error. */ + if (s->fd < 0) { + return; + } + + ts = muldiv64(qemu_get_clock(vm_clock), 1000000, ticks_per_sec); + caplen = size > s->pcap_caplen ? s->pcap_caplen : size; + + hdr.ts.tv_sec = ts / 1000000; + hdr.ts.tv_usec = ts % 1000000; + hdr.caplen = caplen; + hdr.len = size; + if (write(s->fd, &hdr, sizeof(hdr)) != sizeof(hdr) || + write(s->fd, buf, caplen) != caplen) { + qemu_log("-net dump write error - stop dump\n"); + close(s->fd); + s->fd = -1; + } +} + +static void net_dump_cleanup(VLANClientState *vc) +{ + DumpState *s = vc->opaque; + + close(s->fd); + qemu_free(s); +} + +static int net_dump_init(VLANState *vlan, const char *device, + const char *name, const char *filename, int len) +{ + struct pcap_file_hdr hdr; + DumpState *s; + + s = qemu_malloc(sizeof(DumpState)); + + s->fd = open(filename, O_CREAT | O_WRONLY, 0644); + if (s->fd < 0) { + fprintf(stderr, "-net dump: can't open %s\n", filename); + return -1; + } + + s->pcap_caplen = len; + + hdr.magic = PCAP_MAGIC; + hdr.version_major = 2; + hdr.version_minor = 4; + hdr.thiszone = 0; + hdr.sigfigs = 0; + hdr.snaplen = s->pcap_caplen; + hdr.linktype = 1; + + if (write(s->fd, &hdr, sizeof(hdr)) < sizeof(hdr)) { + perror("-net dump write error"); + close(s->fd); + qemu_free(s); + return -1; + } + + s->pcap_vc = qemu_new_vlan_client(vlan, device, name, dump_receive, NULL, + net_dump_cleanup, s); + snprintf(s->pcap_vc->info_str, sizeof(s->pcap_vc->info_str), + "dump to %s (len=%d)", filename, len); + return 0; +} + /* find or alloc a new VLAN */ VLANState *qemu_find_vlan(int id) { @@ -1647,7 +1791,7 @@ int net_client_init(const char *device, const char *p) uint8_t *macaddr; int idx = nic_get_free_idx(); - if (check_params(buf, sizeof(buf), nic_params, p) < 0) { + if (check_params(nic_params, p) < 0) { fprintf(stderr, "qemu: invalid parameter '%s' in '%s'\n", buf, p); return -1; @@ -1698,7 +1842,7 @@ int net_client_init(const char *device, const char *p) static const char * const slirp_params[] = { "vlan", "name", "hostname", "restrict", "ip", NULL }; - if (check_params(buf, sizeof(buf), slirp_params, p) < 0) { + if (check_params(slirp_params, p) < 0) { fprintf(stderr, "qemu: invalid parameter '%s' in '%s'\n", buf, p); return -1; @@ -1749,7 +1893,7 @@ int net_client_init(const char *device, const char *p) }; char ifname[64]; - if (check_params(buf, sizeof(buf), tap_params, p) < 0) { + if (check_params(tap_params, p) < 0) { fprintf(stderr, "qemu: invalid parameter '%s' in '%s'\n", buf, p); return -1; @@ -1770,7 +1914,7 @@ int net_client_init(const char *device, const char *p) int fd; vlan->nb_host_devs++; if (get_param_value(buf, sizeof(buf), "fd", p) > 0) { - if (check_params(buf, sizeof(buf), fd_params, p) < 0) { + if (check_params(fd_params, p) < 0) { fprintf(stderr, "qemu: invalid parameter '%s' in '%s'\n", buf, p); return -1; @@ -1783,7 +1927,7 @@ int net_client_init(const char *device, const char *p) static const char * const tap_params[] = { "vlan", "name", "ifname", "script", "downscript", NULL }; - if (check_params(buf, sizeof(buf), tap_params, p) < 0) { + if (check_params(tap_params, p) < 0) { fprintf(stderr, "qemu: invalid parameter '%s' in '%s'\n", buf, p); return -1; @@ -1804,7 +1948,7 @@ int net_client_init(const char *device, const char *p) if (!strcmp(device, "socket")) { if (get_param_value(buf, sizeof(buf), "fd", p) > 0) { int fd; - if (check_params(buf, sizeof(buf), fd_params, p) < 0) { + if (check_params(fd_params, p) < 0) { fprintf(stderr, "qemu: invalid parameter '%s' in '%s'\n", buf, p); return -1; @@ -1817,7 +1961,7 @@ int net_client_init(const char *device, const char *p) static const char * const listen_params[] = { "vlan", "name", "listen", NULL }; - if (check_params(buf, sizeof(buf), listen_params, p) < 0) { + if (check_params(listen_params, p) < 0) { fprintf(stderr, "qemu: invalid parameter '%s' in '%s'\n", buf, p); return -1; @@ -1827,7 +1971,7 @@ int net_client_init(const char *device, const char *p) static const char * const connect_params[] = { "vlan", "name", "connect", NULL }; - if (check_params(buf, sizeof(buf), connect_params, p) < 0) { + if (check_params(connect_params, p) < 0) { fprintf(stderr, "qemu: invalid parameter '%s' in '%s'\n", buf, p); return -1; @@ -1837,7 +1981,7 @@ int net_client_init(const char *device, const char *p) static const char * const mcast_params[] = { "vlan", "name", "mcast", NULL }; - if (check_params(buf, sizeof(buf), mcast_params, p) < 0) { + if (check_params(mcast_params, p) < 0) { fprintf(stderr, "qemu: invalid parameter '%s' in '%s'\n", buf, p); return -1; @@ -1858,7 +2002,7 @@ int net_client_init(const char *device, const char *p) char vde_sock[1024], vde_group[512]; int vde_port, vde_mode; - if (check_params(buf, sizeof(buf), vde_params, p) < 0) { + if (check_params(vde_params, p) < 0) { fprintf(stderr, "qemu: invalid parameter '%s' in '%s'\n", buf, p); return -1; @@ -1883,7 +2027,17 @@ int net_client_init(const char *device, const char *p) ret = net_vde_init(vlan, device, name, vde_sock, vde_port, vde_group, vde_mode); } else #endif - { + if (!strcmp(device, "dump")) { + int len = 65536; + + if (get_param_value(buf, sizeof(buf), "len", p) > 0) { + len = strtol(buf, NULL, 0); + } + if (!get_param_value(buf, sizeof(buf), "file", p)) { + snprintf(buf, sizeof(buf), "qemu-vlan%d.pcap", vlan_id); + } + ret = net_dump_init(vlan, device, name, buf, len); + } else { fprintf(stderr, "Unknown network device: %s\n", device); ret = -1; goto out; @@ -1908,7 +2062,7 @@ void net_client_uninit(NICInfo *nd) static int net_host_check_device(const char *device) { int i; - const char *valid_param_list[] = { "tap", "socket" + const char *valid_param_list[] = { "tap", "socket", "dump" #ifdef CONFIG_SLIRP ,"user" #endif @@ -1931,7 +2085,9 @@ void net_host_device_add(Monitor *mon, const char *device, const char *opts) monitor_printf(mon, "invalid host network device %s\n", device); return; } - net_client_init(device, opts); + if (net_client_init(device, opts ? opts : "") < 0) { + monitor_printf(mon, "adding host network device %s failed\n", device); + } } void net_host_device_remove(Monitor *mon, int vlan_id, const char *device)