Statistics
| Branch: | Revision:

root / net / slirp.c @ 5a01e99f

History | View | Annotate | Download (21.2 kB)

1
/*
2
 * QEMU System Emulator
3
 *
4
 * Copyright (c) 2003-2008 Fabrice Bellard
5
 *
6
 * Permission is hereby granted, free of charge, to any person obtaining a copy
7
 * of this software and associated documentation files (the "Software"), to deal
8
 * in the Software without restriction, including without limitation the rights
9
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
 * copies of the Software, and to permit persons to whom the Software is
11
 * furnished to do so, subject to the following conditions:
12
 *
13
 * The above copyright notice and this permission notice shall be included in
14
 * all copies or substantial portions of the Software.
15
 *
16
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22
 * THE SOFTWARE.
23
 */
24
#include "net/slirp.h"
25

    
26
#include "config-host.h"
27

    
28
#include "net.h"
29
#include "monitor.h"
30
#include "sysemu.h"
31
#include "qemu_socket.h"
32
#include "slirp/libslirp.h"
33

    
34
static int get_str_sep(char *buf, int buf_size, const char **pp, int sep)
35
{
36
    const char *p, *p1;
37
    int len;
38
    p = *pp;
39
    p1 = strchr(p, sep);
40
    if (!p1)
41
        return -1;
42
    len = p1 - p;
43
    p1++;
44
    if (buf_size > 0) {
45
        if (len > buf_size - 1)
46
            len = buf_size - 1;
47
        memcpy(buf, p, len);
48
        buf[len] = '\0';
49
    }
50
    *pp = p1;
51
    return 0;
52
}
53

    
54
/* slirp network adapter */
55

    
56
#define SLIRP_CFG_HOSTFWD 1
57
#define SLIRP_CFG_LEGACY  2
58

    
59
struct slirp_config_str {
60
    struct slirp_config_str *next;
61
    int flags;
62
    char str[1024];
63
    int legacy_format;
64
};
65

    
66
typedef struct SlirpState {
67
    VLANClientState nc;
68
    QTAILQ_ENTRY(SlirpState) entry;
69
    Slirp *slirp;
70
#ifndef _WIN32
71
    char smb_dir[128];
72
#endif
73
} SlirpState;
74

    
75
static struct slirp_config_str *slirp_configs;
76
const char *legacy_tftp_prefix;
77
const char *legacy_bootp_filename;
78
static QTAILQ_HEAD(slirp_stacks, SlirpState) slirp_stacks =
79
    QTAILQ_HEAD_INITIALIZER(slirp_stacks);
80

    
81
static int slirp_hostfwd(SlirpState *s, const char *redir_str,
82
                         int legacy_format);
83
static int slirp_guestfwd(SlirpState *s, const char *config_str,
84
                          int legacy_format);
85

    
86
#ifndef _WIN32
87
static const char *legacy_smb_export;
88

    
89
static int slirp_smb(SlirpState *s, const char *exported_dir,
90
                     struct in_addr vserver_addr);
91
static void slirp_smb_cleanup(SlirpState *s);
92
#else
93
static inline void slirp_smb_cleanup(SlirpState *s) { }
94
#endif
95

    
96
int slirp_can_output(void *opaque)
97
{
98
    SlirpState *s = opaque;
99

    
100
    return qemu_can_send_packet(&s->nc);
101
}
102

    
103
void slirp_output(void *opaque, const uint8_t *pkt, int pkt_len)
104
{
105
    SlirpState *s = opaque;
106

    
107
    qemu_send_packet(&s->nc, pkt, pkt_len);
108
}
109

    
110
static ssize_t net_slirp_receive(VLANClientState *nc, const uint8_t *buf, size_t size)
111
{
112
    SlirpState *s = DO_UPCAST(SlirpState, nc, nc);
113

    
114
    slirp_input(s->slirp, buf, size);
115

    
116
    return size;
117
}
118

    
119
static void net_slirp_cleanup(VLANClientState *nc)
120
{
121
    SlirpState *s = DO_UPCAST(SlirpState, nc, nc);
122

    
123
    slirp_cleanup(s->slirp);
124
    slirp_smb_cleanup(s);
125
    QTAILQ_REMOVE(&slirp_stacks, s, entry);
126
}
127

    
128
static NetClientInfo net_slirp_info = {
129
    .type = NET_CLIENT_TYPE_SLIRP,
130
    .size = sizeof(SlirpState),
131
    .receive = net_slirp_receive,
132
    .cleanup = net_slirp_cleanup,
133
};
134

    
135
static int net_slirp_init(VLANState *vlan, const char *model,
136
                          const char *name, int restricted,
137
                          const char *vnetwork, const char *vhost,
138
                          const char *vhostname, const char *tftp_export,
139
                          const char *bootfile, const char *vdhcp_start,
140
                          const char *vnameserver, const char *smb_export,
141
                          const char *vsmbserver)
142
{
143
    /* default settings according to historic slirp */
144
    struct in_addr net  = { .s_addr = htonl(0x0a000200) }; /* 10.0.2.0 */
145
    struct in_addr mask = { .s_addr = htonl(0xffffff00) }; /* 255.255.255.0 */
146
    struct in_addr host = { .s_addr = htonl(0x0a000202) }; /* 10.0.2.2 */
147
    struct in_addr dhcp = { .s_addr = htonl(0x0a00020f) }; /* 10.0.2.15 */
148
    struct in_addr dns  = { .s_addr = htonl(0x0a000203) }; /* 10.0.2.3 */
149
#ifndef _WIN32
150
    struct in_addr smbsrv = { .s_addr = 0 };
151
#endif
152
    VLANClientState *nc;
153
    SlirpState *s;
154
    char buf[20];
155
    uint32_t addr;
156
    int shift;
157
    char *end;
158
    struct slirp_config_str *config;
159

    
160
    if (!tftp_export) {
161
        tftp_export = legacy_tftp_prefix;
162
    }
163
    if (!bootfile) {
164
        bootfile = legacy_bootp_filename;
165
    }
166

    
167
    if (vnetwork) {
168
        if (get_str_sep(buf, sizeof(buf), &vnetwork, '/') < 0) {
169
            if (!inet_aton(vnetwork, &net)) {
170
                return -1;
171
            }
172
            addr = ntohl(net.s_addr);
173
            if (!(addr & 0x80000000)) {
174
                mask.s_addr = htonl(0xff000000); /* class A */
175
            } else if ((addr & 0xfff00000) == 0xac100000) {
176
                mask.s_addr = htonl(0xfff00000); /* priv. 172.16.0.0/12 */
177
            } else if ((addr & 0xc0000000) == 0x80000000) {
178
                mask.s_addr = htonl(0xffff0000); /* class B */
179
            } else if ((addr & 0xffff0000) == 0xc0a80000) {
180
                mask.s_addr = htonl(0xffff0000); /* priv. 192.168.0.0/16 */
181
            } else if ((addr & 0xffff0000) == 0xc6120000) {
182
                mask.s_addr = htonl(0xfffe0000); /* tests 198.18.0.0/15 */
183
            } else if ((addr & 0xe0000000) == 0xe0000000) {
184
                mask.s_addr = htonl(0xffffff00); /* class C */
185
            } else {
186
                mask.s_addr = htonl(0xfffffff0); /* multicast/reserved */
187
            }
188
        } else {
189
            if (!inet_aton(buf, &net)) {
190
                return -1;
191
            }
192
            shift = strtol(vnetwork, &end, 10);
193
            if (*end != '\0') {
194
                if (!inet_aton(vnetwork, &mask)) {
195
                    return -1;
196
                }
197
            } else if (shift < 4 || shift > 32) {
198
                return -1;
199
            } else {
200
                mask.s_addr = htonl(0xffffffff << (32 - shift));
201
            }
202
        }
203
        net.s_addr &= mask.s_addr;
204
        host.s_addr = net.s_addr | (htonl(0x0202) & ~mask.s_addr);
205
        dhcp.s_addr = net.s_addr | (htonl(0x020f) & ~mask.s_addr);
206
        dns.s_addr  = net.s_addr | (htonl(0x0203) & ~mask.s_addr);
207
    }
208

    
209
    if (vhost && !inet_aton(vhost, &host)) {
210
        return -1;
211
    }
212
    if ((host.s_addr & mask.s_addr) != net.s_addr) {
213
        return -1;
214
    }
215

    
216
    if (vdhcp_start && !inet_aton(vdhcp_start, &dhcp)) {
217
        return -1;
218
    }
219
    if ((dhcp.s_addr & mask.s_addr) != net.s_addr ||
220
        dhcp.s_addr == host.s_addr || dhcp.s_addr == dns.s_addr) {
221
        return -1;
222
    }
223

    
224
    if (vnameserver && !inet_aton(vnameserver, &dns)) {
225
        return -1;
226
    }
227
    if ((dns.s_addr & mask.s_addr) != net.s_addr ||
228
        dns.s_addr == host.s_addr) {
229
        return -1;
230
    }
231

    
232
#ifndef _WIN32
233
    if (vsmbserver && !inet_aton(vsmbserver, &smbsrv)) {
234
        return -1;
235
    }
236
#endif
237

    
238
    nc = qemu_new_net_client(&net_slirp_info, vlan, NULL, model, name);
239

    
240
    snprintf(nc->info_str, sizeof(nc->info_str),
241
             "net=%s, restricted=%c", inet_ntoa(net), restricted ? 'y' : 'n');
242

    
243
    s = DO_UPCAST(SlirpState, nc, nc);
244

    
245
    s->slirp = slirp_init(restricted, net, mask, host, vhostname,
246
                          tftp_export, bootfile, dhcp, dns, s);
247
    QTAILQ_INSERT_TAIL(&slirp_stacks, s, entry);
248

    
249
    for (config = slirp_configs; config; config = config->next) {
250
        if (config->flags & SLIRP_CFG_HOSTFWD) {
251
            if (slirp_hostfwd(s, config->str,
252
                              config->flags & SLIRP_CFG_LEGACY) < 0)
253
                goto error;
254
        } else {
255
            if (slirp_guestfwd(s, config->str,
256
                               config->flags & SLIRP_CFG_LEGACY) < 0)
257
                goto error;
258
        }
259
    }
260
#ifndef _WIN32
261
    if (!smb_export) {
262
        smb_export = legacy_smb_export;
263
    }
264
    if (smb_export) {
265
        if (slirp_smb(s, smb_export, smbsrv) < 0)
266
            goto error;
267
    }
268
#endif
269

    
270
    return 0;
271

    
272
error:
273
    qemu_del_vlan_client(nc);
274
    return -1;
275
}
276

    
277
static SlirpState *slirp_lookup(Monitor *mon, const char *vlan,
278
                                const char *stack)
279
{
280

    
281
    if (vlan) {
282
        VLANClientState *nc;
283
        nc = qemu_find_vlan_client_by_name(mon, strtol(vlan, NULL, 0), stack);
284
        if (!nc) {
285
            return NULL;
286
        }
287
        if (strcmp(nc->model, "user")) {
288
            monitor_printf(mon, "invalid device specified\n");
289
            return NULL;
290
        }
291
        return DO_UPCAST(SlirpState, nc, nc);
292
    } else {
293
        if (QTAILQ_EMPTY(&slirp_stacks)) {
294
            monitor_printf(mon, "user mode network stack not in use\n");
295
            return NULL;
296
        }
297
        return QTAILQ_FIRST(&slirp_stacks);
298
    }
299
}
300

    
301
void net_slirp_hostfwd_remove(Monitor *mon, const QDict *qdict)
302
{
303
    struct in_addr host_addr = { .s_addr = INADDR_ANY };
304
    int host_port;
305
    char buf[256] = "";
306
    const char *src_str, *p;
307
    SlirpState *s;
308
    int is_udp = 0;
309
    int err;
310
    const char *arg1 = qdict_get_str(qdict, "arg1");
311
    const char *arg2 = qdict_get_try_str(qdict, "arg2");
312
    const char *arg3 = qdict_get_try_str(qdict, "arg3");
313

    
314
    if (arg2) {
315
        s = slirp_lookup(mon, arg1, arg2);
316
        src_str = arg3;
317
    } else {
318
        s = slirp_lookup(mon, NULL, NULL);
319
        src_str = arg1;
320
    }
321
    if (!s) {
322
        return;
323
    }
324

    
325
    if (!src_str || !src_str[0])
326
        goto fail_syntax;
327

    
328
    p = src_str;
329
    get_str_sep(buf, sizeof(buf), &p, ':');
330

    
331
    if (!strcmp(buf, "tcp") || buf[0] == '\0') {
332
        is_udp = 0;
333
    } else if (!strcmp(buf, "udp")) {
334
        is_udp = 1;
335
    } else {
336
        goto fail_syntax;
337
    }
338

    
339
    if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) {
340
        goto fail_syntax;
341
    }
342
    if (buf[0] != '\0' && !inet_aton(buf, &host_addr)) {
343
        goto fail_syntax;
344
    }
345

    
346
    host_port = atoi(p);
347

    
348
    err = slirp_remove_hostfwd(QTAILQ_FIRST(&slirp_stacks)->slirp, is_udp,
349
                               host_addr, host_port);
350

    
351
    monitor_printf(mon, "host forwarding rule for %s %s\n", src_str,
352
                   err ? "removed" : "not found");
353
    return;
354

    
355
 fail_syntax:
356
    monitor_printf(mon, "invalid format\n");
357
}
358

    
359
static int slirp_hostfwd(SlirpState *s, const char *redir_str,
360
                         int legacy_format)
361
{
362
    struct in_addr host_addr = { .s_addr = INADDR_ANY };
363
    struct in_addr guest_addr = { .s_addr = 0 };
364
    int host_port, guest_port;
365
    const char *p;
366
    char buf[256];
367
    int is_udp;
368
    char *end;
369

    
370
    p = redir_str;
371
    if (!p || get_str_sep(buf, sizeof(buf), &p, ':') < 0) {
372
        goto fail_syntax;
373
    }
374
    if (!strcmp(buf, "tcp") || buf[0] == '\0') {
375
        is_udp = 0;
376
    } else if (!strcmp(buf, "udp")) {
377
        is_udp = 1;
378
    } else {
379
        goto fail_syntax;
380
    }
381

    
382
    if (!legacy_format) {
383
        if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) {
384
            goto fail_syntax;
385
        }
386
        if (buf[0] != '\0' && !inet_aton(buf, &host_addr)) {
387
            goto fail_syntax;
388
        }
389
    }
390

    
391
    if (get_str_sep(buf, sizeof(buf), &p, legacy_format ? ':' : '-') < 0) {
392
        goto fail_syntax;
393
    }
394
    host_port = strtol(buf, &end, 0);
395
    if (*end != '\0' || host_port < 1 || host_port > 65535) {
396
        goto fail_syntax;
397
    }
398

    
399
    if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) {
400
        goto fail_syntax;
401
    }
402
    if (buf[0] != '\0' && !inet_aton(buf, &guest_addr)) {
403
        goto fail_syntax;
404
    }
405

    
406
    guest_port = strtol(p, &end, 0);
407
    if (*end != '\0' || guest_port < 1 || guest_port > 65535) {
408
        goto fail_syntax;
409
    }
410

    
411
    if (slirp_add_hostfwd(s->slirp, is_udp, host_addr, host_port, guest_addr,
412
                          guest_port) < 0) {
413
        qemu_error("could not set up host forwarding rule '%s'\n",
414
                   redir_str);
415
        return -1;
416
    }
417
    return 0;
418

    
419
 fail_syntax:
420
    qemu_error("invalid host forwarding rule '%s'\n", redir_str);
421
    return -1;
422
}
423

    
424
void net_slirp_hostfwd_add(Monitor *mon, const QDict *qdict)
425
{
426
    const char *redir_str;
427
    SlirpState *s;
428
    const char *arg1 = qdict_get_str(qdict, "arg1");
429
    const char *arg2 = qdict_get_try_str(qdict, "arg2");
430
    const char *arg3 = qdict_get_try_str(qdict, "arg3");
431

    
432
    if (arg2) {
433
        s = slirp_lookup(mon, arg1, arg2);
434
        redir_str = arg3;
435
    } else {
436
        s = slirp_lookup(mon, NULL, NULL);
437
        redir_str = arg1;
438
    }
439
    if (s) {
440
        slirp_hostfwd(s, redir_str, 0);
441
    }
442

    
443
}
444

    
445
int net_slirp_redir(const char *redir_str)
446
{
447
    struct slirp_config_str *config;
448

    
449
    if (QTAILQ_EMPTY(&slirp_stacks)) {
450
        config = qemu_malloc(sizeof(*config));
451
        pstrcpy(config->str, sizeof(config->str), redir_str);
452
        config->flags = SLIRP_CFG_HOSTFWD | SLIRP_CFG_LEGACY;
453
        config->next = slirp_configs;
454
        slirp_configs = config;
455
        return 0;
456
    }
457

    
458
    return slirp_hostfwd(QTAILQ_FIRST(&slirp_stacks), redir_str, 1);
459
}
460

    
461
#ifndef _WIN32
462

    
463
/* automatic user mode samba server configuration */
464
static void slirp_smb_cleanup(SlirpState *s)
465
{
466
    char cmd[128];
467
    int ret;
468

    
469
    if (s->smb_dir[0] != '\0') {
470
        snprintf(cmd, sizeof(cmd), "rm -rf %s", s->smb_dir);
471
        ret = system(cmd);
472
        if (!WIFEXITED(ret)) {
473
            qemu_error("'%s' failed.\n", cmd);
474
        } else if (WEXITSTATUS(ret)) {
475
            qemu_error("'%s' failed. Error code: %d\n",
476
                    cmd, WEXITSTATUS(ret));
477
        }
478
        s->smb_dir[0] = '\0';
479
    }
480
}
481

    
482
static int slirp_smb(SlirpState* s, const char *exported_dir,
483
                     struct in_addr vserver_addr)
484
{
485
    static int instance;
486
    char smb_conf[128];
487
    char smb_cmdline[128];
488
    FILE *f;
489

    
490
    snprintf(s->smb_dir, sizeof(s->smb_dir), "/tmp/qemu-smb.%ld-%d",
491
             (long)getpid(), instance++);
492
    if (mkdir(s->smb_dir, 0700) < 0) {
493
        qemu_error("could not create samba server dir '%s'\n", s->smb_dir);
494
        return -1;
495
    }
496
    snprintf(smb_conf, sizeof(smb_conf), "%s/%s", s->smb_dir, "smb.conf");
497

    
498
    f = fopen(smb_conf, "w");
499
    if (!f) {
500
        slirp_smb_cleanup(s);
501
        qemu_error("could not create samba server configuration file '%s'\n",
502
                   smb_conf);
503
        return -1;
504
    }
505
    fprintf(f,
506
            "[global]\n"
507
            "private dir=%s\n"
508
            "smb ports=0\n"
509
            "socket address=127.0.0.1\n"
510
            "pid directory=%s\n"
511
            "lock directory=%s\n"
512
            "log file=%s/log.smbd\n"
513
            "smb passwd file=%s/smbpasswd\n"
514
            "security = share\n"
515
            "[qemu]\n"
516
            "path=%s\n"
517
            "read only=no\n"
518
            "guest ok=yes\n",
519
            s->smb_dir,
520
            s->smb_dir,
521
            s->smb_dir,
522
            s->smb_dir,
523
            s->smb_dir,
524
            exported_dir
525
            );
526
    fclose(f);
527

    
528
    snprintf(smb_cmdline, sizeof(smb_cmdline), "%s -s %s",
529
             SMBD_COMMAND, smb_conf);
530

    
531
    if (slirp_add_exec(s->slirp, 0, smb_cmdline, &vserver_addr, 139) < 0) {
532
        slirp_smb_cleanup(s);
533
        qemu_error("conflicting/invalid smbserver address\n");
534
        return -1;
535
    }
536
    return 0;
537
}
538

    
539
/* automatic user mode samba server configuration (legacy interface) */
540
int net_slirp_smb(const char *exported_dir)
541
{
542
    struct in_addr vserver_addr = { .s_addr = 0 };
543

    
544
    if (legacy_smb_export) {
545
        fprintf(stderr, "-smb given twice\n");
546
        return -1;
547
    }
548
    legacy_smb_export = exported_dir;
549
    if (!QTAILQ_EMPTY(&slirp_stacks)) {
550
        return slirp_smb(QTAILQ_FIRST(&slirp_stacks), exported_dir,
551
                         vserver_addr);
552
    }
553
    return 0;
554
}
555

    
556
#endif /* !defined(_WIN32) */
557

    
558
struct GuestFwd {
559
    CharDriverState *hd;
560
    struct in_addr server;
561
    int port;
562
    Slirp *slirp;
563
};
564

    
565
static int guestfwd_can_read(void *opaque)
566
{
567
    struct GuestFwd *fwd = opaque;
568
    return slirp_socket_can_recv(fwd->slirp, fwd->server, fwd->port);
569
}
570

    
571
static void guestfwd_read(void *opaque, const uint8_t *buf, int size)
572
{
573
    struct GuestFwd *fwd = opaque;
574
    slirp_socket_recv(fwd->slirp, fwd->server, fwd->port, buf, size);
575
}
576

    
577
static int slirp_guestfwd(SlirpState *s, const char *config_str,
578
                          int legacy_format)
579
{
580
    struct in_addr server = { .s_addr = 0 };
581
    struct GuestFwd *fwd;
582
    const char *p;
583
    char buf[128];
584
    char *end;
585
    int port;
586

    
587
    p = config_str;
588
    if (legacy_format) {
589
        if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) {
590
            goto fail_syntax;
591
        }
592
    } else {
593
        if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) {
594
            goto fail_syntax;
595
        }
596
        if (strcmp(buf, "tcp") && buf[0] != '\0') {
597
            goto fail_syntax;
598
        }
599
        if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) {
600
            goto fail_syntax;
601
        }
602
        if (buf[0] != '\0' && !inet_aton(buf, &server)) {
603
            goto fail_syntax;
604
        }
605
        if (get_str_sep(buf, sizeof(buf), &p, '-') < 0) {
606
            goto fail_syntax;
607
        }
608
    }
609
    port = strtol(buf, &end, 10);
610
    if (*end != '\0' || port < 1 || port > 65535) {
611
        goto fail_syntax;
612
    }
613

    
614
    fwd = qemu_malloc(sizeof(struct GuestFwd));
615
    snprintf(buf, sizeof(buf), "guestfwd.tcp:%d", port);
616
    fwd->hd = qemu_chr_open(buf, p, NULL);
617
    if (!fwd->hd) {
618
        qemu_error("could not open guest forwarding device '%s'\n", buf);
619
        qemu_free(fwd);
620
        return -1;
621
    }
622

    
623
    if (slirp_add_exec(s->slirp, 3, fwd->hd, &server, port) < 0) {
624
        qemu_error("conflicting/invalid host:port in guest forwarding "
625
                   "rule '%s'\n", config_str);
626
        qemu_free(fwd);
627
        return -1;
628
    }
629
    fwd->server = server;
630
    fwd->port = port;
631
    fwd->slirp = s->slirp;
632

    
633
    qemu_chr_add_handlers(fwd->hd, guestfwd_can_read, guestfwd_read,
634
                          NULL, fwd);
635
    return 0;
636

    
637
 fail_syntax:
638
    qemu_error("invalid guest forwarding rule '%s'\n", config_str);
639
    return -1;
640
}
641

    
642
void do_info_usernet(Monitor *mon)
643
{
644
    SlirpState *s;
645

    
646
    QTAILQ_FOREACH(s, &slirp_stacks, entry) {
647
        monitor_printf(mon, "VLAN %d (%s):\n",
648
                       s->nc.vlan ? s->nc.vlan->id : -1,
649
                       s->nc.name);
650
        slirp_connection_info(s->slirp, mon);
651
    }
652
}
653

    
654
static int net_init_slirp_configs(const char *name, const char *value, void *opaque)
655
{
656
    struct slirp_config_str *config;
657

    
658
    if (strcmp(name, "hostfwd") != 0 && strcmp(name, "guestfwd") != 0) {
659
        return 0;
660
    }
661

    
662
    config = qemu_mallocz(sizeof(*config));
663

    
664
    pstrcpy(config->str, sizeof(config->str), value);
665

    
666
    if (!strcmp(name, "hostfwd")) {
667
        config->flags = SLIRP_CFG_HOSTFWD;
668
    }
669

    
670
    config->next = slirp_configs;
671
    slirp_configs = config;
672

    
673
    return 0;
674
}
675

    
676
int net_init_slirp(QemuOpts *opts,
677
                   Monitor *mon,
678
                   const char *name,
679
                   VLANState *vlan)
680
{
681
    struct slirp_config_str *config;
682
    const char *vhost;
683
    const char *vhostname;
684
    const char *vdhcp_start;
685
    const char *vnamesrv;
686
    const char *tftp_export;
687
    const char *bootfile;
688
    const char *smb_export;
689
    const char *vsmbsrv;
690
    char *vnet = NULL;
691
    int restricted = 0;
692
    int ret;
693

    
694
    vhost       = qemu_opt_get(opts, "host");
695
    vhostname   = qemu_opt_get(opts, "hostname");
696
    vdhcp_start = qemu_opt_get(opts, "dhcpstart");
697
    vnamesrv    = qemu_opt_get(opts, "dns");
698
    tftp_export = qemu_opt_get(opts, "tftp");
699
    bootfile    = qemu_opt_get(opts, "bootfile");
700
    smb_export  = qemu_opt_get(opts, "smb");
701
    vsmbsrv     = qemu_opt_get(opts, "smbserver");
702

    
703
    if (qemu_opt_get(opts, "ip")) {
704
        const char *ip = qemu_opt_get(opts, "ip");
705
        int l = strlen(ip) + strlen("/24") + 1;
706

    
707
        vnet = qemu_malloc(l);
708

    
709
        /* emulate legacy ip= parameter */
710
        pstrcpy(vnet, l, ip);
711
        pstrcat(vnet, l, "/24");
712
    }
713

    
714
    if (qemu_opt_get(opts, "net")) {
715
        if (vnet) {
716
            qemu_free(vnet);
717
        }
718
        vnet = qemu_strdup(qemu_opt_get(opts, "net"));
719
    }
720

    
721
    if (qemu_opt_get(opts, "restrict") &&
722
        qemu_opt_get(opts, "restrict")[0] == 'y') {
723
        restricted = 1;
724
    }
725

    
726
    qemu_opt_foreach(opts, net_init_slirp_configs, NULL, 0);
727

    
728
    ret = net_slirp_init(vlan, "user", name, restricted, vnet, vhost,
729
                         vhostname, tftp_export, bootfile, vdhcp_start,
730
                         vnamesrv, smb_export, vsmbsrv);
731

    
732
    while (slirp_configs) {
733
        config = slirp_configs;
734
        slirp_configs = config->next;
735
        qemu_free(config);
736
    }
737

    
738
    if (ret != -1 && vlan) {
739
        vlan->nb_host_devs++;
740
    }
741

    
742
    qemu_free(vnet);
743

    
744
    return ret;
745
}
746

    
747
int net_slirp_parse_legacy(QemuOptsList *opts_list, const char *optarg, int *ret)
748
{
749
    if (strcmp(opts_list->name, "net") != 0 ||
750
        strncmp(optarg, "channel,", strlen("channel,")) != 0) {
751
        return 0;
752
    }
753

    
754
    /* handle legacy -net channel,port:chr */
755
    optarg += strlen("channel,");
756

    
757
    if (QTAILQ_EMPTY(&slirp_stacks)) {
758
        struct slirp_config_str *config;
759

    
760
        config = qemu_malloc(sizeof(*config));
761
        pstrcpy(config->str, sizeof(config->str), optarg);
762
        config->flags = SLIRP_CFG_LEGACY;
763
        config->next = slirp_configs;
764
        slirp_configs = config;
765
        *ret = 0;
766
    } else {
767
        *ret = slirp_guestfwd(QTAILQ_FIRST(&slirp_stacks), optarg, 1);
768
    }
769

    
770
    return 1;
771
}
772