From nobody Fri May 17 13:37:30 2024 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=reject dis=none) header.from=google.com ARC-Seal: i=1; a=rsa-sha256; t=1597130000; cv=none; d=zohomail.com; s=zohoarc; b=bZcCE9TJFmCevfL6/NrLTCrzfiQBUAwCoP9aVcvTOqHbrURxCMJbEr04MPcZTVeJXPT/PjKRYma8SssITv/uOcQOj4GAosStAyPeM6l3irJk7N7xDEJy2Eew/6uYDI70dBvCC344zcuA56IhL6rm9PE9bGDI1OZUtHtQjm+uEbc= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1597130000; h=Content-Type:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To; bh=p92oowU9ZC1iU/Ox3DTKv9I37S1q6EF9YrLFp30qbYg=; b=CS+ws2LERBI1Fb3P/Drsh0jifTheJTt0oJfY3vsvHAcglvLn1xp+EQU/h5OHbqxfeKuWeI798Q3U4remlAsxeHSCIo/Af2Qu/VkJVA/GPdAzftuz4ESHkU1UDSfgv/XcDpztajT0wCjYwcjye7iEHV3LTK2g0YUy/lD1XubUtS4= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=reject dis=none) header.from= Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1597130000206701.0865636076653; Tue, 11 Aug 2020 00:13:20 -0700 (PDT) Received: from localhost ([::1]:45742 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1k5OTG-0008Nj-Ve for importer@patchew.org; Tue, 11 Aug 2020 03:13:19 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:52766) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from <3Q0QyXwMKCpQG0K4CC492.0CAE2AI-12J29BCB4BI.CF4@flex--scw.bounces.google.com>) id 1k5OQ3-0004tF-Gi for qemu-devel@nongnu.org; Tue, 11 Aug 2020 03:09:59 -0400 Received: from mail-yb1-xb4a.google.com ([2607:f8b0:4864:20::b4a]:50832) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from <3Q0QyXwMKCpQG0K4CC492.0CAE2AI-12J29BCB4BI.CF4@flex--scw.bounces.google.com>) id 1k5OQ1-0000kY-RB for qemu-devel@nongnu.org; Tue, 11 Aug 2020 03:09:59 -0400 Received: by mail-yb1-xb4a.google.com with SMTP id u189so15666105ybg.17 for ; Tue, 11 Aug 2020 00:09:56 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=p92oowU9ZC1iU/Ox3DTKv9I37S1q6EF9YrLFp30qbYg=; b=vuI8lyEKsYwoI7xSTLJUzpuEDBHgrrvOdEWYuEtcfBUfWNjambssmcotPuM2oeKiqY JPbzMZNAc93MBulP7nEHOTyQl7+Th66HznMkllK2ZW+G9jr2Nts3QiZLe4D+W9+Dnymz D9SFp5fPKcAvq/IrbD50TSnNhBgXDyr6XJN+fbogMACBbSSixeEIHUKFyihvA2nNmrJN 0wYlnCExxlvnhpAe43zPpbnGhr3bO3iVBFIqToC+2EBMSo/8qsURYCdM/o1IFggJqxZS QmqNaM4GioyJ9a/7x0JhkUDmUXp9zL5z1smDO4kjz1PcVPQ9ie86BvUtBzy0Js9IfNBM 2+BA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=p92oowU9ZC1iU/Ox3DTKv9I37S1q6EF9YrLFp30qbYg=; b=KTtOeUrxgoNOP/fWXRP7xLDxvQE8Lc3eNokudb//Z3rPghW4dO3umLixBAJwCvQSXu y+COriSkZVjujhSfYFOru3ybjrhpP6FAwkNUptgaN1AadQVxWUu8wseiLntP5DRla833 0YFfmGZYg2xRNH6pEU3el/OVn7ivO7H9Xitlvbu0LxE8LvSiOeXEH4iCh/1Y8K8H8Dc5 PSrDVWiAzy9H3Scj+qNW9FIaQ/2I7w3NRTe/gGjp6jELAyzot7bGm+NWhLU+3WvdFbG1 fTw/SykJWAl/9pZ51rOuOBEW+vKctzSWJlXv+n0hLzZbbNZX4jXNrGyZ0NitzIYoZ/Qu Mkuw== X-Gm-Message-State: AOAM532//WKKU0xdLjunKJWKO9T0l46Bffn5RhjZA7AJ7FiPRhXG9W1l dyZ1DzyeXOaYbmRUHth+ceqaiXc6w0TWZU75pGrXFu5Z2Sav57XD+RGuPv551wOi8sd7xUNgn5n rJ3/haZ7NGmdkQdKF7djAtNQfq8H8y/0em1PMybd1VXrV2p+rftmL X-Google-Smtp-Source: ABdhPJz8dwbOvoQpcPDcvQJAMYBZtYmGnQVvOQmmNivr9Ni3SebyqabG0zDmEwBiMSDMmrKKf//S/eU= X-Received: by 2002:a25:3b0d:: with SMTP id i13mr45459447yba.314.1597129795399; Tue, 11 Aug 2020 00:09:55 -0700 (PDT) Date: Tue, 11 Aug 2020 00:09:41 -0700 In-Reply-To: Message-Id: <020a4b8e2185a0aab62c99abd0d8f9d8ff315c37.1597129029.git.scw@google.com> Mime-Version: 1.0 References: X-Mailer: git-send-email 2.28.0.220.ged08abb693-goog Subject: [PATCH v2 1/8] linux-user: Support F_ADD_SEALS and F_GET_SEALS fcntls From: Shu-Chun Weng To: qemu-devel@nongnu.org Cc: Shu-Chun Weng , laurent@vivier.eu Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=2607:f8b0:4864:20::b4a; envelope-from=3Q0QyXwMKCpQG0K4CC492.0CAE2AI-12J29BCB4BI.CF4@flex--scw.bounces.google.com; helo=mail-yb1-xb4a.google.com X-detected-operating-system: by eggs.gnu.org: No matching host in p0f cache. That's all we know. X-Spam_score_int: -105 X-Spam_score: -10.6 X-Spam_bar: ---------- X-Spam_report: (-10.6 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_MED=-1, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, USER_IN_DEF_DKIM_WL=-7.5 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail-DKIM: pass (identity @google.com) Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Also reorder blocks so that they are all in the same order everywhere. Signed-off-by: Shu-Chun Weng Reviewed-by: Laurent Vivier --- v1 -> v2: Updated print_fcntl(). linux-user/strace.c | 55 ++++++++++++++++++++++++++++++++------- linux-user/syscall.c | 10 +++++++ linux-user/syscall_defs.h | 14 +++++----- 3 files changed, 64 insertions(+), 15 deletions(-) diff --git a/linux-user/strace.c b/linux-user/strace.c index 13981341b3..4fff24b880 100644 --- a/linux-user/strace.c +++ b/linux-user/strace.c @@ -1684,6 +1684,18 @@ print_fcntl(const struct syscallname *name, qemu_log("F_SETFL,"); print_open_flags(arg2, 1); break; + case TARGET_F_OFD_GETLK: + qemu_log("F_OFD_GETLK,"); + print_pointer(arg2, 1); + break; + case TARGET_F_OFD_SETLK: + qemu_log("F_OFD_SETLK,"); + print_pointer(arg2, 1); + break; + case TARGET_F_OFD_SETLKW: + qemu_log("F_OFD_SETLKW,"); + print_pointer(arg2, 1); + break; case TARGET_F_GETLK: qemu_log("F_GETLK,"); print_pointer(arg2, 1); @@ -1726,26 +1738,51 @@ print_fcntl(const struct syscallname *name, #endif case TARGET_F_SETLEASE: qemu_log("F_SETLEASE,"); - print_raw_param(TARGET_ABI_FMT_ld, arg2, 0); + print_raw_param(TARGET_ABI_FMT_ld, arg2, 1); break; case TARGET_F_GETLEASE: qemu_log("F_GETLEASE"); break; - case TARGET_F_SETPIPE_SZ: - qemu_log("F_SETPIPE_SZ,"); - print_raw_param(TARGET_ABI_FMT_ld, arg2, 1); - break; - case TARGET_F_GETPIPE_SZ: - qemu_log("F_GETPIPE_SZ"); - break; +#ifdef F_DUPFD_CLOEXEC case TARGET_F_DUPFD_CLOEXEC: qemu_log("F_DUPFD_CLOEXEC,"); print_raw_param(TARGET_ABI_FMT_ld, arg2, 1); break; +#endif case TARGET_F_NOTIFY: qemu_log("F_NOTIFY,"); - print_raw_param(TARGET_ABI_FMT_ld, arg2, 0); + print_raw_param(TARGET_ABI_FMT_ld, arg2, 1); break; +#ifdef F_GETOWN_EX + case TARGET_F_GETOWN_EX: + qemu_log("F_GETOWN_EX,"); + print_pointer(arg2, 1); + break; +#endif +#ifdef F_SETOWN_EX + case TARGET_F_SETOWN_EX: + qemu_log("F_SETOWN_EX,"); + print_pointer(arg2, 1); + break; +#endif +#ifdef F_SETPIPE_SZ + case TARGET_F_SETPIPE_SZ: + qemu_log("F_SETPIPE_SZ,"); + print_raw_param(TARGET_ABI_FMT_ld, arg2, 1); + break; + case TARGET_F_GETPIPE_SZ: + qemu_log("F_GETPIPE_SZ"); + break; +#endif +#ifdef F_ADD_SEALS + case TARGET_F_ADD_SEALS: + qemu_log("F_ADD_SEALS,"); + print_raw_param("0x"TARGET_ABI_FMT_lx, arg2, 1); + break; + case TARGET_F_GET_SEALS: + qemu_log("F_GET_SEALS"); + break; +#endif default: print_raw_param(TARGET_ABI_FMT_ld, arg1, 0); print_pointer(arg2, 1); diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 945fc25279..5645862798 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -6305,6 +6305,14 @@ static int target_to_host_fcntl_cmd(int cmd) case TARGET_F_GETPIPE_SZ: ret =3D F_GETPIPE_SZ; break; +#endif +#ifdef F_ADD_SEALS + case TARGET_F_ADD_SEALS: + ret =3D F_ADD_SEALS; + break; + case TARGET_F_GET_SEALS: + ret =3D F_GET_SEALS; + break; #endif default: ret =3D -TARGET_EINVAL; @@ -6591,6 +6599,8 @@ static abi_long do_fcntl(int fd, int cmd, abi_ulong a= rg) case TARGET_F_GETLEASE: case TARGET_F_SETPIPE_SZ: case TARGET_F_GETPIPE_SZ: + case TARGET_F_ADD_SEALS: + case TARGET_F_GET_SEALS: ret =3D get_errno(safe_fcntl(fd, host_cmd, arg)); break; =20 diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index 3c261cff0e..70df1a94fb 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -2292,12 +2292,14 @@ struct target_statfs64 { #endif =20 #define TARGET_F_LINUX_SPECIFIC_BASE 1024 -#define TARGET_F_SETLEASE (TARGET_F_LINUX_SPECIFIC_BASE + 0) -#define TARGET_F_GETLEASE (TARGET_F_LINUX_SPECIFIC_BASE + 1) -#define TARGET_F_DUPFD_CLOEXEC (TARGET_F_LINUX_SPECIFIC_BASE + 6) -#define TARGET_F_SETPIPE_SZ (TARGET_F_LINUX_SPECIFIC_BASE + 7) -#define TARGET_F_GETPIPE_SZ (TARGET_F_LINUX_SPECIFIC_BASE + 8) -#define TARGET_F_NOTIFY (TARGET_F_LINUX_SPECIFIC_BASE+2) +#define TARGET_F_SETLEASE (TARGET_F_LINUX_SPECIFIC_BASE + 0) +#define TARGET_F_GETLEASE (TARGET_F_LINUX_SPECIFIC_BASE + 1) +#define TARGET_F_DUPFD_CLOEXEC (TARGET_F_LINUX_SPECIFIC_BASE + 6) +#define TARGET_F_NOTIFY (TARGET_F_LINUX_SPECIFIC_BASE + 2) +#define TARGET_F_SETPIPE_SZ (TARGET_F_LINUX_SPECIFIC_BASE + 7) +#define TARGET_F_GETPIPE_SZ (TARGET_F_LINUX_SPECIFIC_BASE + 8) +#define TARGET_F_ADD_SEALS (TARGET_F_LINUX_SPECIFIC_BASE + 9) +#define TARGET_F_GET_SEALS (TARGET_F_LINUX_SPECIFIC_BASE + 10) =20 #include "target_fcntl.h" =20 --=20 2.28.0.220.ged08abb693-goog From nobody Fri May 17 13:37:30 2024 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=reject dis=none) header.from=google.com ARC-Seal: i=1; a=rsa-sha256; t=1597129929; cv=none; d=zohomail.com; s=zohoarc; b=C2mTK1p460ZL+yLsXz1G4QC7+DLqOOwPvJ8H33vJuy58tiIxtIUzBERt2aAgCh2Eut+eSdJAJ5+0BYxZvGPWIUVTvFw4BRKIA0cV1lTJikU/Js2g+V+6ZQzGz6QPTNH47dxYOpr4JwSjAgecLhXXmfVn6E7XGiRQvCdYxBfJPmA= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1597129929; h=Content-Type:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To; bh=KOl6cq6IjMqpEhD/kHPtyKl8qR4OtmqTxSk98Aj4Ezw=; b=lrbfTGbodfq2VDbzIe1XDKolJvrggNYzx/jGZ4uKQl5viOXORRwx3YtvibA5KfWjD0cM1FMvQ3VDvhziut+qNXBuQ3YZFJI48PB8KjM2cdiSpSG7dedib6SXBJa4C7IUf7jr4EmvrmyhGw5BwAx1xY/sUtuTJzrRub36OFGZsR4= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=reject dis=none) header.from= Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1597129929203897.5175908306861; Tue, 11 Aug 2020 00:12:09 -0700 (PDT) Received: from localhost ([::1]:40580 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1k5OS8-0006IL-2U for importer@patchew.org; Tue, 11 Aug 2020 03:12:08 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:52776) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from <3RUQyXwMKCpYI2M6EE6B4.2ECG4CK-34L4BDED6DK.EH6@flex--scw.bounces.google.com>) id 1k5OQ4-0004ug-KZ for qemu-devel@nongnu.org; Tue, 11 Aug 2020 03:10:00 -0400 Received: from mail-yb1-xb4a.google.com ([2607:f8b0:4864:20::b4a]:53319) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from <3RUQyXwMKCpYI2M6EE6B4.2ECG4CK-34L4BDED6DK.EH6@flex--scw.bounces.google.com>) id 1k5OQ3-0000kk-1J for qemu-devel@nongnu.org; Tue, 11 Aug 2020 03:10:00 -0400 Received: by mail-yb1-xb4a.google.com with SMTP id d26so15749429yba.20 for ; Tue, 11 Aug 2020 00:09:58 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=KOl6cq6IjMqpEhD/kHPtyKl8qR4OtmqTxSk98Aj4Ezw=; b=qA3kiYx7CMnnRBAOMofzmp6ZPT++yucztp/xlZzbakC5dC8zSvVTtwRBPmPBo99F34 ++Hm6EF+AKCjzjAErpMW2VyQatr1IlYn2P58vkxsBN80Zs9lUHBF+W2Il1EuI2/mJMg4 xbJL3MtjsRbXLGvKRkWlRXdwcDFG5M+Ef2Eu4iaq+f0rcI+W3aABIc3WAJT9BvIgs9kX bcKYWdf0apz3YPW5yrwj0gFQxb9m3ehW8Fq5SRq4qmkuS01ctEImLHGUENuQio2O4X0O dKfBePYgAE56QzVdzRavwYygdM5GOj3lFNg7iRGwwQwnkMCLz9HuElyVrnNohNpV/ZVM KW1Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=KOl6cq6IjMqpEhD/kHPtyKl8qR4OtmqTxSk98Aj4Ezw=; b=g0V57tCWa1NctTf8zF2dvCyEZhxWVDecBMiVLqLclPBf7Pp7Dox1ydsk+pJCONs1WD m6I71mWu/IWSXrIZWziV75qclS5rY1i/Bd1QSHrSULHnSGAot5bKnH4mkiRKbfWO5pf3 eUaGPnjcyaUAF9LazzK9v4jbsyJwSR92SDGaI+3VAnobWxpMN8li07Z4O9j3c1fGPGDq Z0ubA8oL0U/nyFti1fRvadYLzS4SK4BZVon35gfQTDIJyOfKJcGjVyrTbTdzPr/Dw94p bMIqWsJpz0twdhR0h5pQoN4wdNgewY3YcF+bjVtz4nbIJZlx5oM6P3qgHJ3tY5nP1Tup ulKQ== X-Gm-Message-State: AOAM531Ipsa5KXjYF2xkJ0GaNbhxBZQ8yL3qSQmPnnGADkx+b2oJTuPD 6VsSGiCNC8L/C6PVHo8uIRWXKZrXk6dOkmLRpeV5kn1p524d22yJbc/RYyEHMBNGgHrOQty64rt eG57/5O6UCk2ahcXbkgO7q2JWIVYAMjf+cFI+UK2pSc/lxIKO9KP0 X-Google-Smtp-Source: ABdhPJywbTZAZr4pvyFKc4CT+AEyzs28KTLqCHe8wOL1Urxw3v8g5ZU5uYhUch0tPH1IMgjzjt9YnnU= X-Received: by 2002:a25:83c1:: with SMTP id v1mr44915743ybm.264.1597129797343; Tue, 11 Aug 2020 00:09:57 -0700 (PDT) Date: Tue, 11 Aug 2020 00:09:42 -0700 In-Reply-To: Message-Id: <71ad91e4ee9f41f439086d8f9de60501ad304859.1597129029.git.scw@google.com> Mime-Version: 1.0 References: X-Mailer: git-send-email 2.28.0.220.ged08abb693-goog Subject: [PATCH v2 2/8] linux-user: add missing UDP get/setsockopt option From: Shu-Chun Weng To: qemu-devel@nongnu.org Cc: Shu-Chun Weng , laurent@vivier.eu Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=2607:f8b0:4864:20::b4a; envelope-from=3RUQyXwMKCpYI2M6EE6B4.2ECG4CK-34L4BDED6DK.EH6@flex--scw.bounces.google.com; helo=mail-yb1-xb4a.google.com X-detected-operating-system: by eggs.gnu.org: No matching host in p0f cache. That's all we know. X-Spam_score_int: -105 X-Spam_score: -10.6 X-Spam_bar: ---------- X-Spam_report: (-10.6 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_MED=-1, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, USER_IN_DEF_DKIM_WL=-7.5 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail-DKIM: pass (identity @google.com) Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" SOL_UDP manipulate options at UDP level. All six options currently defined in linux source include/uapi/linux/udp.h take integer values. Signed-off-by: Shu-Chun Weng Reviewed-by: Laurent Vivier --- v1 -> v2: Split out SOL_UDP into own patch. Updated do_print_sockopt(). linux-user/strace.c | 6 ++++++ linux-user/syscall.c | 7 +++++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/linux-user/strace.c b/linux-user/strace.c index 4fff24b880..854b54a2ad 100644 --- a/linux-user/strace.c +++ b/linux-user/strace.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -2190,6 +2191,11 @@ static void do_print_sockopt(const char *name, abi_l= ong arg1) print_raw_param(TARGET_ABI_FMT_ld, optname, 0); print_pointer(optval, 0); break; + case SOL_UDP: + qemu_log("SOL_UDP,"); + print_raw_param(TARGET_ABI_FMT_ld, optname, 0); + print_pointer(optval, 0); + break; case SOL_IP: qemu_log("SOL_IP,"); print_raw_param(TARGET_ABI_FMT_ld, optname, 0); diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 5645862798..177eec5201 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -53,6 +53,7 @@ //#include #include #include +#include #include #include #include @@ -1938,7 +1939,8 @@ static abi_long do_setsockopt(int sockfd, int level, = int optname, =20 switch(level) { case SOL_TCP: - /* TCP options all take an 'int' value. */ + case SOL_UDP: + /* TCP and UDP options all take an 'int' value. */ if (optlen < sizeof(uint32_t)) return -TARGET_EINVAL; =20 @@ -2586,7 +2588,8 @@ get_timeout: } break; case SOL_TCP: - /* TCP options all take an 'int' value. */ + case SOL_UDP: + /* TCP and UDP options all take an 'int' value. */ int_case: if (get_user_u32(len, optlen)) return -TARGET_EFAULT; --=20 2.28.0.220.ged08abb693-goog From nobody Fri May 17 13:37:30 2024 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=reject dis=none) header.from=google.com ARC-Seal: i=1; a=rsa-sha256; t=1597130008; cv=none; d=zohomail.com; s=zohoarc; b=N1d1fGQWrhDYtr/9Npx3hFrpcjwEQm6yh34rxoGgIDj/xH/KjvUoP6D/C2uVp5ZMDZqI6MYE12lueMzhri2Ts/dNnoPKM9H2vvGXXAKWc8OOvGaTh2i93ySF71R+aoYUGO6FjZBxwoXkC/xT+wUxm8CLOYXQzxcmt2kBLQoVQbc= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1597130008; h=Content-Type:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To; bh=+M+uJICEFeg+txNwQtx91pgPQOjSg5KEj10o5w9tEBM=; b=lYoHdlCyw8FXvbcr5wnLmmH9CbBjk21116b0Vq7fSs64lPgT9mgjjTPaXt3m6gQzahWhNtNKthLGrR/0gL+NvDKNx1e9O5UGCNVOw1af8ERvFkb+evJxdvPiy/mtzF6YQaP6b1RAjHrQ+ZFg0aJGBVPBGfQHx90qLTqJEqiwtDk= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=reject dis=none) header.from= Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1597130008424447.26044005413735; Tue, 11 Aug 2020 00:13:28 -0700 (PDT) Received: from localhost ([::1]:46040 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1k5OTP-0008Uz-8c for importer@patchew.org; Tue, 11 Aug 2020 03:13:27 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:52790) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from <3R0QyXwMKCpgK4O8GG8D6.4GEI6EM-56N6DFGF8FM.GJ8@flex--scw.bounces.google.com>) id 1k5OQ6-0004x2-NV for qemu-devel@nongnu.org; Tue, 11 Aug 2020 03:10:02 -0400 Received: from mail-yb1-xb4a.google.com ([2607:f8b0:4864:20::b4a]:40277) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from <3R0QyXwMKCpgK4O8GG8D6.4GEI6EM-56N6DFGF8FM.GJ8@flex--scw.bounces.google.com>) id 1k5OQ5-0000ky-2r for qemu-devel@nongnu.org; Tue, 11 Aug 2020 03:10:02 -0400 Received: by mail-yb1-xb4a.google.com with SMTP id l67so15698188ybb.7 for ; Tue, 11 Aug 2020 00:10:00 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=+M+uJICEFeg+txNwQtx91pgPQOjSg5KEj10o5w9tEBM=; b=MysnBrixrRZSukqLhob985+MpOw8BqS/sOAuzlZetszjKXJeVeDyvsZw+xknOfNyOP q+ZjmML36OO/jDlwRvVaKMeEB5M3wCMlrG6x1Qto3VJhQ89U9ixpwzBAnOudmvt4gC+P XZJoj/ezaaK1JwV+2+TEkkUqQEXZIJGVybRdrxKOyj9VBkzT1Wn3pCIEk+A7ypL4o2tA +UCGxrAklG8sQyJJ2/nuLBlztUMk2z14/lDLDNLd4V505Qymypa1EKNQdwvjSF0FsCq6 W7n+DkdbYL6IYeh7WrxEbdU7B6y7aXn4QaRaXOs6nTuz+B18v0xNPXCLMrYprzdiySD8 0YOw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=+M+uJICEFeg+txNwQtx91pgPQOjSg5KEj10o5w9tEBM=; b=QT7Ph7DG4wsMwQ+yZ5DuPkSMa4wQFcgNMkXoLGLmeinpoRDvek9EX6zAiynTAJLRzL WNVcCdlWQUALEqNF2jPmapspg72QwE8RX9YGFJyxAr5Tzz/sjpWZDZcwX58qLXkZeAD+ MckVVgkrJtg1O4VoDXtyEZNkH7tqji5v9j2GKsrCNVpfmJVbCCJwdE17NujIJyaNPK3T TOGcyRpbxhhbr3DHYTvqYDt50sSP98TZ6s3yox5NjhEoOErADVrJZ587dJcm8urNGkYV HDNunkuwCLuJkdlwnjpFwIcTh8CB2QMB/8kFcTl99K52mDQ4IN50juv1Po4mwU5JdFGA GFkw== X-Gm-Message-State: AOAM53386/PCzo8GlyKjxUDOBLvCBlK5vVvgLjZO4hj1znEcECrpUjVa YaLNEVwVYIEBkMLm0hsX29P8CXTVO7JmcuvSiMpYKyjlwzy5k0AVTkS0khfVwmYqEACrw8eBLcS bJqSE9/R9yt1ccyttV2bZvD6HMWUWe0Mlt0xBxYHFmCSNP+KN/jH2 X-Google-Smtp-Source: ABdhPJxKoxWeJvLmEYlfgZ6I+Ec6rwkk6fUbiDEfAgQa06x60jxY2qcrMD7vnpI5xcCorHO4slwVVwg= X-Received: by 2002:a5b:b45:: with SMTP id b5mr45443180ybr.294.1597129799243; Tue, 11 Aug 2020 00:09:59 -0700 (PDT) Date: Tue, 11 Aug 2020 00:09:43 -0700 In-Reply-To: Message-Id: <9a8368ac4b1988dbfb2465a926d769bdc23011a1.1597129029.git.scw@google.com> Mime-Version: 1.0 References: X-Mailer: git-send-email 2.28.0.220.ged08abb693-goog Subject: [PATCH v2 3/8] linux-user: add missing IPv6 get/setsockopt option From: Shu-Chun Weng To: qemu-devel@nongnu.org Cc: Shu-Chun Weng , laurent@vivier.eu Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=2607:f8b0:4864:20::b4a; envelope-from=3R0QyXwMKCpgK4O8GG8D6.4GEI6EM-56N6DFGF8FM.GJ8@flex--scw.bounces.google.com; helo=mail-yb1-xb4a.google.com X-detected-operating-system: by eggs.gnu.org: No matching host in p0f cache. That's all we know. X-Spam_score_int: -105 X-Spam_score: -10.6 X-Spam_bar: ---------- X-Spam_report: (-10.6 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_MED=-1, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, USER_IN_DEF_DKIM_WL=-7.5 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail-DKIM: pass (identity @google.com) Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" IPV6_ADDR_PREFERENCES (RFC5014: Source address selection) was not supported. Signed-off-by: Shu-Chun Weng Reviewed-by: Laurent Vivier --- v1 -> v2: Split out IPV6 options into own patch. do_print_sockopt() changes added in a separate patch since a large number= of unrelated changes are involved. linux-user/syscall.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/linux-user/syscall.c b/linux-user/syscall.c index 177eec5201..cda194a7cc 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -51,6 +51,7 @@ #include #include //#include +#include #include #include #include @@ -2026,6 +2027,7 @@ static abi_long do_setsockopt(int sockfd, int level, = int optname, case IPV6_RECVDSTOPTS: case IPV6_2292DSTOPTS: case IPV6_TCLASS: + case IPV6_ADDR_PREFERENCES: #ifdef IPV6_RECVPATHMTU case IPV6_RECVPATHMTU: #endif @@ -2680,6 +2682,7 @@ get_timeout: case IPV6_RECVDSTOPTS: case IPV6_2292DSTOPTS: case IPV6_TCLASS: + case IPV6_ADDR_PREFERENCES: #ifdef IPV6_RECVPATHMTU case IPV6_RECVPATHMTU: #endif --=20 2.28.0.220.ged08abb693-goog From nobody Fri May 17 13:37:30 2024 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=reject dis=none) header.from=google.com ARC-Seal: i=1; a=rsa-sha256; t=1597129932; cv=none; d=zohomail.com; s=zohoarc; b=Esn5e0rP4rGLvUJG+O/4lI6xYFpMcUZrrXxvDZIynlGCRmICVNq6tkRx11zYKvXxVQzzYFIeiVg7IFLnjzyGp/lKhLzHPBm8DtdCLgwxDdUt52xLImaywH9jLRw1D0tDX0WWCQtYHBwnsb0JZFAAa0w6N/rvVl31imPc+Q6Gvgo= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1597129932; h=Content-Type:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To; bh=kIYHcj8O3Sfi4MxJmcqz8ARBjlQe767Toz5vJcOBiIo=; b=dpuLpEXgaw/zbvEWrQ/mnUsOFPM8V3wNZJ3f66moCm8rU997yHDAqJaaYnAJo9cVoLyBzOencathwywjf5dgtyH0/5T+XlqzGkxZx41Qs0/OQwho98+5g3kQHjgBI0Txx5KVOxVgj1U4gANdVFM7ojL80XH9UEoQXkKxrE1fnrc= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=reject dis=none) header.from= Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1597129932528578.4375990403495; Tue, 11 Aug 2020 00:12:12 -0700 (PDT) Received: from localhost ([::1]:40868 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1k5OSB-0006PK-7C for importer@patchew.org; Tue, 11 Aug 2020 03:12:11 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:52810) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from <3SUQyXwMKCpoM6QAIIAF8.6IGK8GO-78P8FHIHAHO.ILA@flex--scw.bounces.google.com>) id 1k5OQC-00050C-IR for qemu-devel@nongnu.org; Tue, 11 Aug 2020 03:10:08 -0400 Received: from mail-yb1-xb49.google.com ([2607:f8b0:4864:20::b49]:53014) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from <3SUQyXwMKCpoM6QAIIAF8.6IGK8GO-78P8FHIHAHO.ILA@flex--scw.bounces.google.com>) id 1k5OQ7-0000l9-HL for qemu-devel@nongnu.org; Tue, 11 Aug 2020 03:10:08 -0400 Received: by mail-yb1-xb49.google.com with SMTP id x10so15513318ybj.19 for ; Tue, 11 Aug 2020 00:10:02 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=kIYHcj8O3Sfi4MxJmcqz8ARBjlQe767Toz5vJcOBiIo=; b=VWRDYSIM5vTXIVcgrPYgfGx8la+AIP1rMuns3KBfJ5/F75+tNJgZcqQUOZNrAxwve5 LgeLjYaXSUg5d7bBwlFT1kUPKojAzoSSZhjiMyrQU4XKu4DEWDjh5r4Iy2L0LpiO/E/H 7EV7ACmZ7uDO7fHkRCLudmvgvYmqu4je8v8odXRATcuq77dLvOcKxb1Z/AdoMfIWyEck gQfTG0bvASOoC6GqMRcdR7G9Za76QirK+lglZ94P+AjdyeJh6Sh0x7cIY9+badPDBFhG n3Na6AQem5CCL6bREiX9I2GaIHef1lt03/BWKRWLjw3Y5WVh7DH9ZFwThc3NeGaQcv8z wGEg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=kIYHcj8O3Sfi4MxJmcqz8ARBjlQe767Toz5vJcOBiIo=; b=SY03JdHcRm0g4f+jBz6m3lGG5Ee1I8D+AssImcv8hpq7jcyex9KLfqy5RZQOENJykN 88CarY9VeudsRzN2oLsiBl/k56nQy4sOmieWQweisOiRPMDFTj8X/CyXblxVRniQ6WN1 5EOwE1BV/oaQ4/It0F0RNoO5G3EmBxYojnJXooFds1fnNLu0VhAWDTJtRMlKqGZs6emL Ul6+GnPic07VCTAMv854htaFypP1VQWFmksCvpLObLcVxucwiulBVy7VwqXxc+Ry+D6t qDlwpWHr/AtcSpFaxHej0ot1/YkrwXEhKYuMI32zWw6sGMvpHm0DFMfcLzaY0CiSIc2w bCfQ== X-Gm-Message-State: AOAM531e/QWucRtIRVN1/01O2BC4RuNYRx30IxpJ6OvgQpXBMKSbajnv Mhu/z6HlfGrwMXwknut8m9OWMeUv9wzEBJFrEt/X1H/65H38XF0KCrmzbcCajrV7SCVsfogYoYO I7HB3cwzUgezRwvsfaJFUEbka0VER6pChr61E1oBena+ioLAuxfsA X-Google-Smtp-Source: ABdhPJwQnWeGsbzG9OmLZJ/f7NJFcGXqIIFQdcH7aJyscPo22k+tzzqS6Mb4R9/BogOnpKohJx/wcZA= X-Received: by 2002:a25:aaf3:: with SMTP id t106mr42481925ybi.56.1597129801240; Tue, 11 Aug 2020 00:10:01 -0700 (PDT) Date: Tue, 11 Aug 2020 00:09:44 -0700 In-Reply-To: Message-Id: <7d61f792c22de8df3c6a9438eacc3906620e7c54.1597129029.git.scw@google.com> Mime-Version: 1.0 References: X-Mailer: git-send-email 2.28.0.220.ged08abb693-goog Subject: [PATCH v2 4/8] linux-user: Add IPv6 options to do_print_sockopt() From: Shu-Chun Weng To: qemu-devel@nongnu.org Cc: Shu-Chun Weng , laurent@vivier.eu Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=2607:f8b0:4864:20::b49; envelope-from=3SUQyXwMKCpoM6QAIIAF8.6IGK8GO-78P8FHIHAHO.ILA@flex--scw.bounces.google.com; helo=mail-yb1-xb49.google.com X-detected-operating-system: by eggs.gnu.org: No matching host in p0f cache. That's all we know. X-Spam_score_int: -105 X-Spam_score: -10.6 X-Spam_bar: ---------- X-Spam_report: (-10.6 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_MED=-1, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, USER_IN_DEF_DKIM_WL=-7.5 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail-DKIM: pass (identity @google.com) Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Signed-off-by: Shu-Chun Weng Reviewed-by: Laurent Vivier --- v1 -> v2: New: Add all IPV6 options to do_print_sockopt(), including the newly supp= orted IPV6_ADDR_PREFERENCES. linux-user/strace.c | 108 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 108 insertions(+) diff --git a/linux-user/strace.c b/linux-user/strace.c index 854b54a2ad..089fb3968e 100644 --- a/linux-user/strace.c +++ b/linux-user/strace.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -2307,6 +2308,113 @@ print_optint: break; } break; + case SOL_IPV6: + qemu_log("SOL_IPV6,"); + switch (optname) { + case IPV6_MTU_DISCOVER: + qemu_log("IPV6_MTU_DISCOVER,"); + goto print_optint; + case IPV6_MTU: + qemu_log("IPV6_MTU,"); + goto print_optint; + case IPV6_V6ONLY: + qemu_log("IPV6_V6ONLY,"); + goto print_optint; + case IPV6_RECVPKTINFO: + qemu_log("IPV6_RECVPKTINFO,"); + goto print_optint; + case IPV6_UNICAST_HOPS: + qemu_log("IPV6_UNICAST_HOPS,"); + goto print_optint; + case IPV6_MULTICAST_HOPS: + qemu_log("IPV6_MULTICAST_HOPS,"); + goto print_optint; + case IPV6_MULTICAST_LOOP: + qemu_log("IPV6_MULTICAST_LOOP,"); + goto print_optint; + case IPV6_RECVERR: + qemu_log("IPV6_RECVERR,"); + goto print_optint; + case IPV6_RECVHOPLIMIT: + qemu_log("IPV6_RECVHOPLIMIT,"); + goto print_optint; + case IPV6_2292HOPLIMIT: + qemu_log("IPV6_2292HOPLIMIT,"); + goto print_optint; + case IPV6_CHECKSUM: + qemu_log("IPV6_CHECKSUM,"); + goto print_optint; + case IPV6_ADDRFORM: + qemu_log("IPV6_ADDRFORM,"); + goto print_optint; + case IPV6_2292PKTINFO: + qemu_log("IPV6_2292PKTINFO,"); + goto print_optint; + case IPV6_RECVTCLASS: + qemu_log("IPV6_RECVTCLASS,"); + goto print_optint; + case IPV6_RECVRTHDR: + qemu_log("IPV6_RECVRTHDR,"); + goto print_optint; + case IPV6_2292RTHDR: + qemu_log("IPV6_2292RTHDR,"); + goto print_optint; + case IPV6_RECVHOPOPTS: + qemu_log("IPV6_RECVHOPOPTS,"); + goto print_optint; + case IPV6_2292HOPOPTS: + qemu_log("IPV6_2292HOPOPTS,"); + goto print_optint; + case IPV6_RECVDSTOPTS: + qemu_log("IPV6_RECVDSTOPTS,"); + goto print_optint; + case IPV6_2292DSTOPTS: + qemu_log("IPV6_2292DSTOPTS,"); + goto print_optint; + case IPV6_TCLASS: + qemu_log("IPV6_TCLASS,"); + goto print_optint; + case IPV6_ADDR_PREFERENCES: + qemu_log("IPV6_ADDR_PREFERENCES,"); + goto print_optint; +#ifdef IPV6_RECVPATHMTU + case IPV6_RECVPATHMTU: + qemu_log("IPV6_RECVPATHMTU,"); + goto print_optint; +#endif +#ifdef IPV6_TRANSPARENT + case IPV6_TRANSPARENT: + qemu_log("IPV6_TRANSPARENT,"); + goto print_optint; +#endif +#ifdef IPV6_FREEBIND + case IPV6_FREEBIND: + qemu_log("IPV6_FREEBIND,"); + goto print_optint; +#endif +#ifdef IPV6_RECVORIGDSTADDR + case IPV6_RECVORIGDSTADDR: + qemu_log("IPV6_RECVORIGDSTADDR,"); + goto print_optint; +#endif + case IPV6_PKTINFO: + qemu_log("IPV6_PKTINFO,"); + print_pointer(optval, 0); + break; + case IPV6_ADD_MEMBERSHIP: + qemu_log("IPV6_ADD_MEMBERSHIP,"); + print_pointer(optval, 0); + break; + case IPV6_DROP_MEMBERSHIP: + qemu_log("IPV6_DROP_MEMBERSHIP,"); + print_pointer(optval, 0); + break; + default: + print_raw_param(TARGET_ABI_FMT_ld, optname, 0); + print_pointer(optval, 0); + break; + } + break; default: print_raw_param(TARGET_ABI_FMT_ld, level, 0); print_raw_param(TARGET_ABI_FMT_ld, optname, 0); --=20 2.28.0.220.ged08abb693-goog From nobody Fri May 17 13:37:30 2024 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=reject dis=none) header.from=google.com ARC-Seal: i=1; a=rsa-sha256; t=1597130140; cv=none; d=zohomail.com; s=zohoarc; b=JY84Megaa5rBnfcgOS9oPsrjAYDbs3z7Q9aBtKZRtwZrDs2jzOpZOFKgJPSK2ir/WjQSbqFYSA/i0pwTt4gd4t5re15ZYXWcU33LAwb9VelmdpYmm5cvBpCpqFmi9xPwQVSlTfAAzp7qZZAAGedQSfXSxmErSPBzFh33OAudRVQ= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1597130140; h=Content-Type:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To; bh=fVISdSL7SAJXIAhsvIFI0k3nRGfVddtDxh8lna7beHE=; b=eWS6TIYO4BE73q2XZqIT47aqS1BtKskc73tKoALBTOFK0T4UVpdMB/Url26XMkUT9+peL06QIFb7GW2/QJslp3ChwFoGPheDDBpPAQKJof9psqjlzg0uyzkzqI8p98XfCml5guHuvEWtSVVIEKutwXfYNkR/cGTmulsSvUtL6O8= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=reject dis=none) header.from= Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1597130140166873.0945376433127; Tue, 11 Aug 2020 00:15:40 -0700 (PDT) Received: from localhost ([::1]:51110 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1k5OVW-0002B4-Cj for importer@patchew.org; Tue, 11 Aug 2020 03:15:38 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:52856) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from <3S0QyXwMKCpwO8SCKKCHA.8KIMAIQ-9ARAHJKJCJQ.KNC@flex--scw.bounces.google.com>) id 1k5OQF-00053E-H0 for qemu-devel@nongnu.org; Tue, 11 Aug 2020 03:10:12 -0400 Received: from mail-pg1-x549.google.com ([2607:f8b0:4864:20::549]:36932) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from <3S0QyXwMKCpwO8SCKKCHA.8KIMAIQ-9ARAHJKJCJQ.KNC@flex--scw.bounces.google.com>) id 1k5OQC-0000lO-Jr for qemu-devel@nongnu.org; Tue, 11 Aug 2020 03:10:11 -0400 Received: by mail-pg1-x549.google.com with SMTP id x3so2809984pga.4 for ; Tue, 11 Aug 2020 00:10:04 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=fVISdSL7SAJXIAhsvIFI0k3nRGfVddtDxh8lna7beHE=; b=JGpkjbK6mQEmWi0MfJvr22Rep72csiZp1ei1jhprBf4ADIdIq7X6CgTTsO9WXYMNg1 8JRUuboKXkBk5WrFXcx/H2gYM6PlHBGd9eBrott7aLdrxc2f1kGz0Q07pXahk1APyhJy nfI6pF8l74FXUswGs7YVFHjXZGNqQ0rowwMa55LFRWZkiWdsh2h6Z0yqFyjZ1P5qhW6x rGhWFthkFumiVT2CoAY/iRIOJyL1fu3ojONRq59cUE82uN7cbMBHcGt3kKpt+JWV/UNg aGXgydYveTJPV8kafSGhDc16OriJa25/rOPJFsQVyGE3CpFPERvejfPomZnkD2p3BAMt Z0Tg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=fVISdSL7SAJXIAhsvIFI0k3nRGfVddtDxh8lna7beHE=; b=lIa3aJdFysZIbxvmgWeJPzZ1SQY7RYAsgB0q+/IjfjYzZN+AoK/P5rd5frYFWT6bs+ yrljIvMdz774Np7dS0fBCtBYoYD2NVTfXJDYWeDrtWoZQ9ZrmelHLkULnAgEZtUdSEpD AX04NzD8pJtPQ7Tly7c1Putce5QyMxe/al+1HiTpiNE77i65u7fJf+v6hHcEL5ufSjov WnPtTg9U4jeDh/KMRAzEZ62qpmWJ8s9nBNf4e2lu2/Qu50Uo6zrdpyzMCmyR539oruLm 6L+vTY9+Y3+3fjPRAxxSgawZwAAODV+f0jOFVtkbSU7R1ioZvisyeMug0ft+qZJkFsVF PQmA== X-Gm-Message-State: AOAM531zBs7VL9+dY2UtELKWwfi+HSorifmaoAwkAd5XGGPuxI5j0kJb +jARaXfoCLOsCLal0qf1sChGobnLjRnC4ZllvcJfo5R2YRihP4afKW2LOu9zeLtiZJaNMF/5c56 /x9mmlCG3xAraPAwupo/psG7u/0JcBoCsj16MBiD+peXxOug4PMVg X-Google-Smtp-Source: ABdhPJx/NtwZ1UMPr7MkwTrX/HHBUcm2gkeANgpp3t9Jg0pnU/oEiexadAYN8Sfy8TdNWzaIPGnclvE= X-Received: by 2002:a17:90a:9b88:: with SMTP id g8mr3275892pjp.143.1597129803232; Tue, 11 Aug 2020 00:10:03 -0700 (PDT) Date: Tue, 11 Aug 2020 00:09:45 -0700 In-Reply-To: Message-Id: <611db81c87911cb38a35e5f761e11b76e1f0d538.1597129029.git.scw@google.com> Mime-Version: 1.0 References: X-Mailer: git-send-email 2.28.0.220.ged08abb693-goog Subject: [PATCH v2 5/8] linux-user: Update SO_TIMESTAMP to SO_TIMESTAMP_OLD/NEW From: Shu-Chun Weng To: qemu-devel@nongnu.org Cc: Shu-Chun Weng , laurent@vivier.eu Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=2607:f8b0:4864:20::549; envelope-from=3S0QyXwMKCpwO8SCKKCHA.8KIMAIQ-9ARAHJKJCJQ.KNC@flex--scw.bounces.google.com; helo=mail-pg1-x549.google.com X-detected-operating-system: by eggs.gnu.org: No matching host in p0f cache. That's all we know. X-Spam_score_int: -105 X-Spam_score: -10.6 X-Spam_bar: ---------- X-Spam_report: (-10.6 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_MED=-1, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, USER_IN_DEF_DKIM_WL=-7.5 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail-DKIM: pass (identity @google.com) Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Both guest options map to host SO_TIMESTAMP while keeping a global bit to remember if the guest expects the old or the new format. Don't support programs mixing two formats. Added a multiarch test to verify. Signed-off-by: Shu-Chun Weng --- v1 -> v2: Only keep track of old or new format globally, remove support for differe= nt sockets mixing different formats. Fix style problems. linux-user/alpha/sockbits.h | 8 +- linux-user/generic/sockbits.h | 9 +- linux-user/hppa/sockbits.h | 8 +- linux-user/mips/sockbits.h | 8 +- linux-user/sparc/sockbits.h | 8 +- linux-user/strace.c | 7 +- linux-user/syscall.c | 91 ++++++-- tests/tcg/multiarch/socket_timestamp.c | 296 +++++++++++++++++++++++++ 8 files changed, 408 insertions(+), 27 deletions(-) create mode 100644 tests/tcg/multiarch/socket_timestamp.c diff --git a/linux-user/alpha/sockbits.h b/linux-user/alpha/sockbits.h index d54dc98c09..40f0644df0 100644 --- a/linux-user/alpha/sockbits.h +++ b/linux-user/alpha/sockbits.h @@ -48,8 +48,6 @@ #define TARGET_SO_DETACH_FILTER 27 =20 #define TARGET_SO_PEERNAME 28 -#define TARGET_SO_TIMESTAMP 29 -#define TARGET_SCM_TIMESTAMP TARGET_SO_TIMESTAMP =20 #define TARGET_SO_PEERSEC 30 #define TARGET_SO_PASSSEC 34 @@ -75,6 +73,12 @@ /* Instruct lower device to use last 4-bytes of skb data as FCS */ #define TARGET_SO_NOFCS 43 =20 +#define TARGET_SO_TIMESTAMP_OLD 29 +#define TARGET_SCM_TIMESTAMP_OLD TARGET_SO_TIMESTAMP_OLD + +#define TARGET_SO_TIMESTAMP_NEW 63 +#define TARGET_SCM_TIMESTAMP_NEW TARGET_SO_TIMESTAMP_NEW + /* TARGET_O_NONBLOCK clashes with the bits used for socket types. Therefo= re we * have to define SOCK_NONBLOCK to a different value here. */ diff --git a/linux-user/generic/sockbits.h b/linux-user/generic/sockbits.h index e44733c601..532cf2d3dc 100644 --- a/linux-user/generic/sockbits.h +++ b/linux-user/generic/sockbits.h @@ -49,10 +49,15 @@ #define TARGET_SO_DETACH_FILTER 27 =20 #define TARGET_SO_PEERNAME 28 -#define TARGET_SO_TIMESTAMP 29 -#define TARGET_SCM_TIMESTAMP TARGET_SO_TIMESTAMP =20 #define TARGET_SO_ACCEPTCONN 30 =20 #define TARGET_SO_PEERSEC 31 + +#define TARGET_SO_TIMESTAMP_OLD 29 +#define TARGET_SCM_TIMESTAMP_OLD TARGET_SO_TIMESTAMP_OLD + +#define TARGET_SO_TIMESTAMP_NEW 63 +#define TARGET_SCM_TIMESTAMP_NEW TARGET_SO_TIMESTAMP_NEW + #endif diff --git a/linux-user/hppa/sockbits.h b/linux-user/hppa/sockbits.h index 23f69a3293..284a47e74e 100644 --- a/linux-user/hppa/sockbits.h +++ b/linux-user/hppa/sockbits.h @@ -29,8 +29,6 @@ #define TARGET_SO_BSDCOMPAT 0x400e #define TARGET_SO_PASSCRED 0x4010 #define TARGET_SO_PEERCRED 0x4011 -#define TARGET_SO_TIMESTAMP 0x4012 -#define TARGET_SCM_TIMESTAMP TARGET_SO_TIMESTAMP #define TARGET_SO_TIMESTAMPNS 0x4013 #define TARGET_SCM_TIMESTAMPNS TARGET_SO_TIMESTAMPNS =20 @@ -67,6 +65,12 @@ =20 #define TARGET_SO_CNX_ADVICE 0x402E =20 +#define TARGET_SO_TIMESTAMP_OLD 0x4012 +#define TARGET_SCM_TIMESTAMP_OLD TARGET_SO_TIMESTAMP_OLD + +#define TARGET_SO_TIMESTAMP_NEW 0x4038 +#define TARGET_SCM_TIMESTAMP_NEW TARGET_SO_TIMESTAMP_NEW + /* TARGET_O_NONBLOCK clashes with the bits used for socket types. Therefo= re we * have to define SOCK_NONBLOCK to a different value here. */ diff --git a/linux-user/mips/sockbits.h b/linux-user/mips/sockbits.h index 0f022cd598..b4c39d9588 100644 --- a/linux-user/mips/sockbits.h +++ b/linux-user/mips/sockbits.h @@ -61,14 +61,18 @@ #define TARGET_SO_DETACH_FILTER 27 =20 #define TARGET_SO_PEERNAME 28 -#define TARGET_SO_TIMESTAMP 29 -#define SCM_TIMESTAMP SO_TIMESTAMP =20 #define TARGET_SO_PEERSEC 30 #define TARGET_SO_SNDBUFFORCE 31 #define TARGET_SO_RCVBUFFORCE 33 #define TARGET_SO_PASSSEC 34 =20 +#define TARGET_SO_TIMESTAMP_OLD 29 +#define TARGET_SCM_TIMESTAMP_OLD TARGET_SO_TIMESTAMP_OLD + +#define TARGET_SO_TIMESTAMP_NEW 63 +#define TARGET_SCM_TIMESTAMP_NEW TARGET_SO_TIMESTAMP_NEW + /** sock_type - Socket types * * Please notice that for binary compat reasons MIPS has to diff --git a/linux-user/sparc/sockbits.h b/linux-user/sparc/sockbits.h index 0a822e3e1f..07440efd14 100644 --- a/linux-user/sparc/sockbits.h +++ b/linux-user/sparc/sockbits.h @@ -48,8 +48,6 @@ #define TARGET_SO_GET_FILTER TARGET_SO_ATTACH_FILTER =20 #define TARGET_SO_PEERNAME 0x001c -#define TARGET_SO_TIMESTAMP 0x001d -#define TARGET_SCM_TIMESTAMP TARGET_SO_TIMESTAMP =20 #define TARGET_SO_PEERSEC 0x001e #define TARGET_SO_PASSSEC 0x001f @@ -104,6 +102,12 @@ =20 #define TARGET_SO_ZEROCOPY 0x003e =20 +#define TARGET_SO_TIMESTAMP_OLD 0x001d +#define TARGET_SCM_TIMESTAMP_OLD TARGET_SO_TIMESTAMP_OLD + +#define TARGET_SO_TIMESTAMP_NEW 0x0046 +#define TARGET_SCM_TIMESTAMP_NEW TARGET_SO_TIMESTAMP_NEW + /* Security levels - as per NRL IPv6 - don't actually do anything */ #define TARGET_SO_SECURITY_AUTHENTICATION 0x5001 #define TARGET_SO_SECURITY_ENCRYPTION_TRANSPORT 0x5002 diff --git a/linux-user/strace.c b/linux-user/strace.c index 089fb3968e..a11a5e9e86 100644 --- a/linux-user/strace.c +++ b/linux-user/strace.c @@ -2257,8 +2257,11 @@ print_optint: case TARGET_SO_PASSCRED: qemu_log("SO_PASSCRED,"); goto print_optint; - case TARGET_SO_TIMESTAMP: - qemu_log("SO_TIMESTAMP,"); + case TARGET_SO_TIMESTAMP_OLD: + qemu_log("SO_TIMESTAMP_OLD,"); + goto print_optint; + case TARGET_SO_TIMESTAMP_NEW: + qemu_log("SO_TIMESTAMP_NEW,"); goto print_optint; case TARGET_SO_RCVLOWAT: qemu_log("SO_RCVLOWAT,"); diff --git a/linux-user/syscall.c b/linux-user/syscall.c index cda194a7cc..e6b1a18cc0 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -1697,6 +1697,18 @@ static inline abi_long target_to_host_cmsg(struct ms= ghdr *msgh, return 0; } =20 +/* + * Linux kernel actually keeps track of whether the old version (potential= ly + * 32-bit time_t) or the new version is used for each socket. Instead of + * replicate it will all the complexity, we only keep track of one global = state, + * which is enough for guest programs that don't intentionally mix the two + * versions. + */ +static enum TargetTimestampVersion { + TARGET_TIMESTAMP_OLD, + TARGET_TIMESTAMP_NEW, +} target_expected_timestamp_version =3D TARGET_TIMESTAMP_OLD; + static inline abi_long host_to_target_cmsg(struct target_msghdr *target_ms= gh, struct msghdr *msgh) { @@ -1747,8 +1759,17 @@ static inline abi_long host_to_target_cmsg(struct ta= rget_msghdr *target_msgh, switch (cmsg->cmsg_level) { case SOL_SOCKET: switch (cmsg->cmsg_type) { - case SO_TIMESTAMP: - tgt_len =3D sizeof(struct target_timeval); + case SCM_TIMESTAMP: + switch (target_expected_timestamp_version) { + case TARGET_TIMESTAMP_OLD: + tgt_len =3D sizeof(struct target_timeval); + target_cmsg->cmsg_type =3D tswap32(TARGET_SCM_TIMESTAM= P_OLD); + break; + case TARGET_TIMESTAMP_NEW: + tgt_len =3D sizeof(struct target__kernel_sock_timeval); + target_cmsg->cmsg_type =3D tswap32(TARGET_SCM_TIMESTAM= P_NEW); + break; + } break; default: break; @@ -1782,20 +1803,39 @@ static inline abi_long host_to_target_cmsg(struct t= arget_msghdr *target_msgh, } break; } - case SO_TIMESTAMP: + case SCM_TIMESTAMP: { struct timeval *tv =3D (struct timeval *)data; - struct target_timeval *target_tv =3D - (struct target_timeval *)target_data; - - if (len !=3D sizeof(struct timeval) || - tgt_len !=3D sizeof(struct target_timeval)) { + if (len !=3D sizeof(struct timeval)) { goto unimplemented; } =20 - /* copy struct timeval to target */ - __put_user(tv->tv_sec, &target_tv->tv_sec); - __put_user(tv->tv_usec, &target_tv->tv_usec); + switch (target_expected_timestamp_version) { + case TARGET_TIMESTAMP_OLD: + { + struct target_timeval *target_tv =3D + (struct target_timeval *)target_data; + if (tgt_len !=3D sizeof(struct target_timeval)) { + goto unimplemented; + } + + __put_user(tv->tv_sec, &target_tv->tv_sec); + __put_user(tv->tv_usec, &target_tv->tv_usec); + break; + } + case TARGET_TIMESTAMP_NEW: + { + struct target__kernel_sock_timeval *target_tv =3D + (struct target__kernel_sock_timeval *)target_data; + if (tgt_len !=3D sizeof(struct target__kernel_sock_tim= eval)) { + goto unimplemented; + } + + __put_user(tv->tv_sec, &target_tv->tv_sec); + __put_user(tv->tv_usec, &target_tv->tv_usec); + break; + } + } break; } case SCM_CREDENTIALS: @@ -1937,6 +1977,8 @@ static abi_long do_setsockopt(int sockfd, int level, = int optname, int val; struct ip_mreqn *ip_mreq; struct ip_mreq_source *ip_mreq_source; + enum TargetTimestampVersion target_timestamp_version =3D + target_expected_timestamp_version; =20 switch(level) { case SOL_TCP: @@ -2331,9 +2373,14 @@ set_timeout: case TARGET_SO_PASSSEC: optname =3D SO_PASSSEC; break; - case TARGET_SO_TIMESTAMP: - optname =3D SO_TIMESTAMP; - break; + case TARGET_SO_TIMESTAMP_OLD: + target_timestamp_version =3D TARGET_TIMESTAMP_OLD; + optname =3D SO_TIMESTAMP; + break; + case TARGET_SO_TIMESTAMP_NEW: + target_timestamp_version =3D TARGET_TIMESTAMP_NEW; + optname =3D SO_TIMESTAMP; + break; case TARGET_SO_RCVLOWAT: optname =3D SO_RCVLOWAT; break; @@ -2346,6 +2393,9 @@ set_timeout: if (get_user_u32(val, optval_addr)) return -TARGET_EFAULT; ret =3D get_errno(setsockopt(sockfd, SOL_SOCKET, optname, &val, sizeof(va= l))); + if (!is_error(ret) && optname =3D=3D SO_TIMESTAMP) { + target_expected_timestamp_version =3D target_timestamp_version; + } break; #ifdef SOL_NETLINK case SOL_NETLINK: @@ -2396,6 +2446,7 @@ static abi_long do_getsockopt(int sockfd, int level, = int optname, abi_long ret; int len, val; socklen_t lv; + int timestamp_format_matches =3D 0; =20 switch(level) { case TARGET_SOL_SOCKET: @@ -2576,7 +2627,14 @@ get_timeout: case TARGET_SO_PASSCRED: optname =3D SO_PASSCRED; goto int_case; - case TARGET_SO_TIMESTAMP: + case TARGET_SO_TIMESTAMP_OLD: + timestamp_format_matches =3D + (target_expected_timestamp_version =3D=3D TARGET_TIMESTAMP= _OLD); + optname =3D SO_TIMESTAMP; + goto int_case; + case TARGET_SO_TIMESTAMP_NEW: + timestamp_format_matches =3D + (target_expected_timestamp_version =3D=3D TARGET_TIMESTAMP= _NEW); optname =3D SO_TIMESTAMP; goto int_case; case TARGET_SO_RCVLOWAT: @@ -2604,6 +2662,9 @@ get_timeout: if (optname =3D=3D SO_TYPE) { val =3D host_to_target_sock_type(val); } + if (optname =3D=3D SO_TIMESTAMP) { + val =3D val && timestamp_format_matches; + } if (len > lv) len =3D lv; if (len =3D=3D 4) { diff --git a/tests/tcg/multiarch/socket_timestamp.c b/tests/tcg/multiarch/s= ocket_timestamp.c new file mode 100644 index 0000000000..71ab1845de --- /dev/null +++ b/tests/tcg/multiarch/socket_timestamp.c @@ -0,0 +1,296 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __kernel_old_timeval +#define kernel_old_timeval __kernel_old_timeval +#else +struct kernel_old_timeval { + __kernel_long_t tv_sec; + __kernel_long_t tv_usec; +}; +#endif + +struct kernel_sock_timeval { + int64_t tv_sec; + int64_t tv_usec; +}; + +int create_udp_socket(struct sockaddr_in *sockaddr) +{ + socklen_t sockaddr_len; + int sock =3D socket(AF_INET, SOCK_DGRAM, 0); + if (sock < 0) { + int err =3D errno; + fprintf(stderr, "Failed to create server socket: %s\n", strerror(e= rr)); + exit(err); + } + + memset(sockaddr, 0, sizeof(*sockaddr)); + sockaddr->sin_family =3D AF_INET; + sockaddr->sin_port =3D htons(0); /* let kernel select a port for us */ + sockaddr->sin_addr.s_addr =3D htonl(INADDR_LOOPBACK); + + if (bind(sock, (struct sockaddr *)sockaddr, sizeof(*sockaddr)) < 0) { + int err =3D errno; + fprintf(stderr, "Failed to bind server socket: %s\n", strerror(err= )); + exit(err); + } + + sockaddr_len =3D sizeof(*sockaddr); + if (getsockname(sock, (struct sockaddr *)sockaddr, &sockaddr_len) < 0)= { + int err =3D errno; + fprintf(stderr, "Failed to get socket name: %s\n", strerror(err)); + exit(err); + } + return sock; +} + +/* + * Checks that the timestamp in the message is not after the reception tim= estamp + * as well as the reception time is within 10 seconds of the message time. + */ +void check_timestamp_difference(const struct timeval *msg_tv, + const struct timeval *pkt_tv) +{ + if (pkt_tv->tv_sec < msg_tv->tv_sec || + (pkt_tv->tv_sec =3D=3D msg_tv->tv_sec && pkt_tv->tv_usec < msg_tv-= >tv_usec)) + { + fprintf(stderr, + "Packet received before sent: %lld.%06lld < %lld.%06lld\n", + (long long)pkt_tv->tv_sec, (long long)pkt_tv->tv_usec, + (long long)msg_tv->tv_sec, (long long)msg_tv->tv_usec); + exit(-1); + } + + if (pkt_tv->tv_sec > msg_tv->tv_sec + 10 || + (pkt_tv->tv_sec =3D=3D msg_tv->tv_sec + 10 && + pkt_tv->tv_usec > msg_tv->tv_usec)) { + fprintf(stderr, + "Packet received more than 10 seconds after sent: " + "%lld.%06lld > %lld.%06lld + 10\n", + (long long)pkt_tv->tv_sec, (long long)pkt_tv->tv_usec, + (long long)msg_tv->tv_sec, (long long)msg_tv->tv_usec); + exit(-1); + } +} + +void send_current_time(int sock, struct sockaddr_in server_sockaddr) +{ + struct timeval tv =3D {0, 0}; + gettimeofday(&tv, NULL); + sendto(sock, &tv, sizeof(tv), 0, (struct sockaddr *)&server_sockaddr, + sizeof(server_sockaddr)); +} + +typedef void (*get_timeval_t)(const struct cmsghdr *cmsg, struct timeval *= tv); + + +void receive_packet(int sock, get_timeval_t get_timeval) +{ + struct msghdr msg =3D {0}; + + char iobuf[1024]; + struct iovec iov; + + union { + /* + * 128 bytes are enough for all existing + * timeval/timespec/scm_timestamping structures. + */ + char cmsg_buf[CMSG_SPACE(128)]; + struct cmsghdr align; + } u; + struct cmsghdr *cmsg; + struct timeval msg_tv, pkt_tv; + + int res; + + iov.iov_base =3D iobuf; + iov.iov_len =3D sizeof(iobuf); + + msg.msg_iov =3D &iov; + msg.msg_iovlen =3D 1; + msg.msg_control =3D (caddr_t)u.cmsg_buf; + msg.msg_controllen =3D sizeof(u.cmsg_buf); + + res =3D recvmsg(sock, &msg, 0); + if (res < 0) { + int err =3D errno; + fprintf(stderr, "Failed to receive packet: %s\n", strerror(err)); + exit(err); + } + + assert(res =3D=3D sizeof(struct timeval)); + assert(iov.iov_base =3D=3D iobuf); + memcpy(&msg_tv, iov.iov_base, sizeof(msg_tv)); + printf("Message timestamp: %lld.%06lld\n", + (long long)msg_tv.tv_sec, (long long)msg_tv.tv_usec); + + cmsg =3D CMSG_FIRSTHDR(&msg); + assert(cmsg); + (*get_timeval)(cmsg, &pkt_tv); + printf("Packet timestamp: %lld.%06lld\n", + (long long)pkt_tv.tv_sec, (long long)pkt_tv.tv_usec); + + check_timestamp_difference(&msg_tv, &pkt_tv); +} + +void get_timeval_from_so_timestamp(const struct cmsghdr *cmsg, + struct timeval *tv) +{ + assert(cmsg->cmsg_level =3D=3D SOL_SOCKET); + assert(cmsg->cmsg_type =3D=3D SCM_TIMESTAMP); + assert(cmsg->cmsg_len =3D=3D CMSG_LEN(sizeof(struct timeval))); + memcpy(tv, CMSG_DATA(cmsg), sizeof(*tv)); +} + +#ifdef SO_TIMESTAMP_OLD +void get_timeval_from_so_timestamp_old(const struct cmsghdr *cmsg, + struct timeval *tv) +{ + struct kernel_old_timeval old_tv; + assert(cmsg->cmsg_level =3D=3D SOL_SOCKET); + assert(cmsg->cmsg_type =3D=3D SO_TIMESTAMP_OLD); + assert(cmsg->cmsg_len =3D=3D CMSG_LEN(sizeof(old_tv))); + + memcpy(&old_tv, CMSG_DATA(cmsg), sizeof(old_tv)); + tv->tv_sec =3D old_tv.tv_sec; + tv->tv_usec =3D old_tv.tv_usec; +} + +#ifdef SO_TIMESTAMP_NEW +void get_timeval_from_so_timestamp_new(const struct cmsghdr *cmsg, + struct timeval *tv) +{ + struct kernel_sock_timeval sock_tv; + assert(cmsg->cmsg_level =3D=3D SOL_SOCKET); + assert(cmsg->cmsg_type =3D=3D SO_TIMESTAMP_NEW); + assert(cmsg->cmsg_len =3D=3D CMSG_LEN(sizeof(sock_tv))); + + memcpy(&sock_tv, CMSG_DATA(cmsg), sizeof(sock_tv)); + tv->tv_sec =3D sock_tv.tv_sec; + tv->tv_usec =3D sock_tv.tv_usec; +} +#endif /* defined(SO_TIMESTAMP_NEW) */ +#endif /* defined(SO_TIMESTAMP_OLD) */ + +void set_socket_option(int sock, int sockopt, int on) +{ + socklen_t len; + int val =3D on; + if (setsockopt(sock, SOL_SOCKET, sockopt, &val, sizeof(val)) < 0) { + int err =3D errno; + fprintf(stderr, "Failed to setsockopt %d (%s): %s\n", + sockopt, on ? "on" : "off", strerror(err)); + exit(err); + } + + len =3D sizeof(val); + val =3D -1; + if (getsockopt(sock, SOL_SOCKET, sockopt, &val, &len) < 0) { + int err =3D errno; + fprintf(stderr, "Failed to getsockopt (%d): %s\n", sock, strerror(= err)); + exit(err); + } + assert(len =3D=3D sizeof(val)); + assert(val =3D=3D on); +} + +int main(int argc, char **argv) +{ + int parent_sock, child_sock; + struct sockaddr_in parent_sockaddr, child_sockaddr; + int pid; + struct timeval tv =3D {0, 0}; + gettimeofday(&tv, NULL); + + parent_sock =3D create_udp_socket(&parent_sockaddr); + child_sock =3D create_udp_socket(&child_sockaddr); + + printf("Parent sock bound to port %d\nChild sock bound to port %d\n", + parent_sockaddr.sin_port, child_sockaddr.sin_port); + + pid =3D fork(); + if (pid < 0) { + fprintf(stderr, "SKIPPED. Failed to fork: %s\n", strerror(errno)); + } else if (pid =3D=3D 0) { + close(child_sock); + + /* Test 1: SO_TIMESTAMP */ + send_current_time(parent_sock, child_sockaddr); + + if (tv.tv_sec > 0x7fffff00) { + /* Too close to y2038 problem, old system may not work. */ + close(parent_sock); + return 0; + } + +#ifdef SO_TIMESTAMP_OLD + if (SO_TIMESTAMP_OLD !=3D SO_TIMESTAMP) { + /* Test 2a: SO_TIMESTAMP_OLD */ + set_socket_option(parent_sock, SO_TIMESTAMP_OLD, 1); + receive_packet(parent_sock, &get_timeval_from_so_timestamp_old= ); + set_socket_option(parent_sock, SO_TIMESTAMP_OLD, 0); + } +#ifdef SO_TIMESTAMP_NEW + else { + /* Test 2b: SO_TIMESTAMP_NEW */ + set_socket_option(parent_sock, SO_TIMESTAMP_NEW, 1); + receive_packet(parent_sock, &get_timeval_from_so_timestamp_new= ); + set_socket_option(parent_sock, SO_TIMESTAMP_NEW, 0); + } +#endif /* defined(SO_TIMESTAMP_NEW) */ +#endif /* defined(SO_TIMESTAMP_OLD) */ + + close(parent_sock); + } else { + int child_status; + close(parent_sock); + + /* Test 1: SO_TIMESTAMP */ + set_socket_option(child_sock, SO_TIMESTAMP, 1); + receive_packet(child_sock, &get_timeval_from_so_timestamp); + set_socket_option(child_sock, SO_TIMESTAMP, 0); + + if (tv.tv_sec > 0x7fffff00) { + /* Too close to y2038 problem, old system may not work. */ + close(child_sock); + return 0; + } + +#ifdef SO_TIMESTAMP_OLD + if (SO_TIMESTAMP_OLD !=3D SO_TIMESTAMP) { + /* Test 2a: SO_TIMESTAMP_OLD */ + send_current_time(child_sock, parent_sockaddr); + } +#ifdef SO_TIMESTAMP_NEW + else { + /* Test 2b: SO_TIMESTAMP_NEW */ + send_current_time(child_sock, parent_sockaddr); + } +#endif /* defined(SO_TIMESTAMP_NEW) */ +#endif /* defined(SO_TIMESTAMP_OLD) */ + + close(child_sock); + + if (waitpid(pid, &child_status, 0) < 0) { + int err =3D errno; + fprintf(stderr, "Final wait() failed: %s\n", strerror(err)); + return err; + } + return child_status; + } + return 0; +} --=20 2.28.0.220.ged08abb693-goog From nobody Fri May 17 13:37:30 2024 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=reject dis=none) header.from=google.com ARC-Seal: i=1; a=rsa-sha256; t=1597130281; cv=none; d=zohomail.com; s=zohoarc; b=MJsYINVtZaHcm90XKG/7v/pnQXArnD1yoHR+izpNzEN1HXspTf/mChGj+AwGutpFs/LCJpIXF/ecAL0UPT8f0xd4zyHOxyg6mG0YT3VNenFskYDMFqFeXnpR0oMvQciz2UZ/Kdl3IyEPO1GVFC4dtkDXddMFEGuwPHh/OeXYWWs= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1597130281; h=Content-Type:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To; bh=lupeHQJbERWglyw4xCqAoxNscLoaY2JNBpDbeVjSONs=; b=faK1W6WGNlVdGZghx75drzrrAr81OcHY/W30yuHI3kjygOH5x/msBfzxJq+9HxrT5+6jA37i8eSrMHEf6Vsv162WvL7fB+iM8K5xAeSh/KRN4eDijECvVQaUjxJm7wu3TfS665i9dFRFkUcoZz6zKTgM3v4uqJcfoGyu1GNYWbQ= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=reject dis=none) header.from= Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1597130281209933.1273545327123; Tue, 11 Aug 2020 00:18:01 -0700 (PDT) Received: from localhost ([::1]:55378 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1k5OXn-00042h-H7 for importer@patchew.org; Tue, 11 Aug 2020 03:17:59 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:52880) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from <3TUQyXwMKCp4QAUEMMEJC.AMKOCKS-BCTCJLMLELS.MPE@flex--scw.bounces.google.com>) id 1k5OQI-00056Q-7S for qemu-devel@nongnu.org; Tue, 11 Aug 2020 03:10:14 -0400 Received: from mail-yb1-xb4a.google.com ([2607:f8b0:4864:20::b4a]:40278) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from <3TUQyXwMKCp4QAUEMMEJC.AMKOCKS-BCTCJLMLELS.MPE@flex--scw.bounces.google.com>) id 1k5OQD-0000lU-1U for qemu-devel@nongnu.org; Tue, 11 Aug 2020 03:10:13 -0400 Received: by mail-yb1-xb4a.google.com with SMTP id l67so15698412ybb.7 for ; Tue, 11 Aug 2020 00:10:05 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=lupeHQJbERWglyw4xCqAoxNscLoaY2JNBpDbeVjSONs=; b=jkSCHaKTZeIBxlPShD7/01Sz00Xv8wqN47f3ezLKkdtMtJHuIVlYOyqGLn0EDfg+zv WqD3MYmR62y4/U7G1pxNnCV/q3kOMydveWcDWBzxM3txHXQr0lB28rdhkqLb0bu98K8D EfK6Wa4p8sGGr5iosWLeZKzA54Umb3f5UWiURA10MdkG9uz+dyC5gikXqjiD4OfUiE/x 6+zjA/nEuycavmS9cpWcuSTQkIfL0g4AITo85oJxLm6FnX4CttEOOrIV64tIuxm0ZV41 8uos8NLbSctQUgZUvrHGBrjhVgQa/ePinuv3h5DnnOuSv0npNU+5OcBGXrZSLXkaucQP eIwA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=lupeHQJbERWglyw4xCqAoxNscLoaY2JNBpDbeVjSONs=; b=q7noMHtp8Ru7OUQcpLbSnfo08fcodXBRSUCsWvmNko43+QX0wNZQPyBcZ+XEof6PDP 0VyFk+hT7qwfvNsewFi6EVHcHiN0uYzG/EP4PPYufLFlvwyGQuMglwWzZrMrjsZOvVkT pwaTbtEw/5DLiFzaeDXaLeeYIBV3b6o6voQTaIvRtPQgivMHvJgLJW1h06jKMXmutwCn Rz1kx/wWyNR9Vc7XSUaSrKtZRjU0zvJ8M79W8+pMQ4gyrvWmhws46KN1UKRSRsrUzZgU E1R7OxQiTq71ZqruCpXkDlMRF57HSmwIuthm701ioXM7w1OmI6XpkvPxh93ti+pWOLAD On/A== X-Gm-Message-State: AOAM5313C5hQ8tKK50c8XYgBf8O++ZTiQpa1QM2aeF5i5/tTV8F/MePA RwRnes99upu3PlR5k/23FXGuVrUQor33QSZZlFPIEHOCHkFfRfN+i6pMVkAIAst11JqDxyfqC3w soQo1BuEZ0WCbR7f9AnyLgqaltiI6n/XdoEfi8gMxFSZXqXaFQdAQ X-Google-Smtp-Source: ABdhPJzLU2c3hD0/n2tD1Hn2I6FMAa2lPt3A7Fscr4YqIaYkSL3j16BsM1Eqy5e+3tzC7UCqKLbUHkU= X-Received: by 2002:a25:340d:: with SMTP id b13mr17204029yba.62.1597129805222; Tue, 11 Aug 2020 00:10:05 -0700 (PDT) Date: Tue, 11 Aug 2020 00:09:46 -0700 In-Reply-To: Message-Id: Mime-Version: 1.0 References: X-Mailer: git-send-email 2.28.0.220.ged08abb693-goog Subject: [PATCH v2 6/8] linux-user: setsockopt() SO_TIMESTAMPNS and SO_TIMESTAMPING From: Shu-Chun Weng To: qemu-devel@nongnu.org Cc: Shu-Chun Weng , laurent@vivier.eu Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=2607:f8b0:4864:20::b4a; envelope-from=3TUQyXwMKCp4QAUEMMEJC.AMKOCKS-BCTCJLMLELS.MPE@flex--scw.bounces.google.com; helo=mail-yb1-xb4a.google.com X-detected-operating-system: by eggs.gnu.org: No matching host in p0f cache. That's all we know. X-Spam_score_int: -105 X-Spam_score: -10.6 X-Spam_bar: ---------- X-Spam_report: (-10.6 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_MED=-1, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, USER_IN_DEF_DKIM_WL=-7.5 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail-DKIM: pass (identity @google.com) Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" This change supports SO_TIMESTAMPNS_OLD/NEW and SO_TIMESTAMPING_OLD/NEW for setsocketopt() with SOL_SOCKET. Based on the SO_TIMESTAMP_OLD/NEW framework. The three pairs share the same flag `SOCK_TSTAMP_NEW` in linux kernel for deciding if the old or the new format is used. Signed-off-by: Shu-Chun Weng --- v1 -> v2: Only keep track of old/new format in a global state. Fix style problems. linux-user/alpha/sockbits.h | 13 +- linux-user/generic/sockbits.h | 8 + linux-user/hppa/sockbits.h | 12 +- linux-user/mips/sockbits.h | 8 + linux-user/sparc/sockbits.h | 13 +- linux-user/strace.c | 12 + linux-user/syscall.c | 149 ++++++++- tests/tcg/multiarch/socket_timestamp.c | 442 +++++++++++++++++++------ 8 files changed, 540 insertions(+), 117 deletions(-) diff --git a/linux-user/alpha/sockbits.h b/linux-user/alpha/sockbits.h index 40f0644df0..c2c88f432b 100644 --- a/linux-user/alpha/sockbits.h +++ b/linux-user/alpha/sockbits.h @@ -51,8 +51,6 @@ =20 #define TARGET_SO_PEERSEC 30 #define TARGET_SO_PASSSEC 34 -#define TARGET_SO_TIMESTAMPNS 35 -#define TARGET_SCM_TIMESTAMPNS TARGET_SO_TIMESTAMPNS =20 /* Security levels - as per NRL IPv6 - don't actually do anything */ #define TARGET_SO_SECURITY_AUTHENTICATION 19 @@ -61,9 +59,6 @@ =20 #define TARGET_SO_MARK 36 =20 -#define TARGET_SO_TIMESTAMPING 37 -#define TARGET_SCM_TIMESTAMPING TARGET_SO_TIMESTAMPING - #define TARGET_SO_RXQ_OVFL 40 =20 #define TARGET_SO_WIFI_STATUS 41 @@ -75,9 +70,17 @@ =20 #define TARGET_SO_TIMESTAMP_OLD 29 #define TARGET_SCM_TIMESTAMP_OLD TARGET_SO_TIMESTAMP_OLD +#define TARGET_SO_TIMESTAMPNS_OLD 35 +#define TARGET_SCM_TIMESTAMPNS_OLD TARGET_SO_TIMESTAMPNS_OLD +#define TARGET_SO_TIMESTAMPING_OLD 37 +#define TARGET_SCM_TIMESTAMPING_OLD TARGET_SO_TIMESTAMPING_OLD =20 #define TARGET_SO_TIMESTAMP_NEW 63 #define TARGET_SCM_TIMESTAMP_NEW TARGET_SO_TIMESTAMP_NEW +#define TARGET_SO_TIMESTAMPNS_NEW 64 +#define TARGET_SCM_TIMESTAMPNS_NEW TARGET_SO_TIMESTAMPNS_NEW +#define TARGET_SO_TIMESTAMPING_NEW 65 +#define TARGET_SCM_TIMESTAMPING_NEW TARGET_SO_TIMESTAMPING_NEW =20 /* TARGET_O_NONBLOCK clashes with the bits used for socket types. Therefo= re we * have to define SOCK_NONBLOCK to a different value here. diff --git a/linux-user/generic/sockbits.h b/linux-user/generic/sockbits.h index 532cf2d3dc..a0496d8751 100644 --- a/linux-user/generic/sockbits.h +++ b/linux-user/generic/sockbits.h @@ -56,8 +56,16 @@ =20 #define TARGET_SO_TIMESTAMP_OLD 29 #define TARGET_SCM_TIMESTAMP_OLD TARGET_SO_TIMESTAMP_OLD +#define TARGET_SO_TIMESTAMPNS_OLD 35 +#define TARGET_SCM_TIMESTAMPNS_OLD TARGET_SO_TIMESTAMPNS_OLD +#define TARGET_SO_TIMESTAMPING_OLD 37 +#define TARGET_SCM_TIMESTAMPING_OLD TARGET_SO_TIMESTAMPING_OLD =20 #define TARGET_SO_TIMESTAMP_NEW 63 #define TARGET_SCM_TIMESTAMP_NEW TARGET_SO_TIMESTAMP_NEW +#define TARGET_SO_TIMESTAMPNS_NEW 64 +#define TARGET_SCM_TIMESTAMPNS_NEW TARGET_SO_TIMESTAMPNS_NEW +#define TARGET_SO_TIMESTAMPING_NEW 65 +#define TARGET_SCM_TIMESTAMPING_NEW TARGET_SO_TIMESTAMPING_NEW =20 #endif diff --git a/linux-user/hppa/sockbits.h b/linux-user/hppa/sockbits.h index 284a47e74e..d7e9aa340d 100644 --- a/linux-user/hppa/sockbits.h +++ b/linux-user/hppa/sockbits.h @@ -29,8 +29,6 @@ #define TARGET_SO_BSDCOMPAT 0x400e #define TARGET_SO_PASSCRED 0x4010 #define TARGET_SO_PEERCRED 0x4011 -#define TARGET_SO_TIMESTAMPNS 0x4013 -#define TARGET_SCM_TIMESTAMPNS TARGET_SO_TIMESTAMPNS =20 #define TARGET_SO_SECURITY_AUTHENTICATION 0x4016 #define TARGET_SO_SECURITY_ENCRYPTION_TRANSPORT 0x4017 @@ -44,8 +42,6 @@ #define TARGET_SO_PEERSEC 0x401d #define TARGET_SO_PASSSEC 0x401e #define TARGET_SO_MARK 0x401f -#define TARGET_SO_TIMESTAMPING 0x4020 -#define TARGET_SCM_TIMESTAMPING TARGET_SO_TIMESTAMPING #define TARGET_SO_RXQ_OVFL 0x4021 #define TARGET_SO_WIFI_STATUS 0x4022 #define TARGET_SCM_WIFI_STATUS TARGET_SO_WIFI_STATUS @@ -67,9 +63,17 @@ =20 #define TARGET_SO_TIMESTAMP_OLD 0x4012 #define TARGET_SCM_TIMESTAMP_OLD TARGET_SO_TIMESTAMP_OLD +#define TARGET_SO_TIMESTAMPNS_OLD 0x4013 +#define TARGET_SCM_TIMESTAMPNS_OLD TARGET_SO_TIMESTAMPNS_OLD +#define TARGET_SO_TIMESTAMPING_OLD 0x4020 +#define TARGET_SCM_TIMESTAMPING_OLD TARGET_SO_TIMESTAMPING_OLD =20 #define TARGET_SO_TIMESTAMP_NEW 0x4038 #define TARGET_SCM_TIMESTAMP_NEW TARGET_SO_TIMESTAMP_NEW +#define TARGET_SO_TIMESTAMPNS_NEW 0x4039 +#define TARGET_SCM_TIMESTAMPNS_NEW TARGET_SO_TIMESTAMPNS_NEW +#define TARGET_SO_TIMESTAMPING_NEW 0x403A +#define TARGET_SCM_TIMESTAMPING_NEW TARGET_SO_TIMESTAMPING_NEW =20 /* TARGET_O_NONBLOCK clashes with the bits used for socket types. Therefo= re we * have to define SOCK_NONBLOCK to a different value here. diff --git a/linux-user/mips/sockbits.h b/linux-user/mips/sockbits.h index b4c39d9588..49524e23ac 100644 --- a/linux-user/mips/sockbits.h +++ b/linux-user/mips/sockbits.h @@ -69,9 +69,17 @@ =20 #define TARGET_SO_TIMESTAMP_OLD 29 #define TARGET_SCM_TIMESTAMP_OLD TARGET_SO_TIMESTAMP_OLD +#define TARGET_SO_TIMESTAMPNS_OLD 35 +#define TARGET_SCM_TIMESTAMPNS_OLD TARGET_SO_TIMESTAMPNS_OLD +#define TARGET_SO_TIMESTAMPING_OLD 37 +#define TARGET_SCM_TIMESTAMPING_OLD TARGET_SO_TIMESTAMPING_OLD =20 #define TARGET_SO_TIMESTAMP_NEW 63 #define TARGET_SCM_TIMESTAMP_NEW TARGET_SO_TIMESTAMP_NEW +#define TARGET_SO_TIMESTAMPNS_NEW 64 +#define TARGET_SCM_TIMESTAMPNS_NEW TARGET_SO_TIMESTAMPNS_NEW +#define TARGET_SO_TIMESTAMPING_NEW 65 +#define TARGET_SCM_TIMESTAMPING_NEW TARGET_SO_TIMESTAMPING_NEW =20 /** sock_type - Socket types * diff --git a/linux-user/sparc/sockbits.h b/linux-user/sparc/sockbits.h index 07440efd14..c5fade3ad1 100644 --- a/linux-user/sparc/sockbits.h +++ b/linux-user/sparc/sockbits.h @@ -51,14 +51,9 @@ =20 #define TARGET_SO_PEERSEC 0x001e #define TARGET_SO_PASSSEC 0x001f -#define TARGET_SO_TIMESTAMPNS 0x0021 -#define TARGET_SCM_TIMESTAMPNS TARGET_SO_TIMESTAMPNS =20 #define TARGET_SO_MARK 0x0022 =20 -#define TARGET_SO_TIMESTAMPING 0x0023 -#define TARGET_SCM_TIMESTAMPING TARGET_SO_TIMESTAMPING - #define TARGET_SO_RXQ_OVFL 0x0024 =20 #define TARGET_SO_WIFI_STATUS 0x0025 @@ -104,9 +99,17 @@ =20 #define TARGET_SO_TIMESTAMP_OLD 0x001d #define TARGET_SCM_TIMESTAMP_OLD TARGET_SO_TIMESTAMP_OLD +#define TARGET_SO_TIMESTAMPNS_OLD 0x0021 +#define TARGET_SCM_TIMESTAMPNS_OLD TARGET_SO_TIMESTAMPNS_OLD +#define TARGET_SO_TIMESTAMPING_OLD 0x0023 +#define TARGET_SCM_TIMESTAMPING_OLD TARGET_SO_TIMESTAMPING_OLD =20 #define TARGET_SO_TIMESTAMP_NEW 0x0046 #define TARGET_SCM_TIMESTAMP_NEW TARGET_SO_TIMESTAMP_NEW +#define TARGET_SO_TIMESTAMPNS_NEW 0x0042 +#define TARGET_SCM_TIMESTAMPNS_NEW TARGET_SO_TIMESTAMPNS_NEW +#define TARGET_SO_TIMESTAMPING_NEW 0x0043 +#define TARGET_SCM_TIMESTAMPING_NEW TARGET_SO_TIMESTAMPING_NEW =20 /* Security levels - as per NRL IPv6 - don't actually do anything */ #define TARGET_SO_SECURITY_AUTHENTICATION 0x5001 diff --git a/linux-user/strace.c b/linux-user/strace.c index a11a5e9e86..7aabb3c972 100644 --- a/linux-user/strace.c +++ b/linux-user/strace.c @@ -2260,9 +2260,21 @@ print_optint: case TARGET_SO_TIMESTAMP_OLD: qemu_log("SO_TIMESTAMP_OLD,"); goto print_optint; + case TARGET_SO_TIMESTAMPNS_OLD: + qemu_log("SO_TIMESTAMPNS_OLD,"); + goto print_optint; + case TARGET_SO_TIMESTAMPING_OLD: + qemu_log("SO_TIMESTAMPING_OLD,"); + goto print_optint; case TARGET_SO_TIMESTAMP_NEW: qemu_log("SO_TIMESTAMP_NEW,"); goto print_optint; + case TARGET_SO_TIMESTAMPNS_NEW: + qemu_log("SO_TIMESTAMPNS_NEW,"); + goto print_optint; + case TARGET_SO_TIMESTAMPING_NEW: + qemu_log("SO_TIMESTAMPING_NEW,"); + goto print_optint; case TARGET_SO_RCVLOWAT: qemu_log("SO_RCVLOWAT,"); goto print_optint; diff --git a/linux-user/syscall.c b/linux-user/syscall.c index e6b1a18cc0..bfc4219104 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -1771,6 +1771,34 @@ static inline abi_long host_to_target_cmsg(struct ta= rget_msghdr *target_msgh, break; } break; + case SCM_TIMESTAMPNS: + switch (target_expected_timestamp_version) { + case TARGET_TIMESTAMP_OLD: + tgt_len =3D sizeof(struct target_timespec); + target_cmsg->cmsg_type =3D + tswap32(TARGET_SCM_TIMESTAMPNS_OLD); + break; + case TARGET_TIMESTAMP_NEW: + tgt_len =3D sizeof(struct target__kernel_timespec); + target_cmsg->cmsg_type =3D + tswap32(TARGET_SCM_TIMESTAMPNS_NEW); + break; + } + break; + case SCM_TIMESTAMPING: + switch (target_expected_timestamp_version) { + case TARGET_TIMESTAMP_OLD: + tgt_len =3D sizeof(struct target_timespec[3]); + target_cmsg->cmsg_type =3D + tswap32(TARGET_SCM_TIMESTAMPING_OLD); + break; + case TARGET_TIMESTAMP_NEW: + tgt_len =3D sizeof(struct target__kernel_timespec[3]); + target_cmsg->cmsg_type =3D + tswap32(TARGET_SCM_TIMESTAMPING_NEW); + break; + } + break; default: break; } @@ -1838,6 +1866,81 @@ static inline abi_long host_to_target_cmsg(struct ta= rget_msghdr *target_msgh, } break; } + case SCM_TIMESTAMPNS: + { + struct timespec *ts =3D (struct timespec *)data; + if (len !=3D sizeof(struct timespec)) { + goto unimplemented; + } + + switch (target_expected_timestamp_version) { + case TARGET_TIMESTAMP_OLD: + { + struct target_timespec *target_ts =3D + (struct target_timespec *)target_data; + if (tgt_len !=3D sizeof(struct target_timespec)) { + goto unimplemented; + } + + __put_user(ts->tv_sec, &target_ts->tv_sec); + __put_user(ts->tv_nsec, &target_ts->tv_nsec); + break; + } + case TARGET_TIMESTAMP_NEW: + { + struct target__kernel_timespec *target_ts =3D + (struct target__kernel_timespec *)target_data; + if (tgt_len !=3D sizeof(struct target__kernel_timespec= )) { + goto unimplemented; + } + + __put_user(ts->tv_sec, &target_ts->tv_sec); + __put_user(ts->tv_nsec, &target_ts->tv_nsec); + break; + } + } + break; + } + case SCM_TIMESTAMPING: + { + int i; + struct timespec *ts =3D (struct timespec *)data; + if (len !=3D sizeof(struct timespec[3])) { + goto unimplemented; + } + + switch (target_expected_timestamp_version) { + case TARGET_TIMESTAMP_OLD: + { + struct target_timespec *target_ts =3D + (struct target_timespec *)target_data; + if (tgt_len !=3D sizeof(struct target_timespec[3])) { + goto unimplemented; + } + + for (i =3D 0; i < 3; ++i) { + __put_user(ts[i].tv_sec, &target_ts[i].tv_sec); + __put_user(ts[i].tv_nsec, &target_ts[i].tv_nsec); + } + break; + } + case TARGET_TIMESTAMP_NEW: + { + struct target__kernel_timespec *target_ts =3D + (struct target__kernel_timespec *)target_data; + if (tgt_len !=3D sizeof(struct target__kernel_timespec= [3])) { + goto unimplemented; + } + + for (i =3D 0; i < 3; ++i) { + __put_user(ts[i].tv_sec, &target_ts[i].tv_sec); + __put_user(ts[i].tv_nsec, &target_ts[i].tv_nsec); + } + break; + } + } + break; + } case SCM_CREDENTIALS: { struct ucred *cred =3D (struct ucred *)data; @@ -2381,6 +2484,22 @@ set_timeout: target_timestamp_version =3D TARGET_TIMESTAMP_NEW; optname =3D SO_TIMESTAMP; break; + case TARGET_SO_TIMESTAMPNS_OLD: + target_timestamp_version =3D TARGET_TIMESTAMP_OLD; + optname =3D SO_TIMESTAMPNS; + break; + case TARGET_SO_TIMESTAMPNS_NEW: + target_timestamp_version =3D TARGET_TIMESTAMP_NEW; + optname =3D SO_TIMESTAMPNS; + break; + case TARGET_SO_TIMESTAMPING_OLD: + target_timestamp_version =3D TARGET_TIMESTAMP_OLD; + optname =3D SO_TIMESTAMPING; + break; + case TARGET_SO_TIMESTAMPING_NEW: + target_timestamp_version =3D TARGET_TIMESTAMP_NEW; + optname =3D SO_TIMESTAMPING; + break; case TARGET_SO_RCVLOWAT: optname =3D SO_RCVLOWAT; break; @@ -2393,7 +2512,9 @@ set_timeout: if (get_user_u32(val, optval_addr)) return -TARGET_EFAULT; ret =3D get_errno(setsockopt(sockfd, SOL_SOCKET, optname, &val, sizeof(va= l))); - if (!is_error(ret) && optname =3D=3D SO_TIMESTAMP) { + if (!is_error(ret) && + (optname =3D=3D SO_TIMESTAMP || optname =3D=3D SO_TIMESTAMPNS = || + optname =3D=3D SO_TIMESTAMPING)) { target_expected_timestamp_version =3D target_timestamp_version; } break; @@ -2637,6 +2758,26 @@ get_timeout: (target_expected_timestamp_version =3D=3D TARGET_TIMESTAMP= _NEW); optname =3D SO_TIMESTAMP; goto int_case; + case TARGET_SO_TIMESTAMPNS_OLD: + timestamp_format_matches =3D + (target_expected_timestamp_version =3D=3D TARGET_TIMESTAMP= _OLD); + optname =3D SO_TIMESTAMPNS; + goto int_case; + case TARGET_SO_TIMESTAMPNS_NEW: + timestamp_format_matches =3D + (target_expected_timestamp_version =3D=3D TARGET_TIMESTAMP= _NEW); + optname =3D SO_TIMESTAMPNS; + goto int_case; + case TARGET_SO_TIMESTAMPING_OLD: + timestamp_format_matches =3D + (target_expected_timestamp_version =3D=3D TARGET_TIMESTAMP= _OLD); + optname =3D SO_TIMESTAMPING; + goto int_case; + case TARGET_SO_TIMESTAMPING_NEW: + timestamp_format_matches =3D + (target_expected_timestamp_version =3D=3D TARGET_TIMESTAMP= _NEW); + optname =3D SO_TIMESTAMPING; + goto int_case; case TARGET_SO_RCVLOWAT: optname =3D SO_RCVLOWAT; goto int_case; @@ -2661,9 +2802,9 @@ get_timeout: return ret; if (optname =3D=3D SO_TYPE) { val =3D host_to_target_sock_type(val); - } - if (optname =3D=3D SO_TIMESTAMP) { - val =3D val && timestamp_format_matches; + } else if ((optname =3D=3D SO_TIMESTAMP || optname =3D=3D SO_TIMES= TAMPNS || + optname =3D=3D SO_TIMESTAMPING) && !timestamp_format_m= atches) { + val =3D 0; } if (len > lv) len =3D lv; diff --git a/tests/tcg/multiarch/socket_timestamp.c b/tests/tcg/multiarch/s= ocket_timestamp.c index 71ab1845de..3ae833ad44 100644 --- a/tests/tcg/multiarch/socket_timestamp.c +++ b/tests/tcg/multiarch/socket_timestamp.c @@ -1,5 +1,6 @@ #include #include +#include #include #include #include @@ -11,6 +12,7 @@ #include #include #include +#include #include =20 #ifdef __kernel_old_timeval @@ -27,6 +29,33 @@ struct kernel_sock_timeval { int64_t tv_usec; }; =20 +struct kernel_old_timespec { + __kernel_long_t tv_sec; + long tv_nsec; +}; + +struct kernel_timespec { + int64_t tv_sec; + long long tv_nsec; +}; + +struct scm_timestamping { + struct timespec ts[3]; +}; + +struct scm_old_timestamping { + struct kernel_old_timespec ts[3]; +}; + +struct scm_timestamping64 { + struct kernel_timespec ts[3]; +}; + +const int so_timestamping_flags =3D + SOF_TIMESTAMPING_RX_HARDWARE | + SOF_TIMESTAMPING_RX_SOFTWARE | + SOF_TIMESTAMPING_SOFTWARE; + int create_udp_socket(struct sockaddr_in *sockaddr) { socklen_t sockaddr_len; @@ -61,43 +90,47 @@ int create_udp_socket(struct sockaddr_in *sockaddr) * Checks that the timestamp in the message is not after the reception tim= estamp * as well as the reception time is within 10 seconds of the message time. */ -void check_timestamp_difference(const struct timeval *msg_tv, - const struct timeval *pkt_tv) +void check_timestamp_difference(const struct timespec *msg_ts, + const struct timespec *pkt_ts) { - if (pkt_tv->tv_sec < msg_tv->tv_sec || - (pkt_tv->tv_sec =3D=3D msg_tv->tv_sec && pkt_tv->tv_usec < msg_tv-= >tv_usec)) + if (pkt_ts->tv_sec < msg_ts->tv_sec || + (pkt_ts->tv_sec =3D=3D msg_ts->tv_sec && pkt_ts->tv_nsec < msg_ts-= >tv_nsec)) { fprintf(stderr, - "Packet received before sent: %lld.%06lld < %lld.%06lld\n", - (long long)pkt_tv->tv_sec, (long long)pkt_tv->tv_usec, - (long long)msg_tv->tv_sec, (long long)msg_tv->tv_usec); + "Packet received before sent: %lld.%06lld < %lld.%09lld\n", + (long long)pkt_ts->tv_sec, (long long)pkt_ts->tv_nsec, + (long long)msg_ts->tv_sec, (long long)msg_ts->tv_nsec); exit(-1); } =20 - if (pkt_tv->tv_sec > msg_tv->tv_sec + 10 || - (pkt_tv->tv_sec =3D=3D msg_tv->tv_sec + 10 && - pkt_tv->tv_usec > msg_tv->tv_usec)) { + if (pkt_ts->tv_sec > msg_ts->tv_sec + 10 || + (pkt_ts->tv_sec =3D=3D msg_ts->tv_sec + 10 && + pkt_ts->tv_nsec > msg_ts->tv_nsec)) { fprintf(stderr, "Packet received more than 10 seconds after sent: " - "%lld.%06lld > %lld.%06lld + 10\n", - (long long)pkt_tv->tv_sec, (long long)pkt_tv->tv_usec, - (long long)msg_tv->tv_sec, (long long)msg_tv->tv_usec); + "%lld.%06lld > %lld.%09lld + 10\n", + (long long)pkt_ts->tv_sec, (long long)pkt_ts->tv_nsec, + (long long)msg_ts->tv_sec, (long long)msg_ts->tv_nsec); exit(-1); } } =20 void send_current_time(int sock, struct sockaddr_in server_sockaddr) { - struct timeval tv =3D {0, 0}; - gettimeofday(&tv, NULL); - sendto(sock, &tv, sizeof(tv), 0, (struct sockaddr *)&server_sockaddr, + struct timespec ts =3D {0, 0}; + clock_gettime(CLOCK_REALTIME, &ts); +#ifdef MSG_CONFIRM + const int flags =3D MSG_CONFIRM; +#else + const int flags =3D 0; +#endif + sendto(sock, &ts, sizeof(ts), flags, (struct sockaddr *)&server_sockad= dr, sizeof(server_sockaddr)); } =20 -typedef void (*get_timeval_t)(const struct cmsghdr *cmsg, struct timeval *= tv); +typedef void (*get_timespec_t)(const struct cmsghdr *cmsg, struct timespec= *tv); =20 - -void receive_packet(int sock, get_timeval_t get_timeval) +void receive_packet(int sock, get_timespec_t get_timespec) { struct msghdr msg =3D {0}; =20 @@ -113,7 +146,7 @@ void receive_packet(int sock, get_timeval_t get_timeval) struct cmsghdr align; } u; struct cmsghdr *cmsg; - struct timeval msg_tv, pkt_tv; + struct timespec msg_ts, pkt_ts; =20 int res; =20 @@ -134,31 +167,35 @@ void receive_packet(int sock, get_timeval_t get_timev= al) =20 assert(res =3D=3D sizeof(struct timeval)); assert(iov.iov_base =3D=3D iobuf); - memcpy(&msg_tv, iov.iov_base, sizeof(msg_tv)); - printf("Message timestamp: %lld.%06lld\n", - (long long)msg_tv.tv_sec, (long long)msg_tv.tv_usec); + memcpy(&msg_ts, iov.iov_base, sizeof(msg_ts)); + printf("Message timestamp: %lld.%09lld\n", + (long long)msg_ts.tv_sec, (long long)msg_ts.tv_nsec); =20 cmsg =3D CMSG_FIRSTHDR(&msg); assert(cmsg); - (*get_timeval)(cmsg, &pkt_tv); - printf("Packet timestamp: %lld.%06lld\n", - (long long)pkt_tv.tv_sec, (long long)pkt_tv.tv_usec); + (*get_timespec)(cmsg, &pkt_ts); + printf("Packet timestamp: %lld.%09lld\n", + (long long)pkt_ts.tv_sec, (long long)pkt_ts.tv_nsec); =20 - check_timestamp_difference(&msg_tv, &pkt_tv); + check_timestamp_difference(&msg_ts, &pkt_ts); } =20 -void get_timeval_from_so_timestamp(const struct cmsghdr *cmsg, - struct timeval *tv) +void get_timespec_from_so_timestamp(const struct cmsghdr *cmsg, + struct timespec *ts) { + struct timeval tv; assert(cmsg->cmsg_level =3D=3D SOL_SOCKET); assert(cmsg->cmsg_type =3D=3D SCM_TIMESTAMP); - assert(cmsg->cmsg_len =3D=3D CMSG_LEN(sizeof(struct timeval))); - memcpy(tv, CMSG_DATA(cmsg), sizeof(*tv)); + assert(cmsg->cmsg_len =3D=3D CMSG_LEN(sizeof(tv))); + + memcpy(&tv, CMSG_DATA(cmsg), sizeof(tv)); + ts->tv_sec =3D tv.tv_sec; + ts->tv_nsec =3D tv.tv_usec * 1000LL; } =20 #ifdef SO_TIMESTAMP_OLD -void get_timeval_from_so_timestamp_old(const struct cmsghdr *cmsg, - struct timeval *tv) +void get_timespec_from_so_timestamp_old(const struct cmsghdr *cmsg, + struct timespec *ts) { struct kernel_old_timeval old_tv; assert(cmsg->cmsg_level =3D=3D SOL_SOCKET); @@ -166,13 +203,13 @@ void get_timeval_from_so_timestamp_old(const struct c= msghdr *cmsg, assert(cmsg->cmsg_len =3D=3D CMSG_LEN(sizeof(old_tv))); =20 memcpy(&old_tv, CMSG_DATA(cmsg), sizeof(old_tv)); - tv->tv_sec =3D old_tv.tv_sec; - tv->tv_usec =3D old_tv.tv_usec; + ts->tv_sec =3D old_tv.tv_sec; + ts->tv_nsec =3D old_tv.tv_usec * 1000LL; } =20 #ifdef SO_TIMESTAMP_NEW -void get_timeval_from_so_timestamp_new(const struct cmsghdr *cmsg, - struct timeval *tv) +void get_timespec_from_so_timestamp_new(const struct cmsghdr *cmsg, + struct timespec *ts) { struct kernel_sock_timeval sock_tv; assert(cmsg->cmsg_level =3D=3D SOL_SOCKET); @@ -180,42 +217,298 @@ void get_timeval_from_so_timestamp_new(const struct = cmsghdr *cmsg, assert(cmsg->cmsg_len =3D=3D CMSG_LEN(sizeof(sock_tv))); =20 memcpy(&sock_tv, CMSG_DATA(cmsg), sizeof(sock_tv)); - tv->tv_sec =3D sock_tv.tv_sec; - tv->tv_usec =3D sock_tv.tv_usec; + ts->tv_sec =3D sock_tv.tv_sec; + ts->tv_nsec =3D sock_tv.tv_usec * 1000LL; } #endif /* defined(SO_TIMESTAMP_NEW) */ #endif /* defined(SO_TIMESTAMP_OLD) */ =20 -void set_socket_option(int sock, int sockopt, int on) +void get_timespec_from_so_timestampns(const struct cmsghdr *cmsg, + struct timespec *ts) +{ + assert(cmsg->cmsg_level =3D=3D SOL_SOCKET); + assert(cmsg->cmsg_type =3D=3D SCM_TIMESTAMPNS); + assert(cmsg->cmsg_len =3D=3D CMSG_LEN(sizeof(*ts))); + + memcpy(ts, CMSG_DATA(cmsg), sizeof(*ts)); +} + +#ifdef SO_TIMESTAMPNS_OLD +void get_timespec_from_so_timestampns_old(const struct cmsghdr *cmsg, + struct timespec *ts) +{ + struct kernel_old_timespec old_ts; + assert(cmsg->cmsg_level =3D=3D SOL_SOCKET); + assert(cmsg->cmsg_type =3D=3D SO_TIMESTAMPNS_OLD); + assert(cmsg->cmsg_len =3D=3D CMSG_LEN(sizeof(old_ts))); + + memcpy(&old_ts, CMSG_DATA(cmsg), sizeof(old_ts)); + ts->tv_sec =3D old_ts.tv_sec; + ts->tv_nsec =3D old_ts.tv_nsec; +} + +#ifdef SO_TIMESTAMPNS_NEW +void get_timespec_from_so_timestampns_new(const struct cmsghdr *cmsg, + struct timespec *ts) +{ + struct kernel_timespec sock_ts; + assert(cmsg->cmsg_level =3D=3D SOL_SOCKET); + assert(cmsg->cmsg_type =3D=3D SO_TIMESTAMPNS_NEW); + assert(cmsg->cmsg_len =3D=3D CMSG_LEN(sizeof(sock_ts))); + + memcpy(&sock_ts, CMSG_DATA(cmsg), sizeof(sock_ts)); + ts->tv_sec =3D sock_ts.tv_sec; + ts->tv_nsec =3D sock_ts.tv_nsec; +} +#endif /* defined(SO_TIMESTAMPNS_NEW) */ +#endif /* defined(SO_TIMESTAMPNS_OLD) */ + +void get_timespec_from_so_timestamping(const struct cmsghdr *cmsg, + struct timespec *ts) +{ + int i; + struct scm_timestamping tss; + assert(cmsg->cmsg_level =3D=3D SOL_SOCKET); + assert(cmsg->cmsg_type =3D=3D SCM_TIMESTAMPING); + assert(cmsg->cmsg_len =3D=3D CMSG_LEN(sizeof(tss))); + + memcpy(&tss, CMSG_DATA(cmsg), sizeof(tss)); + + for (i =3D 0; i < 3; ++i) { + if (tss.ts[i].tv_sec || tss.ts[i].tv_nsec) { + *ts =3D tss.ts[i]; + return; + } + } + assert(!"All three entries in scm_timestamping are empty"); +} + +#ifdef SO_TIMESTAMPING_OLD +void get_timespec_from_so_timestamping_old(const struct cmsghdr *cmsg, + struct timespec *ts) +{ + int i; + struct scm_old_timestamping tss; + assert(cmsg->cmsg_level =3D=3D SOL_SOCKET); + assert(cmsg->cmsg_type =3D=3D SO_TIMESTAMPING_OLD); + assert(cmsg->cmsg_len =3D=3D CMSG_LEN(sizeof(tss))); + + memcpy(&tss, CMSG_DATA(cmsg), sizeof(tss)); + + for (i =3D 0; i < 3; ++i) { + if (tss.ts[i].tv_sec || tss.ts[i].tv_nsec) { + ts->tv_sec =3D tss.ts[i].tv_sec; + ts->tv_nsec =3D tss.ts[i].tv_nsec; + return; + } + } + assert(!"All three entries in scm_old_timestamping are empty"); +} + +#ifdef SO_TIMESTAMPING_NEW +void get_timespec_from_so_timestamping_new(const struct cmsghdr *cmsg, + struct timespec *ts) +{ + int i; + struct scm_timestamping64 tss; + assert(cmsg->cmsg_level =3D=3D SOL_SOCKET); + assert(cmsg->cmsg_type =3D=3D SO_TIMESTAMPING_NEW); + assert(cmsg->cmsg_len =3D=3D CMSG_LEN(sizeof(tss))); + + memcpy(&tss, CMSG_DATA(cmsg), sizeof(tss)); + for (i =3D 0; i < 3; ++i) { + if (tss.ts[i].tv_sec || tss.ts[i].tv_nsec) { + ts->tv_sec =3D tss.ts[i].tv_sec; + ts->tv_nsec =3D tss.ts[i].tv_nsec; + return; + } + } + assert(!"All three entries in scm_timestamp64 are empty"); +} +#endif /* defined(SO_TIMESTAMPING_NEW) */ +#endif /* defined(SO_TIMESTAMPING_OLD) */ + +void set_socket_option(int sock, int sockopt, int set_to) { socklen_t len; - int val =3D on; + int val =3D set_to; if (setsockopt(sock, SOL_SOCKET, sockopt, &val, sizeof(val)) < 0) { int err =3D errno; - fprintf(stderr, "Failed to setsockopt %d (%s): %s\n", - sockopt, on ? "on" : "off", strerror(err)); + fprintf(stderr, "Failed at setsockopt(%d, SOL_SOCKET, %d, %d): %s\= n", + sock, sockopt, set_to, strerror(err)); exit(err); } =20 +#ifdef SO_TIMESTAMPING_NEW + if (sockopt =3D=3D SO_TIMESTAMPING_NEW) { + /* + * `getsockopt(sock, SOL_SOCKET, SO_TIMESTAMPING_NEW)` not impleme= nted + * as of linux kernel v5.8-rc4. + */ + return; + } +#endif + len =3D sizeof(val); val =3D -1; if (getsockopt(sock, SOL_SOCKET, sockopt, &val, &len) < 0) { int err =3D errno; - fprintf(stderr, "Failed to getsockopt (%d): %s\n", sock, strerror(= err)); + fprintf(stderr, "Failed at getsockopt(%d, SOL_SOCKET, %d): %s\n", + sock, sockopt, strerror(err)); exit(err); } assert(len =3D=3D sizeof(val)); - assert(val =3D=3D on); + assert(val =3D=3D set_to); +} + +void child_steps(int sock, struct sockaddr_in addr, int run_old) +{ + /* Test 1: SO_TIMESTAMP */ + send_current_time(sock, addr); + + /* Test 2: SO_TIMESTAMPNS */ + printf("Test 2: SO_TIMESTAMPNS\n"); + set_socket_option(sock, SO_TIMESTAMPNS, 1); + receive_packet(sock, &get_timespec_from_so_timestampns); + set_socket_option(sock, SO_TIMESTAMPNS, 0); + + /* Test 3: SO_TIMESTAMPING */ + send_current_time(sock, addr); + + if (!run_old) { + return; + } + +#ifdef SO_TIMESTAMP_OLD + if (SO_TIMESTAMP_OLD !=3D SO_TIMESTAMP) { + /* Test 4a: SO_TIMESTAMP_OLD */ + printf("Test 4a: SO_TIMESTAMP_OLD\n"); + set_socket_option(sock, SO_TIMESTAMP_OLD, 1); + receive_packet(sock, &get_timespec_from_so_timestamp_old); + set_socket_option(sock, SO_TIMESTAMP_OLD, 0); + } +#ifdef SO_TIMESTAMP_NEW + else { + /* Test 4b: SO_TIMESTAMP_NEW */ + printf("Test 4b: SO_TIMESTAMP_NEW\n"); + set_socket_option(sock, SO_TIMESTAMP_NEW, 1); + receive_packet(sock, &get_timespec_from_so_timestamp_new); + set_socket_option(sock, SO_TIMESTAMP_NEW, 0); + } +#endif /* defined(SO_TIMESTAMP_NEW) */ +#endif /* defined(SO_TIMESTAMP_OLD) */ + +#ifdef SO_TIMESTAMPNS_OLD + if (SO_TIMESTAMPNS_OLD !=3D SO_TIMESTAMPNS) { + /* Test 5a: SO_TIMESTAMPNS_OLD */ + send_current_time(sock, addr); + } +#ifdef SO_TIMESTAMPNS_NEW + else { + /* Test 5b: SO_TIMESTAMPNS_NEW */ + send_current_time(sock, addr); + } +#endif /* defined(SO_TIMESTAMPNS_NEW) */ +#endif /* defined(SO_TIMESTAMPNS_OLD) */ + +#ifdef SO_TIMESTAMPING_OLD + if (SO_TIMESTAMPING_OLD !=3D SO_TIMESTAMPING) { + /* Test 6a: SO_TIMESTAMPING_OLD */ + printf("Test 6a: SO_TIMESTAMPING_OLD\n"); + set_socket_option(sock, SO_TIMESTAMPING_OLD, so_timestamping_flags= ); + receive_packet(sock, &get_timespec_from_so_timestamping_old); + set_socket_option(sock, SO_TIMESTAMPING_OLD, 0); + } +#ifdef SO_TIMESTAMPING_NEW + else { + /* Test 6b: SO_TIMESTAMPING_NEW */ + printf("Test 6b: SO_TIMESTAMPING_NEW\n"); + set_socket_option(sock, SO_TIMESTAMPING_NEW, so_timestamping_flags= ); + receive_packet(sock, &get_timespec_from_so_timestamping_new); + set_socket_option(sock, SO_TIMESTAMPING_NEW, 0); + } +#endif /* defined(SO_TIMESTAMPING_NEW) */ +#endif /* defined(SO_TIMESTAMPING_OLD) */ +} + +void parent_steps(int sock, struct sockaddr_in addr, int run_old) +{ + /* Test 1: SO_TIMESTAMP */ + printf("Test 1: SO_TIMESTAMP\n"); + set_socket_option(sock, SO_TIMESTAMP, 1); + receive_packet(sock, &get_timespec_from_so_timestamp); + set_socket_option(sock, SO_TIMESTAMP, 0); + + /* Test 2: SO_TIMESTAMPNS */ + send_current_time(sock, addr); + + /* Test 3: SO_TIMESTAMPING */ + printf("Test 3: SO_TIMESTAMPING\n"); + set_socket_option(sock, SO_TIMESTAMPING, so_timestamping_flags); + receive_packet(sock, &get_timespec_from_so_timestamping); + set_socket_option(sock, SO_TIMESTAMPING, 0); + + if (!run_old) { + return; + } + +#ifdef SO_TIMESTAMP_OLD + if (SO_TIMESTAMP_OLD !=3D SO_TIMESTAMP) { + /* Test 4a: SO_TIMESTAMP_OLD */ + send_current_time(sock, addr); + } +#ifdef SO_TIMESTAMP_NEW + else { + /* Test 4b: SO_TIMESTAMP_NEW */ + send_current_time(sock, addr); + } +#endif /* defined(SO_TIMESTAMP_NEW) */ +#endif /* defined(SO_TIMESTAMP_OLD) */ + +#ifdef SO_TIMESTAMPNS_OLD + if (SO_TIMESTAMPNS_OLD !=3D SO_TIMESTAMPNS) { + /* Test 5a: SO_TIMESTAMPNS_OLD */ + printf("Test 5a: SO_TIMESTAMPNS_OLD\n"); + set_socket_option(sock, SO_TIMESTAMPNS_OLD, 1); + receive_packet(sock, &get_timespec_from_so_timestampns_old); + set_socket_option(sock, SO_TIMESTAMPNS_OLD, 0); + } +#ifdef SO_TIMESTAMPNS_NEW + else { + /* Test 5b: SO_TIMESTAMPNS_NEW */ + printf("Test 5b: SO_TIMESTAMPNS_NEW\n"); + set_socket_option(sock, SO_TIMESTAMPNS_NEW, 1); + receive_packet(sock, &get_timespec_from_so_timestampns_new); + set_socket_option(sock, SO_TIMESTAMPNS_NEW, 0); + } +#endif /* defined(SO_TIMESTAMPNS_NEW) */ +#endif /* defined(SO_TIMESTAMPNS_OLD) */ + +#ifdef SO_TIMESTAMPING_OLD + if (SO_TIMESTAMPING_OLD !=3D SO_TIMESTAMPING) { + /* Test 6a: SO_TIMESTAMPING_OLD */ + send_current_time(sock, addr); + } +#ifdef SO_TIMESTAMPING_NEW + else { + /* Test 6b: SO_TIMESTAMPING_NEW */ + send_current_time(sock, addr); + } +#endif /* defined(SO_TIMESTAMPING_NEW) */ +#endif /* defined(SO_TIMESTAMPING_OLD) */ } =20 int main(int argc, char **argv) { int parent_sock, child_sock; struct sockaddr_in parent_sockaddr, child_sockaddr; - int pid; + int pid, run_old; struct timeval tv =3D {0, 0}; gettimeofday(&tv, NULL); =20 + /* Too close to y2038 old systems may not work. */ + run_old =3D tv.tv_sec < 0x7fffff00; + parent_sock =3D create_udp_socket(&parent_sockaddr); child_sock =3D create_udp_socket(&child_sockaddr); =20 @@ -226,64 +519,15 @@ int main(int argc, char **argv) if (pid < 0) { fprintf(stderr, "SKIPPED. Failed to fork: %s\n", strerror(errno)); } else if (pid =3D=3D 0) { - close(child_sock); - - /* Test 1: SO_TIMESTAMP */ - send_current_time(parent_sock, child_sockaddr); - - if (tv.tv_sec > 0x7fffff00) { - /* Too close to y2038 problem, old system may not work. */ - close(parent_sock); - return 0; - } - -#ifdef SO_TIMESTAMP_OLD - if (SO_TIMESTAMP_OLD !=3D SO_TIMESTAMP) { - /* Test 2a: SO_TIMESTAMP_OLD */ - set_socket_option(parent_sock, SO_TIMESTAMP_OLD, 1); - receive_packet(parent_sock, &get_timeval_from_so_timestamp_old= ); - set_socket_option(parent_sock, SO_TIMESTAMP_OLD, 0); - } -#ifdef SO_TIMESTAMP_NEW - else { - /* Test 2b: SO_TIMESTAMP_NEW */ - set_socket_option(parent_sock, SO_TIMESTAMP_NEW, 1); - receive_packet(parent_sock, &get_timeval_from_so_timestamp_new= ); - set_socket_option(parent_sock, SO_TIMESTAMP_NEW, 0); - } -#endif /* defined(SO_TIMESTAMP_NEW) */ -#endif /* defined(SO_TIMESTAMP_OLD) */ - close(parent_sock); + child_steps(child_sock, parent_sockaddr, run_old); + close(child_sock); } else { int child_status; - close(parent_sock); - - /* Test 1: SO_TIMESTAMP */ - set_socket_option(child_sock, SO_TIMESTAMP, 1); - receive_packet(child_sock, &get_timeval_from_so_timestamp); - set_socket_option(child_sock, SO_TIMESTAMP, 0); - - if (tv.tv_sec > 0x7fffff00) { - /* Too close to y2038 problem, old system may not work. */ - close(child_sock); - return 0; - } - -#ifdef SO_TIMESTAMP_OLD - if (SO_TIMESTAMP_OLD !=3D SO_TIMESTAMP) { - /* Test 2a: SO_TIMESTAMP_OLD */ - send_current_time(child_sock, parent_sockaddr); - } -#ifdef SO_TIMESTAMP_NEW - else { - /* Test 2b: SO_TIMESTAMP_NEW */ - send_current_time(child_sock, parent_sockaddr); - } -#endif /* defined(SO_TIMESTAMP_NEW) */ -#endif /* defined(SO_TIMESTAMP_OLD) */ =20 close(child_sock); + parent_steps(parent_sock, child_sockaddr, run_old); + close(parent_sock); =20 if (waitpid(pid, &child_status, 0) < 0) { int err =3D errno; --=20 2.28.0.220.ged08abb693-goog From nobody Fri May 17 13:37:30 2024 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=reject dis=none) header.from=google.com ARC-Seal: i=1; a=rsa-sha256; t=1597130207; cv=none; d=zohomail.com; s=zohoarc; b=hWSjdXCSLi4/bdkrun+HGI9i7SgyFhM17BKpWkBR+aLqL8z+nSMmsLuyYWDS+JmFOIrek053CSsZxwFENldfzERsLMw5y9oE93uaILfErwrZgCq1Yz8fbMpuoKS0cieC+oAEgr3E9szBT4WLXB2AuX+uSNFDA9AWsWyencPlX0o= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1597130207; h=Content-Type:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To; bh=n8F3e7zpn77NODyrxjfL4R2P/H4DSjSuJcBVxAzaq1k=; b=e9irEoiuBdWL6jZ/IwjBZc8XkK5e6sn7Dmdb62vOURROS9lYQdQgGugS584cg2KDWwf4YUmv/zUI2rUzE/0A/GtJHjMREphv0c/bEYL6pgoFViyoVr75J0hQIjgBfICAgNNwM+ZDUkqnkMNKBiJobsjo5nPkuZvlgDhz26HKyzU= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=reject dis=none) header.from= Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1597130206787663.7734542391171; Tue, 11 Aug 2020 00:16:46 -0700 (PDT) Received: from localhost ([::1]:53246 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1k5OWY-000399-Dw for importer@patchew.org; Tue, 11 Aug 2020 03:16:42 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:52870) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from <3T0QyXwMKCqASCWGOOGLE.COMQEMU-DEVELNONGNU.ORG@flex--scw.bounces.google.com>) id 1k5OQG-00053r-Fa for qemu-devel@nongnu.org; Tue, 11 Aug 2020 03:10:12 -0400 Received: from mail-yb1-xb4a.google.com ([2607:f8b0:4864:20::b4a]:54374) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from <3T0QyXwMKCqASCWGOOGLE.COMQEMU-DEVELNONGNU.ORG@flex--scw.bounces.google.com>) id 1k5OQD-0000la-7p for qemu-devel@nongnu.org; Tue, 11 Aug 2020 03:10:12 -0400 Received: by mail-yb1-xb4a.google.com with SMTP id b127so15635436ybh.21 for ; Tue, 11 Aug 2020 00:10:07 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=n8F3e7zpn77NODyrxjfL4R2P/H4DSjSuJcBVxAzaq1k=; b=iyrVYF9ozKSnxO1QZnM8zZPM2mkYzBI9Ry1cBHQeBZ4//+N03tLM2ZqETqZYSNdNTX B7QKH20/Q1/8DLPbRmr+/3prjjXesigvkk76rjS2A8AAarEM67+cbLlA3+oV9MgNBD+o CiXbC0aPWSh327Mubz7+QU/ix8bTStl0LhvqFe1GcyXQv15Up34ACFBSren68/I5zShY TJ98FbACqu2WFhJ17OWOWd/A5kN8FOrVzRLRxCGDAERi/QBc/axl2Kvolxxem77rCxTZ U1hOa8uXxDqGkOTs69EKsi3O0EDvQs08+6Id/cnaTGAnBzhZEgbOvRVpAfQwzOiFRH7R hD8g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=n8F3e7zpn77NODyrxjfL4R2P/H4DSjSuJcBVxAzaq1k=; b=lqh9md738G+CPpQHTtQbCyW/tRJM+bhO6YEbiXy0KypGw8LhaUBv+vBtoxy4QDl8nu lptABBgWHPkpBMxZL1XTX0toOZpPZ54+4SNVf57Jj/XHhMoQahvbxs8xak48quqEhOlf n1sswgdpWvLte+bV1N6l+mK+sSaxyqwAfzbhiw6klUlHwGt59fyhQKEFHBcXcTWp0VUU UxL57aq0xSJVFjKmGdzg4pBydcn8jy1E1cVBeBAiSItjacO2IwqJDcXb5Ovw8XaxVoac EXC07TB6r6NHHc45BQurl+gWtUsUlZ6yo7LnNC0C1batEbPZkKuJPExWel+G2M8ZI848 Halw== X-Gm-Message-State: AOAM530DtwkWbnA+juKul+tq1NL3M78NMwX5ehaiS7/hGm22dzWYaZg7 u1SJxlyzfPN7dFcHO1PZTs5p84gjwMx/q+iBYg/ihEYhqfmEhoI1fSpj/vXxS/OLVbwb4htfxWx tQH5tzmYHup6Yk0RRHWaHQvGDsW7F+6iPV9kr50tifbPckHkq/GxC X-Google-Smtp-Source: ABdhPJy8Rf8yBiLXH8BBrs6AzIrKEI/+b5JmglIj3LqwlGp9EBheSAxE/VQkUMA+p8LGS8OxBQ0eiYs= X-Received: by 2002:a25:3790:: with SMTP id e138mr18979408yba.421.1597129807111; Tue, 11 Aug 2020 00:10:07 -0700 (PDT) Date: Tue, 11 Aug 2020 00:09:47 -0700 In-Reply-To: Message-Id: Mime-Version: 1.0 References: X-Mailer: git-send-email 2.28.0.220.ged08abb693-goog Subject: [PATCH v2 7/8] thunk: supports flexible arrays From: Shu-Chun Weng To: qemu-devel@nongnu.org Cc: Shu-Chun Weng , laurent@vivier.eu Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=2607:f8b0:4864:20::b4a; envelope-from=3T0QyXwMKCqASCWGOOGLE.COMQEMU-DEVELNONGNU.ORG@flex--scw.bounces.google.com; helo=mail-yb1-xb4a.google.com X-detected-operating-system: by eggs.gnu.org: No matching host in p0f cache. That's all we know. X-Spam_score_int: -105 X-Spam_score: -10.6 X-Spam_bar: ---------- X-Spam_report: (-10.6 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_MED=-1, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, USER_IN_DEF_DKIM_WL=-7.5 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail-DKIM: pass (identity @google.com) Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Flexible arrays may appear in the last field of a struct and are heavily used in the ioctl(SIOCETHTOOL) system call on Linux. E.g. struct ethtool_regs { __u32 cmd; __u32 version; /* driver-specific, indicates different chips/revs */ __u32 len; /* bytes */ __u8 data[0]; }; where number of elements in `data` is specified in `len`. It is translated into: STRUCT(ethtool_regs, TYPE_INT, /* cmd */ TYPE_INT, /* version */ TYPE_INT, /* len */ MK_FLEXIBLE_ARRAY(TYPE_CHAR, 2)) /* data[0]: len */ where the "2" passed to `MK_FLEXIBLE_ARRAY` means the number of element is specified by field number 2 (0-index). Signed-off-by: Shu-Chun Weng --- v1 -> v2: Fix style problems. include/exec/user/thunk.h | 24 ++++++ thunk.c | 152 +++++++++++++++++++++++++++++++++++++- 2 files changed, 174 insertions(+), 2 deletions(-) diff --git a/include/exec/user/thunk.h b/include/exec/user/thunk.h index 7992475c9f..d0d7c83f1f 100644 --- a/include/exec/user/thunk.h +++ b/include/exec/user/thunk.h @@ -39,12 +39,21 @@ typedef enum argtype { TYPE_ARRAY, TYPE_STRUCT, TYPE_OLDDEVT, + TYPE_FLEXIBLE_ARRAY, } argtype; =20 #define MK_PTR(type) TYPE_PTR, type #define MK_ARRAY(type, size) TYPE_ARRAY, size, type #define MK_STRUCT(id) TYPE_STRUCT, id =20 +/* + * Should only appear as the last element of a TYPE_STRUCT. `len_field_idx= ` is + * the index into the fields in the enclosing struct that specify the leng= th of + * the flexibly array. The length field MUST be a TYPE_INT field. + */ +#define MK_FLEXIBLE_ARRAY(type, len_field_idx) \ + TYPE_FLEXIBLE_ARRAY, (len_field_idx), type + #define THUNK_TARGET 0 #define THUNK_HOST 1 =20 @@ -55,6 +64,8 @@ typedef struct { int *field_offsets[2]; /* special handling */ void (*convert[2])(void *dst, const void *src); + int (*thunk_size[2])(const void *src); + int size[2]; int align[2]; const char *name; @@ -75,6 +86,11 @@ const argtype *thunk_convert(void *dst, const void *src, const argtype *type_ptr, int to_host); const argtype *thunk_print(void *arg, const argtype *type_ptr); =20 +bool thunk_type_has_flexible_array(const argtype *type_ptr); +/* thunk_type_size but can handle TYPE_FLEXIBLE_ARRAY */ +int thunk_type_size_with_src(const void *src, const argtype *type_ptr, + int is_host); + extern StructEntry *struct_entries; =20 int thunk_type_size_array(const argtype *type_ptr, int is_host); @@ -137,6 +153,12 @@ static inline int thunk_type_size(const argtype *type_= ptr, int is_host) case TYPE_STRUCT: se =3D struct_entries + type_ptr[1]; return se->size[is_host]; + case TYPE_FLEXIBLE_ARRAY: + /* + * Flexible arrays do not count toward sizeof(). Users of structur= es + * containing them need to calculate it themselves. + */ + return 0; default: g_assert_not_reached(); } @@ -187,6 +209,8 @@ static inline int thunk_type_align(const argtype *type_= ptr, int is_host) case TYPE_STRUCT: se =3D struct_entries + type_ptr[1]; return se->align[is_host]; + case TYPE_FLEXIBLE_ARRAY: + return thunk_type_align_array(type_ptr + 2, is_host); default: g_assert_not_reached(); } diff --git a/thunk.c b/thunk.c index c5d9719747..d9c6cba3bd 100644 --- a/thunk.c +++ b/thunk.c @@ -50,6 +50,8 @@ static inline const argtype *thunk_type_next(const argtyp= e *type_ptr) return thunk_type_next_ptr(type_ptr + 1); case TYPE_STRUCT: return type_ptr + 1; + case TYPE_FLEXIBLE_ARRAY: + return thunk_type_next_ptr(type_ptr + 1); default: return NULL; } @@ -122,6 +124,34 @@ void thunk_register_struct_direct(int id, const char *= name, se->name =3D name; } =20 +static const argtype * +thunk_convert_flexible_array(void *dst, const void *src, + const uint8_t *dst_struct, + const uint8_t *src_struct, const argtype *typ= e_ptr, + const StructEntry *se, int to_host) { + int len_field_idx, dst_size, src_size, i; + uint32_t array_length; + uint8_t *d; + const uint8_t *s; + + assert(*type_ptr =3D=3D TYPE_FLEXIBLE_ARRAY); + type_ptr++; + len_field_idx =3D *type_ptr++; + array_length =3D + *(const uint32_t *)(to_host ? + dst_struct + se->field_offsets[1][len_field_id= x] : + src_struct + se->field_offsets[0][len_field_id= x]); + dst_size =3D thunk_type_size(type_ptr, to_host); + src_size =3D thunk_type_size(type_ptr, to_host); + d =3D dst; + s =3D src; + for (i =3D 0; i < array_length; i++) { + thunk_convert(d, s, type_ptr, to_host); + d +=3D dst_size; + s +=3D src_size; + } + return thunk_type_next(type_ptr); +} =20 /* now we can define the main conversion functions */ const argtype *thunk_convert(void *dst, const void *src, @@ -246,7 +276,7 @@ const argtype *thunk_convert(void *dst, const void *src, =20 assert(*type_ptr < max_struct_entries); se =3D struct_entries + *type_ptr++; - if (se->convert[0] !=3D NULL) { + if (se->convert[to_host] !=3D NULL) { /* specific conversion is needed */ (*se->convert[to_host])(dst, src); } else { @@ -256,7 +286,18 @@ const argtype *thunk_convert(void *dst, const void *sr= c, src_offsets =3D se->field_offsets[1 - to_host]; d =3D dst; s =3D src; - for(i =3D 0;i < se->nb_fields; i++) { + for (i =3D 0; i < se->nb_fields; i++) { + if (*field_types =3D=3D TYPE_FLEXIBLE_ARRAY) { + field_types =3D thunk_convert_flexible_array( + d + dst_offsets[i], + s + src_offsets[i], + d, + s, + field_types, + se, + to_host); + continue; + } field_types =3D thunk_convert(d + dst_offsets[i], s + src_offsets[i], field_types, to_host); @@ -264,6 +305,11 @@ const argtype *thunk_convert(void *dst, const void *sr= c, } } break; + case TYPE_FLEXIBLE_ARRAY: + fprintf(stderr, + "Invalid flexible array (type 0x%x) outside of a structure= \n", + type); + break; default: fprintf(stderr, "Invalid type 0x%x\n", type); break; @@ -271,6 +317,45 @@ const argtype *thunk_convert(void *dst, const void *sr= c, return type_ptr; } =20 +static const argtype * +thunk_print_flexible_array(void *arg, const uint8_t *arg_struct, + const argtype *type_ptr, const StructEntry *se)= { + int array_length, len_field_idx, arg_size, i; + uint8_t *a; + int is_string =3D 0; + + assert(*type_ptr =3D=3D TYPE_FLEXIBLE_ARRAY); + type_ptr++; + len_field_idx =3D *type_ptr++; + + array_length =3D tswap32( + *(const uint32_t *)(arg_struct + se->field_offsets[0][len_field_id= x])); + arg_size =3D thunk_type_size(type_ptr, 0); + a =3D arg; + + if (*type_ptr =3D=3D TYPE_CHAR) { + qemu_log("\""); + is_string =3D 1; + } else { + qemu_log("["); + } + + for (i =3D 0; i < array_length; i++) { + if (i > 0 && !is_string) { + qemu_log(","); + } + thunk_print(a, type_ptr); + a +=3D arg_size; + } + + if (is_string) { + qemu_log("\""); + } else { + qemu_log("]"); + } + return thunk_type_next(type_ptr); +} + const argtype *thunk_print(void *arg, const argtype *type_ptr) { int type; @@ -414,17 +499,80 @@ const argtype *thunk_print(void *arg, const argtype *= type_ptr) if (i > 0) { qemu_log(","); } + if (*field_types =3D=3D TYPE_FLEXIBLE_ARRAY) { + field_types =3D thunk_print_flexible_array( + a + arg_offsets[i], a, field_types, se); + continue; + } field_types =3D thunk_print(a + arg_offsets[i], field_type= s); } qemu_log("}"); } break; + case TYPE_FLEXIBLE_ARRAY: + fprintf(stderr, + "Invalid flexible array (type 0x%x) outside of a structure= \n", + type); + break; default: g_assert_not_reached(); } return type_ptr; } =20 +bool thunk_type_has_flexible_array(const argtype *type_ptr) +{ + int i; + const StructEntry *se; + const argtype *field_types; + if (*type_ptr !=3D TYPE_STRUCT) { + return false; + } + se =3D struct_entries + type_ptr[1]; + field_types =3D se->field_types; + for (i =3D 0; i < se->nb_fields; i++) { + if (*field_types =3D=3D TYPE_FLEXIBLE_ARRAY) { + return true; + } + field_types =3D thunk_type_next(type_ptr); + } + return false; +} + +int thunk_type_size_with_src(const void *src, const argtype *type_ptr, + int is_host) +{ + switch (*type_ptr) { + case TYPE_STRUCT: { + int i; + const StructEntry *se =3D struct_entries + type_ptr[1]; + const argtype *field_types; + if (se->thunk_size[is_host] !=3D NULL) { + return (*se->thunk_size[is_host])(src); + } + + field_types =3D se->field_types; + for (i =3D 0; i < se->nb_fields; i++) { + if (*field_types =3D=3D TYPE_FLEXIBLE_ARRAY) { + uint32_t array_length =3D *(const uint32_t *)( + (const uint8_t *)src + + se->field_offsets[is_host][field_types[1]]); + if (!is_host) { + array_length =3D tswap32(array_length); + } + return se->size[is_host] + + array_length * + thunk_type_size(field_types + 2, is_host); + } + field_types =3D thunk_type_next(type_ptr); + } + return se->size[is_host]; + } + default: + return thunk_type_size(type_ptr, is_host); + } +} + /* from em86 */ =20 /* Utility function: Table-driven functions to translate bitmasks --=20 2.28.0.220.ged08abb693-goog From nobody Fri May 17 13:37:30 2024 Delivered-To: importer@patchew.org Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass(p=reject dis=none) header.from=google.com ARC-Seal: i=1; a=rsa-sha256; t=1597130392; cv=none; d=zohomail.com; s=zohoarc; b=f0h/bXkzOiqit89GFe590cfKlIIit10pQv3NhwKWd6+zPiSb1V53NoqD+aeCwxgYB9ScVDaQD0/p1oo3gNfIV4wJ2mD6TDanL7zmhWB8LlQcPB3WxqYjJ0mBAUcxhCzskb78nkDzrDWzruuitYVeazb6A+OJuMxuG24kfUIKWRU= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1597130392; h=Content-Type:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To; bh=ZERXMS+SXAABAqLVUQOVcRTGLiljhw8gKHawKgDemuU=; b=Ve7/vl+Y7FQbzudl2pavBhyqozmOdOVXetomUkQtG3Z1MRO0dHePpSca2wkwJ1oL1kyl3kH8hOBAEk93Ex4Jy9s9Uc5ppJ5gqoGP/L3+lP4gFkDm3ejjZZzHQiofAxWtVNtp14QqC+LoTCuKRvz5/y9pZtMyO5wMRrnJQ2OifAs= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=pass header.from= (p=reject dis=none) header.from= Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1597130391995928.8003398768146; Tue, 11 Aug 2020 00:19:51 -0700 (PDT) Received: from localhost ([::1]:57506 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1k5OZa-0004zS-Hq for importer@patchew.org; Tue, 11 Aug 2020 03:19:50 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:52910) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from <3UUQyXwMKCqIUEYIQQING.EQOSGOW-FGXGNPQPIPW.QTI@flex--scw.bounces.google.com>) id 1k5OQK-00058W-7d for qemu-devel@nongnu.org; Tue, 11 Aug 2020 03:10:16 -0400 Received: from mail-yb1-xb49.google.com ([2607:f8b0:4864:20::b49]:43468) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from <3UUQyXwMKCqIUEYIQQING.EQOSGOW-FGXGNPQPIPW.QTI@flex--scw.bounces.google.com>) id 1k5OQF-0000lk-KZ for qemu-devel@nongnu.org; Tue, 11 Aug 2020 03:10:15 -0400 Received: by mail-yb1-xb49.google.com with SMTP id x184so15666451ybx.10 for ; Tue, 11 Aug 2020 00:10:10 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=ZERXMS+SXAABAqLVUQOVcRTGLiljhw8gKHawKgDemuU=; b=YEeYtJqG3jVCvTIFlIeybA+Qr+YYzWGLXcYF5G4hcGsQhHMWHcAErQhWZS9gZ4kLqv oWMePti/JltUVDH0hQCn3lWoUkgeLE8HTNBA/SJ6bq7vlDcOmdD8s9Z7VXlTBbo+5GXD 3SqboYR0IxfwGaiLgof0G5rAwTOSBzr+QN1GILaEv6qS9MEAbA2ntLt9tKnMOOkAGLHU SQe8dTNEFkBP4/FoGcFbPS8zywwrsApAL37wu+7mpYTinY7RrJyJE5lUz8rOgYEKegUL DGiHIdyQ0wKFUYbN1PHNyjCfPj6PLu2tZom8kDdxI83wdWUXi754dv8knSXNzcX/iPFo OhhQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=ZERXMS+SXAABAqLVUQOVcRTGLiljhw8gKHawKgDemuU=; b=oGJGGOS80D5WyamoCMYU/chXXj+gGcSrLB0/cVZ72a2nBCypmMB0b7QQk/Hilnhmy6 tM7RB8YeMgkubN2FZ/+IgtnlYVCw7uLuPXXx7f6frxtiRTuG0OPkdWhO6sRi9G9Nz0Dw HQ7y+2gskFcbguskRJDsTDB9KKnn2QeLmVBRX4MZPvb/Nr8zve4SRd7h/gwZnddSTfUF 0Vr+GwRr02AkSqkvv2CN82wT2CJozkyipyRSkOnNti2XXe/JGCu1sM6WkOHj3budS6nf TrlL72sWHoIPxNzKK/p1vpZOCSMmszrIF4obnPsmre07NOf02Qy7hjybZCSWfqOjzpCI 2ZAQ== X-Gm-Message-State: AOAM532UPCnwc0vYdT9+TcTitottZEdqrFe59w3sfdUYvRb1gOcVuQeK 1fTVErHRkhx4HZBqW1a+B2iwMa30X0wHAg/BlJSkY5J6JrB2L+cUXEOUNeJ1CPq6rPymQJgs4GW ZcHvR2DYKvRGiv2KaqYsw4WoJ2NIymXhIZW8cIPPxXyh020ndbc8k X-Google-Smtp-Source: ABdhPJy0NWyTcfRoRqSgibZWdYkXuvr6QJ7JM45lGUcxWuTVcAG+W97LI89U3l1PnUjXj1caVbbOivE= X-Received: by 2002:a25:ae83:: with SMTP id b3mr46188966ybj.354.1597129809182; Tue, 11 Aug 2020 00:10:09 -0700 (PDT) Date: Tue, 11 Aug 2020 00:09:48 -0700 In-Reply-To: Message-Id: <61323061160b6d21f43b266764eda813b5e021e2.1597129029.git.scw@google.com> Mime-Version: 1.0 References: X-Mailer: git-send-email 2.28.0.220.ged08abb693-goog Subject: [PATCH v2 8/8] linux-user: Add support for SIOCETHTOOL ioctl From: Shu-Chun Weng To: qemu-devel@nongnu.org Cc: Shu-Chun Weng , laurent@vivier.eu Received-SPF: pass (zohomail.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Received-SPF: pass client-ip=2607:f8b0:4864:20::b49; envelope-from=3UUQyXwMKCqIUEYIQQING.EQOSGOW-FGXGNPQPIPW.QTI@flex--scw.bounces.google.com; helo=mail-yb1-xb49.google.com X-detected-operating-system: by eggs.gnu.org: No matching host in p0f cache. That's all we know. X-Spam_score_int: -105 X-Spam_score: -10.6 X-Spam_bar: ---------- X-Spam_report: (-10.6 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_MED=-1, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, USER_IN_DEF_DKIM_WL=-7.5 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail-DKIM: pass (identity @google.com) Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" The ioctl numeric values are platform-independent and determined by the file include/uapi/linux/sockios.h in Linux kernel source code: #define SIOCETHTOOL 0x8946 These ioctls get (or set) various structures pointed by the field ifr_data in the structure ifreq depending on the first 4 bytes of the memory region. This change clones the ioctl framework into ethtool-specific dispatch logic in its own file. A number of definitions previously only visible in syscall.c are thus exported to syscall_defs.h to be used in the new files. Signed-off-by: Shu-Chun Weng --- v1 -> v2: Fix style problems. linux-user/Makefile.objs | 3 +- linux-user/ethtool.c | 840 ++++++++++++++++++++++++++++++++++ linux-user/ethtool.h | 20 + linux-user/ethtool_entries.h | 107 +++++ linux-user/ioctls.h | 2 + linux-user/qemu.h | 1 + linux-user/syscall.c | 36 +- linux-user/syscall_defs.h | 12 + linux-user/syscall_types.h | 280 ++++++++++++ tests/tcg/multiarch/ethtool.c | 423 +++++++++++++++++ 10 files changed, 1712 insertions(+), 12 deletions(-) create mode 100644 linux-user/ethtool.c create mode 100644 linux-user/ethtool.h create mode 100644 linux-user/ethtool_entries.h create mode 100644 tests/tcg/multiarch/ethtool.c diff --git a/linux-user/Makefile.objs b/linux-user/Makefile.objs index 1940910a73..971d43173a 100644 --- a/linux-user/Makefile.objs +++ b/linux-user/Makefile.objs @@ -1,7 +1,8 @@ obj-y =3D main.o syscall.o strace.o mmap.o signal.o \ elfload.o linuxload.o uaccess.o uname.o \ safe-syscall.o $(TARGET_ABI_DIR)/signal.o \ - $(TARGET_ABI_DIR)/cpu_loop.o exit.o fd-trans.o + $(TARGET_ABI_DIR)/cpu_loop.o exit.o fd-trans.o \ + ethtool.o =20 obj-$(TARGET_HAS_BFLT) +=3D flatload.o obj-$(TARGET_I386) +=3D vm86.o diff --git a/linux-user/ethtool.c b/linux-user/ethtool.c new file mode 100644 index 0000000000..fac97b9ba1 --- /dev/null +++ b/linux-user/ethtool.c @@ -0,0 +1,840 @@ +/* + * Linux ioctl system call SIOCETHTOOL requests + * + * Copyright (c) 2020 Shu-Chun Weng + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ +#include "qemu/osdep.h" +#include +#include +#include +#include +#include +#include "ethtool.h" +#include "qemu.h" +#include "syscall_defs.h" + +/* Non-standard ethtool structure definitions. */ +/* + * struct ethtool_rxnfc { + * __u32 cmd; + * __u32 flow_type; + * __u64 data; + * struct ethtool_rx_flow_spec fs; + * union { + * __u32 rule_cnt; + * __u32 rss_context; + * }; + * __u32 rule_locs[0]; + * }; + * + * Originally defined for ETHTOOL_{G,S}RXFH with only the cmd, flow_type a= nd + * data members. For other commands, dedicated standard structure definiti= ons + * are listed in syscall_types.h. + */ +static void host_to_target_ethtool_rxnfc_get_set_rxfh(void *dst, + const void *src) +{ + static const argtype ethtool_rx_flow_spec_argtype[] =3D { + MK_STRUCT(STRUCT_ethtool_rx_flow_spec), TYPE_NULL }; + struct ethtool_rxnfc *target =3D dst; + const struct ethtool_rxnfc *host =3D src; + + target->cmd =3D tswap32(host->cmd); + target->flow_type =3D tswap32(host->flow_type); + target->data =3D tswap64(host->data); + + if (host->cmd =3D=3D ETHTOOL_SRXFH) { + /* + * struct ethtool_rxnfc was originally defined for ETHTOOL_{G,S}RX= FH + * with only the cmd, flow_type and data members. Guest program mi= ght + * still be using that definition. + */ + return; + } + if (host->cmd !=3D ETHTOOL_GRXFH) { + fprintf(stderr, "host_to_target_ethtool_rxnfc_get_set_rxfh called = with " + "command 0x%x which is not ETHTOOL_SRXFH or ETHTOOL_GRXFH\= n", + host->cmd); + } + if ((host->flow_type & FLOW_RSS) =3D=3D 0) { + return; + } + /* + * If `FLOW_RSS` was requested then guest program must be using the new + * definition. + */ + thunk_convert(&target->fs, &host->fs, ethtool_rx_flow_spec_argtype, + THUNK_TARGET); + target->rule_cnt =3D tswap32(host->rule_cnt); +} + +static void target_to_host_ethtool_rxnfc_get_set_rxfh(void *dst, + const void *src) +{ + static const argtype ethtool_rx_flow_spec_argtype[] =3D { + MK_STRUCT(STRUCT_ethtool_rx_flow_spec), TYPE_NULL }; + struct ethtool_rxnfc *host =3D dst; + const struct ethtool_rxnfc *target =3D src; + + host->cmd =3D tswap32(target->cmd); + host->flow_type =3D tswap32(target->flow_type); + host->data =3D tswap64(target->data); + + if (host->cmd =3D=3D ETHTOOL_SRXFH) { + /* + * struct ethtool_rxnfc was originally defined for ETHTOOL_{G,S}RX= FH + * with only the cmd, flow_type and data members. Guest program mi= ght + * still be using that definition. + */ + return; + } + if (host->cmd !=3D ETHTOOL_GRXFH) { + fprintf(stderr, "target_to_host_ethtool_rxnfc_get_set_rxfh called = with " + "command 0x%x which is not ETHTOOL_SRXFH or ETHTOOL_GRXFH\= n", + host->cmd); + } + if ((host->flow_type & FLOW_RSS) =3D=3D 0) { + return; + } + /* + * If `FLOW_RSS` was requested then guest program must be using the new + * definition. + */ + thunk_convert(&host->fs, &target->fs, ethtool_rx_flow_spec_argtype, + THUNK_HOST); + host->rule_cnt =3D tswap32(target->rule_cnt); +} + +static int target_ethtool_rxnfc_get_set_rxfh_size(const void *src) +{ + const struct ethtool_rxnfc *target =3D src; + int cmd =3D tswap32(target->cmd); + if (cmd =3D=3D ETHTOOL_SRXFH || + (cmd =3D=3D ETHTOOL_GRXFH && + (tswap32(target->flow_type) & FLOW_RSS) =3D=3D 0)) { + return 16; + } + return sizeof(struct ethtool_rxnfc); +} + +static int host_ethtool_rxnfc_get_set_rxfh_size(const void *src) +{ + const struct ethtool_rxnfc *host =3D src; + if (host->cmd =3D=3D ETHTOOL_SRXFH || + (host->cmd =3D=3D ETHTOOL_GRXFH && (host->flow_type & FLOW_RSS) = =3D=3D 0)) { + return 16; + } + return sizeof(struct ethtool_rxnfc); +} + +const StructEntry struct_ethtool_rxnfc_get_set_rxfh_def =3D { + .convert =3D { + host_to_target_ethtool_rxnfc_get_set_rxfh, + target_to_host_ethtool_rxnfc_get_set_rxfh }, + .thunk_size =3D { + target_ethtool_rxnfc_get_set_rxfh_size, + host_ethtool_rxnfc_get_set_rxfh_size }, + .size =3D { 16, 16 }, + .align =3D { + __alignof__(struct ethtool_rxnfc), + __alignof__(struct ethtool_rxnfc) }, +}; + +/* + * struct ethtool_sset_info { + * __u32 cmd; + * __u32 reserved; + * __u64 sset_mask; + * __u32 data[0]; + * }; + * + * `sset_mask` is a bitmask of string sets. `data` is the buffer for strin= g set + * sizes, containing number of 1s in `sset_mask`'s binary representation n= umber + * of 4-byte entries. + * + * Since all fields are fixed-width and number of 1s in `sset_mask` does n= ot + * change between architectures, host-to-target and target-to-host are + * identical. + */ +static void convert_ethtool_sset_info(void *dst, const void *src) +{ + int i, set_count; + struct ethtool_sset_info *dst_sset_info =3D dst; + const struct ethtool_sset_info *src_sset_info =3D src; + + dst_sset_info->cmd =3D tswap32(src_sset_info->cmd); + dst_sset_info->sset_mask =3D tswap64(src_sset_info->sset_mask); + + set_count =3D ctpop64(src_sset_info->sset_mask); + for (i =3D 0; i < set_count; ++i) { + dst_sset_info->data[i] =3D tswap32(src_sset_info->data[i]); + } +} + +static int ethtool_sset_info_size(const void *src) +{ + const struct ethtool_sset_info *src_sset_info =3D src; + return sizeof(struct ethtool_sset_info) + + ctpop64(src_sset_info->sset_mask) * sizeof(src_sset_info->data[0]); +} + +const StructEntry struct_ethtool_sset_info_def =3D { + .convert =3D { + convert_ethtool_sset_info, convert_ethtool_sset_info }, + .thunk_size =3D { + ethtool_sset_info_size, ethtool_sset_info_size }, + .size =3D { + sizeof(struct ethtool_sset_info), + sizeof(struct ethtool_sset_info) }, + .align =3D { + __alignof__(struct ethtool_sset_info), + __alignof__(struct ethtool_sset_info) }, +}; + +/* + * struct ethtool_rxfh { + * __u32 cmd; + * __u32 rss_context; + * __u32 indir_size; + * __u32 key_size; + * __u8 hfunc; + * __u8 rsvd8[3]; + * __u32 rsvd32; + * __u32 rss_config[0]; + * }; + * + * `rss_config`: indirection table of `indir_size` __u32 elements, followe= d by + * hash key of `key_size` bytes. + * + * `indir_size` could be ETH_RXFH_INDIR_NO_CHANGE when `cmd` is ETHTOOL_SR= SSH + * and there would be no indircetion table in `rss_config`. + */ +static void convert_ethtool_rxfh_header(void *dst, const void *src) +{ + struct ethtool_rxfh *dst_rxfh =3D dst; + const struct ethtool_rxfh *src_rxfh =3D src; + + dst_rxfh->cmd =3D tswap32(src_rxfh->cmd); + dst_rxfh->rss_context =3D tswap32(src_rxfh->rss_context); + dst_rxfh->indir_size =3D tswap32(src_rxfh->indir_size); + dst_rxfh->key_size =3D tswap32(src_rxfh->key_size); + dst_rxfh->hfunc =3D src_rxfh->hfunc; + dst_rxfh->rsvd8[0] =3D src_rxfh->rsvd8[0]; + dst_rxfh->rsvd8[1] =3D src_rxfh->rsvd8[1]; + dst_rxfh->rsvd8[2] =3D src_rxfh->rsvd8[2]; + dst_rxfh->rsvd32 =3D tswap32(src_rxfh->rsvd32); +} + +static void convert_ethtool_rxfh_rss_config( + void *dst, const void *src, uint32_t indir_size, uint32_t key_size) { + uint32_t *dst_rss_config =3D (uint32_t *)dst; + const uint32_t *src_rss_config =3D (const uint32_t *)src; + int i; + for (i =3D 0; i < indir_size; ++i) { + dst_rss_config[i] =3D tswap32(src_rss_config[i]); + } + if (key_size > 0) { + memcpy(dst_rss_config + indir_size, + src_rss_config + indir_size, + key_size); + } +} + +static void host_to_target_ethtool_rxfh(void *dst, const void *src) +{ + struct ethtool_rxfh *target =3D dst; + const struct ethtool_rxfh *host =3D src; + + convert_ethtool_rxfh_header(dst, src); + + const uint32_t indir_size =3D + host->cmd =3D=3D ETHTOOL_SRSSH && + host->indir_size =3D=3D ETH_RXFH_INDIR_NO_CHANGE ? + 0 : + host->indir_size; + convert_ethtool_rxfh_rss_config(target->rss_config, host->rss_config, + indir_size, host->key_size); +} + +static void target_to_host_ethtool_rxfh(void *dst, const void *src) +{ + struct ethtool_rxfh *host =3D dst; + const struct ethtool_rxfh *target =3D src; + + convert_ethtool_rxfh_header(dst, src); + + const uint32_t indir_size =3D + host->cmd =3D=3D ETHTOOL_SRSSH && + host->indir_size =3D=3D ETH_RXFH_INDIR_NO_CHANGE ? + 0 : + host->indir_size; + convert_ethtool_rxfh_rss_config(host->rss_config, target->rss_config, + indir_size, host->key_size); +} + +static int target_ethtool_rxfh_size(const void *src) +{ + const struct ethtool_rxfh *target =3D src; + if (tswap32(target->cmd) =3D=3D ETHTOOL_SRSSH && + tswap32(target->indir_size) =3D=3D ETH_RXFH_INDIR_NO_CHANGE) { + return sizeof(struct ethtool_rxfh) + tswap32(target->key_size); + } + return sizeof(struct ethtool_rxfh) + + tswap32(target->indir_size) * sizeof(target->rss_config[0]) + + tswap32(target->key_size); +} + +static int host_ethtool_rxfh_size(const void *src) +{ + const struct ethtool_rxfh *host =3D src; + if (host->cmd =3D=3D ETHTOOL_SRSSH && + host->indir_size =3D=3D ETH_RXFH_INDIR_NO_CHANGE) { + return sizeof(struct ethtool_rxfh) + host->key_size; + } + return sizeof(struct ethtool_rxfh) + + host->indir_size * sizeof(host->rss_config[0]) + + host->key_size; +} + +const StructEntry struct_ethtool_rxfh_def =3D { + .convert =3D { + host_to_target_ethtool_rxfh, target_to_host_ethtool_rxfh }, + .thunk_size =3D { + target_ethtool_rxfh_size, host_ethtool_rxfh_size }, + .size =3D { + sizeof(struct ethtool_rxfh), sizeof(struct ethtool_rxfh) }, + .align =3D { + __alignof__(struct ethtool_rxfh), __alignof__(struct ethtool_rxfh)= }, +}; + +/* + * struct ethtool_link_settings { + * __u32 cmd; + * __u32 speed; + * __u8 duplex; + * __u8 port; + * __u8 phy_address; + * __u8 autoneg; + * __u8 mdio_support; + * __u8 eth_tp_mdix; + * __u8 eth_tp_mdix_ctrl; + * __s8 link_mode_masks_nwords; + * __u8 transceiver; + * __u8 reserved1[3]; + * __u32 reserved[7]; + * __u32 link_mode_masks[0]; + * }; + * + * layout of link_mode_masks fields: + * __u32 map_supported[link_mode_masks_nwords]; + * __u32 map_advertising[link_mode_masks_nwords]; + * __u32 map_lp_advertising[link_mode_masks_nwords]; + * + * `link_mode_masks_nwords` can be negative when returning from kernel if = the + * provided request size is not supported. + */ + +static void host_to_target_ethtool_link_settings(void *dst, const void *sr= c) +{ + int i; + struct ethtool_link_settings *target =3D dst; + const struct ethtool_link_settings *host =3D src; + + target->cmd =3D tswap32(host->cmd); + target->speed =3D tswap32(host->speed); + target->duplex =3D host->duplex; + target->port =3D host->port; + target->phy_address =3D host->phy_address; + target->autoneg =3D host->autoneg; + target->mdio_support =3D host->mdio_support; + target->eth_tp_mdix =3D host->eth_tp_mdix; + target->eth_tp_mdix_ctrl =3D host->eth_tp_mdix_ctrl; + target->link_mode_masks_nwords =3D host->link_mode_masks_nwords; + target->transceiver =3D host->transceiver; + for (i =3D 0; i < 3; ++i) { + target->reserved1[i] =3D host->reserved1[i]; + } + for (i =3D 0; i < 7; ++i) { + target->reserved[i] =3D tswap32(host->reserved[i]); + } + + if (host->link_mode_masks_nwords > 0) { + for (i =3D 0; i < host->link_mode_masks_nwords * 3; ++i) { + target->link_mode_masks[i] =3D tswap32(host->link_mode_masks[i= ]); + } + } +} + +static void target_to_host_ethtool_link_settings(void *dst, const void *sr= c) +{ + int i; + struct ethtool_link_settings *host =3D dst; + const struct ethtool_link_settings *target =3D src; + + host->cmd =3D tswap32(target->cmd); + host->speed =3D tswap32(target->speed); + host->duplex =3D target->duplex; + host->port =3D target->port; + host->phy_address =3D target->phy_address; + host->autoneg =3D target->autoneg; + host->mdio_support =3D target->mdio_support; + host->eth_tp_mdix =3D target->eth_tp_mdix; + host->eth_tp_mdix_ctrl =3D target->eth_tp_mdix_ctrl; + host->link_mode_masks_nwords =3D target->link_mode_masks_nwords; + host->transceiver =3D target->transceiver; + for (i =3D 0; i < 3; ++i) { + host->reserved1[i] =3D target->reserved1[i]; + } + for (i =3D 0; i < 7; ++i) { + host->reserved[i] =3D tswap32(target->reserved[i]); + } + + if (host->link_mode_masks_nwords > 0) { + for (i =3D 0; i < host->link_mode_masks_nwords * 3; ++i) { + host->link_mode_masks[i] =3D tswap32(target->link_mode_masks[i= ]); + } + } +} + +static int target_ethtool_link_settings_size(const void *src) +{ + const struct ethtool_link_settings *target =3D src; + if (target->link_mode_masks_nwords > 0) { + return sizeof(struct ethtool_link_settings) + + 3 * target->link_mode_masks_nwords * + sizeof(target->link_mode_masks[0]); + } else { + return sizeof(struct ethtool_link_settings); + } +} + +static int host_ethtool_link_settings_size(const void *src) +{ + const struct ethtool_link_settings *host =3D src; + if (host->link_mode_masks_nwords > 0) { + return sizeof(struct ethtool_link_settings) + + 3 * host->link_mode_masks_nwords * + sizeof(host->link_mode_masks[0]); + } else { + return sizeof(struct ethtool_link_settings); + } +} + +const StructEntry struct_ethtool_link_settings_def =3D { + .convert =3D { + host_to_target_ethtool_link_settings, + target_to_host_ethtool_link_settings + }, + .thunk_size =3D { + target_ethtool_link_settings_size, host_ethtool_link_settings_size= }, + .size =3D { + sizeof(struct ethtool_link_settings), + sizeof(struct ethtool_link_settings) }, + .align =3D { + __alignof__(struct ethtool_link_settings), + __alignof__(struct ethtool_link_settings) }, +}; + +/* + * struct ethtool_per_queue_op { + * __u32 cmd; + * __u32 sub_command; + * __u32 queue_mask[__KERNEL_DIV_ROUND_UP(MAX_NUM_QUEUE, 32)]; + * char data[]; + * }; + * + * `queue_mask` are a series of bitmasks of the queues. `data` is a comple= te + * command structure for each of the queues addressed. + * + * When `cmd` is `ETHTOOL_PERQUEUE` and `sub_command` is `ETHTOOL_GCOALESC= E` or + * `ETHTOOL_SCOALESCE`, the command structure is `struct ethtool_coalesce`. + */ +static void host_to_target_ethtool_per_queue_op(void *dst, const void *src) +{ + static const argtype ethtool_coalesce_argtype[] =3D { + MK_STRUCT(STRUCT_ethtool_coalesce), TYPE_NULL }; + int i, queue_count; + struct ethtool_per_queue_op *target =3D dst; + const struct ethtool_per_queue_op *host =3D src; + + target->cmd =3D tswap32(host->cmd); + target->sub_command =3D tswap32(host->sub_command); + + queue_count =3D 0; + for (i =3D 0; i < __KERNEL_DIV_ROUND_UP(MAX_NUM_QUEUE, 32); ++i) { + target->queue_mask[i] =3D tswap32(host->queue_mask[i]); + queue_count +=3D ctpop32(host->queue_mask[i]); + } + + if (host->cmd !=3D ETHTOOL_PERQUEUE || + (host->sub_command !=3D ETHTOOL_GCOALESCE && + host->sub_command !=3D ETHTOOL_SCOALESCE)) { + fprintf(stderr, + "Unknown command 0x%x sub_command 0x%x for " + "ethtool_per_queue_op, unable to convert the `data` field " + "(host-to-target)\n", + host->cmd, host->sub_command); + return; + } + + for (i =3D 0; i < queue_count; ++i) { + thunk_convert(target->data + i * sizeof(struct ethtool_coalesce), + host->data + i * sizeof(struct ethtool_coalesce), + ethtool_coalesce_argtype, THUNK_TARGET); + } +} + +static void target_to_host_ethtool_per_queue_op(void *dst, const void *src) +{ + static const argtype ethtool_coalesce_argtype[] =3D { + MK_STRUCT(STRUCT_ethtool_coalesce), TYPE_NULL }; + int i, queue_count; + struct ethtool_per_queue_op *host =3D dst; + const struct ethtool_per_queue_op *target =3D src; + + host->cmd =3D tswap32(target->cmd); + host->sub_command =3D tswap32(target->sub_command); + + queue_count =3D 0; + for (i =3D 0; i < __KERNEL_DIV_ROUND_UP(MAX_NUM_QUEUE, 32); ++i) { + host->queue_mask[i] =3D tswap32(target->queue_mask[i]); + queue_count +=3D ctpop32(host->queue_mask[i]); + } + + if (host->cmd !=3D ETHTOOL_PERQUEUE || + (host->sub_command !=3D ETHTOOL_GCOALESCE && + host->sub_command !=3D ETHTOOL_SCOALESCE)) { + fprintf(stderr, + "Unknown command 0x%x sub_command 0x%x for " + "ethtool_per_queue_op, unable to convert the `data` field " + "(target-to-host)\n", + host->cmd, host->sub_command); + return; + } + + for (i =3D 0; i < queue_count; ++i) { + thunk_convert(host->data + i * sizeof(struct ethtool_coalesce), + target->data + i * sizeof(struct ethtool_coalesce), + ethtool_coalesce_argtype, THUNK_HOST); + } +} + +static int target_ethtool_per_queue_op_size(const void *src) +{ + int i, queue_count; + const struct ethtool_per_queue_op *target =3D src; + + if (tswap32(target->cmd) !=3D ETHTOOL_PERQUEUE || + (tswap32(target->sub_command) !=3D ETHTOOL_GCOALESCE && + tswap32(target->sub_command) !=3D ETHTOOL_SCOALESCE)) { + fprintf(stderr, + "Unknown command 0x%x sub_command 0x%x for " + "ethtool_per_queue_op, unable to compute the size of the " + "`data` field (target)\n", + tswap32(target->cmd), tswap32(target->sub_command)); + return sizeof(struct ethtool_per_queue_op); + } + + queue_count =3D 0; + for (i =3D 0; i < __KERNEL_DIV_ROUND_UP(MAX_NUM_QUEUE, 32); ++i) { + queue_count +=3D ctpop32(target->queue_mask[i]); + } + return sizeof(struct ethtool_per_queue_op) + + queue_count * sizeof(struct ethtool_coalesce); +} + +static int host_ethtool_per_queue_op_size(const void *src) +{ + int i, queue_count; + const struct ethtool_per_queue_op *host =3D src; + + if (host->cmd !=3D ETHTOOL_PERQUEUE || + (host->sub_command !=3D ETHTOOL_GCOALESCE && + host->sub_command !=3D ETHTOOL_SCOALESCE)) { + fprintf(stderr, + "Unknown command 0x%x sub_command 0x%x for " + "ethtool_per_queue_op, unable to compute the size of the " + "`data` field (host)\n", + host->cmd, host->sub_command); + return sizeof(struct ethtool_per_queue_op); + } + + queue_count =3D 0; + for (i =3D 0; i < __KERNEL_DIV_ROUND_UP(MAX_NUM_QUEUE, 32); ++i) { + queue_count +=3D ctpop32(host->queue_mask[i]); + } + return sizeof(struct ethtool_per_queue_op) + + queue_count * sizeof(struct ethtool_coalesce); +} + +const StructEntry struct_ethtool_per_queue_op_def =3D { + .convert =3D { + host_to_target_ethtool_per_queue_op, + target_to_host_ethtool_per_queue_op + }, + .thunk_size =3D { + target_ethtool_per_queue_op_size, host_ethtool_per_queue_op_size }, + .size =3D { + sizeof(struct ethtool_per_queue_op), + sizeof(struct ethtool_per_queue_op) }, + .align =3D { + __alignof__(struct ethtool_per_queue_op), + __alignof__(struct ethtool_per_queue_op) }, +}; + +#define safe_dev_ethtool(fd, ...) \ + safe_syscall(__NR_ioctl, (fd), SIOCETHTOOL, __VA_ARGS__) + +typedef struct EthtoolEntry EthtoolEntry; + +typedef abi_long do_ethtool_fn(const EthtoolEntry *ee, uint8_t *buf_temp, + int fd, struct ifreq *host_ifreq); + +struct EthtoolEntry { + uint32_t cmd; + int access; + do_ethtool_fn *do_ethtool; + const argtype arg_type[3]; +}; + +#define ETHT_R 0x0001 +#define ETHT_W 0x0002 +#define ETHT_RW (ETHT_R | ETHT_W) + +static do_ethtool_fn do_ethtool_get_rxfh; + +static EthtoolEntry ethtool_entries[] =3D { +#define ETHTOOL(cmd, access, ...) \ + { cmd, access, 0, { __VA_ARGS__ } }, +#define ETHTOOL_SPECIAL(cmd, access, dofn, ...) \ + { cmd, access, dofn, { __VA_ARGS__ } }, +#include "ethtool_entries.h" +#undef ETHTOOL +#undef ETHTOOL_SPECIAL + { 0, 0 }, +}; + +/* + * ETHTOOL_GRSSH has two modes of operations: querying the sizes of the in= dir + * and key as well as actually querying the indir and key. When either + * `indir_size` or `key_size` is zero, the size of the corresponding entry= is + * retrieved and updated into the `ethtool_rxfh` struct. When either of th= em is + * non-zero, the actually indir or key is written to `rss_config`. + * + * This causes a problem for the generic framework which converts between = host + * and target structures without the context. When the convertion function= sees + * an `ethtool_rxfh` struct with non-zero `indir_size` or `key_size`, it h= as to + * assume that there are entries in `rss_config` and needs to convert them. + * Unfortunately, when converting the returned `ethtool_rxfh` struct from = host + * to target after an ETHTOOL_GRSSH call with the first mode, the `indir_s= ize` + * and `key_size` fields are populated but there is no actual data to be + * converted. More importantly, user programs would not have prepared enou= gh + * memory for the convertion to take place safely. + * + * ETHTOOL_GRSSH thus needs a special implementation which is aware of the= two + * modes of operations and converts the structure accordingly. + */ +abi_long do_ethtool_get_rxfh(const EthtoolEntry *ee, uint8_t *buf_temp, + int fd, struct ifreq *host_ifreq) +{ + const argtype *arg_type =3D ee->arg_type; + const abi_long ifreq_data =3D (abi_long)(unsigned long)host_ifreq->ifr= _data; + struct ethtool_rxfh *rxfh =3D (struct ethtool_rxfh *)buf_temp; + uint32_t user_indir_size, user_key_size; + abi_long ret; + void *argptr; + + assert(arg_type[0] =3D=3D TYPE_PTR); + assert(ee->access =3D=3D IOC_RW); + arg_type++; + + /* + * As of Linux kernel v5.8-rc4, ETHTOOL_GRSSH calls never read the + * `rss_config` part. Converting only the "header" part suffices. + */ + argptr =3D lock_user(VERIFY_READ, ifreq_data, sizeof(*rxfh), 1); + if (!argptr) { + return -TARGET_EFAULT; + } + convert_ethtool_rxfh_header(rxfh, argptr); + unlock_user(argptr, ifreq_data, sizeof(*rxfh)); + + if (rxfh->cmd !=3D ETHTOOL_GRSSH) { + return -TARGET_EINVAL; + } + user_indir_size =3D rxfh->indir_size; + user_key_size =3D rxfh->key_size; + + host_ifreq->ifr_data =3D (void *)rxfh; + ret =3D get_errno(safe_dev_ethtool(fd, host_ifreq)); + + /* + * When a user program supplies `indir_size` or `key_size` but does not + * match what the kernel has, the syscall returns EINVAL but the struc= ture + * is already updated. Mimicking it here. + */ + argptr =3D lock_user(VERIFY_WRITE, ifreq_data, sizeof(*rxfh), 0); + if (!argptr) { + return -TARGET_EFAULT; + } + convert_ethtool_rxfh_header(argptr, rxfh); + unlock_user(argptr, ifreq_data, 0); + + if (is_error(ret)) { + return ret; + } + + if (user_indir_size > 0 || user_key_size > 0) { + const int rss_config_size =3D + user_indir_size * sizeof(rxfh->rss_config[0]) + user_key_size; + argptr =3D lock_user(VERIFY_WRITE, ifreq_data + sizeof(*rxfh), + rss_config_size, 0); + if (!argptr) { + return -TARGET_EFAULT; + } + convert_ethtool_rxfh_rss_config(argptr, rxfh->rss_config, + user_indir_size, user_key_size); + unlock_user(argptr, ifreq_data + sizeof(*rxfh), rss_config_size); + } + return ret; +} + +/* + * Calculates the size of the data type represented by `type_ptr` with + * `guest_addr` being the underlying memory. Since `type_ptr` may contain + * flexible arrays, we need access to the underlying memory to determine t= heir + * sizes. + */ +static int thunk_size(abi_long guest_addr, const argtype *type_ptr) +{ + /* + * lock_user based on `thunk_type_size` then call `thunk_type_size_wit= h_src` + * on it. + */ + void *src; + int type_size =3D thunk_type_size(type_ptr, /*is_host=3D*/ 0); + if (!thunk_type_has_flexible_array(type_ptr)) { + return type_size; + } + + src =3D lock_user(VERIFY_READ, guest_addr, type_size, 0); + type_size =3D thunk_type_size_with_src(src, type_ptr, /*is_host=3D*/ 0= ); + unlock_user(src, guest_addr, 0); + + return type_size; +} + +abi_long dev_ethtool(int fd, uint8_t *buf_temp) +{ + uint32_t *cmd; + uint32_t host_cmd; + const EthtoolEntry *ee; + const argtype *arg_type; + abi_long ret; + int target_size; + void *argptr; + + /* + * Make a copy of `host_ifreq` because we are going to reuse `buf_temp= ` and + * overwrite it. Further, we will overwrite `host_ifreq.ifreq_data`, so + * keep a copy in `ifreq_data`. + */ + struct ifreq host_ifreq =3D *(struct ifreq *)(unsigned long)buf_temp; + const abi_long ifreq_data =3D (abi_long)(unsigned long)host_ifreq.ifr_= data; + + cmd =3D (uint32_t *)lock_user(VERIFY_READ, ifreq_data, sizeof(uint32_t= ), 0); + host_cmd =3D tswap32(*cmd); + unlock_user(cmd, ifreq_data, 0); + + ee =3D ethtool_entries; + for (;;) { + if (ee->cmd =3D=3D 0) { + qemu_log_mask(LOG_UNIMP, "Unsupported ethtool cmd=3D0x%04lx\n", + (long)host_cmd); + return -TARGET_ENOSYS; + } + if (ee->cmd =3D=3D host_cmd) { + break; + } + ee++; + } + if (ee->do_ethtool) { + return ee->do_ethtool(ee, buf_temp, fd, &host_ifreq); + } + + host_ifreq.ifr_data =3D buf_temp; + /* Even for ETHT_R, cmd still needs to be copied. */ + *(uint32_t *)buf_temp =3D host_cmd; + + arg_type =3D ee->arg_type; + switch (arg_type[0]) { + case TYPE_NULL: + /* no argument other than cmd */ + ret =3D get_errno(safe_dev_ethtool(fd, &host_ifreq)); + break; + case TYPE_PTR: + arg_type++; + target_size =3D thunk_size(ifreq_data, arg_type); + switch (ee->access) { + case ETHT_R: + ret =3D get_errno(safe_dev_ethtool(fd, &host_ifreq)); + if (!is_error(ret)) { + argptr =3D lock_user(VERIFY_WRITE, ifreq_data, target_size= , 0); + if (!argptr) { + return -TARGET_EFAULT; + } + thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET); + unlock_user(argptr, ifreq_data, target_size); + } + break; + case ETHT_W: + argptr =3D lock_user(VERIFY_READ, ifreq_data, target_size, 1); + if (!argptr) { + return -TARGET_EFAULT; + } + thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST); + unlock_user(argptr, ifreq_data, 0); + ret =3D get_errno(safe_dev_ethtool(fd, &host_ifreq)); + break; + default: + case ETHT_RW: + argptr =3D lock_user(VERIFY_READ, ifreq_data, target_size, 1); + if (!argptr) { + return -TARGET_EFAULT; + } + thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST); + unlock_user(argptr, ifreq_data, 0); + ret =3D get_errno(safe_dev_ethtool(fd, &host_ifreq)); + if (!is_error(ret)) { + argptr =3D lock_user(VERIFY_WRITE, ifreq_data, target_size= , 0); + if (!argptr) { + return -TARGET_EFAULT; + } + thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET); + unlock_user(argptr, ifreq_data, target_size); + } + break; + } + break; + default: + qemu_log_mask(LOG_UNIMP, + "Unsupported ethtool type: cmd=3D0x%04lx type=3D%d\n= ", + (long)host_cmd, arg_type[0]); + ret =3D -TARGET_ENOSYS; + break; + } + return ret; +} diff --git a/linux-user/ethtool.h b/linux-user/ethtool.h new file mode 100644 index 0000000000..6942aef095 --- /dev/null +++ b/linux-user/ethtool.h @@ -0,0 +1,20 @@ +#ifndef ETHTOOL_H +#define ETHTOOL_H + +#include +#include "qemu.h" + +extern const StructEntry struct_ethtool_rxnfc_get_set_rxfh_def; +extern const StructEntry struct_ethtool_sset_info_def; +extern const StructEntry struct_ethtool_rxfh_def; +extern const StructEntry struct_ethtool_link_settings_def; +extern const StructEntry struct_ethtool_per_queue_op_def; + +/* + * Takes the file descriptor and the buffer for temporarily storing data r= ead + * from / to be written to guest memory. `buf_temp` must now contain the h= ost + * representation of `struct ifreq`. + */ +abi_long dev_ethtool(int fd, uint8_t *buf_temp); + +#endif /* ETHTOOL_H */ diff --git a/linux-user/ethtool_entries.h b/linux-user/ethtool_entries.h new file mode 100644 index 0000000000..14f4e80a21 --- /dev/null +++ b/linux-user/ethtool_entries.h @@ -0,0 +1,107 @@ + ETHTOOL(ETHTOOL_GSET, ETHT_R, MK_PTR(MK_STRUCT(STRUCT_ethtool_cmd))) + ETHTOOL(ETHTOOL_SSET, ETHT_W, MK_PTR(MK_STRUCT(STRUCT_ethtool_cmd))) + ETHTOOL(ETHTOOL_GDRVINFO, ETHT_R, MK_PTR(MK_STRUCT(STRUCT_ethtool_drvinf= o))) + ETHTOOL(ETHTOOL_GREGS, ETHT_RW, MK_PTR(MK_STRUCT(STRUCT_ethtool_regs))) + ETHTOOL(ETHTOOL_GWOL, ETHT_R, MK_PTR(MK_STRUCT(STRUCT_ethtool_wolinfo))) + ETHTOOL(ETHTOOL_SWOL, ETHT_W, MK_PTR(MK_STRUCT(STRUCT_ethtool_wolinfo))) + ETHTOOL(ETHTOOL_GMSGLVL, ETHT_R, MK_PTR(MK_STRUCT(STRUCT_ethtool_value))) + ETHTOOL(ETHTOOL_SMSGLVL, ETHT_W, MK_PTR(MK_STRUCT(STRUCT_ethtool_value))) + ETHTOOL(ETHTOOL_GEEE, ETHT_R, MK_PTR(MK_STRUCT(STRUCT_ethtool_eee))) + ETHTOOL(ETHTOOL_SEEE, ETHT_W, MK_PTR(MK_STRUCT(STRUCT_ethtool_eee))) + ETHTOOL(ETHTOOL_NWAY_RST, 0, TYPE_NULL) + ETHTOOL(ETHTOOL_GLINK, ETHT_R, MK_PTR(MK_STRUCT(STRUCT_ethtool_value))) + ETHTOOL(ETHTOOL_GEEPROM, ETHT_RW, MK_PTR(MK_STRUCT(STRUCT_ethtool_eeprom= ))) + ETHTOOL(ETHTOOL_SEEPROM, ETHT_RW, MK_PTR(MK_STRUCT(STRUCT_ethtool_eeprom= ))) + ETHTOOL(ETHTOOL_GCOALESCE, ETHT_R, MK_PTR(MK_STRUCT(STRUCT_ethtool_coale= sce))) + ETHTOOL(ETHTOOL_SCOALESCE, ETHT_W, MK_PTR(MK_STRUCT(STRUCT_ethtool_coale= sce))) + ETHTOOL(ETHTOOL_GRINGPARAM, ETHT_R, + MK_PTR(MK_STRUCT(STRUCT_ethtool_ringparam))) + ETHTOOL(ETHTOOL_SRINGPARAM, ETHT_W, + MK_PTR(MK_STRUCT(STRUCT_ethtool_ringparam))) + ETHTOOL(ETHTOOL_GPAUSEPARAM, ETHT_R, + MK_PTR(MK_STRUCT(STRUCT_ethtool_pauseparam))) + ETHTOOL(ETHTOOL_SPAUSEPARAM, ETHT_W, + MK_PTR(MK_STRUCT(STRUCT_ethtool_pauseparam))) + ETHTOOL(ETHTOOL_TEST, ETHT_RW, MK_PTR(MK_STRUCT(STRUCT_ethtool_test))) + ETHTOOL(ETHTOOL_GSTRINGS, ETHT_RW, MK_PTR(MK_STRUCT(STRUCT_ethtool_gstri= ngs))) + ETHTOOL(ETHTOOL_PHYS_ID, ETHT_W, MK_PTR(MK_STRUCT(STRUCT_ethtool_value))) + ETHTOOL(ETHTOOL_GSTATS, ETHT_RW, MK_PTR(MK_STRUCT(STRUCT_ethtool_stats))) + ETHTOOL(ETHTOOL_GPERMADDR, ETHT_RW, + MK_PTR(MK_STRUCT(STRUCT_ethtool_perm_addr))) + ETHTOOL(ETHTOOL_GFLAGS, ETHT_R, MK_PTR(MK_STRUCT(STRUCT_ethtool_value))) + ETHTOOL(ETHTOOL_SFLAGS, ETHT_W, MK_PTR(MK_STRUCT(STRUCT_ethtool_value))) + ETHTOOL(ETHTOOL_GPFLAGS, ETHT_R, MK_PTR(MK_STRUCT(STRUCT_ethtool_value))) + ETHTOOL(ETHTOOL_SPFLAGS, ETHT_W, MK_PTR(MK_STRUCT(STRUCT_ethtool_value))) + ETHTOOL(ETHTOOL_GRXFH, ETHT_RW, + MK_PTR(MK_STRUCT(STRUCT_ethtool_rxnfc_get_set_rxfh))) + ETHTOOL(ETHTOOL_GRXRINGS, ETHT_RW, + MK_PTR(MK_STRUCT(STRUCT_ethtool_rxnfc_rss_context))) + ETHTOOL(ETHTOOL_GRXCLSRLCNT, ETHT_RW, + MK_PTR(MK_STRUCT(STRUCT_ethtool_rxnfc_rule_cnt))) + ETHTOOL(ETHTOOL_GRXCLSRULE, ETHT_RW, + MK_PTR(MK_STRUCT(STRUCT_ethtool_rxnfc_rss_context))) + ETHTOOL(ETHTOOL_GRXCLSRLALL, ETHT_RW, + MK_PTR(MK_STRUCT(STRUCT_ethtool_rxnfc_rule_locs))) + ETHTOOL(ETHTOOL_SRXFH, ETHT_W, + MK_PTR(MK_STRUCT(STRUCT_ethtool_rxnfc_get_set_rxfh))) + ETHTOOL(ETHTOOL_SRXCLSRLDEL, ETHT_W, + MK_PTR(MK_STRUCT(STRUCT_ethtool_rxnfc_rss_context))) + ETHTOOL(ETHTOOL_SRXCLSRLINS, ETHT_W, + MK_PTR(MK_STRUCT(STRUCT_ethtool_rxnfc_rss_context))) + ETHTOOL(ETHTOOL_FLASHDEV, ETHT_W, MK_PTR(MK_STRUCT(STRUCT_ethtool_flash)= )) + ETHTOOL(ETHTOOL_RESET, ETHT_RW, MK_PTR(MK_STRUCT(STRUCT_ethtool_value))) + ETHTOOL(ETHTOOL_GSSET_INFO, ETHT_RW, + MK_PTR(MK_STRUCT(STRUCT_ethtool_sset_info))) + ETHTOOL(ETHTOOL_GRXFHINDIR, ETHT_RW, + MK_PTR(MK_STRUCT(STRUCT_ethtool_rxfh_indir))) + ETHTOOL(ETHTOOL_SRXFHINDIR, ETHT_W, + MK_PTR(MK_STRUCT(STRUCT_ethtool_rxfh_indir))) + ETHTOOL_SPECIAL(ETHTOOL_GRSSH, ETHT_RW, do_ethtool_get_rxfh, + MK_PTR(MK_STRUCT(STRUCT_ethtool_rxfh))) + ETHTOOL(ETHTOOL_SRSSH, ETHT_RW, + MK_PTR(MK_STRUCT(STRUCT_ethtool_rxfh))) + ETHTOOL(ETHTOOL_GFEATURES, ETHT_RW, + MK_PTR(MK_STRUCT(STRUCT_ethtool_gfeatures))) + ETHTOOL(ETHTOOL_SFEATURES, ETHT_W, + MK_PTR(MK_STRUCT(STRUCT_ethtool_sfeatures))) + ETHTOOL(ETHTOOL_GTXCSUM, ETHT_R, MK_PTR(MK_STRUCT(STRUCT_ethtool_value))) + ETHTOOL(ETHTOOL_GRXCSUM, ETHT_R, MK_PTR(MK_STRUCT(STRUCT_ethtool_value))) + ETHTOOL(ETHTOOL_GSG, ETHT_R, MK_PTR(MK_STRUCT(STRUCT_ethtool_value))) + ETHTOOL(ETHTOOL_GTSO, ETHT_R, MK_PTR(MK_STRUCT(STRUCT_ethtool_value))) + ETHTOOL(ETHTOOL_GGSO, ETHT_R, MK_PTR(MK_STRUCT(STRUCT_ethtool_value))) + ETHTOOL(ETHTOOL_GGRO, ETHT_R, MK_PTR(MK_STRUCT(STRUCT_ethtool_value))) + ETHTOOL(ETHTOOL_STXCSUM, ETHT_W, MK_PTR(MK_STRUCT(STRUCT_ethtool_value))) + ETHTOOL(ETHTOOL_SRXCSUM, ETHT_W, MK_PTR(MK_STRUCT(STRUCT_ethtool_value))) + ETHTOOL(ETHTOOL_SSG, ETHT_W, MK_PTR(MK_STRUCT(STRUCT_ethtool_value))) + ETHTOOL(ETHTOOL_STSO, ETHT_W, MK_PTR(MK_STRUCT(STRUCT_ethtool_value))) + ETHTOOL(ETHTOOL_SGSO, ETHT_W, MK_PTR(MK_STRUCT(STRUCT_ethtool_value))) + ETHTOOL(ETHTOOL_SGRO, ETHT_W, MK_PTR(MK_STRUCT(STRUCT_ethtool_value))) + ETHTOOL(ETHTOOL_GCHANNELS, ETHT_R, MK_PTR(MK_STRUCT(STRUCT_ethtool_chann= els))) + ETHTOOL(ETHTOOL_SCHANNELS, ETHT_W, MK_PTR(MK_STRUCT(STRUCT_ethtool_chann= els))) + ETHTOOL(ETHTOOL_SET_DUMP, ETHT_W, + MK_PTR(MK_STRUCT(STRUCT_ethtool_dump_no_data))) + ETHTOOL(ETHTOOL_GET_DUMP_FLAG, ETHT_RW, + MK_PTR(MK_STRUCT(STRUCT_ethtool_dump_no_data))) + ETHTOOL(ETHTOOL_GET_DUMP_DATA, ETHT_RW, + MK_PTR(MK_STRUCT(STRUCT_ethtool_dump))) + ETHTOOL(ETHTOOL_GET_TS_INFO, ETHT_R, + MK_PTR(MK_STRUCT(STRUCT_ethtool_ts_info))) + ETHTOOL(ETHTOOL_GMODULEINFO, ETHT_RW, + MK_PTR(MK_STRUCT(STRUCT_ethtool_modinfo))) + ETHTOOL(ETHTOOL_GMODULEEEPROM, ETHT_RW, + MK_PTR(MK_STRUCT(STRUCT_ethtool_eeprom))) + ETHTOOL(ETHTOOL_GTUNABLE, ETHT_RW, MK_PTR(MK_STRUCT(STRUCT_ethtool_tunab= le))) + ETHTOOL(ETHTOOL_STUNABLE, ETHT_W, MK_PTR(MK_STRUCT(STRUCT_ethtool_tunabl= e))) + ETHTOOL(ETHTOOL_GPHYSTATS, ETHT_RW, MK_PTR(MK_STRUCT(STRUCT_ethtool_stat= s))) + ETHTOOL(ETHTOOL_PERQUEUE, ETHT_RW, + MK_PTR(MK_STRUCT(STRUCT_ethtool_per_queue_op))) + ETHTOOL(ETHTOOL_GLINKSETTINGS, ETHT_RW, + MK_PTR(MK_STRUCT(STRUCT_ethtool_link_settings))) + ETHTOOL(ETHTOOL_SLINKSETTINGS, ETHT_W, + MK_PTR(MK_STRUCT(STRUCT_ethtool_link_settings))) + ETHTOOL(ETHTOOL_PHY_GTUNABLE, ETHT_RW, + MK_PTR(MK_STRUCT(STRUCT_ethtool_tunable))) + ETHTOOL(ETHTOOL_PHY_STUNABLE, ETHT_W, + MK_PTR(MK_STRUCT(STRUCT_ethtool_tunable))) + ETHTOOL(ETHTOOL_GFECPARAM, ETHT_R, MK_PTR(MK_STRUCT(STRUCT_ethtool_fecpa= ram))) + ETHTOOL(ETHTOOL_GFECPARAM, ETHT_W, MK_PTR(MK_STRUCT(STRUCT_ethtool_fecpa= ram))) diff --git a/linux-user/ioctls.h b/linux-user/ioctls.h index 0713ae1311..fd6ac963ec 100644 --- a/linux-user/ioctls.h +++ b/linux-user/ioctls.h @@ -238,6 +238,8 @@ IOCTL(SIOCSIFHWADDR, IOC_W, MK_PTR(MK_STRUCT(STRUCT_sockaddr_ifreq))) IOCTL(SIOCGIFTXQLEN, IOC_W | IOC_R, MK_PTR(MK_STRUCT(STRUCT_sockaddr_ifr= eq))) IOCTL(SIOCSIFTXQLEN, IOC_W, MK_PTR(MK_STRUCT(STRUCT_sockaddr_ifreq))) + IOCTL_SPECIAL(SIOCETHTOOL, IOC_W | IOC_R, do_ioctl_ethtool, + MK_PTR(MK_STRUCT(STRUCT_ptr_ifreq))) IOCTL(SIOCGIFMETRIC, IOC_W | IOC_R, MK_PTR(MK_STRUCT(STRUCT_int_ifreq))) IOCTL(SIOCSIFMETRIC, IOC_W, MK_PTR(MK_STRUCT(STRUCT_int_ifreq))) IOCTL(SIOCGIFMTU, IOC_W | IOC_R, MK_PTR(MK_STRUCT(STRUCT_int_ifreq))) diff --git a/linux-user/qemu.h b/linux-user/qemu.h index 5c964389c1..43f00681f8 100644 --- a/linux-user/qemu.h +++ b/linux-user/qemu.h @@ -231,6 +231,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long ar= g1, abi_long arg2, abi_long arg3, abi_long arg4, abi_long arg5, abi_long arg6, abi_long arg7, abi_long arg8); +abi_long get_errno(abi_long ret); extern __thread CPUState *thread_cpu; void cpu_loop(CPUArchState *env); const char *target_strerror(int err); diff --git a/linux-user/syscall.c b/linux-user/syscall.c index bfc4219104..41fea53716 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -127,6 +127,7 @@ #include "qapi/error.h" #include "fd-trans.h" #include "tcg/tcg.h" +#include "ethtool.h" =20 #ifndef CLONE_IO #define CLONE_IO 0x80000000 /* Clone io context */ @@ -676,7 +677,7 @@ static inline int target_to_host_errno(int err) return err; } =20 -static inline abi_long get_errno(abi_long ret) +abi_long get_errno(abi_long ret) { if (ret =3D=3D -1) return -host_to_target_errno(errno); @@ -4732,16 +4733,6 @@ static abi_long do_ipc(CPUArchState *cpu_env, #endif =20 /* kernel structure types definitions */ - -#define STRUCT(name, ...) STRUCT_ ## name, -#define STRUCT_SPECIAL(name) STRUCT_ ## name, -enum { -#include "syscall_types.h" -STRUCT_MAX -}; -#undef STRUCT -#undef STRUCT_SPECIAL - #define STRUCT(name, ...) static const argtype struct_ ## name ## _def[] = =3D { __VA_ARGS__, TYPE_NULL }; #define STRUCT_SPECIAL(name) #include "syscall_types.h" @@ -4839,6 +4830,29 @@ static abi_long do_ioctl_fs_ioc_fiemap(const IOCTLEn= try *ie, uint8_t *buf_temp, } #endif =20 +static abi_long do_ioctl_ethtool(const IOCTLEntry *ie, uint8_t *buf_temp, + int fd, int cmd, abi_long arg) +{ + const argtype *arg_type =3D ie->arg_type; + int target_size; + void *argptr; + + assert(arg_type[0] =3D=3D TYPE_PTR); + assert(ie->access =3D=3D IOC_RW); + + arg_type++; + target_size =3D thunk_type_size(arg_type, 0); + + argptr =3D lock_user(VERIFY_READ, arg, target_size, 1); + if (!argptr) { + return -TARGET_EFAULT; + } + thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST); + unlock_user(argptr, arg, target_size); + + return dev_ethtool(fd, buf_temp); +} + static abi_long do_ioctl_ifconf(const IOCTLEntry *ie, uint8_t *buf_temp, int fd, int cmd, abi_long arg) { diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index 70df1a94fb..e25a8cbcc8 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -866,6 +866,8 @@ struct target_rtc_pll_info { #define TARGET_SIOCGIFTXQLEN 0x8942 /* Get the tx queue length = */ #define TARGET_SIOCSIFTXQLEN 0x8943 /* Set the tx queue length = */ =20 +#define TARGET_SIOCETHTOOL 0x8946 /* Ethtool interface = */ + /* ARP cache control calls. */ #define TARGET_OLD_SIOCDARP 0x8950 /* old delete ARP table ent= ry */ #define TARGET_OLD_SIOCGARP 0x8951 /* old get ARP table entry = */ @@ -2776,4 +2778,14 @@ struct target_statx { /* 0x100 */ }; =20 +/* kernel structure types definitions */ +#define STRUCT(name, ...) STRUCT_ ## name, +#define STRUCT_SPECIAL(name) STRUCT_ ## name, +enum { +#include "syscall_types.h" +STRUCT_MAX +}; +#undef STRUCT +#undef STRUCT_SPECIAL + #endif diff --git a/linux-user/syscall_types.h b/linux-user/syscall_types.h index 3f1f033464..559924c752 100644 --- a/linux-user/syscall_types.h +++ b/linux-user/syscall_types.h @@ -1,3 +1,4 @@ + STRUCT_SPECIAL(termios) =20 STRUCT(winsize, @@ -464,3 +465,282 @@ STRUCT(usbdevfs_disconnect_claim, TYPE_INT, /* flags */ MK_ARRAY(TYPE_CHAR, USBDEVFS_MAXDRIVERNAME + 1)) /* driver */ #endif /* CONFIG_USBFS */ + +/* ethtool ioctls */ +STRUCT(ethtool_cmd, + TYPE_INT, /* cmd */ + TYPE_INT, /* supported */ + TYPE_INT, /* advertising */ + TYPE_SHORT, /* speed */ + TYPE_CHAR, /* duplex */ + TYPE_CHAR, /* port */ + TYPE_CHAR, /* phy_address */ + TYPE_CHAR, /* transceiver */ + TYPE_CHAR, /* autoneg */ + TYPE_CHAR, /* mdio_support */ + TYPE_INT, /* maxtxpkt */ + TYPE_INT, /* maxrxpkt */ + TYPE_SHORT, /* speed_hi */ + TYPE_CHAR, /* eth_tp_mdix */ + TYPE_CHAR, /* eth_tp_mdix_ctrl */ + TYPE_INT, /* lp_advertising */ + MK_ARRAY(TYPE_INT, 2)) /* reserved */ + +STRUCT(ethtool_drvinfo, + TYPE_INT, /* cmd */ + MK_ARRAY(TYPE_CHAR, 32), /* driver */ + MK_ARRAY(TYPE_CHAR, 32), /* version */ + MK_ARRAY(TYPE_CHAR, 32), /* fw_version[ETHTOOL_FWVERS_LEN] */ + MK_ARRAY(TYPE_CHAR, 32), /* bus_info[ETHTOOL_BUSINFO_LEN] */ + MK_ARRAY(TYPE_CHAR, 32), /* erom_version[ETHTOOL_EROMVERS_LEN] */ + MK_ARRAY(TYPE_CHAR, 12), /* reserved2 */ + TYPE_INT, /* n_priv_flags */ + TYPE_INT, /* n_stats */ + TYPE_INT, /* testinfo_len */ + TYPE_INT, /* eedump_len */ + TYPE_INT) /* regdump_len */ + +STRUCT(ethtool_regs, + TYPE_INT, /* cmd */ + TYPE_INT, /* version */ + TYPE_INT, /* len */ + MK_FLEXIBLE_ARRAY(TYPE_CHAR, 2)) /* data[0]: len */ + +STRUCT(ethtool_wolinfo, + TYPE_INT, /* cmd */ + TYPE_INT, /* supported */ + TYPE_INT, /* wolopts */ + MK_ARRAY(TYPE_CHAR, 6)) /* sopass[SOPASS_MAX] */ + +STRUCT(ethtool_value, + TYPE_INT, /* cmd */ + TYPE_INT) /* data */ + +STRUCT(ethtool_eee, + TYPE_INT, /* cmd */ + TYPE_INT, /* supported */ + TYPE_INT, /* advertised */ + TYPE_INT, /* lp_advertised */ + TYPE_INT, /* eee_active */ + TYPE_INT, /* eee_enabled */ + TYPE_INT, /* tx_lpi_enabled */ + TYPE_INT, /* tx_lpi_timer */ + MK_ARRAY(TYPE_INT, 2)) /* reserved */ + +STRUCT(ethtool_eeprom, + TYPE_INT, /* cmd */ + TYPE_INT, /* magic */ + TYPE_INT, /* offset */ + TYPE_INT, /* len */ + MK_FLEXIBLE_ARRAY(TYPE_CHAR, 3)) /* data[0]: len */ + +STRUCT(ethtool_coalesce, + TYPE_INT, /* cmd */ + TYPE_INT, /* rx_coalesce_usecs */ + TYPE_INT, /* rx_max_coalesced_frames */ + TYPE_INT, /* rx_coalesce_usecs_irq */ + TYPE_INT, /* rx_max_coalesced_frames_irq */ + TYPE_INT, /* tx_coalesce_usecs */ + TYPE_INT, /* tx_max_coalesced_frames */ + TYPE_INT, /* tx_coalesce_usecs_irq */ + TYPE_INT, /* tx_max_coalesced_frames_irq */ + TYPE_INT, /* stats_block_coalesce_usecs */ + TYPE_INT, /* use_adaptive_rx_coalesce */ + TYPE_INT, /* use_adaptive_tx_coalesce */ + TYPE_INT, /* pkt_rate_low */ + TYPE_INT, /* rx_coalesce_usecs_low */ + TYPE_INT, /* rx_max_coalesced_frames_low */ + TYPE_INT, /* tx_coalesce_usecs_low */ + TYPE_INT, /* tx_max_coalesced_frames_low */ + TYPE_INT, /* pkt_rate_high */ + TYPE_INT, /* rx_coalesce_usecs_high */ + TYPE_INT, /* rx_max_coalesced_frames_high */ + TYPE_INT, /* tx_coalesce_usecs_high */ + TYPE_INT, /* tx_max_coalesced_frames_high */ + TYPE_INT) /* rate_sample_interval */ + +STRUCT(ethtool_ringparam, + TYPE_INT, /* cmd */ + TYPE_INT, /* rx_max_pending */ + TYPE_INT, /* rx_mini_max_pending */ + TYPE_INT, /* rx_jumbo_max_pending */ + TYPE_INT, /* tx_max_pending */ + TYPE_INT, /* rx_pending */ + TYPE_INT, /* rx_mini_pending */ + TYPE_INT, /* rx_jumbo_pending */ + TYPE_INT) /* tx_pending */ + +STRUCT(ethtool_pauseparam, + TYPE_INT, /* cmd */ + TYPE_INT, /* autoneg */ + TYPE_INT, /* rx_pause */ + TYPE_INT) /* tx_pause */ + +STRUCT(ethtool_test, + TYPE_INT, /* cmd */ + TYPE_INT, /* flags */ + TYPE_INT, /* reserved */ + TYPE_INT, /* len */ + MK_FLEXIBLE_ARRAY(TYPE_LONGLONG, 3)) /* data[0]: len */ + +STRUCT(ethtool_gstrings, + TYPE_INT, /* cmd */ + TYPE_INT, /* string_set */ + TYPE_INT, /* len */ + MK_FLEXIBLE_ARRAY(MK_ARRAY(TYPE_CHAR, 32), 2)) + /* data[0]: len * ETH_GSTRING_LEN */ + +STRUCT(ethtool_stats, + TYPE_INT, /* cmd */ + TYPE_INT, /* n_stats */ + MK_FLEXIBLE_ARRAY(TYPE_LONGLONG, 1)) /* data[0]: n_stats */ + +STRUCT(ethtool_perm_addr, + TYPE_INT, /* cmd */ + TYPE_INT, /* size */ + MK_FLEXIBLE_ARRAY(TYPE_CHAR, 1)) /* data[0]: size */ + +STRUCT(ethtool_flow_ext, + MK_ARRAY(TYPE_CHAR, 2), /* padding */ + MK_ARRAY(TYPE_CHAR, 6), /* h_dest[ETH_ALEN] */ + MK_ARRAY(TYPE_CHAR, 2), /* __be16 vlan_etype */ + MK_ARRAY(TYPE_CHAR, 2), /* __be16 vlan_tci */ + MK_ARRAY(TYPE_CHAR, 8)) /* __be32 data[2] */ + +/* + * Union ethtool_flow_union contains alternatives that are either struct t= hat + * only uses __be* types or char/__u8, or "__u8 hdata[52]". We can treat i= t as + * byte array in all cases. + */ +STRUCT(ethtool_rx_flow_spec, + TYPE_INT, /* flow_type */ + MK_ARRAY(TYPE_CHAR, 52), /* union ethtool_flow_union h_u= */ + MK_STRUCT(STRUCT_ethtool_flow_ext), /* h_ext */ + MK_ARRAY(TYPE_CHAR, 52), /* union ethtool_flow_union m_u= */ + MK_STRUCT(STRUCT_ethtool_flow_ext), /* m_ext */ + TYPE_LONGLONG, /* ring_cookie */ + TYPE_INT) /* location */ + +STRUCT(ethtool_rxnfc_rss_context, + TYPE_INT, /* cmd */ + TYPE_INT, /* flow_type */ + TYPE_LONGLONG, /* data */ + MK_STRUCT(STRUCT_ethtool_rx_flow_spec), /* fs */ + TYPE_INT) /* rss_context */ + +STRUCT(ethtool_rxnfc_rule_cnt, + TYPE_INT, /* cmd */ + TYPE_INT, /* flow_type */ + TYPE_LONGLONG, /* data */ + MK_STRUCT(STRUCT_ethtool_rx_flow_spec), /* fs */ + TYPE_INT) /* rss_cnt */ + +STRUCT(ethtool_rxnfc_rule_locs, + TYPE_INT, /* cmd */ + TYPE_INT, /* flow_type */ + TYPE_LONGLONG, /* data */ + MK_STRUCT(STRUCT_ethtool_rx_flow_spec), /* fs */ + TYPE_INT, /* rss_cnt */ + MK_FLEXIBLE_ARRAY(TYPE_INT, 4)) /* rule_locs[0]: rss_cnt */ + +/* + * For ETHTOOL_{G,S}RXFH, originally only the first three fields are defin= ed, + * but with certain options, more fields are used. + */ +STRUCT_SPECIAL(ethtool_rxnfc_get_set_rxfh) + +STRUCT(ethtool_flash, + TYPE_INT, /* cmd */ + TYPE_INT, /* region */ + MK_ARRAY(TYPE_CHAR, 128)) /* data[ETHTOOL_FLASH_MAX_FILENAME] */ + +STRUCT_SPECIAL(ethtool_sset_info) + +STRUCT(ethtool_rxfh_indir, + TYPE_INT, /* cmd */ + TYPE_INT, /* size */ + MK_FLEXIBLE_ARRAY(TYPE_INT, 1)) /* ring_index[0]: size */ + +STRUCT_SPECIAL(ethtool_rxfh) + +STRUCT(ethtool_get_features_block, + TYPE_INT, /* available */ + TYPE_INT, /* requested */ + TYPE_INT, /* active */ + TYPE_INT) /* never_changed */ + +STRUCT(ethtool_gfeatures, + TYPE_INT, /* cmd */ + TYPE_INT, /* size */ + MK_FLEXIBLE_ARRAY(MK_STRUCT(STRUCT_ethtool_get_features_block), 1)) + /* features[0]: size */ + +STRUCT(ethtool_set_features_block, + TYPE_INT, /* valid */ + TYPE_INT) /* requested */ + +STRUCT(ethtool_sfeatures, + TYPE_INT, /* cmd */ + TYPE_INT, /* size */ + MK_FLEXIBLE_ARRAY(MK_STRUCT(STRUCT_ethtool_set_features_block), 1)) + /* features[0]: size */ + +STRUCT(ethtool_channels, + TYPE_INT, /* cmd */ + TYPE_INT, /* max_rx */ + TYPE_INT, /* max_tx */ + TYPE_INT, /* max_other */ + TYPE_INT, /* max_combined */ + TYPE_INT, /* rx_count */ + TYPE_INT, /* tx_count */ + TYPE_INT, /* other_count */ + TYPE_INT) /* combined_count */ + +/* + * For ETHTOOL_SET_DUMP and ETHTOOL_GET_DUMP_FLAG, the flexible array `dat= a` is + * not used. + */ +STRUCT(ethtool_dump_no_data, + TYPE_INT, /* cmd */ + TYPE_INT, /* version */ + TYPE_INT, /* flag */ + TYPE_INT) /* len */ + +STRUCT(ethtool_dump, + TYPE_INT, /* cmd */ + TYPE_INT, /* version */ + TYPE_INT, /* flag */ + TYPE_INT, /* len */ + MK_FLEXIBLE_ARRAY(TYPE_CHAR, 3)) /* data[0]: len */ + +STRUCT(ethtool_ts_info, + TYPE_INT, /* cmd */ + TYPE_INT, /* so_timestamping */ + TYPE_INT, /* phc_index */ + TYPE_INT, /* tx_types */ + MK_ARRAY(TYPE_INT, 3), /* tx_reserved */ + TYPE_INT, /* rx_filters */ + MK_ARRAY(TYPE_INT, 3)) /* rx_reserved */ + +STRUCT(ethtool_modinfo, + TYPE_INT, /* cmd */ + TYPE_INT, /* type */ + TYPE_INT, /* eeprom_len */ + MK_ARRAY(TYPE_INT, 8)) /* reserved */ + +STRUCT(ethtool_tunable, + TYPE_INT, /* cmd */ + TYPE_INT, /* id */ + TYPE_INT, /* type_id */ + TYPE_INT, /* len */ + MK_FLEXIBLE_ARRAY(TYPE_PTRVOID, 3)) /* data[0]: len */ + +STRUCT_SPECIAL(ethtool_link_settings) + +STRUCT(ethtool_fecparam, + TYPE_INT, /* cmd */ + TYPE_INT, /* active_fec */ + TYPE_INT, /* fec */ + TYPE_INT) /* reserved */ + +STRUCT_SPECIAL(ethtool_per_queue_op) diff --git a/tests/tcg/multiarch/ethtool.c b/tests/tcg/multiarch/ethtool.c new file mode 100644 index 0000000000..dcb10230e0 --- /dev/null +++ b/tests/tcg/multiarch/ethtool.c @@ -0,0 +1,423 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +const int number_of_entries_to_print =3D 10; +const uint32_t protected_memory_pattern[] =3D { + 0xdeadc0de, 0xb0bb1e, 0xfacade, 0xfeeb1e }; + +static void fail_with(const char *action, const char *cmd_name, int cmd, + int err) +{ + if (errno =3D=3D EOPNOTSUPP) { + printf("Unsupported operation: %s; errno =3D %d: %s.\n" + "TEST SKIPPED (%s =3D 0x%x).\n", + action, err, strerror(err), cmd_name, cmd); + return; + } + if (err) { + fprintf(stderr, + "Failed to %s (%s =3D 0x%x): errno =3D %d: %s\n", + action, cmd_name, cmd, err, strerror(err)); + } else { + fprintf(stderr, + "Failed to %s (%s =3D 0x%x): no errno\n", + action, cmd_name, cmd); + } + exit(err); +} +#define FAIL(action, cmd) fail_with(action, #cmd, cmd, errno) + +/* + * `calloc_protected` and `protected_memory_changed` can be used to verify= that + * a system call does not write pass intended memory boundary. + * + * `ptr =3D calloc_protected(n)` will allocate extra memory after `n` byte= s and + * populate it with a memory pattern. The first `n` bytes are still guaran= teed + * to be zeroed out like `calloc(1, n)`. `protected_memory_changed(ptr, n)` + * takes the pointer and the original size `n` and checks that the memory + * pattern is intact. + */ +uint8_t *calloc_protected(size_t struct_size) +{ + uint8_t *buf =3D (uint8_t *) calloc( + 1, + struct_size + sizeof(protected_memory_pattern)); + memcpy(buf + struct_size, protected_memory_pattern, + sizeof(protected_memory_pattern)); + return buf; +} + +bool protected_memory_changed(const uint8_t *ptr, size_t struct_size) +{ + return memcmp(ptr + struct_size, protected_memory_pattern, + sizeof(protected_memory_pattern)) !=3D 0; +} + +void print_entries(const char *fmt, int len, uint32_t *entries) +{ + int i; + for (i =3D 0; i < len && i < number_of_entries_to_print; ++i) { + printf(fmt, entries[i]); + } + if (len > number_of_entries_to_print) { + printf(" (%d more omitted)", len - number_of_entries_to_print); + } +} + +void basic_test(int socketfd, struct ifreq ifr) +{ + struct ethtool_drvinfo drvinfo; + drvinfo.cmd =3D ETHTOOL_GDRVINFO; + ifr.ifr_data =3D (void *)&drvinfo; + if (ioctl(socketfd, SIOCETHTOOL, &ifr) =3D=3D -1) { + FAIL("get driver info", ETHTOOL_GDRVINFO); + return; + } + printf("Driver: %s (version %s)\n", drvinfo.driver, drvinfo.version); +} + +/* Test flexible array. */ +void test_get_stats(int socketfd, struct ifreq ifr, int n_stats) +{ + int i; + struct ethtool_stats *stats =3D (struct ethtool_stats *)calloc( + 1, sizeof(*stats) + sizeof(stats->data[0]) * n_stats); + stats->cmd =3D ETHTOOL_GSTATS; + stats->n_stats =3D n_stats; + ifr.ifr_data =3D (void *)stats; + if (ioctl(socketfd, SIOCETHTOOL, &ifr) =3D=3D -1) { + FAIL("get statastics", ETHTOOL_GSTATS); + free(stats); + return; + } + if (stats->n_stats !=3D n_stats) { + FAIL("get consistent number of statistics", ETHTOOL_GSTATS); + } + for (i =3D 0; i < stats->n_stats && i < number_of_entries_to_print; ++= i) { + printf("stats[%d] =3D %llu\n", i, (unsigned long long)stats->data[= i]); + } + if (stats->n_stats > number_of_entries_to_print) { + printf("(%d more omitted)\n", + stats->n_stats - number_of_entries_to_print); + } + free(stats); +} + +/* Test flexible array with char array as elements. */ +void test_get_strings(int socketfd, struct ifreq ifr, int n_stats) +{ + int i; + struct ethtool_gstrings *gstrings =3D + (struct ethtool_gstrings *)calloc( + 1, sizeof(*gstrings) + ETH_GSTRING_LEN * n_stats); + gstrings->cmd =3D ETHTOOL_GSTRINGS; + gstrings->string_set =3D ETH_SS_STATS; + gstrings->len =3D n_stats; + ifr.ifr_data =3D (void *)gstrings; + if (ioctl(socketfd, SIOCETHTOOL, &ifr) =3D=3D -1) { + FAIL("get string set", ETHTOOL_GSTRINGS); + free(gstrings); + return; + } + if (gstrings->len !=3D n_stats) { + FAIL("get consistent number of statistics", ETHTOOL_GSTRINGS); + } + for (i =3D 0; i < gstrings->len && i < number_of_entries_to_print; ++i= ) { + printf("stat_names[%d] =3D %.*s\n", + i, ETH_GSTRING_LEN, gstrings->data + i * ETH_GSTRING_LEN); + } + if (gstrings->len > number_of_entries_to_print) { + printf("(%d more omitted)\n", + gstrings->len - number_of_entries_to_print); + } + free(gstrings); +} + +/* + * Testing manual implementation of converting `struct ethtool_sset_info`,= also + * info for subsequent tests. + */ +int test_get_sset_info(int socketfd, struct ifreq ifr) +{ + const int n_sset =3D 2; + int n_stats; + struct ethtool_sset_info *sset_info =3D + (struct ethtool_sset_info *)calloc( + 1, sizeof(*sset_info) + sizeof(sset_info->data[0]) * n_sset); + sset_info->cmd =3D ETHTOOL_GSSET_INFO; + sset_info->sset_mask =3D 1 << ETH_SS_TEST | 1 << ETH_SS_STATS; + assert(__builtin_popcount(sset_info->sset_mask) =3D=3D n_sset); + ifr.ifr_data =3D (void *)sset_info; + if (ioctl(socketfd, SIOCETHTOOL, &ifr) =3D=3D -1) { + fail_with("get string set info", "ETHTOOL_GSSET_INFO", + ETHTOOL_GSSET_INFO, errno); + free(sset_info); + return 0; + } + if ((sset_info->sset_mask & (1 << ETH_SS_STATS)) =3D=3D 0) { + puts("No stats string set info, SKIPPING dependent tests"); + free(sset_info); + return 0; + } + n_stats =3D (sset_info->sset_mask & (1 << ETH_SS_TEST)) ? + sset_info->data[1] : + sset_info->data[0]; + printf("n_stats =3D %d\n", n_stats); + free(sset_info); + return n_stats; +} + +/* + * Test manual implementation of converting `struct ethtool_rxnfc`, focusi= ng on + * the case where only the first three fields are present. (The original s= truct + * definition.) + */ +void test_get_rxfh(int socketfd, struct ifreq ifr) +{ + struct ethtool_rxnfc *rxnfc; + const int rxnfc_first_three_field_size =3D + sizeof(rxnfc->cmd) + sizeof(rxnfc->flow_type) + sizeof(rxnfc->data= ); + rxnfc =3D (struct ethtool_rxnfc *)calloc_protected( + rxnfc_first_three_field_size); + rxnfc->cmd =3D ETHTOOL_GRXFH; + rxnfc->flow_type =3D TCP_V4_FLOW; + ifr.ifr_data =3D (void *)rxnfc; + if (ioctl(socketfd, SIOCETHTOOL, &ifr) =3D=3D -1) { + FAIL("get RX flow classification rules", ETHTOOL_GRXFH); + free(rxnfc); + return; + } + if (protected_memory_changed((const uint8_t *)rxnfc, + rxnfc_first_three_field_size)) { + FAIL("preserve memory after the first three fields", ETHTOOL_GRXFH= ); + } + printf("Flow hash bitmask (flow_type =3D TCP v4): 0x%llx\n", + (unsigned long long)rxnfc->data); + free(rxnfc); +} + +/* Test manual implementation of converting `struct ethtool_link_settings`= . */ +void test_get_link_settings(int socketfd, struct ifreq ifr) +{ + int link_mode_masks_nwords; + struct ethtool_link_settings *link_settings_header =3D + (struct ethtool_link_settings *) calloc_protected( + sizeof(*link_settings_header)); + link_settings_header->cmd =3D ETHTOOL_GLINKSETTINGS; + link_settings_header->link_mode_masks_nwords =3D 0; + ifr.ifr_data =3D (void *)link_settings_header; + if (ioctl(socketfd, SIOCETHTOOL, &ifr) =3D=3D -1) { + FAIL("get link settings mask sizes", ETHTOOL_GLINKSETTINGS); + free(link_settings_header); + return; + } + if (protected_memory_changed((const uint8_t *)link_settings_header, + sizeof(*link_settings_header))) { + FAIL("preserve link_mode_masks", ETHTOOL_GLINKSETTINGS); + } + if (link_settings_header->link_mode_masks_nwords >=3D 0) { + FAIL("complete handshake", ETHTOOL_GLINKSETTINGS); + } + link_mode_masks_nwords =3D -link_settings_header->link_mode_masks_nwor= ds; + + struct ethtool_link_settings *link_settings =3D + (struct ethtool_link_settings *)calloc( + 1, + sizeof(*link_settings) + + sizeof(link_settings_header->link_mode_masks[0]) * + link_mode_masks_nwords * 3); + link_settings->cmd =3D ETHTOOL_GLINKSETTINGS; + link_settings->link_mode_masks_nwords =3D link_mode_masks_nwords; + ifr.ifr_data =3D (void *)link_settings; + if (ioctl(socketfd, SIOCETHTOOL, &ifr) =3D=3D -1) { + FAIL("get link settings", ETHTOOL_GLINKSETTINGS); + free(link_settings_header); + free(link_settings); + return; + } + if (link_settings->link_mode_masks_nwords !=3D link_mode_masks_nwords)= { + FAIL("have consistent number of mode masks", ETHTOOL_GLINKSETTINGS= ); + } + + printf("Link speed: %d MB\n", link_settings->speed); + printf("Number of link mode masks: %d\n", + link_settings->link_mode_masks_nwords); + if (link_settings->link_mode_masks_nwords > 0) { + printf("Supported bitmap:"); + print_entries(" 0x%08x", + link_settings->link_mode_masks_nwords, + link_settings->link_mode_masks); + putchar('\n'); + + printf("Advertising bitmap:"); + print_entries(" 0x%08x", + link_settings->link_mode_masks_nwords, + link_settings->link_mode_masks + + link_settings->link_mode_masks_nwords); + putchar('\n'); + + printf("Lp advertising bitmap:"); + print_entries(" 0x%08x", + link_settings->link_mode_masks_nwords, + link_settings->link_mode_masks + + 2 * link_settings->link_mode_masks_nwords); + putchar('\n'); + } + + free(link_settings_header); + free(link_settings); +} + +/* Test manual implementation of converting `struct ethtool_per_queue_op`.= */ +void test_perqueue(int socketfd, struct ifreq ifr) +{ + const int n_queue =3D 2; + int i; + struct ethtool_per_queue_op *per_queue_op =3D + (struct ethtool_per_queue_op *)calloc( + 1, + sizeof(*per_queue_op) + sizeof(struct ethtool_coalesce) * n_qu= eue); + per_queue_op->cmd =3D ETHTOOL_PERQUEUE; + per_queue_op->sub_command =3D ETHTOOL_GCOALESCE; + per_queue_op->queue_mask[0] =3D 0x3; + ifr.ifr_data =3D (void *)per_queue_op; + if (ioctl(socketfd, SIOCETHTOOL, &ifr) =3D=3D -1) { + FAIL("get coalesce per queue", ETHTOOL_PERQUEUE); + free(per_queue_op); + return; + } + for (i =3D 0; i < n_queue; ++i) { + struct ethtool_coalesce *coalesce =3D (struct ethtool_coalesce *)( + per_queue_op->data + sizeof(*coalesce) * i); + if (coalesce->cmd !=3D ETHTOOL_GCOALESCE) { + fprintf(stderr, + "ETHTOOL_PERQUEUE (%d) sub_command ETHTOOL_GCOALESCE (= %d) " + "fails to set entry %d's cmd to ETHTOOL_GCOALESCE, got= %d " + "instead\n", + ETHTOOL_PERQUEUE, ETHTOOL_GCOALESCE, i, + coalesce->cmd); + exit(-1); + } + printf("rx_coalesce_usecs[%d] =3D %u\nrx_max_coalesced_frames[%d] = =3D %u\n", + i, coalesce->rx_coalesce_usecs, + i, coalesce->rx_max_coalesced_frames); + } + + free(per_queue_op); +} + +/* Test manual implementation of ETHTOOL_GRSSH. */ +void test_get_rssh(int socketfd, struct ifreq ifr) +{ + int i; + struct ethtool_rxfh *rxfh_header =3D + (struct ethtool_rxfh *)calloc_protected(sizeof(*rxfh_header)); + rxfh_header->cmd =3D ETHTOOL_GRSSH; + ifr.ifr_data =3D (void *)rxfh_header; + if (ioctl(socketfd, SIOCETHTOOL, &ifr) =3D=3D -1) { + FAIL("get RX flow hash indir and hash key size", ETHTOOL_GRSSH); + free(rxfh_header); + return; + } + if (protected_memory_changed((const uint8_t *)rxfh_header, + sizeof(*rxfh_header))) { + FAIL("preserve rss_config", ETHTOOL_GRSSH); + } + printf("RX flow hash indir size =3D %d\nRX flow hash key size =3D %d\n= ", + rxfh_header->indir_size, rxfh_header->key_size); + + struct ethtool_rxfh *rxfh =3D (struct ethtool_rxfh *)calloc( + 1, + sizeof(*rxfh) + 4 * rxfh_header->indir_size + rxfh_header->key_siz= e); + *rxfh =3D *rxfh_header; + ifr.ifr_data =3D (void *)rxfh; + if (ioctl(socketfd, SIOCETHTOOL, &ifr) =3D=3D -1) { + FAIL("get RX flow hash indir and hash key", ETHTOOL_GRSSH); + free(rxfh_header); + free(rxfh); + return; + } + + if (rxfh->indir_size =3D=3D 0) { + printf("No RX flow hash indir\n"); + } else { + printf("RX flow hash indir:"); + print_entries(" 0x%08x", rxfh->indir_size, rxfh->rss_config); + putchar('\n'); + } + + if (rxfh->key_size =3D=3D 0) { + printf("No RX flow hash key\n"); + } else { + char *key =3D (char *)(rxfh->rss_config + rxfh->indir_size); + printf("RX flow hash key:"); + for (i =3D 0; i < rxfh->key_size; ++i) { + if (i % 2 =3D=3D 0) { + putchar(' '); + } + printf("%02hhx", key[i]); + } + putchar('\n'); + } + free(rxfh_header); + free(rxfh); +} + +int main(int argc, char **argv) +{ + int socketfd, n_stats, i; + struct ifreq ifr; + + socketfd =3D socket(AF_INET, SOCK_DGRAM, 0); + if (socketfd =3D=3D -1) { + int err =3D errno; + fprintf(stderr, + "Failed to open socket: errno =3D %d: %s\n", + err, strerror(err)); + return err; + } + + for (i =3D 1;; ++i) { + ifr.ifr_ifindex =3D i; + if (ioctl(socketfd, SIOCGIFNAME, &ifr) =3D=3D -1) { + puts("Could not find a non-loopback interface, SKIPPING"); + return 0; + } + if (strncmp(ifr.ifr_name, "lo", IFNAMSIZ) !=3D 0) { + break; + } + } + printf("Interface index: %d\nInterface name: %.*s\n", + ifr.ifr_ifindex, IFNAMSIZ, ifr.ifr_name); + + basic_test(socketfd, ifr); + + n_stats =3D test_get_sset_info(socketfd, ifr); + if (n_stats > 0) { + /* Testing lexible arrays. */ + test_get_stats(socketfd, ifr, n_stats); + test_get_strings(socketfd, ifr, n_stats); + } + + /* Testing manual implementations of structure convertions. */ + test_get_rxfh(socketfd, ifr); + test_get_link_settings(socketfd, ifr); + test_perqueue(socketfd, ifr); + + /* Testing manual implementations of operations. */ + test_get_rssh(socketfd, ifr); + + return 0; +} --=20 2.28.0.220.ged08abb693-goog