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
29 static int slirp_tcp_post_load(void *opaque
, int version
)
31 tcp_template((struct tcpcb
*)opaque
);
36 static const VMStateDescription vmstate_slirp_tcp
= {
39 .post_load
= slirp_tcp_post_load
,
40 .fields
= (VMStateField
[]) {
41 VMSTATE_INT16(t_state
, struct tcpcb
),
42 VMSTATE_INT16_ARRAY(t_timer
, struct tcpcb
, TCPT_NTIMERS
),
43 VMSTATE_INT16(t_rxtshift
, struct tcpcb
),
44 VMSTATE_INT16(t_rxtcur
, struct tcpcb
),
45 VMSTATE_INT16(t_dupacks
, struct tcpcb
),
46 VMSTATE_UINT16(t_maxseg
, struct tcpcb
),
47 VMSTATE_UINT8(t_force
, struct tcpcb
),
48 VMSTATE_UINT16(t_flags
, struct tcpcb
),
49 VMSTATE_UINT32(snd_una
, struct tcpcb
),
50 VMSTATE_UINT32(snd_nxt
, struct tcpcb
),
51 VMSTATE_UINT32(snd_up
, struct tcpcb
),
52 VMSTATE_UINT32(snd_wl1
, struct tcpcb
),
53 VMSTATE_UINT32(snd_wl2
, struct tcpcb
),
54 VMSTATE_UINT32(iss
, struct tcpcb
),
55 VMSTATE_UINT32(snd_wnd
, struct tcpcb
),
56 VMSTATE_UINT32(rcv_wnd
, struct tcpcb
),
57 VMSTATE_UINT32(rcv_nxt
, struct tcpcb
),
58 VMSTATE_UINT32(rcv_up
, struct tcpcb
),
59 VMSTATE_UINT32(irs
, struct tcpcb
),
60 VMSTATE_UINT32(rcv_adv
, struct tcpcb
),
61 VMSTATE_UINT32(snd_max
, struct tcpcb
),
62 VMSTATE_UINT32(snd_cwnd
, struct tcpcb
),
63 VMSTATE_UINT32(snd_ssthresh
, struct tcpcb
),
64 VMSTATE_INT16(t_idle
, struct tcpcb
),
65 VMSTATE_INT16(t_rtt
, struct tcpcb
),
66 VMSTATE_UINT32(t_rtseq
, struct tcpcb
),
67 VMSTATE_INT16(t_srtt
, struct tcpcb
),
68 VMSTATE_INT16(t_rttvar
, struct tcpcb
),
69 VMSTATE_UINT16(t_rttmin
, struct tcpcb
),
70 VMSTATE_UINT32(max_sndwnd
, struct tcpcb
),
71 VMSTATE_UINT8(t_oobflags
, struct tcpcb
),
72 VMSTATE_UINT8(t_iobc
, struct tcpcb
),
73 VMSTATE_INT16(t_softerror
, struct tcpcb
),
74 VMSTATE_UINT8(snd_scale
, struct tcpcb
),
75 VMSTATE_UINT8(rcv_scale
, struct tcpcb
),
76 VMSTATE_UINT8(request_r_scale
, struct tcpcb
),
77 VMSTATE_UINT8(requested_s_scale
, struct tcpcb
),
78 VMSTATE_UINT32(ts_recent
, struct tcpcb
),
79 VMSTATE_UINT32(ts_recent_age
, struct tcpcb
),
80 VMSTATE_UINT32(last_ack_sent
, struct tcpcb
),
85 /* The sbuf has a pair of pointers that are migrated as offsets;
86 * we calculate the offsets and restore the pointers using
87 * pre_save/post_load on a tmp structure.
94 static int sbuf_tmp_pre_save(void *opaque
)
96 struct sbuf_tmp
*tmp
= opaque
;
97 tmp
->woff
= tmp
->parent
->sb_wptr
- tmp
->parent
->sb_data
;
98 tmp
->roff
= tmp
->parent
->sb_rptr
- tmp
->parent
->sb_data
;
103 static int sbuf_tmp_post_load(void *opaque
, int version
)
105 struct sbuf_tmp
*tmp
= opaque
;
106 uint32_t requested_len
= tmp
->parent
->sb_datalen
;
108 /* Allocate the buffer space used by the field after the tmp */
109 sbreserve(tmp
->parent
, tmp
->parent
->sb_datalen
);
111 if (tmp
->parent
->sb_datalen
!= requested_len
) {
114 if (tmp
->woff
>= requested_len
||
115 tmp
->roff
>= requested_len
) {
116 g_critical("invalid sbuf offsets r/w=%u/%u len=%u",
117 tmp
->roff
, tmp
->woff
, requested_len
);
121 tmp
->parent
->sb_wptr
= tmp
->parent
->sb_data
+ tmp
->woff
;
122 tmp
->parent
->sb_rptr
= tmp
->parent
->sb_data
+ tmp
->roff
;
128 static const VMStateDescription vmstate_slirp_sbuf_tmp
= {
129 .name
= "slirp-sbuf-tmp",
130 .post_load
= sbuf_tmp_post_load
,
131 .pre_save
= sbuf_tmp_pre_save
,
133 .fields
= (VMStateField
[]) {
134 VMSTATE_UINT32(woff
, struct sbuf_tmp
),
135 VMSTATE_UINT32(roff
, struct sbuf_tmp
),
136 VMSTATE_END_OF_LIST()
140 static const VMStateDescription vmstate_slirp_sbuf
= {
141 .name
= "slirp-sbuf",
143 .fields
= (VMStateField
[]) {
144 VMSTATE_UINT32(sb_cc
, struct sbuf
),
145 VMSTATE_UINT32(sb_datalen
, struct sbuf
),
146 VMSTATE_WITH_TMP(struct sbuf
, struct sbuf_tmp
, vmstate_slirp_sbuf_tmp
),
147 VMSTATE_VBUFFER_UINT32(sb_data
, struct sbuf
, 0, NULL
, sb_datalen
),
148 VMSTATE_END_OF_LIST()
152 static bool slirp_older_than_v4(void *opaque
, int version_id
)
154 return version_id
< 4;
157 static bool slirp_family_inet(void *opaque
, int version_id
)
159 union slirp_sockaddr
*ssa
= (union slirp_sockaddr
*)opaque
;
160 return ssa
->ss
.ss_family
== AF_INET
;
163 static int slirp_socket_pre_load(void *opaque
)
165 struct socket
*so
= opaque
;
166 if (tcp_attach(so
) < 0) {
169 /* Older versions don't load these fields */
170 so
->so_ffamily
= AF_INET
;
171 so
->so_lfamily
= AF_INET
;
176 #define VMSTATE_SIN4_ADDR(f, s, t) VMSTATE_UINT32_TEST(f, s, t)
178 /* Win uses u_long rather than uint32_t - but it's still 32bits long */
179 #define VMSTATE_SIN4_ADDR(f, s, t) VMSTATE_SINGLE_TEST(f, s, t, 0, \
180 slirp_vmstate_info_uint32, u_long)
183 /* The OS provided ss_family field isn't that portable; it's size
184 * and type varies (16/8 bit, signed, unsigned)
185 * and the values it contains aren't fully portable.
187 typedef struct SS_FamilyTmpStruct
{
188 union slirp_sockaddr
*parent
;
189 uint16_t portable_family
;
190 } SS_FamilyTmpStruct
;
192 #define SS_FAMILY_MIG_IPV4 2 /* Linux, BSD, Win... */
193 #define SS_FAMILY_MIG_IPV6 10 /* Linux */
194 #define SS_FAMILY_MIG_OTHER 0xffff
196 static int ss_family_pre_save(void *opaque
)
198 SS_FamilyTmpStruct
*tss
= opaque
;
200 tss
->portable_family
= SS_FAMILY_MIG_OTHER
;
202 if (tss
->parent
->ss
.ss_family
== AF_INET
) {
203 tss
->portable_family
= SS_FAMILY_MIG_IPV4
;
204 } else if (tss
->parent
->ss
.ss_family
== AF_INET6
) {
205 tss
->portable_family
= SS_FAMILY_MIG_IPV6
;
211 static int ss_family_post_load(void *opaque
, int version_id
)
213 SS_FamilyTmpStruct
*tss
= opaque
;
215 switch (tss
->portable_family
) {
216 case SS_FAMILY_MIG_IPV4
:
217 tss
->parent
->ss
.ss_family
= AF_INET
;
219 case SS_FAMILY_MIG_IPV6
:
220 case 23: /* compatibility: AF_INET6 from mingw */
221 case 28: /* compatibility: AF_INET6 from FreeBSD sys/socket.h */
222 tss
->parent
->ss
.ss_family
= AF_INET6
;
225 g_critical("invalid ss_family type %x", tss
->portable_family
);
232 static const VMStateDescription vmstate_slirp_ss_family
= {
233 .name
= "slirp-socket-addr/ss_family",
234 .pre_save
= ss_family_pre_save
,
235 .post_load
= ss_family_post_load
,
236 .fields
= (VMStateField
[]) {
237 VMSTATE_UINT16(portable_family
, SS_FamilyTmpStruct
),
238 VMSTATE_END_OF_LIST()
242 static const VMStateDescription vmstate_slirp_socket_addr
= {
243 .name
= "slirp-socket-addr",
245 .fields
= (VMStateField
[]) {
246 VMSTATE_WITH_TMP(union slirp_sockaddr
, SS_FamilyTmpStruct
,
247 vmstate_slirp_ss_family
),
248 VMSTATE_SIN4_ADDR(sin
.sin_addr
.s_addr
, union slirp_sockaddr
,
250 VMSTATE_UINT16_TEST(sin
.sin_port
, union slirp_sockaddr
,
254 /* Untested: Needs checking by someone with IPv6 test */
255 VMSTATE_BUFFER_TEST(sin6
.sin6_addr
, union slirp_sockaddr
,
257 VMSTATE_UINT16_TEST(sin6
.sin6_port
, union slirp_sockaddr
,
259 VMSTATE_UINT32_TEST(sin6
.sin6_flowinfo
, union slirp_sockaddr
,
261 VMSTATE_UINT32_TEST(sin6
.sin6_scope_id
, union slirp_sockaddr
,
265 VMSTATE_END_OF_LIST()
269 static const VMStateDescription vmstate_slirp_socket
= {
270 .name
= "slirp-socket",
272 .pre_load
= slirp_socket_pre_load
,
273 .fields
= (VMStateField
[]) {
274 VMSTATE_UINT32(so_urgc
, struct socket
),
275 /* Pre-v4 versions */
276 VMSTATE_SIN4_ADDR(so_faddr
.s_addr
, struct socket
,
277 slirp_older_than_v4
),
278 VMSTATE_SIN4_ADDR(so_laddr
.s_addr
, struct socket
,
279 slirp_older_than_v4
),
280 VMSTATE_UINT16_TEST(so_fport
, struct socket
, slirp_older_than_v4
),
281 VMSTATE_UINT16_TEST(so_lport
, struct socket
, slirp_older_than_v4
),
283 VMSTATE_STRUCT(fhost
, struct socket
, 4, vmstate_slirp_socket_addr
,
284 union slirp_sockaddr
),
285 VMSTATE_STRUCT(lhost
, struct socket
, 4, vmstate_slirp_socket_addr
,
286 union slirp_sockaddr
),
288 VMSTATE_UINT8(so_iptos
, struct socket
),
289 VMSTATE_UINT8(so_emu
, struct socket
),
290 VMSTATE_UINT8(so_type
, struct socket
),
291 VMSTATE_INT32(so_state
, struct socket
),
292 VMSTATE_STRUCT(so_rcv
, struct socket
, 0, vmstate_slirp_sbuf
,
294 VMSTATE_STRUCT(so_snd
, struct socket
, 0, vmstate_slirp_sbuf
,
296 VMSTATE_STRUCT_POINTER(so_tcpcb
, struct socket
, vmstate_slirp_tcp
,
298 VMSTATE_END_OF_LIST()
302 static const VMStateDescription vmstate_slirp_bootp_client
= {
303 .name
= "slirp_bootpclient",
304 .fields
= (VMStateField
[]) {
305 VMSTATE_UINT16(allocated
, BOOTPClient
),
306 VMSTATE_BUFFER(macaddr
, BOOTPClient
),
307 VMSTATE_END_OF_LIST()
311 static const VMStateDescription vmstate_slirp
= {
314 .fields
= (VMStateField
[]) {
315 VMSTATE_UINT16_V(ip_id
, Slirp
, 2),
316 VMSTATE_STRUCT_ARRAY(bootp_clients
, Slirp
, NB_BOOTP_CLIENTS
, 3,
317 vmstate_slirp_bootp_client
, BOOTPClient
),
318 VMSTATE_END_OF_LIST()
322 void slirp_state_save(Slirp
*slirp
, SlirpWriteCb write_cb
, void *opaque
)
324 struct gfwd_list
*ex_ptr
;
326 .write_cb
= write_cb
,
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 slirp_ostream_write_u8(&f
, 42);
340 slirp_vmstate_save_state(&f
, &vmstate_slirp_socket
, so
);
342 slirp_ostream_write_u8(&f
, 0);
344 slirp_vmstate_save_state(&f
, &vmstate_slirp
, slirp
);
348 int slirp_state_load(Slirp
*slirp
, int version_id
,
349 SlirpReadCb read_cb
, void *opaque
)
351 struct gfwd_list
*ex_ptr
;
357 while (slirp_istream_read_u8(&f
)) {
359 struct socket
*so
= socreate(slirp
);
361 ret
= slirp_vmstate_load_state(&f
, &vmstate_slirp_socket
, so
, version_id
);
366 if ((so
->so_faddr
.s_addr
& slirp
->vnetwork_mask
.s_addr
) !=
367 slirp
->vnetwork_addr
.s_addr
) {
370 for (ex_ptr
= slirp
->guestfwd_list
; ex_ptr
; ex_ptr
= ex_ptr
->ex_next
) {
371 if (ex_ptr
->write_cb
&&
372 so
->so_faddr
.s_addr
== ex_ptr
->ex_addr
.s_addr
&&
373 so
->so_fport
== ex_ptr
->ex_fport
) {
382 return slirp_vmstate_load_state(&f
, &vmstate_slirp
, slirp
, version_id
);
385 int slirp_state_version(void)