1 | /* |
2 | * This program is free software; you can redistribute it and/or modify |
3 | * it under the terms of the GNU General Public License as published by |
4 | * the Free Software Foundation; either version 2 of the License, or |
5 | * (at your option) any later version. |
6 | * |
7 | * This program is distributed in the hope that it will be useful, |
8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
10 | * GNU General Public License for more details. |
11 | * |
12 | * You should have received a copy of the GNU General Public License |
13 | * along with this program; if not, see <http://www.gnu.org/licenses/>. |
14 | */ |
15 | |
16 | #include "qemu/osdep.h" |
17 | |
18 | #include <sys/signalfd.h> |
19 | #include <linux/unistd.h> |
20 | #include <linux/audit.h> |
21 | #ifdef CONFIG_INOTIFY |
22 | #include <sys/inotify.h> |
23 | #endif |
24 | #include <linux/netlink.h> |
25 | #ifdef CONFIG_RTNETLINK |
26 | #include <linux/rtnetlink.h> |
27 | #include <linux/if_bridge.h> |
28 | #endif |
29 | #include "qemu.h" |
30 | #include "fd-trans.h" |
31 | |
32 | enum { |
33 | QEMU_IFLA_BR_UNSPEC, |
34 | QEMU_IFLA_BR_FORWARD_DELAY, |
35 | QEMU_IFLA_BR_HELLO_TIME, |
36 | QEMU_IFLA_BR_MAX_AGE, |
37 | QEMU_IFLA_BR_AGEING_TIME, |
38 | QEMU_IFLA_BR_STP_STATE, |
39 | QEMU_IFLA_BR_PRIORITY, |
40 | QEMU_IFLA_BR_VLAN_FILTERING, |
41 | QEMU_IFLA_BR_VLAN_PROTOCOL, |
42 | QEMU_IFLA_BR_GROUP_FWD_MASK, |
43 | QEMU_IFLA_BR_ROOT_ID, |
44 | QEMU_IFLA_BR_BRIDGE_ID, |
45 | QEMU_IFLA_BR_ROOT_PORT, |
46 | QEMU_IFLA_BR_ROOT_PATH_COST, |
47 | QEMU_IFLA_BR_TOPOLOGY_CHANGE, |
48 | QEMU_IFLA_BR_TOPOLOGY_CHANGE_DETECTED, |
49 | QEMU_IFLA_BR_HELLO_TIMER, |
50 | QEMU_IFLA_BR_TCN_TIMER, |
51 | QEMU_IFLA_BR_TOPOLOGY_CHANGE_TIMER, |
52 | QEMU_IFLA_BR_GC_TIMER, |
53 | QEMU_IFLA_BR_GROUP_ADDR, |
54 | QEMU_IFLA_BR_FDB_FLUSH, |
55 | QEMU_IFLA_BR_MCAST_ROUTER, |
56 | QEMU_IFLA_BR_MCAST_SNOOPING, |
57 | QEMU_IFLA_BR_MCAST_QUERY_USE_IFADDR, |
58 | QEMU_IFLA_BR_MCAST_QUERIER, |
59 | QEMU_IFLA_BR_MCAST_HASH_ELASTICITY, |
60 | QEMU_IFLA_BR_MCAST_HASH_MAX, |
61 | QEMU_IFLA_BR_MCAST_LAST_MEMBER_CNT, |
62 | QEMU_IFLA_BR_MCAST_STARTUP_QUERY_CNT, |
63 | QEMU_IFLA_BR_MCAST_LAST_MEMBER_INTVL, |
64 | QEMU_IFLA_BR_MCAST_MEMBERSHIP_INTVL, |
65 | QEMU_IFLA_BR_MCAST_QUERIER_INTVL, |
66 | QEMU_IFLA_BR_MCAST_QUERY_INTVL, |
67 | QEMU_IFLA_BR_MCAST_QUERY_RESPONSE_INTVL, |
68 | QEMU_IFLA_BR_MCAST_STARTUP_QUERY_INTVL, |
69 | QEMU_IFLA_BR_NF_CALL_IPTABLES, |
70 | QEMU_IFLA_BR_NF_CALL_IP6TABLES, |
71 | QEMU_IFLA_BR_NF_CALL_ARPTABLES, |
72 | QEMU_IFLA_BR_VLAN_DEFAULT_PVID, |
73 | QEMU_IFLA_BR_PAD, |
74 | QEMU_IFLA_BR_VLAN_STATS_ENABLED, |
75 | QEMU_IFLA_BR_MCAST_STATS_ENABLED, |
76 | QEMU_IFLA_BR_MCAST_IGMP_VERSION, |
77 | QEMU_IFLA_BR_MCAST_MLD_VERSION, |
78 | QEMU_IFLA_BR_VLAN_STATS_PER_PORT, |
79 | QEMU_IFLA_BR_MULTI_BOOLOPT, |
80 | QEMU___IFLA_BR_MAX, |
81 | }; |
82 | |
83 | enum { |
84 | QEMU_IFLA_UNSPEC, |
85 | QEMU_IFLA_ADDRESS, |
86 | QEMU_IFLA_BROADCAST, |
87 | QEMU_IFLA_IFNAME, |
88 | QEMU_IFLA_MTU, |
89 | QEMU_IFLA_LINK, |
90 | QEMU_IFLA_QDISC, |
91 | QEMU_IFLA_STATS, |
92 | QEMU_IFLA_COST, |
93 | QEMU_IFLA_PRIORITY, |
94 | QEMU_IFLA_MASTER, |
95 | QEMU_IFLA_WIRELESS, |
96 | QEMU_IFLA_PROTINFO, |
97 | QEMU_IFLA_TXQLEN, |
98 | QEMU_IFLA_MAP, |
99 | QEMU_IFLA_WEIGHT, |
100 | QEMU_IFLA_OPERSTATE, |
101 | QEMU_IFLA_LINKMODE, |
102 | QEMU_IFLA_LINKINFO, |
103 | QEMU_IFLA_NET_NS_PID, |
104 | QEMU_IFLA_IFALIAS, |
105 | QEMU_IFLA_NUM_VF, |
106 | QEMU_IFLA_VFINFO_LIST, |
107 | QEMU_IFLA_STATS64, |
108 | QEMU_IFLA_VF_PORTS, |
109 | QEMU_IFLA_PORT_SELF, |
110 | QEMU_IFLA_AF_SPEC, |
111 | QEMU_IFLA_GROUP, |
112 | QEMU_IFLA_NET_NS_FD, |
113 | QEMU_IFLA_EXT_MASK, |
114 | QEMU_IFLA_PROMISCUITY, |
115 | QEMU_IFLA_NUM_TX_QUEUES, |
116 | QEMU_IFLA_NUM_RX_QUEUES, |
117 | QEMU_IFLA_CARRIER, |
118 | QEMU_IFLA_PHYS_PORT_ID, |
119 | QEMU_IFLA_CARRIER_CHANGES, |
120 | QEMU_IFLA_PHYS_SWITCH_ID, |
121 | QEMU_IFLA_LINK_NETNSID, |
122 | QEMU_IFLA_PHYS_PORT_NAME, |
123 | QEMU_IFLA_PROTO_DOWN, |
124 | QEMU_IFLA_GSO_MAX_SEGS, |
125 | QEMU_IFLA_GSO_MAX_SIZE, |
126 | QEMU_IFLA_PAD, |
127 | QEMU_IFLA_XDP, |
128 | QEMU_IFLA_EVENT, |
129 | QEMU_IFLA_NEW_NETNSID, |
130 | QEMU_IFLA_IF_NETNSID, |
131 | QEMU_IFLA_CARRIER_UP_COUNT, |
132 | QEMU_IFLA_CARRIER_DOWN_COUNT, |
133 | QEMU_IFLA_NEW_IFINDEX, |
134 | QEMU_IFLA_MIN_MTU, |
135 | QEMU_IFLA_MAX_MTU, |
136 | QEMU___IFLA_MAX |
137 | }; |
138 | |
139 | enum { |
140 | QEMU_IFLA_BRPORT_UNSPEC, |
141 | QEMU_IFLA_BRPORT_STATE, |
142 | QEMU_IFLA_BRPORT_PRIORITY, |
143 | QEMU_IFLA_BRPORT_COST, |
144 | QEMU_IFLA_BRPORT_MODE, |
145 | QEMU_IFLA_BRPORT_GUARD, |
146 | QEMU_IFLA_BRPORT_PROTECT, |
147 | QEMU_IFLA_BRPORT_FAST_LEAVE, |
148 | QEMU_IFLA_BRPORT_LEARNING, |
149 | QEMU_IFLA_BRPORT_UNICAST_FLOOD, |
150 | QEMU_IFLA_BRPORT_PROXYARP, |
151 | QEMU_IFLA_BRPORT_LEARNING_SYNC, |
152 | QEMU_IFLA_BRPORT_PROXYARP_WIFI, |
153 | QEMU_IFLA_BRPORT_ROOT_ID, |
154 | QEMU_IFLA_BRPORT_BRIDGE_ID, |
155 | QEMU_IFLA_BRPORT_DESIGNATED_PORT, |
156 | QEMU_IFLA_BRPORT_DESIGNATED_COST, |
157 | QEMU_IFLA_BRPORT_ID, |
158 | QEMU_IFLA_BRPORT_NO, |
159 | QEMU_IFLA_BRPORT_TOPOLOGY_CHANGE_ACK, |
160 | QEMU_IFLA_BRPORT_CONFIG_PENDING, |
161 | QEMU_IFLA_BRPORT_MESSAGE_AGE_TIMER, |
162 | QEMU_IFLA_BRPORT_FORWARD_DELAY_TIMER, |
163 | QEMU_IFLA_BRPORT_HOLD_TIMER, |
164 | QEMU_IFLA_BRPORT_FLUSH, |
165 | QEMU_IFLA_BRPORT_MULTICAST_ROUTER, |
166 | QEMU_IFLA_BRPORT_PAD, |
167 | QEMU_IFLA_BRPORT_MCAST_FLOOD, |
168 | QEMU_IFLA_BRPORT_MCAST_TO_UCAST, |
169 | QEMU_IFLA_BRPORT_VLAN_TUNNEL, |
170 | QEMU_IFLA_BRPORT_BCAST_FLOOD, |
171 | QEMU_IFLA_BRPORT_GROUP_FWD_MASK, |
172 | QEMU_IFLA_BRPORT_NEIGH_SUPPRESS, |
173 | QEMU_IFLA_BRPORT_ISOLATED, |
174 | QEMU_IFLA_BRPORT_BACKUP_PORT, |
175 | QEMU___IFLA_BRPORT_MAX |
176 | }; |
177 | |
178 | enum { |
179 | QEMU_IFLA_TUN_UNSPEC, |
180 | QEMU_IFLA_TUN_OWNER, |
181 | QEMU_IFLA_TUN_GROUP, |
182 | QEMU_IFLA_TUN_TYPE, |
183 | QEMU_IFLA_TUN_PI, |
184 | QEMU_IFLA_TUN_VNET_HDR, |
185 | QEMU_IFLA_TUN_PERSIST, |
186 | QEMU_IFLA_TUN_MULTI_QUEUE, |
187 | QEMU_IFLA_TUN_NUM_QUEUES, |
188 | QEMU_IFLA_TUN_NUM_DISABLED_QUEUES, |
189 | QEMU___IFLA_TUN_MAX, |
190 | }; |
191 | |
192 | enum { |
193 | QEMU_IFLA_INFO_UNSPEC, |
194 | QEMU_IFLA_INFO_KIND, |
195 | QEMU_IFLA_INFO_DATA, |
196 | QEMU_IFLA_INFO_XSTATS, |
197 | QEMU_IFLA_INFO_SLAVE_KIND, |
198 | QEMU_IFLA_INFO_SLAVE_DATA, |
199 | QEMU___IFLA_INFO_MAX, |
200 | }; |
201 | |
202 | enum { |
203 | QEMU_IFLA_INET_UNSPEC, |
204 | QEMU_IFLA_INET_CONF, |
205 | QEMU___IFLA_INET_MAX, |
206 | }; |
207 | |
208 | enum { |
209 | QEMU_IFLA_INET6_UNSPEC, |
210 | QEMU_IFLA_INET6_FLAGS, |
211 | QEMU_IFLA_INET6_CONF, |
212 | QEMU_IFLA_INET6_STATS, |
213 | QEMU_IFLA_INET6_MCAST, |
214 | QEMU_IFLA_INET6_CACHEINFO, |
215 | QEMU_IFLA_INET6_ICMP6STATS, |
216 | QEMU_IFLA_INET6_TOKEN, |
217 | QEMU_IFLA_INET6_ADDR_GEN_MODE, |
218 | QEMU___IFLA_INET6_MAX |
219 | }; |
220 | |
221 | enum { |
222 | QEMU_IFLA_XDP_UNSPEC, |
223 | QEMU_IFLA_XDP_FD, |
224 | QEMU_IFLA_XDP_ATTACHED, |
225 | QEMU_IFLA_XDP_FLAGS, |
226 | QEMU_IFLA_XDP_PROG_ID, |
227 | QEMU___IFLA_XDP_MAX, |
228 | }; |
229 | |
230 | enum { |
231 | QEMU_RTA_UNSPEC, |
232 | QEMU_RTA_DST, |
233 | QEMU_RTA_SRC, |
234 | QEMU_RTA_IIF, |
235 | QEMU_RTA_OIF, |
236 | QEMU_RTA_GATEWAY, |
237 | QEMU_RTA_PRIORITY, |
238 | QEMU_RTA_PREFSRC, |
239 | QEMU_RTA_METRICS, |
240 | QEMU_RTA_MULTIPATH, |
241 | QEMU_RTA_PROTOINFO, /* no longer used */ |
242 | QEMU_RTA_FLOW, |
243 | QEMU_RTA_CACHEINFO, |
244 | QEMU_RTA_SESSION, /* no longer used */ |
245 | QEMU_RTA_MP_ALGO, /* no longer used */ |
246 | QEMU_RTA_TABLE, |
247 | QEMU_RTA_MARK, |
248 | QEMU_RTA_MFC_STATS, |
249 | QEMU_RTA_VIA, |
250 | QEMU_RTA_NEWDST, |
251 | QEMU_RTA_PREF, |
252 | QEMU_RTA_ENCAP_TYPE, |
253 | QEMU_RTA_ENCAP, |
254 | QEMU_RTA_EXPIRES, |
255 | QEMU_RTA_PAD, |
256 | QEMU_RTA_UID, |
257 | QEMU_RTA_TTL_PROPAGATE, |
258 | QEMU_RTA_IP_PROTO, |
259 | QEMU_RTA_SPORT, |
260 | QEMU_RTA_DPORT, |
261 | QEMU___RTA_MAX |
262 | }; |
263 | |
264 | TargetFdTrans **target_fd_trans; |
265 | unsigned int target_fd_max; |
266 | |
267 | static void tswap_nlmsghdr(struct nlmsghdr *nlh) |
268 | { |
269 | nlh->nlmsg_len = tswap32(nlh->nlmsg_len); |
270 | nlh->nlmsg_type = tswap16(nlh->nlmsg_type); |
271 | nlh->nlmsg_flags = tswap16(nlh->nlmsg_flags); |
272 | nlh->nlmsg_seq = tswap32(nlh->nlmsg_seq); |
273 | nlh->nlmsg_pid = tswap32(nlh->nlmsg_pid); |
274 | } |
275 | |
276 | static abi_long host_to_target_for_each_nlmsg(struct nlmsghdr *nlh, |
277 | size_t len, |
278 | abi_long (*host_to_target_nlmsg) |
279 | (struct nlmsghdr *)) |
280 | { |
281 | uint32_t nlmsg_len; |
282 | abi_long ret; |
283 | |
284 | while (len > sizeof(struct nlmsghdr)) { |
285 | |
286 | nlmsg_len = nlh->nlmsg_len; |
287 | if (nlmsg_len < sizeof(struct nlmsghdr) || |
288 | nlmsg_len > len) { |
289 | break; |
290 | } |
291 | |
292 | switch (nlh->nlmsg_type) { |
293 | case NLMSG_DONE: |
294 | tswap_nlmsghdr(nlh); |
295 | return 0; |
296 | case NLMSG_NOOP: |
297 | break; |
298 | case NLMSG_ERROR: |
299 | { |
300 | struct nlmsgerr *e = NLMSG_DATA(nlh); |
301 | e->error = tswap32(e->error); |
302 | tswap_nlmsghdr(&e->msg); |
303 | tswap_nlmsghdr(nlh); |
304 | return 0; |
305 | } |
306 | default: |
307 | ret = host_to_target_nlmsg(nlh); |
308 | if (ret < 0) { |
309 | tswap_nlmsghdr(nlh); |
310 | return ret; |
311 | } |
312 | break; |
313 | } |
314 | tswap_nlmsghdr(nlh); |
315 | len -= NLMSG_ALIGN(nlmsg_len); |
316 | nlh = (struct nlmsghdr *)(((char*)nlh) + NLMSG_ALIGN(nlmsg_len)); |
317 | } |
318 | return 0; |
319 | } |
320 | |
321 | static abi_long target_to_host_for_each_nlmsg(struct nlmsghdr *nlh, |
322 | size_t len, |
323 | abi_long (*target_to_host_nlmsg) |
324 | (struct nlmsghdr *)) |
325 | { |
326 | int ret; |
327 | |
328 | while (len > sizeof(struct nlmsghdr)) { |
329 | if (tswap32(nlh->nlmsg_len) < sizeof(struct nlmsghdr) || |
330 | tswap32(nlh->nlmsg_len) > len) { |
331 | break; |
332 | } |
333 | tswap_nlmsghdr(nlh); |
334 | switch (nlh->nlmsg_type) { |
335 | case NLMSG_DONE: |
336 | return 0; |
337 | case NLMSG_NOOP: |
338 | break; |
339 | case NLMSG_ERROR: |
340 | { |
341 | struct nlmsgerr *e = NLMSG_DATA(nlh); |
342 | e->error = tswap32(e->error); |
343 | tswap_nlmsghdr(&e->msg); |
344 | return 0; |
345 | } |
346 | default: |
347 | ret = target_to_host_nlmsg(nlh); |
348 | if (ret < 0) { |
349 | return ret; |
350 | } |
351 | } |
352 | len -= NLMSG_ALIGN(nlh->nlmsg_len); |
353 | nlh = (struct nlmsghdr *)(((char *)nlh) + NLMSG_ALIGN(nlh->nlmsg_len)); |
354 | } |
355 | return 0; |
356 | } |
357 | |
358 | #ifdef CONFIG_RTNETLINK |
359 | static abi_long host_to_target_for_each_nlattr(struct nlattr *nlattr, |
360 | size_t len, void *context, |
361 | abi_long (*host_to_target_nlattr) |
362 | (struct nlattr *, |
363 | void *context)) |
364 | { |
365 | unsigned short nla_len; |
366 | abi_long ret; |
367 | |
368 | while (len > sizeof(struct nlattr)) { |
369 | nla_len = nlattr->nla_len; |
370 | if (nla_len < sizeof(struct nlattr) || |
371 | nla_len > len) { |
372 | break; |
373 | } |
374 | ret = host_to_target_nlattr(nlattr, context); |
375 | nlattr->nla_len = tswap16(nlattr->nla_len); |
376 | nlattr->nla_type = tswap16(nlattr->nla_type); |
377 | if (ret < 0) { |
378 | return ret; |
379 | } |
380 | len -= NLA_ALIGN(nla_len); |
381 | nlattr = (struct nlattr *)(((char *)nlattr) + NLA_ALIGN(nla_len)); |
382 | } |
383 | return 0; |
384 | } |
385 | |
386 | static abi_long host_to_target_for_each_rtattr(struct rtattr *rtattr, |
387 | size_t len, |
388 | abi_long (*host_to_target_rtattr) |
389 | (struct rtattr *)) |
390 | { |
391 | unsigned short rta_len; |
392 | abi_long ret; |
393 | |
394 | while (len > sizeof(struct rtattr)) { |
395 | rta_len = rtattr->rta_len; |
396 | if (rta_len < sizeof(struct rtattr) || |
397 | rta_len > len) { |
398 | break; |
399 | } |
400 | ret = host_to_target_rtattr(rtattr); |
401 | rtattr->rta_len = tswap16(rtattr->rta_len); |
402 | rtattr->rta_type = tswap16(rtattr->rta_type); |
403 | if (ret < 0) { |
404 | return ret; |
405 | } |
406 | len -= RTA_ALIGN(rta_len); |
407 | rtattr = (struct rtattr *)(((char *)rtattr) + RTA_ALIGN(rta_len)); |
408 | } |
409 | return 0; |
410 | } |
411 | |
412 | #define NLA_DATA(nla) ((void *)((char *)(nla)) + NLA_HDRLEN) |
413 | |
414 | static abi_long host_to_target_data_bridge_nlattr(struct nlattr *nlattr, |
415 | void *context) |
416 | { |
417 | uint16_t *u16; |
418 | uint32_t *u32; |
419 | uint64_t *u64; |
420 | |
421 | switch (nlattr->nla_type) { |
422 | /* no data */ |
423 | case QEMU_IFLA_BR_FDB_FLUSH: |
424 | break; |
425 | /* binary */ |
426 | case QEMU_IFLA_BR_GROUP_ADDR: |
427 | break; |
428 | /* uint8_t */ |
429 | case QEMU_IFLA_BR_VLAN_FILTERING: |
430 | case QEMU_IFLA_BR_TOPOLOGY_CHANGE: |
431 | case QEMU_IFLA_BR_TOPOLOGY_CHANGE_DETECTED: |
432 | case QEMU_IFLA_BR_MCAST_ROUTER: |
433 | case QEMU_IFLA_BR_MCAST_SNOOPING: |
434 | case QEMU_IFLA_BR_MCAST_QUERY_USE_IFADDR: |
435 | case QEMU_IFLA_BR_MCAST_QUERIER: |
436 | case QEMU_IFLA_BR_NF_CALL_IPTABLES: |
437 | case QEMU_IFLA_BR_NF_CALL_IP6TABLES: |
438 | case QEMU_IFLA_BR_NF_CALL_ARPTABLES: |
439 | case QEMU_IFLA_BR_VLAN_STATS_ENABLED: |
440 | case QEMU_IFLA_BR_MCAST_STATS_ENABLED: |
441 | case QEMU_IFLA_BR_MCAST_IGMP_VERSION: |
442 | case QEMU_IFLA_BR_MCAST_MLD_VERSION: |
443 | case QEMU_IFLA_BR_VLAN_STATS_PER_PORT: |
444 | break; |
445 | /* uint16_t */ |
446 | case QEMU_IFLA_BR_PRIORITY: |
447 | case QEMU_IFLA_BR_VLAN_PROTOCOL: |
448 | case QEMU_IFLA_BR_GROUP_FWD_MASK: |
449 | case QEMU_IFLA_BR_ROOT_PORT: |
450 | case QEMU_IFLA_BR_VLAN_DEFAULT_PVID: |
451 | u16 = NLA_DATA(nlattr); |
452 | *u16 = tswap16(*u16); |
453 | break; |
454 | /* uint32_t */ |
455 | case QEMU_IFLA_BR_FORWARD_DELAY: |
456 | case QEMU_IFLA_BR_HELLO_TIME: |
457 | case QEMU_IFLA_BR_MAX_AGE: |
458 | case QEMU_IFLA_BR_AGEING_TIME: |
459 | case QEMU_IFLA_BR_STP_STATE: |
460 | case QEMU_IFLA_BR_ROOT_PATH_COST: |
461 | case QEMU_IFLA_BR_MCAST_HASH_ELASTICITY: |
462 | case QEMU_IFLA_BR_MCAST_HASH_MAX: |
463 | case QEMU_IFLA_BR_MCAST_LAST_MEMBER_CNT: |
464 | case QEMU_IFLA_BR_MCAST_STARTUP_QUERY_CNT: |
465 | u32 = NLA_DATA(nlattr); |
466 | *u32 = tswap32(*u32); |
467 | break; |
468 | /* uint64_t */ |
469 | case QEMU_IFLA_BR_HELLO_TIMER: |
470 | case QEMU_IFLA_BR_TCN_TIMER: |
471 | case QEMU_IFLA_BR_GC_TIMER: |
472 | case QEMU_IFLA_BR_TOPOLOGY_CHANGE_TIMER: |
473 | case QEMU_IFLA_BR_MCAST_LAST_MEMBER_INTVL: |
474 | case QEMU_IFLA_BR_MCAST_MEMBERSHIP_INTVL: |
475 | case QEMU_IFLA_BR_MCAST_QUERIER_INTVL: |
476 | case QEMU_IFLA_BR_MCAST_QUERY_INTVL: |
477 | case QEMU_IFLA_BR_MCAST_QUERY_RESPONSE_INTVL: |
478 | case QEMU_IFLA_BR_MCAST_STARTUP_QUERY_INTVL: |
479 | u64 = NLA_DATA(nlattr); |
480 | *u64 = tswap64(*u64); |
481 | break; |
482 | /* ifla_bridge_id: uin8_t[] */ |
483 | case QEMU_IFLA_BR_ROOT_ID: |
484 | case QEMU_IFLA_BR_BRIDGE_ID: |
485 | break; |
486 | /* br_boolopt_multi { uint32_t, uint32_t } */ |
487 | case QEMU_IFLA_BR_MULTI_BOOLOPT: |
488 | u32 = NLA_DATA(nlattr); |
489 | u32[0] = tswap32(u32[0]); /* optval */ |
490 | u32[1] = tswap32(u32[1]); /* optmask */ |
491 | break; |
492 | default: |
493 | gemu_log("Unknown QEMU_IFLA_BR type %d\n" , nlattr->nla_type); |
494 | break; |
495 | } |
496 | return 0; |
497 | } |
498 | |
499 | static abi_long host_to_target_slave_data_bridge_nlattr(struct nlattr *nlattr, |
500 | void *context) |
501 | { |
502 | uint16_t *u16; |
503 | uint32_t *u32; |
504 | uint64_t *u64; |
505 | |
506 | switch (nlattr->nla_type) { |
507 | /* uint8_t */ |
508 | case QEMU_IFLA_BRPORT_STATE: |
509 | case QEMU_IFLA_BRPORT_MODE: |
510 | case QEMU_IFLA_BRPORT_GUARD: |
511 | case QEMU_IFLA_BRPORT_PROTECT: |
512 | case QEMU_IFLA_BRPORT_FAST_LEAVE: |
513 | case QEMU_IFLA_BRPORT_LEARNING: |
514 | case QEMU_IFLA_BRPORT_UNICAST_FLOOD: |
515 | case QEMU_IFLA_BRPORT_PROXYARP: |
516 | case QEMU_IFLA_BRPORT_LEARNING_SYNC: |
517 | case QEMU_IFLA_BRPORT_PROXYARP_WIFI: |
518 | case QEMU_IFLA_BRPORT_TOPOLOGY_CHANGE_ACK: |
519 | case QEMU_IFLA_BRPORT_CONFIG_PENDING: |
520 | case QEMU_IFLA_BRPORT_MULTICAST_ROUTER: |
521 | case QEMU_IFLA_BRPORT_MCAST_FLOOD: |
522 | case QEMU_IFLA_BRPORT_MCAST_TO_UCAST: |
523 | case QEMU_IFLA_BRPORT_VLAN_TUNNEL: |
524 | case QEMU_IFLA_BRPORT_BCAST_FLOOD: |
525 | case QEMU_IFLA_BRPORT_NEIGH_SUPPRESS: |
526 | case QEMU_IFLA_BRPORT_ISOLATED: |
527 | break; |
528 | /* uint16_t */ |
529 | case QEMU_IFLA_BRPORT_PRIORITY: |
530 | case QEMU_IFLA_BRPORT_DESIGNATED_PORT: |
531 | case QEMU_IFLA_BRPORT_DESIGNATED_COST: |
532 | case QEMU_IFLA_BRPORT_ID: |
533 | case QEMU_IFLA_BRPORT_NO: |
534 | case QEMU_IFLA_BRPORT_GROUP_FWD_MASK: |
535 | u16 = NLA_DATA(nlattr); |
536 | *u16 = tswap16(*u16); |
537 | break; |
538 | /* uin32_t */ |
539 | case QEMU_IFLA_BRPORT_COST: |
540 | case QEMU_IFLA_BRPORT_BACKUP_PORT: |
541 | u32 = NLA_DATA(nlattr); |
542 | *u32 = tswap32(*u32); |
543 | break; |
544 | /* uint64_t */ |
545 | case QEMU_IFLA_BRPORT_MESSAGE_AGE_TIMER: |
546 | case QEMU_IFLA_BRPORT_FORWARD_DELAY_TIMER: |
547 | case QEMU_IFLA_BRPORT_HOLD_TIMER: |
548 | u64 = NLA_DATA(nlattr); |
549 | *u64 = tswap64(*u64); |
550 | break; |
551 | /* ifla_bridge_id: uint8_t[] */ |
552 | case QEMU_IFLA_BRPORT_ROOT_ID: |
553 | case QEMU_IFLA_BRPORT_BRIDGE_ID: |
554 | break; |
555 | default: |
556 | gemu_log("Unknown QEMU_IFLA_BRPORT type %d\n" , nlattr->nla_type); |
557 | break; |
558 | } |
559 | return 0; |
560 | } |
561 | |
562 | static abi_long host_to_target_data_tun_nlattr(struct nlattr *nlattr, |
563 | void *context) |
564 | { |
565 | uint32_t *u32; |
566 | |
567 | switch (nlattr->nla_type) { |
568 | /* uint8_t */ |
569 | case QEMU_IFLA_TUN_TYPE: |
570 | case QEMU_IFLA_TUN_PI: |
571 | case QEMU_IFLA_TUN_VNET_HDR: |
572 | case QEMU_IFLA_TUN_PERSIST: |
573 | case QEMU_IFLA_TUN_MULTI_QUEUE: |
574 | break; |
575 | /* uint32_t */ |
576 | case QEMU_IFLA_TUN_NUM_QUEUES: |
577 | case QEMU_IFLA_TUN_NUM_DISABLED_QUEUES: |
578 | case QEMU_IFLA_TUN_OWNER: |
579 | case QEMU_IFLA_TUN_GROUP: |
580 | u32 = NLA_DATA(nlattr); |
581 | *u32 = tswap32(*u32); |
582 | break; |
583 | default: |
584 | gemu_log("Unknown QEMU_IFLA_TUN type %d\n" , nlattr->nla_type); |
585 | break; |
586 | } |
587 | return 0; |
588 | } |
589 | |
590 | struct linkinfo_context { |
591 | int len; |
592 | char *name; |
593 | int slave_len; |
594 | char *slave_name; |
595 | }; |
596 | |
597 | static abi_long host_to_target_data_linkinfo_nlattr(struct nlattr *nlattr, |
598 | void *context) |
599 | { |
600 | struct linkinfo_context *li_context = context; |
601 | |
602 | switch (nlattr->nla_type) { |
603 | /* string */ |
604 | case QEMU_IFLA_INFO_KIND: |
605 | li_context->name = NLA_DATA(nlattr); |
606 | li_context->len = nlattr->nla_len - NLA_HDRLEN; |
607 | break; |
608 | case QEMU_IFLA_INFO_SLAVE_KIND: |
609 | li_context->slave_name = NLA_DATA(nlattr); |
610 | li_context->slave_len = nlattr->nla_len - NLA_HDRLEN; |
611 | break; |
612 | /* stats */ |
613 | case QEMU_IFLA_INFO_XSTATS: |
614 | /* FIXME: only used by CAN */ |
615 | break; |
616 | /* nested */ |
617 | case QEMU_IFLA_INFO_DATA: |
618 | if (strncmp(li_context->name, "bridge" , |
619 | li_context->len) == 0) { |
620 | return host_to_target_for_each_nlattr(NLA_DATA(nlattr), |
621 | nlattr->nla_len, |
622 | NULL, |
623 | host_to_target_data_bridge_nlattr); |
624 | } else if (strncmp(li_context->name, "tun" , |
625 | li_context->len) == 0) { |
626 | return host_to_target_for_each_nlattr(NLA_DATA(nlattr), |
627 | nlattr->nla_len, |
628 | NULL, |
629 | host_to_target_data_tun_nlattr); |
630 | } else { |
631 | gemu_log("Unknown QEMU_IFLA_INFO_KIND %s\n" , li_context->name); |
632 | } |
633 | break; |
634 | case QEMU_IFLA_INFO_SLAVE_DATA: |
635 | if (strncmp(li_context->slave_name, "bridge" , |
636 | li_context->slave_len) == 0) { |
637 | return host_to_target_for_each_nlattr(NLA_DATA(nlattr), |
638 | nlattr->nla_len, |
639 | NULL, |
640 | host_to_target_slave_data_bridge_nlattr); |
641 | } else { |
642 | gemu_log("Unknown QEMU_IFLA_INFO_SLAVE_KIND %s\n" , |
643 | li_context->slave_name); |
644 | } |
645 | break; |
646 | default: |
647 | gemu_log("Unknown host QEMU_IFLA_INFO type: %d\n" , nlattr->nla_type); |
648 | break; |
649 | } |
650 | |
651 | return 0; |
652 | } |
653 | |
654 | static abi_long host_to_target_data_inet_nlattr(struct nlattr *nlattr, |
655 | void *context) |
656 | { |
657 | uint32_t *u32; |
658 | int i; |
659 | |
660 | switch (nlattr->nla_type) { |
661 | case QEMU_IFLA_INET_CONF: |
662 | u32 = NLA_DATA(nlattr); |
663 | for (i = 0; i < (nlattr->nla_len - NLA_HDRLEN) / sizeof(*u32); |
664 | i++) { |
665 | u32[i] = tswap32(u32[i]); |
666 | } |
667 | break; |
668 | default: |
669 | gemu_log("Unknown host AF_INET type: %d\n" , nlattr->nla_type); |
670 | } |
671 | return 0; |
672 | } |
673 | |
674 | static abi_long host_to_target_data_inet6_nlattr(struct nlattr *nlattr, |
675 | void *context) |
676 | { |
677 | uint32_t *u32; |
678 | uint64_t *u64; |
679 | struct ifla_cacheinfo *ci; |
680 | int i; |
681 | |
682 | switch (nlattr->nla_type) { |
683 | /* binaries */ |
684 | case QEMU_IFLA_INET6_TOKEN: |
685 | break; |
686 | /* uint8_t */ |
687 | case QEMU_IFLA_INET6_ADDR_GEN_MODE: |
688 | break; |
689 | /* uint32_t */ |
690 | case QEMU_IFLA_INET6_FLAGS: |
691 | u32 = NLA_DATA(nlattr); |
692 | *u32 = tswap32(*u32); |
693 | break; |
694 | /* uint32_t[] */ |
695 | case QEMU_IFLA_INET6_CONF: |
696 | u32 = NLA_DATA(nlattr); |
697 | for (i = 0; i < (nlattr->nla_len - NLA_HDRLEN) / sizeof(*u32); |
698 | i++) { |
699 | u32[i] = tswap32(u32[i]); |
700 | } |
701 | break; |
702 | /* ifla_cacheinfo */ |
703 | case QEMU_IFLA_INET6_CACHEINFO: |
704 | ci = NLA_DATA(nlattr); |
705 | ci->max_reasm_len = tswap32(ci->max_reasm_len); |
706 | ci->tstamp = tswap32(ci->tstamp); |
707 | ci->reachable_time = tswap32(ci->reachable_time); |
708 | ci->retrans_time = tswap32(ci->retrans_time); |
709 | break; |
710 | /* uint64_t[] */ |
711 | case QEMU_IFLA_INET6_STATS: |
712 | case QEMU_IFLA_INET6_ICMP6STATS: |
713 | u64 = NLA_DATA(nlattr); |
714 | for (i = 0; i < (nlattr->nla_len - NLA_HDRLEN) / sizeof(*u64); |
715 | i++) { |
716 | u64[i] = tswap64(u64[i]); |
717 | } |
718 | break; |
719 | default: |
720 | gemu_log("Unknown host AF_INET6 type: %d\n" , nlattr->nla_type); |
721 | } |
722 | return 0; |
723 | } |
724 | |
725 | static abi_long host_to_target_data_spec_nlattr(struct nlattr *nlattr, |
726 | void *context) |
727 | { |
728 | switch (nlattr->nla_type) { |
729 | case AF_INET: |
730 | return host_to_target_for_each_nlattr(NLA_DATA(nlattr), nlattr->nla_len, |
731 | NULL, |
732 | host_to_target_data_inet_nlattr); |
733 | case AF_INET6: |
734 | return host_to_target_for_each_nlattr(NLA_DATA(nlattr), nlattr->nla_len, |
735 | NULL, |
736 | host_to_target_data_inet6_nlattr); |
737 | default: |
738 | gemu_log("Unknown host AF_SPEC type: %d\n" , nlattr->nla_type); |
739 | break; |
740 | } |
741 | return 0; |
742 | } |
743 | |
744 | static abi_long host_to_target_data_xdp_nlattr(struct nlattr *nlattr, |
745 | void *context) |
746 | { |
747 | uint32_t *u32; |
748 | |
749 | switch (nlattr->nla_type) { |
750 | /* uint8_t */ |
751 | case QEMU_IFLA_XDP_ATTACHED: |
752 | break; |
753 | /* uint32_t */ |
754 | case QEMU_IFLA_XDP_PROG_ID: |
755 | u32 = NLA_DATA(nlattr); |
756 | *u32 = tswap32(*u32); |
757 | break; |
758 | default: |
759 | gemu_log("Unknown host XDP type: %d\n" , nlattr->nla_type); |
760 | break; |
761 | } |
762 | return 0; |
763 | } |
764 | |
765 | static abi_long host_to_target_data_link_rtattr(struct rtattr *rtattr) |
766 | { |
767 | uint32_t *u32; |
768 | struct rtnl_link_stats *st; |
769 | struct rtnl_link_stats64 *st64; |
770 | struct rtnl_link_ifmap *map; |
771 | struct linkinfo_context li_context; |
772 | |
773 | switch (rtattr->rta_type) { |
774 | /* binary stream */ |
775 | case QEMU_IFLA_ADDRESS: |
776 | case QEMU_IFLA_BROADCAST: |
777 | /* string */ |
778 | case QEMU_IFLA_IFNAME: |
779 | case QEMU_IFLA_QDISC: |
780 | break; |
781 | /* uin8_t */ |
782 | case QEMU_IFLA_OPERSTATE: |
783 | case QEMU_IFLA_LINKMODE: |
784 | case QEMU_IFLA_CARRIER: |
785 | case QEMU_IFLA_PROTO_DOWN: |
786 | break; |
787 | /* uint32_t */ |
788 | case QEMU_IFLA_MTU: |
789 | case QEMU_IFLA_LINK: |
790 | case QEMU_IFLA_WEIGHT: |
791 | case QEMU_IFLA_TXQLEN: |
792 | case QEMU_IFLA_CARRIER_CHANGES: |
793 | case QEMU_IFLA_NUM_RX_QUEUES: |
794 | case QEMU_IFLA_NUM_TX_QUEUES: |
795 | case QEMU_IFLA_PROMISCUITY: |
796 | case QEMU_IFLA_EXT_MASK: |
797 | case QEMU_IFLA_LINK_NETNSID: |
798 | case QEMU_IFLA_GROUP: |
799 | case QEMU_IFLA_MASTER: |
800 | case QEMU_IFLA_NUM_VF: |
801 | case QEMU_IFLA_GSO_MAX_SEGS: |
802 | case QEMU_IFLA_GSO_MAX_SIZE: |
803 | case QEMU_IFLA_CARRIER_UP_COUNT: |
804 | case QEMU_IFLA_CARRIER_DOWN_COUNT: |
805 | case QEMU_IFLA_MIN_MTU: |
806 | case QEMU_IFLA_MAX_MTU: |
807 | u32 = RTA_DATA(rtattr); |
808 | *u32 = tswap32(*u32); |
809 | break; |
810 | /* struct rtnl_link_stats */ |
811 | case QEMU_IFLA_STATS: |
812 | st = RTA_DATA(rtattr); |
813 | st->rx_packets = tswap32(st->rx_packets); |
814 | st->tx_packets = tswap32(st->tx_packets); |
815 | st->rx_bytes = tswap32(st->rx_bytes); |
816 | st->tx_bytes = tswap32(st->tx_bytes); |
817 | st->rx_errors = tswap32(st->rx_errors); |
818 | st->tx_errors = tswap32(st->tx_errors); |
819 | st->rx_dropped = tswap32(st->rx_dropped); |
820 | st->tx_dropped = tswap32(st->tx_dropped); |
821 | st->multicast = tswap32(st->multicast); |
822 | st->collisions = tswap32(st->collisions); |
823 | |
824 | /* detailed rx_errors: */ |
825 | st->rx_length_errors = tswap32(st->rx_length_errors); |
826 | st->rx_over_errors = tswap32(st->rx_over_errors); |
827 | st->rx_crc_errors = tswap32(st->rx_crc_errors); |
828 | st->rx_frame_errors = tswap32(st->rx_frame_errors); |
829 | st->rx_fifo_errors = tswap32(st->rx_fifo_errors); |
830 | st->rx_missed_errors = tswap32(st->rx_missed_errors); |
831 | |
832 | /* detailed tx_errors */ |
833 | st->tx_aborted_errors = tswap32(st->tx_aborted_errors); |
834 | st->tx_carrier_errors = tswap32(st->tx_carrier_errors); |
835 | st->tx_fifo_errors = tswap32(st->tx_fifo_errors); |
836 | st->tx_heartbeat_errors = tswap32(st->tx_heartbeat_errors); |
837 | st->tx_window_errors = tswap32(st->tx_window_errors); |
838 | |
839 | /* for cslip etc */ |
840 | st->rx_compressed = tswap32(st->rx_compressed); |
841 | st->tx_compressed = tswap32(st->tx_compressed); |
842 | break; |
843 | /* struct rtnl_link_stats64 */ |
844 | case QEMU_IFLA_STATS64: |
845 | st64 = RTA_DATA(rtattr); |
846 | st64->rx_packets = tswap64(st64->rx_packets); |
847 | st64->tx_packets = tswap64(st64->tx_packets); |
848 | st64->rx_bytes = tswap64(st64->rx_bytes); |
849 | st64->tx_bytes = tswap64(st64->tx_bytes); |
850 | st64->rx_errors = tswap64(st64->rx_errors); |
851 | st64->tx_errors = tswap64(st64->tx_errors); |
852 | st64->rx_dropped = tswap64(st64->rx_dropped); |
853 | st64->tx_dropped = tswap64(st64->tx_dropped); |
854 | st64->multicast = tswap64(st64->multicast); |
855 | st64->collisions = tswap64(st64->collisions); |
856 | |
857 | /* detailed rx_errors: */ |
858 | st64->rx_length_errors = tswap64(st64->rx_length_errors); |
859 | st64->rx_over_errors = tswap64(st64->rx_over_errors); |
860 | st64->rx_crc_errors = tswap64(st64->rx_crc_errors); |
861 | st64->rx_frame_errors = tswap64(st64->rx_frame_errors); |
862 | st64->rx_fifo_errors = tswap64(st64->rx_fifo_errors); |
863 | st64->rx_missed_errors = tswap64(st64->rx_missed_errors); |
864 | |
865 | /* detailed tx_errors */ |
866 | st64->tx_aborted_errors = tswap64(st64->tx_aborted_errors); |
867 | st64->tx_carrier_errors = tswap64(st64->tx_carrier_errors); |
868 | st64->tx_fifo_errors = tswap64(st64->tx_fifo_errors); |
869 | st64->tx_heartbeat_errors = tswap64(st64->tx_heartbeat_errors); |
870 | st64->tx_window_errors = tswap64(st64->tx_window_errors); |
871 | |
872 | /* for cslip etc */ |
873 | st64->rx_compressed = tswap64(st64->rx_compressed); |
874 | st64->tx_compressed = tswap64(st64->tx_compressed); |
875 | break; |
876 | /* struct rtnl_link_ifmap */ |
877 | case QEMU_IFLA_MAP: |
878 | map = RTA_DATA(rtattr); |
879 | map->mem_start = tswap64(map->mem_start); |
880 | map->mem_end = tswap64(map->mem_end); |
881 | map->base_addr = tswap64(map->base_addr); |
882 | map->irq = tswap16(map->irq); |
883 | break; |
884 | /* nested */ |
885 | case QEMU_IFLA_LINKINFO: |
886 | memset(&li_context, 0, sizeof(li_context)); |
887 | return host_to_target_for_each_nlattr(RTA_DATA(rtattr), rtattr->rta_len, |
888 | &li_context, |
889 | host_to_target_data_linkinfo_nlattr); |
890 | case QEMU_IFLA_AF_SPEC: |
891 | return host_to_target_for_each_nlattr(RTA_DATA(rtattr), rtattr->rta_len, |
892 | NULL, |
893 | host_to_target_data_spec_nlattr); |
894 | case QEMU_IFLA_XDP: |
895 | return host_to_target_for_each_nlattr(RTA_DATA(rtattr), rtattr->rta_len, |
896 | NULL, |
897 | host_to_target_data_xdp_nlattr); |
898 | default: |
899 | gemu_log("Unknown host QEMU_IFLA type: %d\n" , rtattr->rta_type); |
900 | break; |
901 | } |
902 | return 0; |
903 | } |
904 | |
905 | static abi_long host_to_target_data_addr_rtattr(struct rtattr *rtattr) |
906 | { |
907 | uint32_t *u32; |
908 | struct ifa_cacheinfo *ci; |
909 | |
910 | switch (rtattr->rta_type) { |
911 | /* binary: depends on family type */ |
912 | case IFA_ADDRESS: |
913 | case IFA_LOCAL: |
914 | break; |
915 | /* string */ |
916 | case IFA_LABEL: |
917 | break; |
918 | /* u32 */ |
919 | case IFA_FLAGS: |
920 | case IFA_BROADCAST: |
921 | u32 = RTA_DATA(rtattr); |
922 | *u32 = tswap32(*u32); |
923 | break; |
924 | /* struct ifa_cacheinfo */ |
925 | case IFA_CACHEINFO: |
926 | ci = RTA_DATA(rtattr); |
927 | ci->ifa_prefered = tswap32(ci->ifa_prefered); |
928 | ci->ifa_valid = tswap32(ci->ifa_valid); |
929 | ci->cstamp = tswap32(ci->cstamp); |
930 | ci->tstamp = tswap32(ci->tstamp); |
931 | break; |
932 | default: |
933 | gemu_log("Unknown host IFA type: %d\n" , rtattr->rta_type); |
934 | break; |
935 | } |
936 | return 0; |
937 | } |
938 | |
939 | static abi_long host_to_target_data_route_rtattr(struct rtattr *rtattr) |
940 | { |
941 | uint32_t *u32; |
942 | struct rta_cacheinfo *ci; |
943 | |
944 | switch (rtattr->rta_type) { |
945 | /* binary: depends on family type */ |
946 | case QEMU_RTA_GATEWAY: |
947 | case QEMU_RTA_DST: |
948 | case QEMU_RTA_PREFSRC: |
949 | break; |
950 | /* u8 */ |
951 | case QEMU_RTA_PREF: |
952 | break; |
953 | /* u32 */ |
954 | case QEMU_RTA_PRIORITY: |
955 | case QEMU_RTA_TABLE: |
956 | case QEMU_RTA_OIF: |
957 | u32 = RTA_DATA(rtattr); |
958 | *u32 = tswap32(*u32); |
959 | break; |
960 | /* struct rta_cacheinfo */ |
961 | case QEMU_RTA_CACHEINFO: |
962 | ci = RTA_DATA(rtattr); |
963 | ci->rta_clntref = tswap32(ci->rta_clntref); |
964 | ci->rta_lastuse = tswap32(ci->rta_lastuse); |
965 | ci->rta_expires = tswap32(ci->rta_expires); |
966 | ci->rta_error = tswap32(ci->rta_error); |
967 | ci->rta_used = tswap32(ci->rta_used); |
968 | #if defined(RTNETLINK_HAVE_PEERINFO) |
969 | ci->rta_id = tswap32(ci->rta_id); |
970 | ci->rta_ts = tswap32(ci->rta_ts); |
971 | ci->rta_tsage = tswap32(ci->rta_tsage); |
972 | #endif |
973 | break; |
974 | default: |
975 | gemu_log("Unknown host RTA type: %d\n" , rtattr->rta_type); |
976 | break; |
977 | } |
978 | return 0; |
979 | } |
980 | |
981 | static abi_long host_to_target_link_rtattr(struct rtattr *rtattr, |
982 | uint32_t rtattr_len) |
983 | { |
984 | return host_to_target_for_each_rtattr(rtattr, rtattr_len, |
985 | host_to_target_data_link_rtattr); |
986 | } |
987 | |
988 | static abi_long host_to_target_addr_rtattr(struct rtattr *rtattr, |
989 | uint32_t rtattr_len) |
990 | { |
991 | return host_to_target_for_each_rtattr(rtattr, rtattr_len, |
992 | host_to_target_data_addr_rtattr); |
993 | } |
994 | |
995 | static abi_long host_to_target_route_rtattr(struct rtattr *rtattr, |
996 | uint32_t rtattr_len) |
997 | { |
998 | return host_to_target_for_each_rtattr(rtattr, rtattr_len, |
999 | host_to_target_data_route_rtattr); |
1000 | } |
1001 | |
1002 | static abi_long host_to_target_data_route(struct nlmsghdr *nlh) |
1003 | { |
1004 | uint32_t nlmsg_len; |
1005 | struct ifinfomsg *ifi; |
1006 | struct ifaddrmsg *ifa; |
1007 | struct rtmsg *rtm; |
1008 | |
1009 | nlmsg_len = nlh->nlmsg_len; |
1010 | switch (nlh->nlmsg_type) { |
1011 | case RTM_NEWLINK: |
1012 | case RTM_DELLINK: |
1013 | case RTM_GETLINK: |
1014 | if (nlh->nlmsg_len >= NLMSG_LENGTH(sizeof(*ifi))) { |
1015 | ifi = NLMSG_DATA(nlh); |
1016 | ifi->ifi_type = tswap16(ifi->ifi_type); |
1017 | ifi->ifi_index = tswap32(ifi->ifi_index); |
1018 | ifi->ifi_flags = tswap32(ifi->ifi_flags); |
1019 | ifi->ifi_change = tswap32(ifi->ifi_change); |
1020 | host_to_target_link_rtattr(IFLA_RTA(ifi), |
1021 | nlmsg_len - NLMSG_LENGTH(sizeof(*ifi))); |
1022 | } |
1023 | break; |
1024 | case RTM_NEWADDR: |
1025 | case RTM_DELADDR: |
1026 | case RTM_GETADDR: |
1027 | if (nlh->nlmsg_len >= NLMSG_LENGTH(sizeof(*ifa))) { |
1028 | ifa = NLMSG_DATA(nlh); |
1029 | ifa->ifa_index = tswap32(ifa->ifa_index); |
1030 | host_to_target_addr_rtattr(IFA_RTA(ifa), |
1031 | nlmsg_len - NLMSG_LENGTH(sizeof(*ifa))); |
1032 | } |
1033 | break; |
1034 | case RTM_NEWROUTE: |
1035 | case RTM_DELROUTE: |
1036 | case RTM_GETROUTE: |
1037 | if (nlh->nlmsg_len >= NLMSG_LENGTH(sizeof(*rtm))) { |
1038 | rtm = NLMSG_DATA(nlh); |
1039 | rtm->rtm_flags = tswap32(rtm->rtm_flags); |
1040 | host_to_target_route_rtattr(RTM_RTA(rtm), |
1041 | nlmsg_len - NLMSG_LENGTH(sizeof(*rtm))); |
1042 | } |
1043 | break; |
1044 | default: |
1045 | return -TARGET_EINVAL; |
1046 | } |
1047 | return 0; |
1048 | } |
1049 | |
1050 | static inline abi_long host_to_target_nlmsg_route(struct nlmsghdr *nlh, |
1051 | size_t len) |
1052 | { |
1053 | return host_to_target_for_each_nlmsg(nlh, len, host_to_target_data_route); |
1054 | } |
1055 | |
1056 | static abi_long target_to_host_for_each_rtattr(struct rtattr *rtattr, |
1057 | size_t len, |
1058 | abi_long (*target_to_host_rtattr) |
1059 | (struct rtattr *)) |
1060 | { |
1061 | abi_long ret; |
1062 | |
1063 | while (len >= sizeof(struct rtattr)) { |
1064 | if (tswap16(rtattr->rta_len) < sizeof(struct rtattr) || |
1065 | tswap16(rtattr->rta_len) > len) { |
1066 | break; |
1067 | } |
1068 | rtattr->rta_len = tswap16(rtattr->rta_len); |
1069 | rtattr->rta_type = tswap16(rtattr->rta_type); |
1070 | ret = target_to_host_rtattr(rtattr); |
1071 | if (ret < 0) { |
1072 | return ret; |
1073 | } |
1074 | len -= RTA_ALIGN(rtattr->rta_len); |
1075 | rtattr = (struct rtattr *)(((char *)rtattr) + |
1076 | RTA_ALIGN(rtattr->rta_len)); |
1077 | } |
1078 | return 0; |
1079 | } |
1080 | |
1081 | static abi_long target_to_host_data_link_rtattr(struct rtattr *rtattr) |
1082 | { |
1083 | switch (rtattr->rta_type) { |
1084 | default: |
1085 | gemu_log("Unknown target QEMU_IFLA type: %d\n" , rtattr->rta_type); |
1086 | break; |
1087 | } |
1088 | return 0; |
1089 | } |
1090 | |
1091 | static abi_long target_to_host_data_addr_rtattr(struct rtattr *rtattr) |
1092 | { |
1093 | switch (rtattr->rta_type) { |
1094 | /* binary: depends on family type */ |
1095 | case IFA_LOCAL: |
1096 | case IFA_ADDRESS: |
1097 | break; |
1098 | default: |
1099 | gemu_log("Unknown target IFA type: %d\n" , rtattr->rta_type); |
1100 | break; |
1101 | } |
1102 | return 0; |
1103 | } |
1104 | |
1105 | static abi_long target_to_host_data_route_rtattr(struct rtattr *rtattr) |
1106 | { |
1107 | uint32_t *u32; |
1108 | switch (rtattr->rta_type) { |
1109 | /* binary: depends on family type */ |
1110 | case QEMU_RTA_DST: |
1111 | case QEMU_RTA_SRC: |
1112 | case QEMU_RTA_GATEWAY: |
1113 | break; |
1114 | /* u32 */ |
1115 | case QEMU_RTA_PRIORITY: |
1116 | case QEMU_RTA_OIF: |
1117 | u32 = RTA_DATA(rtattr); |
1118 | *u32 = tswap32(*u32); |
1119 | break; |
1120 | default: |
1121 | gemu_log("Unknown target RTA type: %d\n" , rtattr->rta_type); |
1122 | break; |
1123 | } |
1124 | return 0; |
1125 | } |
1126 | |
1127 | static void target_to_host_link_rtattr(struct rtattr *rtattr, |
1128 | uint32_t rtattr_len) |
1129 | { |
1130 | target_to_host_for_each_rtattr(rtattr, rtattr_len, |
1131 | target_to_host_data_link_rtattr); |
1132 | } |
1133 | |
1134 | static void target_to_host_addr_rtattr(struct rtattr *rtattr, |
1135 | uint32_t rtattr_len) |
1136 | { |
1137 | target_to_host_for_each_rtattr(rtattr, rtattr_len, |
1138 | target_to_host_data_addr_rtattr); |
1139 | } |
1140 | |
1141 | static void target_to_host_route_rtattr(struct rtattr *rtattr, |
1142 | uint32_t rtattr_len) |
1143 | { |
1144 | target_to_host_for_each_rtattr(rtattr, rtattr_len, |
1145 | target_to_host_data_route_rtattr); |
1146 | } |
1147 | |
1148 | static abi_long target_to_host_data_route(struct nlmsghdr *nlh) |
1149 | { |
1150 | struct ifinfomsg *ifi; |
1151 | struct ifaddrmsg *ifa; |
1152 | struct rtmsg *rtm; |
1153 | |
1154 | switch (nlh->nlmsg_type) { |
1155 | case RTM_GETLINK: |
1156 | break; |
1157 | case RTM_NEWLINK: |
1158 | case RTM_DELLINK: |
1159 | if (nlh->nlmsg_len >= NLMSG_LENGTH(sizeof(*ifi))) { |
1160 | ifi = NLMSG_DATA(nlh); |
1161 | ifi->ifi_type = tswap16(ifi->ifi_type); |
1162 | ifi->ifi_index = tswap32(ifi->ifi_index); |
1163 | ifi->ifi_flags = tswap32(ifi->ifi_flags); |
1164 | ifi->ifi_change = tswap32(ifi->ifi_change); |
1165 | target_to_host_link_rtattr(IFLA_RTA(ifi), nlh->nlmsg_len - |
1166 | NLMSG_LENGTH(sizeof(*ifi))); |
1167 | } |
1168 | break; |
1169 | case RTM_GETADDR: |
1170 | case RTM_NEWADDR: |
1171 | case RTM_DELADDR: |
1172 | if (nlh->nlmsg_len >= NLMSG_LENGTH(sizeof(*ifa))) { |
1173 | ifa = NLMSG_DATA(nlh); |
1174 | ifa->ifa_index = tswap32(ifa->ifa_index); |
1175 | target_to_host_addr_rtattr(IFA_RTA(ifa), nlh->nlmsg_len - |
1176 | NLMSG_LENGTH(sizeof(*ifa))); |
1177 | } |
1178 | break; |
1179 | case RTM_GETROUTE: |
1180 | break; |
1181 | case RTM_NEWROUTE: |
1182 | case RTM_DELROUTE: |
1183 | if (nlh->nlmsg_len >= NLMSG_LENGTH(sizeof(*rtm))) { |
1184 | rtm = NLMSG_DATA(nlh); |
1185 | rtm->rtm_flags = tswap32(rtm->rtm_flags); |
1186 | target_to_host_route_rtattr(RTM_RTA(rtm), nlh->nlmsg_len - |
1187 | NLMSG_LENGTH(sizeof(*rtm))); |
1188 | } |
1189 | break; |
1190 | default: |
1191 | return -TARGET_EOPNOTSUPP; |
1192 | } |
1193 | return 0; |
1194 | } |
1195 | |
1196 | static abi_long target_to_host_nlmsg_route(struct nlmsghdr *nlh, size_t len) |
1197 | { |
1198 | return target_to_host_for_each_nlmsg(nlh, len, target_to_host_data_route); |
1199 | } |
1200 | #endif /* CONFIG_RTNETLINK */ |
1201 | |
1202 | static abi_long host_to_target_data_audit(struct nlmsghdr *nlh) |
1203 | { |
1204 | switch (nlh->nlmsg_type) { |
1205 | default: |
1206 | gemu_log("Unknown host audit message type %d\n" , |
1207 | nlh->nlmsg_type); |
1208 | return -TARGET_EINVAL; |
1209 | } |
1210 | return 0; |
1211 | } |
1212 | |
1213 | static inline abi_long host_to_target_nlmsg_audit(struct nlmsghdr *nlh, |
1214 | size_t len) |
1215 | { |
1216 | return host_to_target_for_each_nlmsg(nlh, len, host_to_target_data_audit); |
1217 | } |
1218 | |
1219 | static abi_long target_to_host_data_audit(struct nlmsghdr *nlh) |
1220 | { |
1221 | switch (nlh->nlmsg_type) { |
1222 | case AUDIT_USER: |
1223 | case AUDIT_FIRST_USER_MSG ... AUDIT_LAST_USER_MSG: |
1224 | case AUDIT_FIRST_USER_MSG2 ... AUDIT_LAST_USER_MSG2: |
1225 | break; |
1226 | default: |
1227 | gemu_log("Unknown target audit message type %d\n" , |
1228 | nlh->nlmsg_type); |
1229 | return -TARGET_EINVAL; |
1230 | } |
1231 | |
1232 | return 0; |
1233 | } |
1234 | |
1235 | static abi_long target_to_host_nlmsg_audit(struct nlmsghdr *nlh, size_t len) |
1236 | { |
1237 | return target_to_host_for_each_nlmsg(nlh, len, target_to_host_data_audit); |
1238 | } |
1239 | |
1240 | static abi_long packet_target_to_host_sockaddr(void *host_addr, |
1241 | abi_ulong target_addr, |
1242 | socklen_t len) |
1243 | { |
1244 | struct sockaddr *addr = host_addr; |
1245 | struct target_sockaddr *target_saddr; |
1246 | |
1247 | target_saddr = lock_user(VERIFY_READ, target_addr, len, 1); |
1248 | if (!target_saddr) { |
1249 | return -TARGET_EFAULT; |
1250 | } |
1251 | |
1252 | memcpy(addr, target_saddr, len); |
1253 | addr->sa_family = tswap16(target_saddr->sa_family); |
1254 | /* spkt_protocol is big-endian */ |
1255 | |
1256 | unlock_user(target_saddr, target_addr, 0); |
1257 | return 0; |
1258 | } |
1259 | |
1260 | TargetFdTrans target_packet_trans = { |
1261 | .target_to_host_addr = packet_target_to_host_sockaddr, |
1262 | }; |
1263 | |
1264 | #ifdef CONFIG_RTNETLINK |
1265 | static abi_long netlink_route_target_to_host(void *buf, size_t len) |
1266 | { |
1267 | abi_long ret; |
1268 | |
1269 | ret = target_to_host_nlmsg_route(buf, len); |
1270 | if (ret < 0) { |
1271 | return ret; |
1272 | } |
1273 | |
1274 | return len; |
1275 | } |
1276 | |
1277 | static abi_long netlink_route_host_to_target(void *buf, size_t len) |
1278 | { |
1279 | abi_long ret; |
1280 | |
1281 | ret = host_to_target_nlmsg_route(buf, len); |
1282 | if (ret < 0) { |
1283 | return ret; |
1284 | } |
1285 | |
1286 | return len; |
1287 | } |
1288 | |
1289 | TargetFdTrans target_netlink_route_trans = { |
1290 | .target_to_host_data = netlink_route_target_to_host, |
1291 | .host_to_target_data = netlink_route_host_to_target, |
1292 | }; |
1293 | #endif /* CONFIG_RTNETLINK */ |
1294 | |
1295 | static abi_long netlink_audit_target_to_host(void *buf, size_t len) |
1296 | { |
1297 | abi_long ret; |
1298 | |
1299 | ret = target_to_host_nlmsg_audit(buf, len); |
1300 | if (ret < 0) { |
1301 | return ret; |
1302 | } |
1303 | |
1304 | return len; |
1305 | } |
1306 | |
1307 | static abi_long netlink_audit_host_to_target(void *buf, size_t len) |
1308 | { |
1309 | abi_long ret; |
1310 | |
1311 | ret = host_to_target_nlmsg_audit(buf, len); |
1312 | if (ret < 0) { |
1313 | return ret; |
1314 | } |
1315 | |
1316 | return len; |
1317 | } |
1318 | |
1319 | TargetFdTrans target_netlink_audit_trans = { |
1320 | .target_to_host_data = netlink_audit_target_to_host, |
1321 | .host_to_target_data = netlink_audit_host_to_target, |
1322 | }; |
1323 | |
1324 | /* signalfd siginfo conversion */ |
1325 | |
1326 | static void |
1327 | host_to_target_signalfd_siginfo(struct signalfd_siginfo *tinfo, |
1328 | const struct signalfd_siginfo *info) |
1329 | { |
1330 | int sig = host_to_target_signal(info->ssi_signo); |
1331 | |
1332 | /* linux/signalfd.h defines a ssi_addr_lsb |
1333 | * not defined in sys/signalfd.h but used by some kernels |
1334 | */ |
1335 | |
1336 | #ifdef BUS_MCEERR_AO |
1337 | if (tinfo->ssi_signo == SIGBUS && |
1338 | (tinfo->ssi_code == BUS_MCEERR_AR || |
1339 | tinfo->ssi_code == BUS_MCEERR_AO)) { |
1340 | uint16_t *ssi_addr_lsb = (uint16_t *)(&info->ssi_addr + 1); |
1341 | uint16_t *tssi_addr_lsb = (uint16_t *)(&tinfo->ssi_addr + 1); |
1342 | *tssi_addr_lsb = tswap16(*ssi_addr_lsb); |
1343 | } |
1344 | #endif |
1345 | |
1346 | tinfo->ssi_signo = tswap32(sig); |
1347 | tinfo->ssi_errno = tswap32(tinfo->ssi_errno); |
1348 | tinfo->ssi_code = tswap32(info->ssi_code); |
1349 | tinfo->ssi_pid = tswap32(info->ssi_pid); |
1350 | tinfo->ssi_uid = tswap32(info->ssi_uid); |
1351 | tinfo->ssi_fd = tswap32(info->ssi_fd); |
1352 | tinfo->ssi_tid = tswap32(info->ssi_tid); |
1353 | tinfo->ssi_band = tswap32(info->ssi_band); |
1354 | tinfo->ssi_overrun = tswap32(info->ssi_overrun); |
1355 | tinfo->ssi_trapno = tswap32(info->ssi_trapno); |
1356 | tinfo->ssi_status = tswap32(info->ssi_status); |
1357 | tinfo->ssi_int = tswap32(info->ssi_int); |
1358 | tinfo->ssi_ptr = tswap64(info->ssi_ptr); |
1359 | tinfo->ssi_utime = tswap64(info->ssi_utime); |
1360 | tinfo->ssi_stime = tswap64(info->ssi_stime); |
1361 | tinfo->ssi_addr = tswap64(info->ssi_addr); |
1362 | } |
1363 | |
1364 | static abi_long host_to_target_data_signalfd(void *buf, size_t len) |
1365 | { |
1366 | int i; |
1367 | |
1368 | for (i = 0; i < len; i += sizeof(struct signalfd_siginfo)) { |
1369 | host_to_target_signalfd_siginfo(buf + i, buf + i); |
1370 | } |
1371 | |
1372 | return len; |
1373 | } |
1374 | |
1375 | TargetFdTrans target_signalfd_trans = { |
1376 | .host_to_target_data = host_to_target_data_signalfd, |
1377 | }; |
1378 | |
1379 | static abi_long swap_data_eventfd(void *buf, size_t len) |
1380 | { |
1381 | uint64_t *counter = buf; |
1382 | int i; |
1383 | |
1384 | if (len < sizeof(uint64_t)) { |
1385 | return -EINVAL; |
1386 | } |
1387 | |
1388 | for (i = 0; i < len; i += sizeof(uint64_t)) { |
1389 | *counter = tswap64(*counter); |
1390 | counter++; |
1391 | } |
1392 | |
1393 | return len; |
1394 | } |
1395 | |
1396 | TargetFdTrans target_eventfd_trans = { |
1397 | .host_to_target_data = swap_data_eventfd, |
1398 | .target_to_host_data = swap_data_eventfd, |
1399 | }; |
1400 | |
1401 | #if (defined(TARGET_NR_inotify_init) && defined(__NR_inotify_init)) || \ |
1402 | (defined(CONFIG_INOTIFY1) && defined(TARGET_NR_inotify_init1) && \ |
1403 | defined(__NR_inotify_init1)) |
1404 | static abi_long host_to_target_data_inotify(void *buf, size_t len) |
1405 | { |
1406 | struct inotify_event *ev; |
1407 | int i; |
1408 | uint32_t name_len; |
1409 | |
1410 | for (i = 0; i < len; i += sizeof(struct inotify_event) + name_len) { |
1411 | ev = (struct inotify_event *)((char *)buf + i); |
1412 | name_len = ev->len; |
1413 | |
1414 | ev->wd = tswap32(ev->wd); |
1415 | ev->mask = tswap32(ev->mask); |
1416 | ev->cookie = tswap32(ev->cookie); |
1417 | ev->len = tswap32(name_len); |
1418 | } |
1419 | |
1420 | return len; |
1421 | } |
1422 | |
1423 | TargetFdTrans target_inotify_trans = { |
1424 | .host_to_target_data = host_to_target_data_inotify, |
1425 | }; |
1426 | #endif |
1427 | |