1 // SPDX-License-Identifier: GPL-2.0-only
7 struct privflags_req_info
{
8 struct ethnl_req_info base
;
11 struct privflags_reply_data
{
12 struct ethnl_reply_data base
;
13 const char (*priv_flag_names
)[ETH_GSTRING_LEN
];
14 unsigned int n_priv_flags
;
18 #define PRIVFLAGS_REPDATA(__reply_base) \
19 container_of(__reply_base, struct privflags_reply_data, base)
21 const struct nla_policy ethnl_privflags_get_policy
[] = {
22 [ETHTOOL_A_PRIVFLAGS_HEADER
] =
23 NLA_POLICY_NESTED(ethnl_header_policy
),
26 static int ethnl_get_priv_flags_info(struct net_device
*dev
,
28 const char (**names
)[ETH_GSTRING_LEN
])
30 const struct ethtool_ops
*ops
= dev
->ethtool_ops
;
33 nflags
= ops
->get_sset_count(dev
, ETH_SS_PRIV_FLAGS
);
38 *names
= kcalloc(nflags
, ETH_GSTRING_LEN
, GFP_KERNEL
);
41 ops
->get_strings(dev
, ETH_SS_PRIV_FLAGS
, (u8
*)*names
);
44 /* We can pass more than 32 private flags to userspace via netlink but
45 * we cannot get more with ethtool_ops::get_priv_flags(). Note that we
46 * must not adjust nflags before allocating the space for flag names
47 * as the buffer must be large enough for all flags.
49 if (WARN_ONCE(nflags
> 32,
50 "device %s reports more than 32 private flags (%d)\n",
51 netdev_name(dev
), nflags
))
58 static int privflags_prepare_data(const struct ethnl_req_info
*req_base
,
59 struct ethnl_reply_data
*reply_base
,
60 struct genl_info
*info
)
62 struct privflags_reply_data
*data
= PRIVFLAGS_REPDATA(reply_base
);
63 struct net_device
*dev
= reply_base
->dev
;
64 const char (*names
)[ETH_GSTRING_LEN
];
65 const struct ethtool_ops
*ops
;
69 ops
= dev
->ethtool_ops
;
70 if (!ops
->get_priv_flags
|| !ops
->get_sset_count
|| !ops
->get_strings
)
72 ret
= ethnl_ops_begin(dev
);
76 ret
= ethnl_get_priv_flags_info(dev
, &nflags
, &names
);
79 data
->priv_flags
= ops
->get_priv_flags(dev
);
80 data
->priv_flag_names
= names
;
81 data
->n_priv_flags
= nflags
;
84 ethnl_ops_complete(dev
);
88 static int privflags_reply_size(const struct ethnl_req_info
*req_base
,
89 const struct ethnl_reply_data
*reply_base
)
91 const struct privflags_reply_data
*data
= PRIVFLAGS_REPDATA(reply_base
);
92 bool compact
= req_base
->flags
& ETHTOOL_FLAG_COMPACT_BITSETS
;
93 const u32 all_flags
= ~(u32
)0 >> (32 - data
->n_priv_flags
);
95 return ethnl_bitset32_size(&data
->priv_flags
, &all_flags
,
97 data
->priv_flag_names
, compact
);
100 static int privflags_fill_reply(struct sk_buff
*skb
,
101 const struct ethnl_req_info
*req_base
,
102 const struct ethnl_reply_data
*reply_base
)
104 const struct privflags_reply_data
*data
= PRIVFLAGS_REPDATA(reply_base
);
105 bool compact
= req_base
->flags
& ETHTOOL_FLAG_COMPACT_BITSETS
;
106 const u32 all_flags
= ~(u32
)0 >> (32 - data
->n_priv_flags
);
108 return ethnl_put_bitset32(skb
, ETHTOOL_A_PRIVFLAGS_FLAGS
,
109 &data
->priv_flags
, &all_flags
,
110 data
->n_priv_flags
, data
->priv_flag_names
,
114 static void privflags_cleanup_data(struct ethnl_reply_data
*reply_data
)
116 struct privflags_reply_data
*data
= PRIVFLAGS_REPDATA(reply_data
);
118 kfree(data
->priv_flag_names
);
121 const struct ethnl_request_ops ethnl_privflags_request_ops
= {
122 .request_cmd
= ETHTOOL_MSG_PRIVFLAGS_GET
,
123 .reply_cmd
= ETHTOOL_MSG_PRIVFLAGS_GET_REPLY
,
124 .hdr_attr
= ETHTOOL_A_PRIVFLAGS_HEADER
,
125 .req_info_size
= sizeof(struct privflags_req_info
),
126 .reply_data_size
= sizeof(struct privflags_reply_data
),
128 .prepare_data
= privflags_prepare_data
,
129 .reply_size
= privflags_reply_size
,
130 .fill_reply
= privflags_fill_reply
,
131 .cleanup_data
= privflags_cleanup_data
,
136 const struct nla_policy ethnl_privflags_set_policy
[] = {
137 [ETHTOOL_A_PRIVFLAGS_HEADER
] =
138 NLA_POLICY_NESTED(ethnl_header_policy
),
139 [ETHTOOL_A_PRIVFLAGS_FLAGS
] = { .type
= NLA_NESTED
},
142 int ethnl_set_privflags(struct sk_buff
*skb
, struct genl_info
*info
)
144 const char (*names
)[ETH_GSTRING_LEN
] = NULL
;
145 struct ethnl_req_info req_info
= {};
146 struct nlattr
**tb
= info
->attrs
;
147 const struct ethtool_ops
*ops
;
148 struct net_device
*dev
;
155 if (!tb
[ETHTOOL_A_PRIVFLAGS_FLAGS
])
157 ret
= ethnl_bitset_is_compact(tb
[ETHTOOL_A_PRIVFLAGS_FLAGS
], &compact
);
160 ret
= ethnl_parse_header_dev_get(&req_info
,
161 tb
[ETHTOOL_A_PRIVFLAGS_HEADER
],
162 genl_info_net(info
), info
->extack
,
167 ops
= dev
->ethtool_ops
;
169 if (!ops
->get_priv_flags
|| !ops
->set_priv_flags
||
170 !ops
->get_sset_count
|| !ops
->get_strings
)
174 ret
= ethnl_ops_begin(dev
);
177 ret
= ethnl_get_priv_flags_info(dev
, &nflags
, compact
? NULL
: &names
);
180 flags
= ops
->get_priv_flags(dev
);
182 ret
= ethnl_update_bitset32(&flags
, nflags
,
183 tb
[ETHTOOL_A_PRIVFLAGS_FLAGS
], names
,
187 ret
= ops
->set_priv_flags(dev
, flags
);
190 ethtool_notify(dev
, ETHTOOL_MSG_PRIVFLAGS_NTF
, NULL
);
195 ethnl_ops_complete(dev
);