[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PULL 01/13] linux-user: Support for NETLINK socket options
From: |
Laurent Vivier |
Subject: |
[PULL 01/13] linux-user: Support for NETLINK socket options |
Date: |
Tue, 5 Nov 2019 19:11:07 +0100 |
From: Josh Kunz <address@hidden>
This change includes support for all AF_NETLINK socket options up to about
kernel version 5.4 (5.4 is not formally released at the time of writing).
Socket options that were introduced in kernel versions before the oldest
currently stable kernel version are guarded by kernel version macros.
This change has been built under gcc 8.3, and clang 9.0, and it passes
`make check`. The netlink options have been tested by emulating some
non-trival software that uses NETLINK socket options, but they have
not been exaustively verified.
Signed-off-by: Josh Kunz <address@hidden>
Message-Id: <address@hidden>
[lv: updated patch according to CODING_STYLE]
Signed-off-by: Laurent Vivier <address@hidden>
---
linux-user/syscall.c | 101 +++++++++++++++++++++++++++++++++++++++++++
1 file changed, 101 insertions(+)
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index f6751eecb78c..247883292ce5 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -2248,6 +2248,39 @@ set_timeout:
return -TARGET_EFAULT;
ret = get_errno(setsockopt(sockfd, SOL_SOCKET, optname, &val,
sizeof(val)));
break;
+#ifdef SOL_NETLINK
+ case SOL_NETLINK:
+ switch (optname) {
+ case NETLINK_PKTINFO:
+ case NETLINK_ADD_MEMBERSHIP:
+ case NETLINK_DROP_MEMBERSHIP:
+ case NETLINK_BROADCAST_ERROR:
+ case NETLINK_NO_ENOBUFS:
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0)
+ case NETLINK_LISTEN_ALL_NSID:
+ case NETLINK_CAP_ACK:
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0) */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)
+ case NETLINK_EXT_ACK:
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0) */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 20, 0)
+ case NETLINK_GET_STRICT_CHK:
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0) */
+ break;
+ default:
+ goto unimplemented;
+ }
+ val = 0;
+ if (optlen < sizeof(uint32_t)) {
+ return -TARGET_EINVAL;
+ }
+ if (get_user_u32(val, optval_addr)) {
+ return -TARGET_EFAULT;
+ }
+ ret = get_errno(setsockopt(sockfd, SOL_NETLINK, optname, &val,
+ sizeof(val)));
+ break;
+#endif /* SOL_NETLINK */
default:
unimplemented:
gemu_log("Unsupported setsockopt level=%d optname=%d\n", level,
optname);
@@ -2532,6 +2565,74 @@ static abi_long do_getsockopt(int sockfd, int level, int
optname,
break;
}
break;
+#ifdef SOL_NETLINK
+ case SOL_NETLINK:
+ switch (optname) {
+ case NETLINK_PKTINFO:
+ case NETLINK_BROADCAST_ERROR:
+ case NETLINK_NO_ENOBUFS:
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0)
+ case NETLINK_LISTEN_ALL_NSID:
+ case NETLINK_CAP_ACK:
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0) */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)
+ case NETLINK_EXT_ACK:
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0) */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 20, 0)
+ case NETLINK_GET_STRICT_CHK:
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0) */
+ if (get_user_u32(len, optlen)) {
+ return -TARGET_EFAULT;
+ }
+ if (len != sizeof(val)) {
+ return -TARGET_EINVAL;
+ }
+ lv = len;
+ ret = get_errno(getsockopt(sockfd, level, optname, &val, &lv));
+ if (ret < 0) {
+ return ret;
+ }
+ if (put_user_u32(lv, optlen)
+ || put_user_u32(val, optval_addr)) {
+ return -TARGET_EFAULT;
+ }
+ break;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0)
+ case NETLINK_LIST_MEMBERSHIPS:
+ {
+ uint32_t *results;
+ int i;
+ if (get_user_u32(len, optlen)) {
+ return -TARGET_EFAULT;
+ }
+ if (len < 0) {
+ return -TARGET_EINVAL;
+ }
+ results = lock_user(VERIFY_WRITE, optval_addr, len, 1);
+ if (!results) {
+ return -TARGET_EFAULT;
+ }
+ lv = len;
+ ret = get_errno(getsockopt(sockfd, level, optname, results, &lv));
+ if (ret < 0) {
+ unlock_user(results, optval_addr, 0);
+ return ret;
+ }
+ /* swap host endianess to target endianess. */
+ for (i = 0; i < (len / sizeof(uint32_t)); i++) {
+ results[i] = tswap32(results[i]);
+ }
+ if (put_user_u32(lv, optlen)) {
+ return -TARGET_EFAULT;
+ }
+ unlock_user(results, optval_addr, 0);
+ break;
+ }
+#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0) */
+ default:
+ goto unimplemented;
+ }
+#endif /* SOL_NETLINK */
default:
unimplemented:
gemu_log("getsockopt level=%d optname=%d not yet supported\n",
--
2.21.0
- [PULL 00/13] Linux user for 4.2 patches, Laurent Vivier, 2019/11/05
- [PULL 13/13] linux-user/alpha: Set r20 secondary return value, Laurent Vivier, 2019/11/05
- [PULL 01/13] linux-user: Support for NETLINK socket options,
Laurent Vivier <=
- [PULL 10/13] linux-user: Rename cpu_clone_regs to cpu_clone_regs_child, Laurent Vivier, 2019/11/05
- [PULL 07/13] linux-user/sparc: Use WREG_SP constant in sparc/signal.c, Laurent Vivier, 2019/11/05
- [PULL 02/13] scripts/qemu-binfmt-conf: Update for sparc64, Laurent Vivier, 2019/11/05
- [PULL 09/13] linux-user/sparc64: Fix target_signal_frame, Laurent Vivier, 2019/11/05
- [PULL 06/13] linux-user/sparc: Begin using WREG constants in sparc/signal.c, Laurent Vivier, 2019/11/05
- [PULL 05/13] linux-user/sparc: Use WREG constants in sparc/target_cpu.h, Laurent Vivier, 2019/11/05
- [PULL 04/13] target/sparc: Define an enumeration for accessing env->regwptr, Laurent Vivier, 2019/11/05
- [PULL 03/13] tests/tcg/multiarch/linux-test: Fix error check for shmat, Laurent Vivier, 2019/11/05
- [PULL 12/13] linux-user/sparc: Fix cpu_clone_regs_*, Laurent Vivier, 2019/11/05
- [PULL 08/13] linux-user/sparc: Fix WREG usage in setup_frame, Laurent Vivier, 2019/11/05