]> Git Repo - qemu.git/blob - slirp/src/state.c
hw/pci-host: Use object_initialize_child for correct reference counting
[qemu.git] / slirp / src / state.c
1 /* SPDX-License-Identifier: MIT */
2 /*
3  * libslirp
4  *
5  * Copyright (c) 2004-2008 Fabrice Bellard
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining a copy
8  * of this software and associated documentation files (the "Software"), to deal
9  * in the Software without restriction, including without limitation the rights
10  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11  * copies of the Software, and to permit persons to whom the Software is
12  * furnished to do so, subject to the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be included in
15  * all copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23  * THE SOFTWARE.
24  */
25 #include "slirp.h"
26 #include "vmstate.h"
27 #include "stream.h"
28
29 static int slirp_tcp_post_load(void *opaque, int version)
30 {
31     tcp_template((struct tcpcb *)opaque);
32
33     return 0;
34 }
35
36 static const VMStateDescription vmstate_slirp_tcp = {
37     .name = "slirp-tcp",
38     .version_id = 0,
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),
81         VMSTATE_END_OF_LIST()
82     }
83 };
84
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.
88  */
89 struct sbuf_tmp {
90     struct sbuf *parent;
91     uint32_t roff, woff;
92 };
93
94 static int sbuf_tmp_pre_save(void *opaque)
95 {
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;
99
100     return 0;
101 }
102
103 static int sbuf_tmp_post_load(void *opaque, int version)
104 {
105     struct sbuf_tmp *tmp = opaque;
106     uint32_t requested_len = tmp->parent->sb_datalen;
107
108     /* Allocate the buffer space used by the field after the tmp */
109     sbreserve(tmp->parent, tmp->parent->sb_datalen);
110
111     if (tmp->parent->sb_datalen != requested_len) {
112         return -ENOMEM;
113     }
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);
118         return -EINVAL;
119     }
120
121     tmp->parent->sb_wptr = tmp->parent->sb_data + tmp->woff;
122     tmp->parent->sb_rptr = tmp->parent->sb_data + tmp->roff;
123
124     return 0;
125 }
126
127
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,
132     .version_id = 0,
133     .fields = (VMStateField[]) {
134         VMSTATE_UINT32(woff, struct sbuf_tmp),
135         VMSTATE_UINT32(roff, struct sbuf_tmp),
136         VMSTATE_END_OF_LIST()
137     }
138 };
139
140 static const VMStateDescription vmstate_slirp_sbuf = {
141     .name = "slirp-sbuf",
142     .version_id = 0,
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()
149     }
150 };
151
152 static bool slirp_older_than_v4(void *opaque, int version_id)
153 {
154     return version_id < 4;
155 }
156
157 static bool slirp_family_inet(void *opaque, int version_id)
158 {
159     union slirp_sockaddr *ssa = (union slirp_sockaddr *)opaque;
160     return ssa->ss.ss_family == AF_INET;
161 }
162
163 static int slirp_socket_pre_load(void *opaque)
164 {
165     struct socket *so = opaque;
166     if (tcp_attach(so) < 0) {
167         return -ENOMEM;
168     }
169     /* Older versions don't load these fields */
170     so->so_ffamily = AF_INET;
171     so->so_lfamily = AF_INET;
172     return 0;
173 }
174
175 #ifndef _WIN32
176 #define VMSTATE_SIN4_ADDR(f, s, t) VMSTATE_UINT32_TEST(f, s, t)
177 #else
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)
181 #endif
182
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.
186  */
187 typedef struct SS_FamilyTmpStruct {
188     union slirp_sockaddr    *parent;
189     uint16_t                 portable_family;
190 } SS_FamilyTmpStruct;
191
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
195
196 static int ss_family_pre_save(void *opaque)
197 {
198     SS_FamilyTmpStruct *tss = opaque;
199
200     tss->portable_family = SS_FAMILY_MIG_OTHER;
201
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;
206     }
207
208     return 0;
209 }
210
211 static int ss_family_post_load(void *opaque, int version_id)
212 {
213     SS_FamilyTmpStruct *tss = opaque;
214
215     switch (tss->portable_family) {
216     case SS_FAMILY_MIG_IPV4:
217         tss->parent->ss.ss_family = AF_INET;
218         break;
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;
223         break;
224     default:
225         g_critical("invalid ss_family type %x", tss->portable_family);
226         return -EINVAL;
227     }
228
229     return 0;
230 }
231
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()
239     }
240 };
241
242 static const VMStateDescription vmstate_slirp_socket_addr = {
243     .name = "slirp-socket-addr",
244     .version_id = 4,
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,
249                             slirp_family_inet),
250         VMSTATE_UINT16_TEST(sin.sin_port, union slirp_sockaddr,
251                             slirp_family_inet),
252
253 #if 0
254         /* Untested: Needs checking by someone with IPv6 test */
255         VMSTATE_BUFFER_TEST(sin6.sin6_addr, union slirp_sockaddr,
256                             slirp_family_inet6),
257         VMSTATE_UINT16_TEST(sin6.sin6_port, union slirp_sockaddr,
258                             slirp_family_inet6),
259         VMSTATE_UINT32_TEST(sin6.sin6_flowinfo, union slirp_sockaddr,
260                             slirp_family_inet6),
261         VMSTATE_UINT32_TEST(sin6.sin6_scope_id, union slirp_sockaddr,
262                             slirp_family_inet6),
263 #endif
264
265         VMSTATE_END_OF_LIST()
266     }
267 };
268
269 static const VMStateDescription vmstate_slirp_socket = {
270     .name = "slirp-socket",
271     .version_id = 4,
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),
282         /* v4 and newer */
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),
287
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,
293                        struct sbuf),
294         VMSTATE_STRUCT(so_snd, struct socket, 0, vmstate_slirp_sbuf,
295                        struct sbuf),
296         VMSTATE_STRUCT_POINTER(so_tcpcb, struct socket, vmstate_slirp_tcp,
297                        struct tcpcb),
298         VMSTATE_END_OF_LIST()
299     }
300 };
301
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()
308     }
309 };
310
311 static const VMStateDescription vmstate_slirp = {
312     .name = "slirp",
313     .version_id = 4,
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()
319     }
320 };
321
322 void slirp_state_save(Slirp *slirp, SlirpWriteCb write_cb, void *opaque)
323 {
324     struct gfwd_list *ex_ptr;
325     SlirpOStream f = {
326         .write_cb = write_cb,
327         .opaque = opaque,
328     };
329
330     for (ex_ptr = slirp->guestfwd_list; ex_ptr; ex_ptr = ex_ptr->ex_next)
331         if (ex_ptr->write_cb) {
332             struct socket *so;
333             so = slirp_find_ctl_socket(slirp, ex_ptr->ex_addr,
334                                        ntohs(ex_ptr->ex_fport));
335             if (!so) {
336                 continue;
337             }
338
339             slirp_ostream_write_u8(&f, 42);
340             slirp_vmstate_save_state(&f, &vmstate_slirp_socket, so);
341         }
342     slirp_ostream_write_u8(&f, 0);
343
344     slirp_vmstate_save_state(&f, &vmstate_slirp, slirp);
345 }
346
347
348 int slirp_state_load(Slirp *slirp, int version_id,
349                      SlirpReadCb read_cb, void *opaque)
350 {
351     struct gfwd_list *ex_ptr;
352     SlirpIStream f = {
353         .read_cb = read_cb,
354         .opaque = opaque,
355     };
356
357     while (slirp_istream_read_u8(&f)) {
358         int ret;
359         struct socket *so = socreate(slirp);
360
361         ret = slirp_vmstate_load_state(&f, &vmstate_slirp_socket, so, version_id);
362         if (ret < 0) {
363             return ret;
364         }
365
366         if ((so->so_faddr.s_addr & slirp->vnetwork_mask.s_addr) !=
367             slirp->vnetwork_addr.s_addr) {
368             return -EINVAL;
369         }
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) {
374                 break;
375             }
376         }
377         if (!ex_ptr) {
378             return -EINVAL;
379         }
380     }
381
382     return slirp_vmstate_load_state(&f, &vmstate_slirp, slirp, version_id);
383 }
384
385 int slirp_state_version(void)
386 {
387     return 4;
388 }
This page took 0.043911 seconds and 4 git commands to generate.