blob: cf52d36ece42d7d9190a3b492af8c9fac5e80e69 [file] [log] [blame]
bellardd75a0b92008-10-17 17:31:57 +00001/*
2 * libslirp glue
3 *
4 * Copyright (c) 2004-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 */
aliguorie1c5a2b2009-01-08 19:18:21 +000024#include "qemu-common.h"
blueswir10580ac92009-01-12 17:51:06 +000025#include "qemu-char.h"
bellardf0cbd3e2004-04-22 00:10:48 +000026#include "slirp.h"
aliguori062e5522009-01-08 19:27:07 +000027#include "hw/hw.h"
bellardf0cbd3e2004-04-22 00:10:48 +000028
29/* host address */
30struct in_addr our_addr;
31/* host dns address */
32struct in_addr dns_addr;
33/* host loopback address */
34struct in_addr loopback_addr;
35
Jan Kiszkaa13a4122009-06-24 14:42:28 +020036/* virtual network configuration */
37struct in_addr vnetwork_addr;
38struct in_addr vnetwork_mask;
39struct in_addr vhost_addr;
40struct in_addr vdhcp_startaddr;
41struct in_addr vnameserver_addr;
bellardf0cbd3e2004-04-22 00:10:48 +000042
Jan Kiszkaa13a4122009-06-24 14:42:28 +020043/* emulated hosts use the MAC addr 52:55:IP:IP:IP:IP */
blueswir19634d902007-10-26 19:01:16 +000044static const uint8_t special_ethaddr[6] = {
Jan Kiszkaa13a4122009-06-24 14:42:28 +020045 0x52, 0x55, 0x00, 0x00, 0x00, 0x00
bellardf0cbd3e2004-04-22 00:10:48 +000046};
47
bellardde806f02008-10-17 17:28:58 +000048/* ARP cache for the guest IP addresses (XXX: allow many entries) */
bellardf0cbd3e2004-04-22 00:10:48 +000049uint8_t client_ethaddr[6];
bellardde806f02008-10-17 17:28:58 +000050static struct in_addr client_ipaddr;
51
52static const uint8_t zero_ethaddr[6] = { 0, 0, 0, 0, 0, 0 };
bellardf0cbd3e2004-04-22 00:10:48 +000053
aliguoria9ba3a82009-01-08 19:24:00 +000054int slirp_restrict;
blueswir1511d2b12009-03-07 15:32:56 +000055static int do_slowtimo;
bellardf0cbd3e2004-04-22 00:10:48 +000056int link_up;
bellarda3d4af02004-09-05 23:10:26 +000057struct ex_list *exec_list;
bellardf0cbd3e2004-04-22 00:10:48 +000058
59/* XXX: suppress those select globals */
60fd_set *global_readfds, *global_writefds, *global_xfds;
61
bellard3f423c92006-04-30 21:34:15 +000062char slirp_hostname[33];
pbrook115defd2006-04-16 11:06:58 +000063
bellardf0cbd3e2004-04-22 00:10:48 +000064#ifdef _WIN32
65
66static int get_dns_addr(struct in_addr *pdns_addr)
67{
bellard379ff532004-07-12 22:33:07 +000068 FIXED_INFO *FixedInfo=NULL;
69 ULONG BufLen;
70 DWORD ret;
71 IP_ADDR_STRING *pIPAddr;
72 struct in_addr tmp_addr;
ths3b46e622007-09-17 08:09:54 +000073
bellard379ff532004-07-12 22:33:07 +000074 FixedInfo = (FIXED_INFO *)GlobalAlloc(GPTR, sizeof(FIXED_INFO));
75 BufLen = sizeof(FIXED_INFO);
ths3b46e622007-09-17 08:09:54 +000076
bellard379ff532004-07-12 22:33:07 +000077 if (ERROR_BUFFER_OVERFLOW == GetNetworkParams(FixedInfo, &BufLen)) {
78 if (FixedInfo) {
79 GlobalFree(FixedInfo);
80 FixedInfo = NULL;
81 }
82 FixedInfo = GlobalAlloc(GPTR, BufLen);
83 }
ths5fafdf22007-09-16 21:08:06 +000084
bellard379ff532004-07-12 22:33:07 +000085 if ((ret = GetNetworkParams(FixedInfo, &BufLen)) != ERROR_SUCCESS) {
86 printf("GetNetworkParams failed. ret = %08x\n", (u_int)ret );
87 if (FixedInfo) {
88 GlobalFree(FixedInfo);
89 FixedInfo = NULL;
90 }
91 return -1;
92 }
ths3b46e622007-09-17 08:09:54 +000093
bellard379ff532004-07-12 22:33:07 +000094 pIPAddr = &(FixedInfo->DnsServerList);
95 inet_aton(pIPAddr->IpAddress.String, &tmp_addr);
96 *pdns_addr = tmp_addr;
bellard379ff532004-07-12 22:33:07 +000097 if (FixedInfo) {
98 GlobalFree(FixedInfo);
99 FixedInfo = NULL;
100 }
101 return 0;
bellardf0cbd3e2004-04-22 00:10:48 +0000102}
103
Jan Kiszkadf461892009-06-24 14:42:30 +0200104static void winsock_cleanup(void)
105{
106 WSACleanup();
107}
108
bellardf0cbd3e2004-04-22 00:10:48 +0000109#else
110
111static int get_dns_addr(struct in_addr *pdns_addr)
112{
113 char buff[512];
blueswir1363a37d2008-08-21 17:58:08 +0000114 char buff2[257];
bellardf0cbd3e2004-04-22 00:10:48 +0000115 FILE *f;
116 int found = 0;
117 struct in_addr tmp_addr;
ths3b46e622007-09-17 08:09:54 +0000118
bellardf0cbd3e2004-04-22 00:10:48 +0000119 f = fopen("/etc/resolv.conf", "r");
120 if (!f)
121 return -1;
122
blueswir131a60e22007-10-26 18:42:59 +0000123#ifdef DEBUG
bellardf0cbd3e2004-04-22 00:10:48 +0000124 lprint("IP address of your DNS(s): ");
blueswir131a60e22007-10-26 18:42:59 +0000125#endif
bellardf0cbd3e2004-04-22 00:10:48 +0000126 while (fgets(buff, 512, f) != NULL) {
127 if (sscanf(buff, "nameserver%*[ \t]%256s", buff2) == 1) {
128 if (!inet_aton(buff2, &tmp_addr))
129 continue;
130 if (tmp_addr.s_addr == loopback_addr.s_addr)
131 tmp_addr = our_addr;
132 /* If it's the first one, set it to dns_addr */
133 if (!found)
134 *pdns_addr = tmp_addr;
blueswir131a60e22007-10-26 18:42:59 +0000135#ifdef DEBUG
bellardf0cbd3e2004-04-22 00:10:48 +0000136 else
137 lprint(", ");
blueswir131a60e22007-10-26 18:42:59 +0000138#endif
bellardf0cbd3e2004-04-22 00:10:48 +0000139 if (++found > 3) {
blueswir131a60e22007-10-26 18:42:59 +0000140#ifdef DEBUG
bellardf0cbd3e2004-04-22 00:10:48 +0000141 lprint("(more)");
blueswir131a60e22007-10-26 18:42:59 +0000142#endif
bellardf0cbd3e2004-04-22 00:10:48 +0000143 break;
blueswir131a60e22007-10-26 18:42:59 +0000144 }
145#ifdef DEBUG
146 else
bellardf0cbd3e2004-04-22 00:10:48 +0000147 lprint("%s", inet_ntoa(tmp_addr));
blueswir131a60e22007-10-26 18:42:59 +0000148#endif
bellardf0cbd3e2004-04-22 00:10:48 +0000149 }
150 }
bellard1d43a712004-07-05 21:18:42 +0000151 fclose(f);
bellardf0cbd3e2004-04-22 00:10:48 +0000152 if (!found)
153 return -1;
154 return 0;
155}
156
157#endif
158
Jan Kiszkadf461892009-06-24 14:42:30 +0200159static void slirp_init_once(void)
bellard379ff532004-07-12 22:33:07 +0000160{
Jan Kiszkadf461892009-06-24 14:42:30 +0200161 static int initialized;
162 struct hostent *he;
163 char our_name[256];
164#ifdef _WIN32
165 WSADATA Data;
bellard379ff532004-07-12 22:33:07 +0000166#endif
167
Jan Kiszkadf461892009-06-24 14:42:30 +0200168 if (initialized) {
169 return;
170 }
171 initialized = 1;
172
173#ifdef _WIN32
174 WSAStartup(MAKEWORD(2,0), &Data);
175 atexit(winsock_cleanup);
176#endif
177
178 loopback_addr.s_addr = htonl(INADDR_LOOPBACK);
179
180 /* FIXME: This address may change during runtime */
181 if (gethostname(our_name, sizeof(our_name)) == 0) {
182 he = gethostbyname(our_name);
183 if (he) {
184 our_addr = *(struct in_addr *)he->h_addr;
185 }
186 }
187 if (our_addr.s_addr == 0) {
188 our_addr = loopback_addr;
189 }
190
191 /* FIXME: This address may change during runtime */
192 if (get_dns_addr(&dns_addr) < 0) {
193 dns_addr = loopback_addr;
194 }
195}
196
aliguori062e5522009-01-08 19:27:07 +0000197static void slirp_state_save(QEMUFile *f, void *opaque);
198static int slirp_state_load(QEMUFile *f, void *opaque, int version_id);
199
Jan Kiszkac92ef6a2009-06-24 14:42:28 +0200200void slirp_init(int restricted, struct in_addr vnetwork,
201 struct in_addr vnetmask, struct in_addr vhost,
202 const char *vhostname, const char *tftp_path,
203 const char *bootfile, struct in_addr vdhcp_start,
204 struct in_addr vnameserver)
bellardf0cbd3e2004-04-22 00:10:48 +0000205{
Jan Kiszkadf461892009-06-24 14:42:30 +0200206 slirp_init_once();
bellard379ff532004-07-12 22:33:07 +0000207
bellardf0cbd3e2004-04-22 00:10:48 +0000208 link_up = 1;
blueswir1511d2b12009-03-07 15:32:56 +0000209 slirp_restrict = restricted;
bellardf0cbd3e2004-04-22 00:10:48 +0000210
211 if_init();
212 ip_init();
213
214 /* Initialise mbufs *after* setting the MTU */
215 m_init();
216
Jan Kiszkac92ef6a2009-06-24 14:42:28 +0200217 vnetwork_addr = vnetwork;
218 vnetwork_mask = vnetmask;
219 vhost_addr = vhost;
220 if (vhostname) {
221 pstrcpy(slirp_hostname, sizeof(slirp_hostname), vhostname);
Jan Kiszkaa13a4122009-06-24 14:42:28 +0200222 }
Jan Kiszkaad196a92009-06-24 14:42:28 +0200223 qemu_free(tftp_prefix);
224 tftp_prefix = NULL;
225 if (tftp_path) {
226 tftp_prefix = qemu_strdup(tftp_path);
227 }
228 qemu_free(bootp_filename);
229 bootp_filename = NULL;
230 if (bootfile) {
231 bootp_filename = qemu_strdup(bootfile);
232 }
Jan Kiszkac92ef6a2009-06-24 14:42:28 +0200233 vdhcp_startaddr = vdhcp_start;
234 vnameserver_addr = vnameserver;
Jan Kiszkaad196a92009-06-24 14:42:28 +0200235
Jan Kiszka285f7a62009-06-24 14:42:30 +0200236 register_savevm("slirp", 0, 2, slirp_state_save, slirp_state_load, NULL);
bellardf0cbd3e2004-04-22 00:10:48 +0000237}
238
239#define CONN_CANFSEND(so) (((so)->so_state & (SS_FCANTSENDMORE|SS_ISFCONNECTED)) == SS_ISFCONNECTED)
240#define CONN_CANFRCV(so) (((so)->so_state & (SS_FCANTRCVMORE|SS_ISFCONNECTED)) == SS_ISFCONNECTED)
241#define UPD_NFDS(x) if (nfds < (x)) nfds = (x)
242
243/*
244 * curtime kept to an accuracy of 1ms
245 */
bellard379ff532004-07-12 22:33:07 +0000246#ifdef _WIN32
247static void updtime(void)
248{
249 struct _timeb tb;
250
251 _ftime(&tb);
Jan Kiszka8ec7f4e2009-06-24 14:42:30 +0200252
253 curtime = tb.time * 1000 + tb.millitm;
bellard379ff532004-07-12 22:33:07 +0000254}
255#else
bellardf0cbd3e2004-04-22 00:10:48 +0000256static void updtime(void)
257{
Jan Kiszka8ec7f4e2009-06-24 14:42:30 +0200258 struct timeval tv;
ths5fafdf22007-09-16 21:08:06 +0000259
Jan Kiszka8ec7f4e2009-06-24 14:42:30 +0200260 gettimeofday(&tv, NULL);
ths5fafdf22007-09-16 21:08:06 +0000261
Jan Kiszka8ec7f4e2009-06-24 14:42:30 +0200262 curtime = tv.tv_sec * 1000 + tv.tv_usec / 1000;
bellardf0cbd3e2004-04-22 00:10:48 +0000263}
bellard379ff532004-07-12 22:33:07 +0000264#endif
bellardf0cbd3e2004-04-22 00:10:48 +0000265
ths5fafdf22007-09-16 21:08:06 +0000266void slirp_select_fill(int *pnfds,
bellardf0cbd3e2004-04-22 00:10:48 +0000267 fd_set *readfds, fd_set *writefds, fd_set *xfds)
268{
269 struct socket *so, *so_next;
270 struct timeval timeout;
271 int nfds;
272 int tmp_time;
273
Jan Kiszkad918f232009-06-24 14:42:30 +0200274 if (!link_up) {
275 return;
276 }
277
bellardf0cbd3e2004-04-22 00:10:48 +0000278 /* fail safe */
279 global_readfds = NULL;
280 global_writefds = NULL;
281 global_xfds = NULL;
ths3b46e622007-09-17 08:09:54 +0000282
bellardf0cbd3e2004-04-22 00:10:48 +0000283 nfds = *pnfds;
284 /*
285 * First, TCP sockets
286 */
287 do_slowtimo = 0;
Jan Kiszkad918f232009-06-24 14:42:30 +0200288
ths5fafdf22007-09-16 21:08:06 +0000289 /*
bellardf0cbd3e2004-04-22 00:10:48 +0000290 * *_slowtimo needs calling if there are IP fragments
291 * in the fragment queue, or there are TCP connections active
292 */
293 do_slowtimo = ((tcb.so_next != &tcb) ||
blueswir1429d0a32009-01-13 19:48:42 +0000294 (&ipq.ip_link != ipq.ip_link.next));
ths3b46e622007-09-17 08:09:54 +0000295
bellardf0cbd3e2004-04-22 00:10:48 +0000296 for (so = tcb.so_next; so != &tcb; so = so_next) {
297 so_next = so->so_next;
ths3b46e622007-09-17 08:09:54 +0000298
bellardf0cbd3e2004-04-22 00:10:48 +0000299 /*
300 * See if we need a tcp_fasttimo
301 */
302 if (time_fasttimo == 0 && so->so_tcpcb->t_flags & TF_DELACK)
303 time_fasttimo = curtime; /* Flag when we want a fasttimo */
ths3b46e622007-09-17 08:09:54 +0000304
bellardf0cbd3e2004-04-22 00:10:48 +0000305 /*
306 * NOFDREF can include still connecting to local-host,
307 * newly socreated() sockets etc. Don't want to select these.
308 */
309 if (so->so_state & SS_NOFDREF || so->s == -1)
310 continue;
ths3b46e622007-09-17 08:09:54 +0000311
bellardf0cbd3e2004-04-22 00:10:48 +0000312 /*
313 * Set for reading sockets which are accepting
314 */
315 if (so->so_state & SS_FACCEPTCONN) {
316 FD_SET(so->s, readfds);
317 UPD_NFDS(so->s);
318 continue;
319 }
ths3b46e622007-09-17 08:09:54 +0000320
bellardf0cbd3e2004-04-22 00:10:48 +0000321 /*
322 * Set for writing sockets which are connecting
323 */
324 if (so->so_state & SS_ISFCONNECTING) {
325 FD_SET(so->s, writefds);
326 UPD_NFDS(so->s);
327 continue;
328 }
ths3b46e622007-09-17 08:09:54 +0000329
bellardf0cbd3e2004-04-22 00:10:48 +0000330 /*
331 * Set for writing if we are connected, can send more, and
332 * we have something to send
333 */
334 if (CONN_CANFSEND(so) && so->so_rcv.sb_cc) {
335 FD_SET(so->s, writefds);
336 UPD_NFDS(so->s);
337 }
ths3b46e622007-09-17 08:09:54 +0000338
bellardf0cbd3e2004-04-22 00:10:48 +0000339 /*
340 * Set for reading (and urgent data) if we are connected, can
341 * receive more, and we have room for it XXX /2 ?
342 */
343 if (CONN_CANFRCV(so) && (so->so_snd.sb_cc < (so->so_snd.sb_datalen/2))) {
344 FD_SET(so->s, readfds);
345 FD_SET(so->s, xfds);
346 UPD_NFDS(so->s);
347 }
348 }
ths3b46e622007-09-17 08:09:54 +0000349
bellardf0cbd3e2004-04-22 00:10:48 +0000350 /*
351 * UDP sockets
352 */
353 for (so = udb.so_next; so != &udb; so = so_next) {
354 so_next = so->so_next;
ths3b46e622007-09-17 08:09:54 +0000355
bellardf0cbd3e2004-04-22 00:10:48 +0000356 /*
357 * See if it's timed out
358 */
359 if (so->so_expire) {
360 if (so->so_expire <= curtime) {
361 udp_detach(so);
362 continue;
363 } else
364 do_slowtimo = 1; /* Let socket expire */
365 }
ths3b46e622007-09-17 08:09:54 +0000366
bellardf0cbd3e2004-04-22 00:10:48 +0000367 /*
368 * When UDP packets are received from over the
369 * link, they're sendto()'d straight away, so
370 * no need for setting for writing
371 * Limit the number of packets queued by this session
372 * to 4. Note that even though we try and limit this
373 * to 4 packets, the session could have more queued
374 * if the packets needed to be fragmented
375 * (XXX <= 4 ?)
376 */
377 if ((so->so_state & SS_ISFCONNECTED) && so->so_queued <= 4) {
378 FD_SET(so->s, readfds);
379 UPD_NFDS(so->s);
380 }
381 }
ths5fafdf22007-09-16 21:08:06 +0000382
bellardf0cbd3e2004-04-22 00:10:48 +0000383 /*
384 * Setup timeout to use minimum CPU usage, especially when idle
385 */
ths5fafdf22007-09-16 21:08:06 +0000386
387 /*
bellardf0cbd3e2004-04-22 00:10:48 +0000388 * First, see the timeout needed by *timo
389 */
390 timeout.tv_sec = 0;
391 timeout.tv_usec = -1;
392 /*
393 * If a slowtimo is needed, set timeout to 500ms from the last
394 * slow timeout. If a fast timeout is needed, set timeout within
395 * 200ms of when it was requested.
396 */
397 if (do_slowtimo) {
398 /* XXX + 10000 because some select()'s aren't that accurate */
399 timeout.tv_usec = ((500 - (curtime - last_slowtimo)) * 1000) + 10000;
400 if (timeout.tv_usec < 0)
401 timeout.tv_usec = 0;
402 else if (timeout.tv_usec > 510000)
403 timeout.tv_usec = 510000;
ths3b46e622007-09-17 08:09:54 +0000404
bellardf0cbd3e2004-04-22 00:10:48 +0000405 /* Can only fasttimo if we also slowtimo */
406 if (time_fasttimo) {
407 tmp_time = (200 - (curtime - time_fasttimo)) * 1000;
408 if (tmp_time < 0)
409 tmp_time = 0;
ths3b46e622007-09-17 08:09:54 +0000410
bellardf0cbd3e2004-04-22 00:10:48 +0000411 /* Choose the smallest of the 2 */
412 if (tmp_time < timeout.tv_usec)
413 timeout.tv_usec = (u_int)tmp_time;
414 }
415 }
416 *pnfds = nfds;
ths5fafdf22007-09-16 21:08:06 +0000417}
bellardf0cbd3e2004-04-22 00:10:48 +0000418
Jan Kiszkad918f232009-06-24 14:42:30 +0200419void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds,
420 int select_error)
bellardf0cbd3e2004-04-22 00:10:48 +0000421{
422 struct socket *so, *so_next;
423 int ret;
424
Jan Kiszkad918f232009-06-24 14:42:30 +0200425 if (!link_up) {
426 return;
427 }
428
bellardf0cbd3e2004-04-22 00:10:48 +0000429 global_readfds = readfds;
430 global_writefds = writefds;
431 global_xfds = xfds;
432
433 /* Update time */
434 updtime();
ths5fafdf22007-09-16 21:08:06 +0000435
bellardf0cbd3e2004-04-22 00:10:48 +0000436 /*
ths5fafdf22007-09-16 21:08:06 +0000437 * See if anything has timed out
bellardf0cbd3e2004-04-22 00:10:48 +0000438 */
bellarddf5f8952005-09-03 10:45:09 +0000439 if (time_fasttimo && ((curtime - time_fasttimo) >= 2)) {
bellardf0cbd3e2004-04-22 00:10:48 +0000440 tcp_fasttimo();
441 time_fasttimo = 0;
442 }
443 if (do_slowtimo && ((curtime - last_slowtimo) >= 499)) {
444 ip_slowtimo();
445 tcp_slowtimo();
446 last_slowtimo = curtime;
447 }
ths5fafdf22007-09-16 21:08:06 +0000448
bellardf0cbd3e2004-04-22 00:10:48 +0000449 /*
450 * Check sockets
451 */
Jan Kiszkad918f232009-06-24 14:42:30 +0200452 if (!select_error) {
bellardf0cbd3e2004-04-22 00:10:48 +0000453 /*
454 * Check TCP sockets
455 */
456 for (so = tcb.so_next; so != &tcb; so = so_next) {
457 so_next = so->so_next;
ths3b46e622007-09-17 08:09:54 +0000458
bellardf0cbd3e2004-04-22 00:10:48 +0000459 /*
460 * FD_ISSET is meaningless on these sockets
461 * (and they can crash the program)
462 */
463 if (so->so_state & SS_NOFDREF || so->s == -1)
464 continue;
ths3b46e622007-09-17 08:09:54 +0000465
bellardf0cbd3e2004-04-22 00:10:48 +0000466 /*
467 * Check for URG data
468 * This will soread as well, so no need to
469 * test for readfds below if this succeeds
470 */
471 if (FD_ISSET(so->s, xfds))
472 sorecvoob(so);
473 /*
474 * Check sockets for reading
475 */
476 else if (FD_ISSET(so->s, readfds)) {
477 /*
478 * Check for incoming connections
479 */
480 if (so->so_state & SS_FACCEPTCONN) {
481 tcp_connect(so);
482 continue;
483 } /* else */
484 ret = soread(so);
ths3b46e622007-09-17 08:09:54 +0000485
bellardf0cbd3e2004-04-22 00:10:48 +0000486 /* Output it if we read something */
487 if (ret > 0)
488 tcp_output(sototcpcb(so));
489 }
ths3b46e622007-09-17 08:09:54 +0000490
bellardf0cbd3e2004-04-22 00:10:48 +0000491 /*
492 * Check sockets for writing
493 */
494 if (FD_ISSET(so->s, writefds)) {
495 /*
496 * Check for non-blocking, still-connecting sockets
497 */
498 if (so->so_state & SS_ISFCONNECTING) {
499 /* Connected */
500 so->so_state &= ~SS_ISFCONNECTING;
ths3b46e622007-09-17 08:09:54 +0000501
malc0a656f52009-05-21 05:26:23 +0400502 ret = send(so->s, (const void *) &ret, 0, 0);
bellardf0cbd3e2004-04-22 00:10:48 +0000503 if (ret < 0) {
504 /* XXXXX Must fix, zero bytes is a NOP */
505 if (errno == EAGAIN || errno == EWOULDBLOCK ||
506 errno == EINPROGRESS || errno == ENOTCONN)
507 continue;
ths3b46e622007-09-17 08:09:54 +0000508
bellardf0cbd3e2004-04-22 00:10:48 +0000509 /* else failed */
Jan Kiszkaf932b6c2009-06-24 14:42:29 +0200510 so->so_state &= SS_PERSISTENT_MASK;
511 so->so_state |= SS_NOFDREF;
bellardf0cbd3e2004-04-22 00:10:48 +0000512 }
513 /* else so->so_state &= ~SS_ISFCONNECTING; */
ths3b46e622007-09-17 08:09:54 +0000514
bellardf0cbd3e2004-04-22 00:10:48 +0000515 /*
516 * Continue tcp_input
517 */
518 tcp_input((struct mbuf *)NULL, sizeof(struct ip), so);
519 /* continue; */
520 } else
521 ret = sowrite(so);
522 /*
ths5fafdf22007-09-16 21:08:06 +0000523 * XXXXX If we wrote something (a lot), there
bellardf0cbd3e2004-04-22 00:10:48 +0000524 * could be a need for a window update.
525 * In the worst case, the remote will send
526 * a window probe to get things going again
527 */
528 }
ths3b46e622007-09-17 08:09:54 +0000529
bellardf0cbd3e2004-04-22 00:10:48 +0000530 /*
531 * Probe a still-connecting, non-blocking socket
532 * to check if it's still alive
533 */
534#ifdef PROBE_CONN
535 if (so->so_state & SS_ISFCONNECTING) {
bellard02d2c542004-10-07 23:27:35 +0000536 ret = recv(so->s, (char *)&ret, 0,0);
ths3b46e622007-09-17 08:09:54 +0000537
bellardf0cbd3e2004-04-22 00:10:48 +0000538 if (ret < 0) {
539 /* XXX */
540 if (errno == EAGAIN || errno == EWOULDBLOCK ||
541 errno == EINPROGRESS || errno == ENOTCONN)
542 continue; /* Still connecting, continue */
ths3b46e622007-09-17 08:09:54 +0000543
bellardf0cbd3e2004-04-22 00:10:48 +0000544 /* else failed */
Jan Kiszkaf932b6c2009-06-24 14:42:29 +0200545 so->so_state &= SS_PERSISTENT_MASK;
546 so->so_state |= SS_NOFDREF;
ths3b46e622007-09-17 08:09:54 +0000547
bellardf0cbd3e2004-04-22 00:10:48 +0000548 /* tcp_input will take care of it */
549 } else {
bellard02d2c542004-10-07 23:27:35 +0000550 ret = send(so->s, &ret, 0,0);
bellardf0cbd3e2004-04-22 00:10:48 +0000551 if (ret < 0) {
552 /* XXX */
553 if (errno == EAGAIN || errno == EWOULDBLOCK ||
554 errno == EINPROGRESS || errno == ENOTCONN)
555 continue;
556 /* else failed */
Jan Kiszkaf932b6c2009-06-24 14:42:29 +0200557 so->so_state &= SS_PERSISTENT_MASK;
558 so->so_state |= SS_NOFDREF;
bellardf0cbd3e2004-04-22 00:10:48 +0000559 } else
560 so->so_state &= ~SS_ISFCONNECTING;
ths3b46e622007-09-17 08:09:54 +0000561
bellardf0cbd3e2004-04-22 00:10:48 +0000562 }
563 tcp_input((struct mbuf *)NULL, sizeof(struct ip),so);
564 } /* SS_ISFCONNECTING */
565#endif
566 }
ths3b46e622007-09-17 08:09:54 +0000567
bellardf0cbd3e2004-04-22 00:10:48 +0000568 /*
569 * Now UDP sockets.
570 * Incoming packets are sent straight away, they're not buffered.
571 * Incoming UDP data isn't buffered either.
572 */
573 for (so = udb.so_next; so != &udb; so = so_next) {
574 so_next = so->so_next;
ths3b46e622007-09-17 08:09:54 +0000575
bellardf0cbd3e2004-04-22 00:10:48 +0000576 if (so->s != -1 && FD_ISSET(so->s, readfds)) {
577 sorecvfrom(so);
578 }
579 }
580 }
ths5fafdf22007-09-16 21:08:06 +0000581
bellardf0cbd3e2004-04-22 00:10:48 +0000582 /*
583 * See if we can start outputting
584 */
Jan Kiszkad918f232009-06-24 14:42:30 +0200585 if (if_queued)
bellardf0cbd3e2004-04-22 00:10:48 +0000586 if_start();
bellard02d2c542004-10-07 23:27:35 +0000587
588 /* clear global file descriptor sets.
589 * these reside on the stack in vl.c
590 * so they're unusable if we're not in
591 * slirp_select_fill or slirp_select_poll.
592 */
593 global_readfds = NULL;
594 global_writefds = NULL;
595 global_xfds = NULL;
bellardf0cbd3e2004-04-22 00:10:48 +0000596}
597
598#define ETH_ALEN 6
599#define ETH_HLEN 14
600
601#define ETH_P_IP 0x0800 /* Internet Protocol packet */
602#define ETH_P_ARP 0x0806 /* Address Resolution packet */
603
604#define ARPOP_REQUEST 1 /* ARP request */
605#define ARPOP_REPLY 2 /* ARP reply */
606
ths5fafdf22007-09-16 21:08:06 +0000607struct ethhdr
bellardf0cbd3e2004-04-22 00:10:48 +0000608{
609 unsigned char h_dest[ETH_ALEN]; /* destination eth addr */
610 unsigned char h_source[ETH_ALEN]; /* source ether addr */
611 unsigned short h_proto; /* packet type ID field */
612};
613
614struct arphdr
615{
616 unsigned short ar_hrd; /* format of hardware address */
617 unsigned short ar_pro; /* format of protocol address */
618 unsigned char ar_hln; /* length of hardware address */
619 unsigned char ar_pln; /* length of protocol address */
620 unsigned short ar_op; /* ARP opcode (command) */
621
622 /*
623 * Ethernet looks like this : This bit is variable sized however...
624 */
625 unsigned char ar_sha[ETH_ALEN]; /* sender hardware address */
Jan Kiszkaa13a4122009-06-24 14:42:28 +0200626 uint32_t ar_sip; /* sender IP address */
bellardf0cbd3e2004-04-22 00:10:48 +0000627 unsigned char ar_tha[ETH_ALEN]; /* target hardware address */
Jan Kiszkaa13a4122009-06-24 14:42:28 +0200628 uint32_t ar_tip ; /* target IP address */
629} __attribute__((packed));
bellardf0cbd3e2004-04-22 00:10:48 +0000630
blueswir18fcd3692008-08-17 20:26:25 +0000631static void arp_input(const uint8_t *pkt, int pkt_len)
bellardf0cbd3e2004-04-22 00:10:48 +0000632{
633 struct ethhdr *eh = (struct ethhdr *)pkt;
634 struct arphdr *ah = (struct arphdr *)(pkt + ETH_HLEN);
635 uint8_t arp_reply[ETH_HLEN + sizeof(struct arphdr)];
636 struct ethhdr *reh = (struct ethhdr *)arp_reply;
637 struct arphdr *rah = (struct arphdr *)(arp_reply + ETH_HLEN);
638 int ar_op;
bellarda3d4af02004-09-05 23:10:26 +0000639 struct ex_list *ex_ptr;
bellardf0cbd3e2004-04-22 00:10:48 +0000640
641 ar_op = ntohs(ah->ar_op);
642 switch(ar_op) {
643 case ARPOP_REQUEST:
Jan Kiszkaa13a4122009-06-24 14:42:28 +0200644 if ((ah->ar_tip & vnetwork_mask.s_addr) == vnetwork_addr.s_addr) {
645 if (ah->ar_tip == vnameserver_addr.s_addr ||
646 ah->ar_tip == vhost_addr.s_addr)
bellarda3d4af02004-09-05 23:10:26 +0000647 goto arp_ok;
648 for (ex_ptr = exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next) {
Jan Kiszkaa13a4122009-06-24 14:42:28 +0200649 if (ex_ptr->ex_addr.s_addr == ah->ar_tip)
bellarda3d4af02004-09-05 23:10:26 +0000650 goto arp_ok;
651 }
652 return;
653 arp_ok:
bellardf0cbd3e2004-04-22 00:10:48 +0000654 /* XXX: make an ARP request to have the client address */
655 memcpy(client_ethaddr, eh->h_source, ETH_ALEN);
656
657 /* ARP request for alias/dns mac address */
658 memcpy(reh->h_dest, pkt + ETH_ALEN, ETH_ALEN);
Jan Kiszkaa13a4122009-06-24 14:42:28 +0200659 memcpy(reh->h_source, special_ethaddr, ETH_ALEN - 4);
660 memcpy(&reh->h_source[2], &ah->ar_tip, 4);
bellardf0cbd3e2004-04-22 00:10:48 +0000661 reh->h_proto = htons(ETH_P_ARP);
662
663 rah->ar_hrd = htons(1);
664 rah->ar_pro = htons(ETH_P_IP);
665 rah->ar_hln = ETH_ALEN;
666 rah->ar_pln = 4;
667 rah->ar_op = htons(ARPOP_REPLY);
668 memcpy(rah->ar_sha, reh->h_source, ETH_ALEN);
Jan Kiszkaa13a4122009-06-24 14:42:28 +0200669 rah->ar_sip = ah->ar_tip;
bellardf0cbd3e2004-04-22 00:10:48 +0000670 memcpy(rah->ar_tha, ah->ar_sha, ETH_ALEN);
Jan Kiszkaa13a4122009-06-24 14:42:28 +0200671 rah->ar_tip = ah->ar_sip;
bellardf0cbd3e2004-04-22 00:10:48 +0000672 slirp_output(arp_reply, sizeof(arp_reply));
673 }
674 break;
bellardde806f02008-10-17 17:28:58 +0000675 case ARPOP_REPLY:
676 /* reply to request of client mac address ? */
677 if (!memcmp(client_ethaddr, zero_ethaddr, ETH_ALEN) &&
Jan Kiszkaa13a4122009-06-24 14:42:28 +0200678 ah->ar_sip == client_ipaddr.s_addr) {
bellardde806f02008-10-17 17:28:58 +0000679 memcpy(client_ethaddr, ah->ar_sha, ETH_ALEN);
680 }
681 break;
bellardf0cbd3e2004-04-22 00:10:48 +0000682 default:
683 break;
684 }
685}
686
687void slirp_input(const uint8_t *pkt, int pkt_len)
688{
689 struct mbuf *m;
690 int proto;
691
692 if (pkt_len < ETH_HLEN)
693 return;
ths3b46e622007-09-17 08:09:54 +0000694
bellardf0cbd3e2004-04-22 00:10:48 +0000695 proto = ntohs(*(uint16_t *)(pkt + 12));
696 switch(proto) {
697 case ETH_P_ARP:
698 arp_input(pkt, pkt_len);
699 break;
700 case ETH_P_IP:
701 m = m_get();
702 if (!m)
703 return;
bellard38f3e7c2006-05-10 19:21:58 +0000704 /* Note: we add to align the IP header */
aurel32e8e880a2008-12-07 18:15:23 +0000705 if (M_FREEROOM(m) < pkt_len + 2) {
706 m_inc(m, pkt_len + 2);
707 }
bellard38f3e7c2006-05-10 19:21:58 +0000708 m->m_len = pkt_len + 2;
709 memcpy(m->m_data + 2, pkt, pkt_len);
bellardf0cbd3e2004-04-22 00:10:48 +0000710
bellard38f3e7c2006-05-10 19:21:58 +0000711 m->m_data += 2 + ETH_HLEN;
712 m->m_len -= 2 + ETH_HLEN;
bellardf0cbd3e2004-04-22 00:10:48 +0000713
714 ip_input(m);
715 break;
716 default:
717 break;
718 }
719}
720
721/* output the IP packet to the ethernet device */
722void if_encap(const uint8_t *ip_data, int ip_data_len)
723{
724 uint8_t buf[1600];
725 struct ethhdr *eh = (struct ethhdr *)buf;
726
727 if (ip_data_len + ETH_HLEN > sizeof(buf))
728 return;
bellardde806f02008-10-17 17:28:58 +0000729
730 if (!memcmp(client_ethaddr, zero_ethaddr, ETH_ALEN)) {
731 uint8_t arp_req[ETH_HLEN + sizeof(struct arphdr)];
732 struct ethhdr *reh = (struct ethhdr *)arp_req;
733 struct arphdr *rah = (struct arphdr *)(arp_req + ETH_HLEN);
734 const struct ip *iph = (const struct ip *)ip_data;
bellardf0cbd3e2004-04-22 00:10:48 +0000735
bellardde806f02008-10-17 17:28:58 +0000736 /* If the client addr is not known, there is no point in
737 sending the packet to it. Normally the sender should have
738 done an ARP request to get its MAC address. Here we do it
739 in place of sending the packet and we hope that the sender
740 will retry sending its packet. */
741 memset(reh->h_dest, 0xff, ETH_ALEN);
Jan Kiszkaa13a4122009-06-24 14:42:28 +0200742 memcpy(reh->h_source, special_ethaddr, ETH_ALEN - 4);
743 memcpy(&reh->h_source[2], &vhost_addr, 4);
bellardde806f02008-10-17 17:28:58 +0000744 reh->h_proto = htons(ETH_P_ARP);
745 rah->ar_hrd = htons(1);
746 rah->ar_pro = htons(ETH_P_IP);
747 rah->ar_hln = ETH_ALEN;
748 rah->ar_pln = 4;
749 rah->ar_op = htons(ARPOP_REQUEST);
750 /* source hw addr */
Jan Kiszkaa13a4122009-06-24 14:42:28 +0200751 memcpy(rah->ar_sha, special_ethaddr, ETH_ALEN - 4);
752 memcpy(&rah->ar_sha[2], &vhost_addr, 4);
bellardde806f02008-10-17 17:28:58 +0000753 /* source IP */
Jan Kiszkaa13a4122009-06-24 14:42:28 +0200754 rah->ar_sip = vhost_addr.s_addr;
bellardde806f02008-10-17 17:28:58 +0000755 /* target hw addr (none) */
756 memset(rah->ar_tha, 0, ETH_ALEN);
757 /* target IP */
Jan Kiszkaa13a4122009-06-24 14:42:28 +0200758 rah->ar_tip = iph->ip_dst.s_addr;
bellardde806f02008-10-17 17:28:58 +0000759 client_ipaddr = iph->ip_dst;
760 slirp_output(arp_req, sizeof(arp_req));
761 } else {
762 memcpy(eh->h_dest, client_ethaddr, ETH_ALEN);
Jan Kiszkaa13a4122009-06-24 14:42:28 +0200763 memcpy(eh->h_source, special_ethaddr, ETH_ALEN - 4);
bellardde806f02008-10-17 17:28:58 +0000764 /* XXX: not correct */
Jan Kiszkaa13a4122009-06-24 14:42:28 +0200765 memcpy(&eh->h_source[2], &vhost_addr, 4);
bellardde806f02008-10-17 17:28:58 +0000766 eh->h_proto = htons(ETH_P_IP);
767 memcpy(buf + sizeof(struct ethhdr), ip_data, ip_data_len);
768 slirp_output(buf, ip_data_len + ETH_HLEN);
769 }
bellardf0cbd3e2004-04-22 00:10:48 +0000770}
bellard9bf05442004-08-25 22:12:49 +0000771
Jan Kiszka9c12a6f2009-06-24 14:42:29 +0200772/* Drop host forwarding rule, return 0 if found. */
Jan Kiszka3c6a0582009-06-24 14:42:28 +0200773int slirp_remove_hostfwd(int is_udp, struct in_addr host_addr, int host_port)
Alexander Grafc1261d82009-05-26 13:03:26 +0200774{
775 struct socket *so;
776 struct socket *head = (is_udp ? &udb : &tcb);
Jan Kiszka2ad82cf2009-06-24 14:42:28 +0200777 struct sockaddr_in addr;
778 int port = htons(host_port);
779 socklen_t addr_len;
Alexander Grafc1261d82009-05-26 13:03:26 +0200780
Alexander Grafc1261d82009-05-26 13:03:26 +0200781 for (so = head->so_next; so != head; so = so->so_next) {
Jan Kiszka2ad82cf2009-06-24 14:42:28 +0200782 addr_len = sizeof(addr);
Jan Kiszka9c12a6f2009-06-24 14:42:29 +0200783 if ((so->so_state & SS_HOSTFWD) &&
784 getsockname(so->s, (struct sockaddr *)&addr, &addr_len) == 0 &&
Jan Kiszka3c6a0582009-06-24 14:42:28 +0200785 addr.sin_addr.s_addr == host_addr.s_addr &&
Jan Kiszka2ad82cf2009-06-24 14:42:28 +0200786 addr.sin_port == port) {
Alexander Grafc1261d82009-05-26 13:03:26 +0200787 close(so->s);
788 sofree(so);
Jan Kiszka9c12a6f2009-06-24 14:42:29 +0200789 return 0;
Alexander Grafc1261d82009-05-26 13:03:26 +0200790 }
791 }
792
Jan Kiszka9c12a6f2009-06-24 14:42:29 +0200793 return -1;
Alexander Grafc1261d82009-05-26 13:03:26 +0200794}
795
Jan Kiszka3c6a0582009-06-24 14:42:28 +0200796int slirp_add_hostfwd(int is_udp, struct in_addr host_addr, int host_port,
Jan Kiszkac92ef6a2009-06-24 14:42:28 +0200797 struct in_addr guest_addr, int guest_port)
bellard9bf05442004-08-25 22:12:49 +0000798{
Jan Kiszkaa13a4122009-06-24 14:42:28 +0200799 if (!guest_addr.s_addr) {
800 guest_addr = vdhcp_startaddr;
801 }
bellard9bf05442004-08-25 22:12:49 +0000802 if (is_udp) {
Jan Kiszka3c6a0582009-06-24 14:42:28 +0200803 if (!udp_listen(host_addr.s_addr, htons(host_port), guest_addr.s_addr,
Jan Kiszka6dd5ffb2009-06-24 14:42:29 +0200804 htons(guest_port), SS_HOSTFWD))
bellard9bf05442004-08-25 22:12:49 +0000805 return -1;
806 } else {
Jan Kiszka3c6a0582009-06-24 14:42:28 +0200807 if (!tcp_listen(host_addr.s_addr, htons(host_port), guest_addr.s_addr,
Jan Kiszka6dd5ffb2009-06-24 14:42:29 +0200808 htons(guest_port), SS_HOSTFWD))
bellard9bf05442004-08-25 22:12:49 +0000809 return -1;
810 }
811 return 0;
812}
bellarda3d4af02004-09-05 23:10:26 +0000813
Jan Kiszkac92ef6a2009-06-24 14:42:28 +0200814int slirp_add_exec(int do_pty, const void *args, struct in_addr guest_addr,
815 int guest_port)
bellarda3d4af02004-09-05 23:10:26 +0000816{
Jan Kiszkac92ef6a2009-06-24 14:42:28 +0200817 if (!guest_addr.s_addr) {
818 guest_addr.s_addr =
819 vnetwork_addr.s_addr | (htonl(0x0204) & ~vnetwork_mask.s_addr);
820 }
Jan Kiszkaa13a4122009-06-24 14:42:28 +0200821 if ((guest_addr.s_addr & vnetwork_mask.s_addr) != vnetwork_addr.s_addr ||
822 guest_addr.s_addr == vhost_addr.s_addr ||
823 guest_addr.s_addr == vnameserver_addr.s_addr) {
824 return -1;
825 }
826 return add_exec(&exec_list, do_pty, (char *)args, guest_addr,
827 htons(guest_port));
bellarda3d4af02004-09-05 23:10:26 +0000828}
aliguorie1c5a2b2009-01-08 19:18:21 +0000829
830ssize_t slirp_send(struct socket *so, const void *buf, size_t len, int flags)
831{
832 if (so->s == -1 && so->extra) {
833 qemu_chr_write(so->extra, buf, len);
834 return len;
835 }
836
837 return send(so->s, buf, len, flags);
838}
839
Jan Kiszkaa13a4122009-06-24 14:42:28 +0200840static struct socket *
841slirp_find_ctl_socket(struct in_addr guest_addr, int guest_port)
aliguorie1c5a2b2009-01-08 19:18:21 +0000842{
Jan Kiszkaa13a4122009-06-24 14:42:28 +0200843 struct socket *so;
aliguorie1c5a2b2009-01-08 19:18:21 +0000844
Jan Kiszkaa13a4122009-06-24 14:42:28 +0200845 for (so = tcb.so_next; so != &tcb; so = so->so_next) {
846 if (so->so_faddr.s_addr == guest_addr.s_addr &&
847 htons(so->so_fport) == guest_port) {
848 return so;
849 }
850 }
851 return NULL;
aliguorie1c5a2b2009-01-08 19:18:21 +0000852}
853
Jan Kiszkac92ef6a2009-06-24 14:42:28 +0200854size_t slirp_socket_can_recv(struct in_addr guest_addr, int guest_port)
aliguorie1c5a2b2009-01-08 19:18:21 +0000855{
856 struct iovec iov[2];
857 struct socket *so;
858
859 if (!link_up)
860 return 0;
861
Jan Kiszkaa13a4122009-06-24 14:42:28 +0200862 so = slirp_find_ctl_socket(guest_addr, guest_port);
aliguorie1c5a2b2009-01-08 19:18:21 +0000863
864 if (!so || so->so_state & SS_NOFDREF)
865 return 0;
866
867 if (!CONN_CANFRCV(so) || so->so_snd.sb_cc >= (so->so_snd.sb_datalen/2))
868 return 0;
869
870 return sopreprbuf(so, iov, NULL);
871}
872
Jan Kiszkac92ef6a2009-06-24 14:42:28 +0200873void slirp_socket_recv(struct in_addr guest_addr, int guest_port,
874 const uint8_t *buf, int size)
aliguorie1c5a2b2009-01-08 19:18:21 +0000875{
876 int ret;
Jan Kiszkaa13a4122009-06-24 14:42:28 +0200877 struct socket *so = slirp_find_ctl_socket(guest_addr, guest_port);
878
aliguorie1c5a2b2009-01-08 19:18:21 +0000879 if (!so)
880 return;
881
blueswir10580ac92009-01-12 17:51:06 +0000882 ret = soreadbuf(so, (const char *)buf, size);
aliguorie1c5a2b2009-01-08 19:18:21 +0000883
884 if (ret > 0)
885 tcp_output(sototcpcb(so));
886}
aliguori062e5522009-01-08 19:27:07 +0000887
888static void slirp_tcp_save(QEMUFile *f, struct tcpcb *tp)
889{
890 int i;
891
892 qemu_put_sbe16(f, tp->t_state);
893 for (i = 0; i < TCPT_NTIMERS; i++)
894 qemu_put_sbe16(f, tp->t_timer[i]);
895 qemu_put_sbe16(f, tp->t_rxtshift);
896 qemu_put_sbe16(f, tp->t_rxtcur);
897 qemu_put_sbe16(f, tp->t_dupacks);
898 qemu_put_be16(f, tp->t_maxseg);
899 qemu_put_sbyte(f, tp->t_force);
900 qemu_put_be16(f, tp->t_flags);
901 qemu_put_be32(f, tp->snd_una);
902 qemu_put_be32(f, tp->snd_nxt);
903 qemu_put_be32(f, tp->snd_up);
904 qemu_put_be32(f, tp->snd_wl1);
905 qemu_put_be32(f, tp->snd_wl2);
906 qemu_put_be32(f, tp->iss);
907 qemu_put_be32(f, tp->snd_wnd);
908 qemu_put_be32(f, tp->rcv_wnd);
909 qemu_put_be32(f, tp->rcv_nxt);
910 qemu_put_be32(f, tp->rcv_up);
911 qemu_put_be32(f, tp->irs);
912 qemu_put_be32(f, tp->rcv_adv);
913 qemu_put_be32(f, tp->snd_max);
914 qemu_put_be32(f, tp->snd_cwnd);
915 qemu_put_be32(f, tp->snd_ssthresh);
916 qemu_put_sbe16(f, tp->t_idle);
917 qemu_put_sbe16(f, tp->t_rtt);
918 qemu_put_be32(f, tp->t_rtseq);
919 qemu_put_sbe16(f, tp->t_srtt);
920 qemu_put_sbe16(f, tp->t_rttvar);
921 qemu_put_be16(f, tp->t_rttmin);
922 qemu_put_be32(f, tp->max_sndwnd);
923 qemu_put_byte(f, tp->t_oobflags);
924 qemu_put_byte(f, tp->t_iobc);
925 qemu_put_sbe16(f, tp->t_softerror);
926 qemu_put_byte(f, tp->snd_scale);
927 qemu_put_byte(f, tp->rcv_scale);
928 qemu_put_byte(f, tp->request_r_scale);
929 qemu_put_byte(f, tp->requested_s_scale);
930 qemu_put_be32(f, tp->ts_recent);
931 qemu_put_be32(f, tp->ts_recent_age);
932 qemu_put_be32(f, tp->last_ack_sent);
933}
934
935static void slirp_sbuf_save(QEMUFile *f, struct sbuf *sbuf)
936{
937 uint32_t off;
938
939 qemu_put_be32(f, sbuf->sb_cc);
940 qemu_put_be32(f, sbuf->sb_datalen);
941 off = (uint32_t)(sbuf->sb_wptr - sbuf->sb_data);
942 qemu_put_sbe32(f, off);
943 off = (uint32_t)(sbuf->sb_rptr - sbuf->sb_data);
944 qemu_put_sbe32(f, off);
945 qemu_put_buffer(f, (unsigned char*)sbuf->sb_data, sbuf->sb_datalen);
946}
947
948static void slirp_socket_save(QEMUFile *f, struct socket *so)
949{
950 qemu_put_be32(f, so->so_urgc);
951 qemu_put_be32(f, so->so_faddr.s_addr);
952 qemu_put_be32(f, so->so_laddr.s_addr);
953 qemu_put_be16(f, so->so_fport);
954 qemu_put_be16(f, so->so_lport);
955 qemu_put_byte(f, so->so_iptos);
956 qemu_put_byte(f, so->so_emu);
957 qemu_put_byte(f, so->so_type);
958 qemu_put_be32(f, so->so_state);
959 slirp_sbuf_save(f, &so->so_rcv);
960 slirp_sbuf_save(f, &so->so_snd);
961 slirp_tcp_save(f, so->so_tcpcb);
962}
963
964static void slirp_state_save(QEMUFile *f, void *opaque)
965{
966 struct ex_list *ex_ptr;
967
968 for (ex_ptr = exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next)
969 if (ex_ptr->ex_pty == 3) {
970 struct socket *so;
971 so = slirp_find_ctl_socket(ex_ptr->ex_addr, ntohs(ex_ptr->ex_fport));
972 if (!so)
973 continue;
974
975 qemu_put_byte(f, 42);
976 slirp_socket_save(f, so);
977 }
978 qemu_put_byte(f, 0);
Jan Kiszka285f7a62009-06-24 14:42:30 +0200979
980 qemu_put_be16(f, ip_id);
aliguori062e5522009-01-08 19:27:07 +0000981}
982
983static void slirp_tcp_load(QEMUFile *f, struct tcpcb *tp)
984{
985 int i;
986
987 tp->t_state = qemu_get_sbe16(f);
988 for (i = 0; i < TCPT_NTIMERS; i++)
989 tp->t_timer[i] = qemu_get_sbe16(f);
990 tp->t_rxtshift = qemu_get_sbe16(f);
991 tp->t_rxtcur = qemu_get_sbe16(f);
992 tp->t_dupacks = qemu_get_sbe16(f);
993 tp->t_maxseg = qemu_get_be16(f);
994 tp->t_force = qemu_get_sbyte(f);
995 tp->t_flags = qemu_get_be16(f);
996 tp->snd_una = qemu_get_be32(f);
997 tp->snd_nxt = qemu_get_be32(f);
998 tp->snd_up = qemu_get_be32(f);
999 tp->snd_wl1 = qemu_get_be32(f);
1000 tp->snd_wl2 = qemu_get_be32(f);
1001 tp->iss = qemu_get_be32(f);
1002 tp->snd_wnd = qemu_get_be32(f);
1003 tp->rcv_wnd = qemu_get_be32(f);
1004 tp->rcv_nxt = qemu_get_be32(f);
1005 tp->rcv_up = qemu_get_be32(f);
1006 tp->irs = qemu_get_be32(f);
1007 tp->rcv_adv = qemu_get_be32(f);
1008 tp->snd_max = qemu_get_be32(f);
1009 tp->snd_cwnd = qemu_get_be32(f);
1010 tp->snd_ssthresh = qemu_get_be32(f);
1011 tp->t_idle = qemu_get_sbe16(f);
1012 tp->t_rtt = qemu_get_sbe16(f);
1013 tp->t_rtseq = qemu_get_be32(f);
1014 tp->t_srtt = qemu_get_sbe16(f);
1015 tp->t_rttvar = qemu_get_sbe16(f);
1016 tp->t_rttmin = qemu_get_be16(f);
1017 tp->max_sndwnd = qemu_get_be32(f);
1018 tp->t_oobflags = qemu_get_byte(f);
1019 tp->t_iobc = qemu_get_byte(f);
1020 tp->t_softerror = qemu_get_sbe16(f);
1021 tp->snd_scale = qemu_get_byte(f);
1022 tp->rcv_scale = qemu_get_byte(f);
1023 tp->request_r_scale = qemu_get_byte(f);
1024 tp->requested_s_scale = qemu_get_byte(f);
1025 tp->ts_recent = qemu_get_be32(f);
1026 tp->ts_recent_age = qemu_get_be32(f);
1027 tp->last_ack_sent = qemu_get_be32(f);
1028 tcp_template(tp);
1029}
1030
1031static int slirp_sbuf_load(QEMUFile *f, struct sbuf *sbuf)
1032{
1033 uint32_t off, sb_cc, sb_datalen;
1034
1035 sb_cc = qemu_get_be32(f);
1036 sb_datalen = qemu_get_be32(f);
1037
1038 sbreserve(sbuf, sb_datalen);
1039
1040 if (sbuf->sb_datalen != sb_datalen)
1041 return -ENOMEM;
1042
1043 sbuf->sb_cc = sb_cc;
1044
1045 off = qemu_get_sbe32(f);
1046 sbuf->sb_wptr = sbuf->sb_data + off;
1047 off = qemu_get_sbe32(f);
1048 sbuf->sb_rptr = sbuf->sb_data + off;
1049 qemu_get_buffer(f, (unsigned char*)sbuf->sb_data, sbuf->sb_datalen);
1050
1051 return 0;
1052}
1053
1054static int slirp_socket_load(QEMUFile *f, struct socket *so)
1055{
1056 if (tcp_attach(so) < 0)
1057 return -ENOMEM;
1058
1059 so->so_urgc = qemu_get_be32(f);
1060 so->so_faddr.s_addr = qemu_get_be32(f);
1061 so->so_laddr.s_addr = qemu_get_be32(f);
1062 so->so_fport = qemu_get_be16(f);
1063 so->so_lport = qemu_get_be16(f);
1064 so->so_iptos = qemu_get_byte(f);
1065 so->so_emu = qemu_get_byte(f);
1066 so->so_type = qemu_get_byte(f);
1067 so->so_state = qemu_get_be32(f);
1068 if (slirp_sbuf_load(f, &so->so_rcv) < 0)
1069 return -ENOMEM;
1070 if (slirp_sbuf_load(f, &so->so_snd) < 0)
1071 return -ENOMEM;
1072 slirp_tcp_load(f, so->so_tcpcb);
1073
1074 return 0;
1075}
1076
1077static int slirp_state_load(QEMUFile *f, void *opaque, int version_id)
1078{
1079 struct ex_list *ex_ptr;
1080 int r;
1081
1082 while ((r = qemu_get_byte(f))) {
1083 int ret;
1084 struct socket *so = socreate();
1085
1086 if (!so)
1087 return -ENOMEM;
1088
1089 ret = slirp_socket_load(f, so);
1090
1091 if (ret < 0)
1092 return ret;
1093
Jan Kiszkaa13a4122009-06-24 14:42:28 +02001094 if ((so->so_faddr.s_addr & vnetwork_mask.s_addr) !=
1095 vnetwork_addr.s_addr) {
aliguori062e5522009-01-08 19:27:07 +00001096 return -EINVAL;
Jan Kiszkaa13a4122009-06-24 14:42:28 +02001097 }
1098 for (ex_ptr = exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next) {
aliguori062e5522009-01-08 19:27:07 +00001099 if (ex_ptr->ex_pty == 3 &&
Jan Kiszkaa13a4122009-06-24 14:42:28 +02001100 so->so_faddr.s_addr == ex_ptr->ex_addr.s_addr &&
1101 so->so_fport == ex_ptr->ex_fport) {
aliguori062e5522009-01-08 19:27:07 +00001102 break;
Jan Kiszkaa13a4122009-06-24 14:42:28 +02001103 }
1104 }
aliguori062e5522009-01-08 19:27:07 +00001105 if (!ex_ptr)
1106 return -EINVAL;
1107
blueswir10580ac92009-01-12 17:51:06 +00001108 so->extra = (void *)ex_ptr->ex_exec;
aliguori062e5522009-01-08 19:27:07 +00001109 }
1110
Jan Kiszka285f7a62009-06-24 14:42:30 +02001111 if (version_id >= 2) {
1112 ip_id = qemu_get_be16(f);
1113 }
1114
aliguori062e5522009-01-08 19:27:07 +00001115 return 0;
1116}