blob: c2e41da74ef26563cb4c98a6a1ee4b3462cfa92c [file] [log] [blame]
Peter Maydelle9dcb6e2014-06-13 15:52:32 +01001/* Android console command implementation.
2 *
3 * Copyright (c) 2014 Linaro Limited
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms and conditions of the GNU General Public License,
7 * version 2 or later, as published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along with
15 * this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#include "android-console.h"
19#include "monitor/monitor.h"
20#include "qemu/sockets.h"
21#include "net/slirp.h"
22#include "slirp/libslirp.h"
23#include "qmp-commands.h"
24
Peter Maydella237a332014-06-16 16:51:41 +010025typedef struct {
26 int is_udp;
27 int host_port;
28 int guest_port;
29} RedirRec;
30
31GList *redir_list;
32
Peter Maydell8d3447d2014-06-17 12:28:43 +010033void android_monitor_print_error(Monitor *mon, const char *fmt, ...)
34{
35 /* Print an error (typically a syntax error from the parser), with
36 * the required "KO: " prefix.
37 */
38 va_list ap;
39
40 monitor_printf(mon, "KO: ");
41 va_start(ap, fmt);
42 monitor_vprintf(mon, fmt, ap);
43 va_end(ap);
44}
45
Peter Maydelle9dcb6e2014-06-13 15:52:32 +010046void android_console_kill(Monitor *mon, const QDict *qdict)
47{
48 monitor_printf(mon, "OK: killing emulator, bye bye\n");
49 monitor_suspend(mon);
50 qmp_quit(NULL);
51}
Peter Maydella237a332014-06-16 16:51:41 +010052
Peter Maydell4e9cc7d2014-06-16 18:58:02 +010053void android_console_quit(Monitor *mon, const QDict *qdict)
54{
55 /* Don't print an OK response for success, just close the connection */
56 if (monitor_disconnect(mon)) {
57 monitor_printf(mon, "KO: this connection doesn't support quitting\n");
58 }
59}
60
Peter Maydella237a332014-06-16 16:51:41 +010061#ifdef CONFIG_SLIRP
62void android_console_redir_list(Monitor *mon, const QDict *qdict)
63{
64 if (!redir_list) {
65 monitor_printf(mon, "no active redirections\n");
66 } else {
67 GList *l;
68
69 for (l = redir_list; l; l = l->next) {
70 RedirRec *r = l->data;
71
72 monitor_printf(mon, "%s:%-5d => %-5d\n", r->is_udp ? "udp" : "tcp",
73 r->host_port, r->guest_port);
74 }
75 }
76 monitor_printf(mon, "OK\n");
77}
78
79static int parse_proto(const char *s)
80{
81 if (!strcmp(s, "tcp")) {
82 return 0;
83 } else if (!strcmp(s, "udp")) {
84 return 1;
85 } else {
86 return -1;
87 }
88}
89
90static int parse_port(const char *s)
91{
92 char *end;
93 int port;
94
95 port = strtol(s, &end, 10);
96 if (*end != 0 || port < 1 || port > 65535) {
97 return 0;
98 }
99 return port;
100}
101
102void android_console_redir_add(Monitor *mon, const QDict *qdict)
103{
104 const char *arg = qdict_get_str(qdict, "arg");
105 char **tokens;
106 int is_udp, host_port, guest_port;
107 Slirp *slirp;
108 Error *err = NULL;
109 struct in_addr host_addr = { .s_addr = htonl(INADDR_LOOPBACK) };
110 struct in_addr guest_addr = { .s_addr = 0 };
111 RedirRec *redir;
112
113 slirp = net_slirp_lookup(NULL, NULL, &err);
114 if (err) {
115 monitor_printf(mon, "KO: %s\n", error_get_pretty(err));
116 error_free(err);
117 return;
118 }
119
120 /* Argument syntax: "proto:hostport:guestport" */
121 tokens = g_strsplit(arg, ":", 0);
122
123 if (g_strv_length(tokens) != 3) {
124 goto fail_syntax;
125 }
126
127 is_udp = parse_proto(tokens[0]);
128 host_port = parse_port(tokens[1]);
129 guest_port = parse_port(tokens[2]);
130
131 if (is_udp < 0 || host_port == 0 || guest_port == 0) {
132 goto fail_syntax;
133 }
134
135 g_strfreev(tokens);
136
137 if (slirp_add_hostfwd(slirp, is_udp, host_addr, host_port,
138 guest_addr, guest_port) < 0) {
139 monitor_printf(mon, "KO: can't setup redirection, "
140 "port probably used by another program on host\n");
141 return;
142 }
143
144 redir = g_new0(RedirRec, 1);
145 redir->is_udp = is_udp;
146 redir->host_port = host_port;
147 redir->guest_port = guest_port;
148 redir_list = g_list_append(redir_list, redir);
149
150 monitor_printf(mon, "OK\n");
151 return;
152
153fail_syntax:
154 monitor_printf(mon, "KO: bad redirection format, try "
155 "(tcp|udp):hostport:guestport\n");
156 g_strfreev(tokens);
157}
158
159static gint redir_cmp(gconstpointer a, gconstpointer b)
160{
161 const RedirRec *ra = a;
162 const RedirRec *rb = b;
163
164 /* For purposes of list deletion, only protocol and host port matter */
165 if (ra->is_udp != rb->is_udp) {
166 return ra->is_udp - rb->is_udp;
167 }
168 return ra->host_port - rb->host_port;
169}
170
171void android_console_redir_del(Monitor *mon, const QDict *qdict)
172{
173 const char *arg = qdict_get_str(qdict, "arg");
174 char **tokens;
175 int is_udp, host_port;
176 Slirp *slirp;
177 Error *err = NULL;
178 struct in_addr host_addr = { .s_addr = INADDR_ANY };
179 RedirRec rr;
180 GList *entry;
181
182 slirp = net_slirp_lookup(NULL, NULL, &err);
183 if (err) {
184 monitor_printf(mon, "KO: %s\n", error_get_pretty(err));
185 error_free(err);
186 return;
187 }
188
189 /* Argument syntax: "proto:hostport" */
190 tokens = g_strsplit(arg, ":", 0);
191
192 if (g_strv_length(tokens) != 2) {
193 goto fail_syntax;
194 }
195
196 is_udp = parse_proto(tokens[0]);
197 host_port = parse_port(tokens[1]);
198
199 if (is_udp < 0 || host_port == 0) {
200 goto fail_syntax;
201 }
202
203 g_strfreev(tokens);
204
205 rr.is_udp = is_udp;
206 rr.host_port = host_port;
207 entry = g_list_find_custom(redir_list, &rr, redir_cmp);
208
209 if (!entry || slirp_remove_hostfwd(slirp, is_udp, host_addr, host_port)) {
210 monitor_printf(mon, "KO: can't remove unknown redirection (%s:%d)\n",
211 is_udp ? "udp" : "tcp", host_port);
212 return;
213 }
214
215 g_free(entry->data);
216 redir_list = g_list_delete_link(redir_list, entry);
217
218 monitor_printf(mon, "OK\n");
219 return;
220
221fail_syntax:
222 monitor_printf(mon, "KO: bad redirection format, try (tcp|udp):hostport\n");
223 g_strfreev(tokens);
224}
225
226#else /* not CONFIG_SLIRP */
227void android_console_redir_list(Monitor *mon, const QDict *qdict)
228{
229 monitor_printf(mon, "KO: emulator not built with CONFIG_SLIRP\n");
230}
231
232void android_console_redir_add(Monitor *mon, const QDict *qdict)
233{
234 monitor_printf(mon, "KO: emulator not built with CONFIG_SLIRP\n");
235}
236
237void android_console_redir_remove(Monitor *mon, const QDict *qdict)
238{
239 monitor_printf(mon, "KO: emulator not built with CONFIG_SLIRP\n");
240}
241#endif
242
Peter Maydellc9bfac32014-06-17 12:30:25 +0100243static const char *redir_list_help =
244 "list current port redirections. "
245 "use 'redir add' and 'redir del' to add and remove them\n"
246 "OK\n";
247
248static const char *redir_add_help =
249 "add a new port redirection, arguments must be:\n"
250 "\n"
251 " redir add <protocol>:<host-port>:<guest-port>\n"
252 "\n"
253 "where: <protocol> is either 'tcp' or 'udp'\n"
254 " <host-port> a number indicating which "
255 "port on the host to open\n"
256 " <guest-port> a number indicating which "
257 "port to route to on the device\n"
258 "\n"
259 "as an example, 'redir tcp:5000:6000' will allow any packets sent to\n"
260 "the host's TCP port 5000 to be routed to TCP port 6000 of the "
261 "emulated device\n"
262 "OK\n";
263
264static const char *redir_del_help =
265 "remove a port redirecion that was created with 'redir add', "
266 "arguments must be:\n\n"
267 " redir del <protocol>:<host-port>\n\n"
268 "see the 'help redir add' for the meaning of <protocol> and <host-port>\n"
269 "OK\n";
270
Peter Maydella237a332014-06-16 16:51:41 +0100271void android_console_redir(Monitor *mon, const QDict *qdict)
272{
Peter Maydellc9bfac32014-06-17 12:30:25 +0100273 /* This only gets called for bad subcommands and help requests */
274 const char *helptext = qdict_get_try_str(qdict, "helptext");
Peter Maydella237a332014-06-16 16:51:41 +0100275
Peter Maydellc9bfac32014-06-17 12:30:25 +0100276 monitor_printf(mon, "help text %s\n", helptext ? helptext : "(null)");
277
278 if (helptext) {
279 if (strstr(helptext, "add")) {
280 monitor_printf(mon, "%s", redir_add_help);
281 return;
282 } else if (strstr(helptext, "del")) {
283 monitor_printf(mon, "%s", redir_del_help);
284 return;
285 } else if (strstr(helptext, "list")) {
286 monitor_printf(mon, "%s", redir_list_help);
287 return;
288 }
Peter Maydella237a332014-06-16 16:51:41 +0100289 }
Peter Maydella237a332014-06-16 16:51:41 +0100290 monitor_printf(mon, "allows you to add, list and remove and/or "
291 "PORT redirection from the host to the device\n"
292 "as an example, 'redir tcp:5000:6000' will route "
293 "any packet sent to the host's TCP port 5000\n"
294 "to TCP port 6000 of the emulated device\n"
295 "\n"
296 "available sub-commands:\n"
297 " list list current redirections\n"
298 " add add new redirection\n"
299 " del remove existing redirection\n"
Peter Maydellc9bfac32014-06-17 12:30:25 +0100300 "\n%s\n",
301 helptext ? "OK" : "KO: missing sub-command");
Peter Maydella237a332014-06-16 16:51:41 +0100302}