|
|
1.1 root 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:
468: if (s->smb_dir[0] != '\0') {
469: snprintf(cmd, sizeof(cmd), "rm -rf %s", s->smb_dir);
470: system(cmd);
471: s->smb_dir[0] = '\0';
472: }
473: }
474:
475: static int slirp_smb(SlirpState* s, const char *exported_dir,
476: struct in_addr vserver_addr)
477: {
478: static int instance;
479: char smb_conf[128];
480: char smb_cmdline[128];
481: FILE *f;
482:
483: snprintf(s->smb_dir, sizeof(s->smb_dir), "/tmp/qemu-smb.%ld-%d",
484: (long)getpid(), instance++);
485: if (mkdir(s->smb_dir, 0700) < 0) {
486: qemu_error("could not create samba server dir '%s'\n", s->smb_dir);
487: return -1;
488: }
489: snprintf(smb_conf, sizeof(smb_conf), "%s/%s", s->smb_dir, "smb.conf");
490:
491: f = fopen(smb_conf, "w");
492: if (!f) {
493: slirp_smb_cleanup(s);
494: qemu_error("could not create samba server configuration file '%s'\n",
495: smb_conf);
496: return -1;
497: }
498: fprintf(f,
499: "[global]\n"
500: "private dir=%s\n"
501: "smb ports=0\n"
502: "socket address=127.0.0.1\n"
503: "pid directory=%s\n"
504: "lock directory=%s\n"
505: "log file=%s/log.smbd\n"
506: "smb passwd file=%s/smbpasswd\n"
507: "security = share\n"
508: "[qemu]\n"
509: "path=%s\n"
510: "read only=no\n"
511: "guest ok=yes\n",
512: s->smb_dir,
513: s->smb_dir,
514: s->smb_dir,
515: s->smb_dir,
516: s->smb_dir,
517: exported_dir
518: );
519: fclose(f);
520:
521: snprintf(smb_cmdline, sizeof(smb_cmdline), "%s -s %s",
522: SMBD_COMMAND, smb_conf);
523:
524: if (slirp_add_exec(s->slirp, 0, smb_cmdline, &vserver_addr, 139) < 0) {
525: slirp_smb_cleanup(s);
526: qemu_error("conflicting/invalid smbserver address\n");
527: return -1;
528: }
529: return 0;
530: }
531:
532: /* automatic user mode samba server configuration (legacy interface) */
533: int net_slirp_smb(const char *exported_dir)
534: {
535: struct in_addr vserver_addr = { .s_addr = 0 };
536:
537: if (legacy_smb_export) {
538: fprintf(stderr, "-smb given twice\n");
539: return -1;
540: }
541: legacy_smb_export = exported_dir;
542: if (!QTAILQ_EMPTY(&slirp_stacks)) {
543: return slirp_smb(QTAILQ_FIRST(&slirp_stacks), exported_dir,
544: vserver_addr);
545: }
546: return 0;
547: }
548:
549: #endif /* !defined(_WIN32) */
550:
551: struct GuestFwd {
552: CharDriverState *hd;
553: struct in_addr server;
554: int port;
555: Slirp *slirp;
556: };
557:
558: static int guestfwd_can_read(void *opaque)
559: {
560: struct GuestFwd *fwd = opaque;
561: return slirp_socket_can_recv(fwd->slirp, fwd->server, fwd->port);
562: }
563:
564: static void guestfwd_read(void *opaque, const uint8_t *buf, int size)
565: {
566: struct GuestFwd *fwd = opaque;
567: slirp_socket_recv(fwd->slirp, fwd->server, fwd->port, buf, size);
568: }
569:
570: static int slirp_guestfwd(SlirpState *s, const char *config_str,
571: int legacy_format)
572: {
573: struct in_addr server = { .s_addr = 0 };
574: struct GuestFwd *fwd;
575: const char *p;
576: char buf[128];
577: char *end;
578: int port;
579:
580: p = config_str;
581: if (legacy_format) {
582: if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) {
583: goto fail_syntax;
584: }
585: } else {
586: if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) {
587: goto fail_syntax;
588: }
589: if (strcmp(buf, "tcp") && buf[0] != '\0') {
590: goto fail_syntax;
591: }
592: if (get_str_sep(buf, sizeof(buf), &p, ':') < 0) {
593: goto fail_syntax;
594: }
595: if (buf[0] != '\0' && !inet_aton(buf, &server)) {
596: goto fail_syntax;
597: }
598: if (get_str_sep(buf, sizeof(buf), &p, '-') < 0) {
599: goto fail_syntax;
600: }
601: }
602: port = strtol(buf, &end, 10);
603: if (*end != '\0' || port < 1 || port > 65535) {
604: goto fail_syntax;
605: }
606:
607: fwd = qemu_malloc(sizeof(struct GuestFwd));
608: snprintf(buf, sizeof(buf), "guestfwd.tcp:%d", port);
609: fwd->hd = qemu_chr_open(buf, p, NULL);
610: if (!fwd->hd) {
611: qemu_error("could not open guest forwarding device '%s'\n", buf);
612: qemu_free(fwd);
613: return -1;
614: }
615:
616: if (slirp_add_exec(s->slirp, 3, fwd->hd, &server, port) < 0) {
617: qemu_error("conflicting/invalid host:port in guest forwarding "
618: "rule '%s'\n", config_str);
619: qemu_free(fwd);
620: return -1;
621: }
622: fwd->server = server;
623: fwd->port = port;
624: fwd->slirp = s->slirp;
625:
626: qemu_chr_add_handlers(fwd->hd, guestfwd_can_read, guestfwd_read,
627: NULL, fwd);
628: return 0;
629:
630: fail_syntax:
631: qemu_error("invalid guest forwarding rule '%s'\n", config_str);
632: return -1;
633: }
634:
635: void do_info_usernet(Monitor *mon)
636: {
637: SlirpState *s;
638:
639: QTAILQ_FOREACH(s, &slirp_stacks, entry) {
640: monitor_printf(mon, "VLAN %d (%s):\n",
641: s->nc.vlan ? s->nc.vlan->id : -1,
642: s->nc.name);
643: slirp_connection_info(s->slirp, mon);
644: }
645: }
646:
647: static int net_init_slirp_configs(const char *name, const char *value, void *opaque)
648: {
649: struct slirp_config_str *config;
650:
651: if (strcmp(name, "hostfwd") != 0 && strcmp(name, "guestfwd") != 0) {
652: return 0;
653: }
654:
655: config = qemu_mallocz(sizeof(*config));
656:
657: pstrcpy(config->str, sizeof(config->str), value);
658:
659: if (!strcmp(name, "hostfwd")) {
660: config->flags = SLIRP_CFG_HOSTFWD;
661: }
662:
663: config->next = slirp_configs;
664: slirp_configs = config;
665:
666: return 0;
667: }
668:
669: int net_init_slirp(QemuOpts *opts,
670: Monitor *mon,
671: const char *name,
672: VLANState *vlan)
673: {
674: struct slirp_config_str *config;
675: const char *vhost;
676: const char *vhostname;
677: const char *vdhcp_start;
678: const char *vnamesrv;
679: const char *tftp_export;
680: const char *bootfile;
681: const char *smb_export;
682: const char *vsmbsrv;
683: char *vnet = NULL;
684: int restricted = 0;
685: int ret;
686:
687: vhost = qemu_opt_get(opts, "host");
688: vhostname = qemu_opt_get(opts, "hostname");
689: vdhcp_start = qemu_opt_get(opts, "dhcpstart");
690: vnamesrv = qemu_opt_get(opts, "dns");
691: tftp_export = qemu_opt_get(opts, "tftp");
692: bootfile = qemu_opt_get(opts, "bootfile");
693: smb_export = qemu_opt_get(opts, "smb");
694: vsmbsrv = qemu_opt_get(opts, "smbserver");
695:
696: if (qemu_opt_get(opts, "ip")) {
697: const char *ip = qemu_opt_get(opts, "ip");
698: int l = strlen(ip) + strlen("/24") + 1;
699:
700: vnet = qemu_malloc(l);
701:
702: /* emulate legacy ip= parameter */
703: pstrcpy(vnet, l, ip);
704: pstrcat(vnet, l, "/24");
705: }
706:
707: if (qemu_opt_get(opts, "net")) {
708: if (vnet) {
709: qemu_free(vnet);
710: }
711: vnet = qemu_strdup(qemu_opt_get(opts, "net"));
712: }
713:
714: if (qemu_opt_get(opts, "restrict") &&
715: qemu_opt_get(opts, "restrict")[0] == 'y') {
716: restricted = 1;
717: }
718:
719: qemu_opt_foreach(opts, net_init_slirp_configs, NULL, 0);
720:
721: ret = net_slirp_init(vlan, "user", name, restricted, vnet, vhost,
722: vhostname, tftp_export, bootfile, vdhcp_start,
723: vnamesrv, smb_export, vsmbsrv);
724:
725: while (slirp_configs) {
726: config = slirp_configs;
727: slirp_configs = config->next;
728: qemu_free(config);
729: }
730:
731: qemu_free(vnet);
732:
733: return ret;
734: }
735:
736: int net_slirp_parse_legacy(QemuOptsList *opts_list, const char *optarg, int *ret)
737: {
738: if (strcmp(opts_list->name, "net") != 0 ||
739: strncmp(optarg, "channel,", strlen("channel,")) != 0) {
740: return 0;
741: }
742:
743: /* handle legacy -net channel,port:chr */
744: optarg += strlen("channel,");
745:
746: if (QTAILQ_EMPTY(&slirp_stacks)) {
747: struct slirp_config_str *config;
748:
749: config = qemu_malloc(sizeof(*config));
750: pstrcpy(config->str, sizeof(config->str), optarg);
751: config->flags = SLIRP_CFG_LEGACY;
752: config->next = slirp_configs;
753: slirp_configs = config;
754: *ret = 0;
755: } else {
756: *ret = slirp_guestfwd(QTAILQ_FIRST(&slirp_stacks), optarg, 1);
757: }
758:
759: return 1;
760: }
761:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.