4 * Copyright (c) 2004-2008 Fabrice Bellard
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:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
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
24 #include "qemu/osdep.h"
28 #include "migration/vmstate.h"
29 #include "migration/qemu-file-types.h"
30 #include "migration/register.h"
32 static int slirp_tcp_post_load(void *opaque
, int version
)
34 tcp_template((struct tcpcb
*)opaque
);
39 static const VMStateDescription vmstate_slirp_tcp
= {
42 .post_load
= slirp_tcp_post_load
,
43 .fields
= (VMStateField
[]) {
44 VMSTATE_INT16(t_state
, struct tcpcb
),
45 VMSTATE_INT16_ARRAY(t_timer
, struct tcpcb
, TCPT_NTIMERS
),
46 VMSTATE_INT16(t_rxtshift
, struct tcpcb
),
47 VMSTATE_INT16(t_rxtcur
, struct tcpcb
),
48 VMSTATE_INT16(t_dupacks
, struct tcpcb
),
49 VMSTATE_UINT16(t_maxseg
, struct tcpcb
),
50 VMSTATE_UINT8(t_force
, struct tcpcb
),
51 VMSTATE_UINT16(t_flags
, struct tcpcb
),
52 VMSTATE_UINT32(snd_una
, struct tcpcb
),
53 VMSTATE_UINT32(snd_nxt
, struct tcpcb
),
54 VMSTATE_UINT32(snd_up
, struct tcpcb
),
55 VMSTATE_UINT32(snd_wl1
, struct tcpcb
),
56 VMSTATE_UINT32(snd_wl2
, struct tcpcb
),
57 VMSTATE_UINT32(iss
, struct tcpcb
),
58 VMSTATE_UINT32(snd_wnd
, struct tcpcb
),
59 VMSTATE_UINT32(rcv_wnd
, struct tcpcb
),
60 VMSTATE_UINT32(rcv_nxt
, struct tcpcb
),
61 VMSTATE_UINT32(rcv_up
, struct tcpcb
),
62 VMSTATE_UINT32(irs
, struct tcpcb
),
63 VMSTATE_UINT32(rcv_adv
, struct tcpcb
),
64 VMSTATE_UINT32(snd_max
, struct tcpcb
),
65 VMSTATE_UINT32(snd_cwnd
, struct tcpcb
),
66 VMSTATE_UINT32(snd_ssthresh
, struct tcpcb
),
67 VMSTATE_INT16(t_idle
, struct tcpcb
),
68 VMSTATE_INT16(t_rtt
, struct tcpcb
),
69 VMSTATE_UINT32(t_rtseq
, struct tcpcb
),
70 VMSTATE_INT16(t_srtt
, struct tcpcb
),
71 VMSTATE_INT16(t_rttvar
, struct tcpcb
),
72 VMSTATE_UINT16(t_rttmin
, struct tcpcb
),
73 VMSTATE_UINT32(max_sndwnd
, struct tcpcb
),
74 VMSTATE_UINT8(t_oobflags
, struct tcpcb
),
75 VMSTATE_UINT8(t_iobc
, struct tcpcb
),
76 VMSTATE_INT16(t_softerror
, struct tcpcb
),
77 VMSTATE_UINT8(snd_scale
, struct tcpcb
),
78 VMSTATE_UINT8(rcv_scale
, struct tcpcb
),
79 VMSTATE_UINT8(request_r_scale
, struct tcpcb
),
80 VMSTATE_UINT8(requested_s_scale
, struct tcpcb
),
81 VMSTATE_UINT32(ts_recent
, struct tcpcb
),
82 VMSTATE_UINT32(ts_recent_age
, struct tcpcb
),
83 VMSTATE_UINT32(last_ack_sent
, struct tcpcb
),
88 /* The sbuf has a pair of pointers that are migrated as offsets;
89 * we calculate the offsets and restore the pointers using
90 * pre_save/post_load on a tmp structure.
97 static int sbuf_tmp_pre_save(void *opaque
)
99 struct sbuf_tmp
*tmp
= opaque
;
100 tmp
->woff
= tmp
->parent
->sb_wptr
- tmp
->parent
->sb_data
;
101 tmp
->roff
= tmp
->parent
->sb_rptr
- tmp
->parent
->sb_data
;
106 static int sbuf_tmp_post_load(void *opaque
, int version
)
108 struct sbuf_tmp
*tmp
= opaque
;
109 uint32_t requested_len
= tmp
->parent
->sb_datalen
;
111 /* Allocate the buffer space used by the field after the tmp */
112 sbreserve(tmp
->parent
, tmp
->parent
->sb_datalen
);
114 if (tmp
->parent
->sb_datalen
!= requested_len
) {
117 if (tmp
->woff
>= requested_len
||
118 tmp
->roff
>= requested_len
) {
119 g_critical("invalid sbuf offsets r/w=%u/%u len=%u",
120 tmp
->roff
, tmp
->woff
, requested_len
);
124 tmp
->parent
->sb_wptr
= tmp
->parent
->sb_data
+ tmp
->woff
;
125 tmp
->parent
->sb_rptr
= tmp
->parent
->sb_data
+ tmp
->roff
;
131 static const VMStateDescription vmstate_slirp_sbuf_tmp
= {
132 .name
= "slirp-sbuf-tmp",
133 .post_load
= sbuf_tmp_post_load
,
134 .pre_save
= sbuf_tmp_pre_save
,
136 .fields
= (VMStateField
[]) {
137 VMSTATE_UINT32(woff
, struct sbuf_tmp
),
138 VMSTATE_UINT32(roff
, struct sbuf_tmp
),
139 VMSTATE_END_OF_LIST()
143 static const VMStateDescription vmstate_slirp_sbuf
= {
144 .name
= "slirp-sbuf",
146 .fields
= (VMStateField
[]) {
147 VMSTATE_UINT32(sb_cc
, struct sbuf
),
148 VMSTATE_UINT32(sb_datalen
, struct sbuf
),
149 VMSTATE_WITH_TMP(struct sbuf
, struct sbuf_tmp
, vmstate_slirp_sbuf_tmp
),
150 VMSTATE_VBUFFER_UINT32(sb_data
, struct sbuf
, 0, NULL
, sb_datalen
),
151 VMSTATE_END_OF_LIST()
155 static bool slirp_older_than_v4(void *opaque
, int version_id
)
157 return version_id
< 4;
160 static bool slirp_family_inet(void *opaque
, int version_id
)
162 union slirp_sockaddr
*ssa
= (union slirp_sockaddr
*)opaque
;
163 return ssa
->ss
.ss_family
== AF_INET
;
166 static int slirp_socket_pre_load(void *opaque
)
168 struct socket
*so
= opaque
;
169 if (tcp_attach(so
) < 0) {
172 /* Older versions don't load these fields */
173 so
->so_ffamily
= AF_INET
;
174 so
->so_lfamily
= AF_INET
;
179 #define VMSTATE_SIN4_ADDR(f, s, t) VMSTATE_UINT32_TEST(f, s, t)
181 /* Win uses u_long rather than uint32_t - but it's still 32bits long */
182 #define VMSTATE_SIN4_ADDR(f, s, t) VMSTATE_SINGLE_TEST(f, s, t, 0, \
183 vmstate_info_uint32, u_long)
186 /* The OS provided ss_family field isn't that portable; it's size
187 * and type varies (16/8 bit, signed, unsigned)
188 * and the values it contains aren't fully portable.
190 typedef struct SS_FamilyTmpStruct
{
191 union slirp_sockaddr
*parent
;
192 uint16_t portable_family
;
193 } SS_FamilyTmpStruct
;
195 #define SS_FAMILY_MIG_IPV4 2 /* Linux, BSD, Win... */
196 #define SS_FAMILY_MIG_IPV6 10 /* Linux */
197 #define SS_FAMILY_MIG_OTHER 0xffff
199 static int ss_family_pre_save(void *opaque
)
201 SS_FamilyTmpStruct
*tss
= opaque
;
203 tss
->portable_family
= SS_FAMILY_MIG_OTHER
;
205 if (tss
->parent
->ss
.ss_family
== AF_INET
) {
206 tss
->portable_family
= SS_FAMILY_MIG_IPV4
;
207 } else if (tss
->parent
->ss
.ss_family
== AF_INET6
) {
208 tss
->portable_family
= SS_FAMILY_MIG_IPV6
;
214 static int ss_family_post_load(void *opaque
, int version_id
)
216 SS_FamilyTmpStruct
*tss
= opaque
;
218 switch (tss
->portable_family
) {
219 case SS_FAMILY_MIG_IPV4
:
220 tss
->parent
->ss
.ss_family
= AF_INET
;
222 case SS_FAMILY_MIG_IPV6
:
223 case 23: /* compatibility: AF_INET6 from mingw */
224 case 28: /* compatibility: AF_INET6 from FreeBSD sys/socket.h */
225 tss
->parent
->ss
.ss_family
= AF_INET6
;
228 g_critical("invalid ss_family type %x", tss
->portable_family
);
235 static const VMStateDescription vmstate_slirp_ss_family
= {
236 .name
= "slirp-socket-addr/ss_family",
237 .pre_save
= ss_family_pre_save
,
238 .post_load
= ss_family_post_load
,
239 .fields
= (VMStateField
[]) {
240 VMSTATE_UINT16(portable_family
, SS_FamilyTmpStruct
),
241 VMSTATE_END_OF_LIST()
245 static const VMStateDescription vmstate_slirp_socket_addr
= {
246 .name
= "slirp-socket-addr",
248 .fields
= (VMStateField
[]) {
249 VMSTATE_WITH_TMP(union slirp_sockaddr
, SS_FamilyTmpStruct
,
250 vmstate_slirp_ss_family
),
251 VMSTATE_SIN4_ADDR(sin
.sin_addr
.s_addr
, union slirp_sockaddr
,
253 VMSTATE_UINT16_TEST(sin
.sin_port
, union slirp_sockaddr
,
257 /* Untested: Needs checking by someone with IPv6 test */
258 VMSTATE_BUFFER_TEST(sin6
.sin6_addr
, union slirp_sockaddr
,
260 VMSTATE_UINT16_TEST(sin6
.sin6_port
, union slirp_sockaddr
,
262 VMSTATE_UINT32_TEST(sin6
.sin6_flowinfo
, union slirp_sockaddr
,
264 VMSTATE_UINT32_TEST(sin6
.sin6_scope_id
, union slirp_sockaddr
,
268 VMSTATE_END_OF_LIST()
272 static const VMStateDescription vmstate_slirp_socket
= {
273 .name
= "slirp-socket",
275 .pre_load
= slirp_socket_pre_load
,
276 .fields
= (VMStateField
[]) {
277 VMSTATE_UINT32(so_urgc
, struct socket
),
278 /* Pre-v4 versions */
279 VMSTATE_SIN4_ADDR(so_faddr
.s_addr
, struct socket
,
280 slirp_older_than_v4
),
281 VMSTATE_SIN4_ADDR(so_laddr
.s_addr
, struct socket
,
282 slirp_older_than_v4
),
283 VMSTATE_UINT16_TEST(so_fport
, struct socket
, slirp_older_than_v4
),
284 VMSTATE_UINT16_TEST(so_lport
, struct socket
, slirp_older_than_v4
),
286 VMSTATE_STRUCT(fhost
, struct socket
, 4, vmstate_slirp_socket_addr
,
287 union slirp_sockaddr
),
288 VMSTATE_STRUCT(lhost
, struct socket
, 4, vmstate_slirp_socket_addr
,
289 union slirp_sockaddr
),
291 VMSTATE_UINT8(so_iptos
, struct socket
),
292 VMSTATE_UINT8(so_emu
, struct socket
),
293 VMSTATE_UINT8(so_type
, struct socket
),
294 VMSTATE_INT32(so_state
, struct socket
),
295 VMSTATE_STRUCT(so_rcv
, struct socket
, 0, vmstate_slirp_sbuf
,
297 VMSTATE_STRUCT(so_snd
, struct socket
, 0, vmstate_slirp_sbuf
,
299 VMSTATE_STRUCT_POINTER(so_tcpcb
, struct socket
, vmstate_slirp_tcp
,
301 VMSTATE_END_OF_LIST()
305 static const VMStateDescription vmstate_slirp_bootp_client
= {
306 .name
= "slirp_bootpclient",
307 .fields
= (VMStateField
[]) {
308 VMSTATE_UINT16(allocated
, BOOTPClient
),
309 VMSTATE_BUFFER(macaddr
, BOOTPClient
),
310 VMSTATE_END_OF_LIST()
314 static const VMStateDescription vmstate_slirp
= {
317 .fields
= (VMStateField
[]) {
318 VMSTATE_UINT16_V(ip_id
, Slirp
, 2),
319 VMSTATE_STRUCT_ARRAY(bootp_clients
, Slirp
, NB_BOOTP_CLIENTS
, 3,
320 vmstate_slirp_bootp_client
, BOOTPClient
),
321 VMSTATE_END_OF_LIST()
325 static void slirp_state_save(QEMUFile
*f
, void *opaque
)
327 Slirp
*slirp
= opaque
;
328 struct gfwd_list
*ex_ptr
;
330 for (ex_ptr
= slirp
->guestfwd_list
; ex_ptr
; ex_ptr
= ex_ptr
->ex_next
)
331 if (ex_ptr
->write_cb
) {
333 so
= slirp_find_ctl_socket(slirp
, ex_ptr
->ex_addr
,
334 ntohs(ex_ptr
->ex_fport
));
339 qemu_put_byte(f
, 42);
340 vmstate_save_state(f
, &vmstate_slirp_socket
, so
, NULL
);
344 vmstate_save_state(f
, &vmstate_slirp
, slirp
, NULL
);
348 static int slirp_state_load(QEMUFile
*f
, void *opaque
, int version_id
)
350 Slirp
*slirp
= opaque
;
351 struct gfwd_list
*ex_ptr
;
353 while (qemu_get_byte(f
)) {
355 struct socket
*so
= socreate(slirp
);
357 ret
= vmstate_load_state(f
, &vmstate_slirp_socket
, so
, version_id
);
362 if ((so
->so_faddr
.s_addr
& slirp
->vnetwork_mask
.s_addr
) !=
363 slirp
->vnetwork_addr
.s_addr
) {
366 for (ex_ptr
= slirp
->guestfwd_list
; ex_ptr
; ex_ptr
= ex_ptr
->ex_next
) {
367 if (ex_ptr
->write_cb
&&
368 so
->so_faddr
.s_addr
== ex_ptr
->ex_addr
.s_addr
&&
369 so
->so_fport
== ex_ptr
->ex_fport
) {
378 return vmstate_load_state(f
, &vmstate_slirp
, slirp
, version_id
);
381 void slirp_state_register(Slirp
*slirp
)
383 static SaveVMHandlers savevm_slirp_state
= {
384 .save_state
= slirp_state_save
,
385 .load_state
= slirp_state_load
,
388 register_savevm_live(NULL
, "slirp", 0, 4, &savevm_slirp_state
, slirp
);
391 void slirp_state_unregister(Slirp
*slirp
)
393 unregister_savevm(NULL
, "slirp", slirp
);