Add the neccessary sockopts for ping and traceroute on IPv6.
This fixes the following qemu warnings with IPv6:
Unsupported ancillary data: 0/2
Unsupported ancillary data: 0/11
Unsupported ancillary data: 41/25
Unsupported setsockopt level=0 optname=12
Unsupported setsockopt level=41 optname=16
Unsupported setsockopt level=41 optname=25
Unsupported setsockopt level=41 optname=50
Unsupported setsockopt level=41 optname=51
Unsupported setsockopt level=41 optname=8
Unsupported setsockopt level=58 optname=1
Tested with hppa-linux-user (big-endian) on x86_64 (little-endian).
Signed-off-by: Helge Deller
---
Changes to v2: (all suggested by Laurent Vivier)
- Drop goto statements and replaced by real code
- New function host_to_target_sockaddr_in6()
- Fix IPV6_PKTINFO which uses in6_pktinfo instead of uint32_t
- Move one IPV6_CHECKSUM from SOL_ICMPV6 to SOL_IPV6
- Fix ICMPV6_FILTER to use icmpv6_filter
Changes to v1:
- Added IPV6_PKTINFO sockopt as reported by Philippe Mathieu-Daudé
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index f569f82..c0c2d3d 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -57,6 +57,8 @@ int __clone2(int (*fn)(void *), void *child_stack_base,
#include
#include
#include
+#include
+#include
#include "qemu-common.h"
#ifdef CONFIG_TIMERFD
#include
@@ -1640,6 +1642,33 @@ static inline abi_long host_to_target_sockaddr(abi_ulong
target_addr,
return 0;
}
+static inline abi_long host_to_target_sockaddr_in6(abi_ulong target_addr,
+ struct sockaddr_in6 *addr,
+ socklen_t len)
+{
+struct target_sockaddr_in6 *target_saddr;
+
+if (len == 0) {
+return 0;
+}
+
+target_saddr = lock_user(VERIFY_WRITE, target_addr, len, 0);
+if (!target_saddr)
+return -TARGET_EFAULT;
+memcpy(target_saddr, addr, len);
+if (len >= offsetof(struct target_sockaddr_in6, sin6_family) +
+sizeof(target_saddr->sin6_family)) {
+target_saddr->sin6_family = tswap16(addr->sin6_family);
+}
+if (len >= offsetof(struct target_sockaddr_in6, sin6_scope_id) +
+sizeof(target_saddr->sin6_scope_id)) {
+target_saddr->sin6_scope_id = tswap16(addr->sin6_scope_id);
+}
+unlock_user(target_saddr, target_addr, len);
+
+return 0;
+}
+
static inline abi_long target_to_host_cmsg(struct msghdr *msgh,
struct target_msghdr *target_msgh)
{
@@ -1839,6 +1868,82 @@ static inline abi_long host_to_target_cmsg(struct
target_msghdr *target_msgh,
}
break;
+case SOL_IP:
+switch (cmsg->cmsg_type) {
+case IP_TTL:
+{
+uint32_t *v = (uint32_t *)data;
+uint32_t *t_int = (uint32_t *)target_data;
+if (tgt_len != CMSG_LEN(0))
+goto unimplemented;
+
+__put_user(*v, t_int);
+break;
+}
+case IP_RECVERR:
+{
+struct errhdr_t {
+ struct sock_extended_err ee;
+ struct sockaddr_in offender;
+};
+struct errhdr_t *errh = (struct errhdr_t *)data;
+struct errhdr_t *target_errh =
+(struct errhdr_t *)target_data;
+
+__put_user(errh->ee.ee_errno, _errh->ee.ee_errno);
+__put_user(errh->ee.ee_origin, _errh->ee.ee_origin);
+__put_user(errh->ee.ee_type, _errh->ee.ee_type);
+__put_user(errh->ee.ee_code, _errh->ee.ee_code);
+__put_user(errh->ee.ee_pad, _errh->ee.ee_pad);
+__put_user(errh->ee.ee_info, _errh->ee.ee_info);
+__put_user(errh->ee.ee_data, _errh->ee.ee_data);
+host_to_target_sockaddr((unsigned long) _errh->offender,
+(void *) >offender, sizeof(errh->offender));
+ break;
+}
+default:
+goto unimplemented;
+}
+break;
+
+case SOL_IPV6:
+switch (cmsg->cmsg_type) {
+case IPV6_HOPLIMIT:
+{
+uint32_t *v = (uint32_t *)data;
+uint32_t *t_int = (uint32_t *)target_data;
+if (tgt_len != CMSG_LEN(0))
+goto unimplemented;
+
+__put_user(*v, t_int);
+ break;
+}
+case IPV6_RECVERR:
+{
+struct errhdr6_t {
+ struct sock_extended_err ee;
+ struct sockaddr_in6 offender;
+};
+struct errhdr6_t *errh = (struct errhdr6_t *)data;
+struct errhdr6_t *target_errh =
+(struct errhdr6_t *)target_data;
+
+__put_user(errh->ee.ee_errno, _errh->ee.ee_errno);
+