Received: by 2002:a25:e7d8:0:0:0:0:0 with SMTP id e207csp970313ybh; Wed, 11 Mar 2020 14:41:46 -0700 (PDT) X-Google-Smtp-Source: ADFU+vvNHtmSP4PgkNVmHnGVzdWNVKGFkzjKbbaAMsfOy8U2DKTVOK0AAVAfOp/wF2NaAC4CpD5u X-Received: by 2002:a05:6808:298:: with SMTP id z24mr461404oic.101.1583962906565; Wed, 11 Mar 2020 14:41:46 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1583962906; cv=none; d=google.com; s=arc-20160816; b=dTfk50TuFdmxKynvdycutfGVpsQ20qEehl7R5Z+gR+ZHohxg/BmTudJcNrn7HL3Hb3 vwRr1V9oB9po0dnUJLN1Sd9H+yDRqWiirrdc3+lVHnULQ9U8k4vuCE1juxEtNgNdFgEB Ax+vzNvLc3tlYJi7XsT5zRYsrG01wun06IeJ/2U+8KkP9rmC2fmqf6Coz/CszI+HdFLB 90Xqs58Ct67lNUH2uXRpbmn3znYELTp/5avJIUJ1yb9eNFDEbB0rNbhRrNqMVLOMzVCC KFqcuzqPs2p5PiS73kaA+DToTFmi55jis5Ldv5e8Vdjxw3Pkj6HDWyb1McfpO/2Ft+5O EkYQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:date:cc:to:subject:from:references :in-reply-to:message-id; bh=SFTP1hG9e7G9TEZF6YVpTeSrQDoi65s1ffx+hKXhACk=; b=gk0ah3n6zPg663RwbZVUOD2InhRjeaU1skaIcpeD07+xgFRWAiSzqiV7KR3CW1+Vnv kEJDMQ9+5G7pTYFZIH/I2wgikN6VBsY72rRDOZ3ahtmrC17/NfoDP9IMt7nONB/2E93Y r1MEIrQTB0vdpaXBb5QiCNHTHC21pJBxeXRzQZA4a9b9YupMri7frAq2+b0shAapTeOQ KZ1+irSAHx6j8fUiTX5LYyqsgKb8mSbYJY9mQVLsxo5lmgQilJKgkstIWK5un/J7Q9ir sbBVI/M+LSl+AXXoQ5HqKAZ+6I1dz6yOSm4qv3ms5jbUqh59Il51z+MhmCCRe/g5qwwj sTSA== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id 38si1126566otm.189.2020.03.11.14.41.34; Wed, 11 Mar 2020 14:41:46 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S2387504AbgCKVk1 (ORCPT + 99 others); Wed, 11 Mar 2020 17:40:27 -0400 Received: from mx2.suse.de ([195.135.220.15]:46396 "EHLO mx2.suse.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1729418AbgCKVk0 (ORCPT ); Wed, 11 Mar 2020 17:40:26 -0400 X-Virus-Scanned: by amavisd-new at test-mx.suse.de Received: from relay2.suse.de (unknown [195.135.220.254]) by mx2.suse.de (Postfix) with ESMTP id E1035AD46; Wed, 11 Mar 2020 21:40:23 +0000 (UTC) Received: by unicorn.suse.cz (Postfix, from userid 1000) id 4AB57E0C0A; Wed, 11 Mar 2020 22:40:23 +0100 (CET) Message-Id: <70fe704ddd961de7250e2cb7800369509ed6e1d8.1583962006.git.mkubecek@suse.cz> In-Reply-To: References: From: Michal Kubecek Subject: [PATCH net-next 04/15] ethtool: add ethnl_parse_bitset() helper To: David Miller , netdev@vger.kernel.org Cc: Jakub Kicinski , Jiri Pirko , Andrew Lunn , Florian Fainelli , John Linville , Johannes Berg , linux-kernel@vger.kernel.org Date: Wed, 11 Mar 2020 22:40:23 +0100 (CET) Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Unlike other SET type commands, modifying netdev features is required to provide a reply telling userspace what was actually changed, compared to what was requested. For that purpose, the "modified" flag provided by ethnl_update_bitset() is not sufficient, we need full information which bits were requested to change. Therefore provide ethnl_parse_bitset() returning effective value and mask bitmaps equivalent to the contents of a bitset nested attribute. Signed-off-by: Michal Kubecek --- net/ethtool/bitset.c | 94 ++++++++++++++++++++++++++++++++++++++++++++ net/ethtool/bitset.h | 4 ++ 2 files changed, 98 insertions(+) diff --git a/net/ethtool/bitset.c b/net/ethtool/bitset.c index ef9197541cb3..db2935206f3d 100644 --- a/net/ethtool/bitset.c +++ b/net/ethtool/bitset.c @@ -588,6 +588,100 @@ int ethnl_update_bitset32(u32 *bitmap, unsigned int nbits, return 0; } +/** + * ethnl_parse_bitset() - Compute effective value and mask from bitset nest + * @val: unsigned long based bitmap to put value into + * @mask: unsigned long based bitmap to put mask into + * @nbits: size of @val and @mask bitmaps + * @attr: nest attribute to parse and apply + * @names: array of bit names; may be null for compact format + * @extack: extack for error reporting + * + * Provide @nbits size long bitmaps for value and mask so that + * x = (val & mask) | (x & ~mask) would modify any @nbits sized bitmap x + * the same way ethnl_update_bitset() with the same bitset attribute would. + * + * Return: negative error code on failure, 0 on success + */ +int ethnl_parse_bitset(unsigned long *val, unsigned long *mask, + unsigned int nbits, const struct nlattr *attr, + ethnl_string_array_t names, + struct netlink_ext_ack *extack) +{ + struct nlattr *tb[ETHTOOL_A_BITSET_MAX + 1]; + const struct nlattr *bit_attr; + bool no_mask; + int rem; + int ret; + + if (!attr) + return 0; + ret = nla_parse_nested(tb, ETHTOOL_A_BITSET_MAX, attr, bitset_policy, + extack); + if (ret < 0) + return ret; + no_mask = tb[ETHTOOL_A_BITSET_NOMASK]; + + if (!tb[ETHTOOL_A_BITSET_BITS]) { + unsigned int change_bits; + + ret = ethnl_compact_sanity_checks(nbits, attr, tb, extack); + if (ret < 0) + return ret; + + change_bits = nla_get_u32(tb[ETHTOOL_A_BITSET_SIZE]); + bitmap_from_arr32(val, nla_data(tb[ETHTOOL_A_BITSET_VALUE]), + change_bits); + if (change_bits < nbits) + bitmap_clear(val, change_bits, nbits - change_bits); + if (no_mask) { + bitmap_fill(mask, nbits); + } else { + bitmap_from_arr32(mask, + nla_data(tb[ETHTOOL_A_BITSET_MASK]), + change_bits); + if (change_bits < nbits) + bitmap_clear(mask, change_bits, + nbits - change_bits); + } + + return 0; + } + + if (tb[ETHTOOL_A_BITSET_VALUE]) { + NL_SET_ERR_MSG_ATTR(extack, tb[ETHTOOL_A_BITSET_VALUE], + "value only allowed in compact bitset"); + return -EINVAL; + } + if (tb[ETHTOOL_A_BITSET_MASK]) { + NL_SET_ERR_MSG_ATTR(extack, tb[ETHTOOL_A_BITSET_MASK], + "mask only allowed in compact bitset"); + return -EINVAL; + } + + bitmap_zero(val, nbits); + if (no_mask) + bitmap_fill(mask, nbits); + else + bitmap_zero(mask, nbits); + + nla_for_each_nested(bit_attr, tb[ETHTOOL_A_BITSET_BITS], rem) { + unsigned int idx; + bool bit_val; + + ret = ethnl_parse_bit(&idx, &bit_val, nbits, bit_attr, no_mask, + names, extack); + if (ret < 0) + return ret; + if (bit_val) + set_bit(idx, val); + if (!no_mask) + set_bit(idx, mask); + } + + return 0; +} + #if BITS_PER_LONG == 64 && defined(__BIG_ENDIAN) /* 64-bit big endian architectures are the only case when u32 based bitmaps diff --git a/net/ethtool/bitset.h b/net/ethtool/bitset.h index b849f9d19676..c2c2e0051d00 100644 --- a/net/ethtool/bitset.h +++ b/net/ethtool/bitset.h @@ -26,5 +26,9 @@ int ethnl_update_bitset(unsigned long *bitmap, unsigned int nbits, int ethnl_update_bitset32(u32 *bitmap, unsigned int nbits, const struct nlattr *attr, ethnl_string_array_t names, struct netlink_ext_ack *extack, bool *mod); +int ethnl_parse_bitset(unsigned long *val, unsigned long *mask, + unsigned int nbits, const struct nlattr *attr, + ethnl_string_array_t names, + struct netlink_ext_ack *extack); #endif /* _NET_ETHTOOL_BITSET_H */ -- 2.25.1