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 static const struct nla_policy
22 privflags_get_policy
[ETHTOOL_A_PRIVFLAGS_MAX
+ 1] = {
23 [ETHTOOL_A_PRIVFLAGS_UNSPEC
] = { .type
= NLA_REJECT
},
24 [ETHTOOL_A_PRIVFLAGS_HEADER
] = { .type
= NLA_NESTED
},
25 [ETHTOOL_A_PRIVFLAGS_FLAGS
] = { .type
= NLA_REJECT
},
28 static int ethnl_get_priv_flags_info(struct net_device
*dev
,
30 const char (**names
)[ETH_GSTRING_LEN
])
32 const struct ethtool_ops
*ops
= dev
->ethtool_ops
;
35 nflags
= ops
->get_sset_count(dev
, ETH_SS_PRIV_FLAGS
);
40 *names
= kcalloc(nflags
, ETH_GSTRING_LEN
, GFP_KERNEL
);
43 ops
->get_strings(dev
, ETH_SS_PRIV_FLAGS
, (u8
*)*names
);
46 /* We can pass more than 32 private flags to userspace via netlink but
47 * we cannot get more with ethtool_ops::get_priv_flags(). Note that we
48 * must not adjust nflags before allocating the space for flag names
49 * as the buffer must be large enough for all flags.
51 if (WARN_ONCE(nflags
> 32,
52 "device %s reports more than 32 private flags (%d)\n",
53 netdev_name(dev
), nflags
))
60 static int privflags_prepare_data(const struct ethnl_req_info
*req_base
,
61 struct ethnl_reply_data
*reply_base
,
62 struct genl_info
*info
)
64 struct privflags_reply_data
*data
= PRIVFLAGS_REPDATA(reply_base
);
65 struct net_device
*dev
= reply_base
->dev
;
66 const char (*names
)[ETH_GSTRING_LEN
];
67 const struct ethtool_ops
*ops
;
71 ops
= dev
->ethtool_ops
;
72 if (!ops
->get_priv_flags
|| !ops
->get_sset_count
|| !ops
->get_strings
)
74 ret
= ethnl_ops_begin(dev
);
78 ret
= ethnl_get_priv_flags_info(dev
, &nflags
, &names
);
81 data
->priv_flags
= ops
->get_priv_flags(dev
);
82 data
->priv_flag_names
= names
;
83 data
->n_priv_flags
= nflags
;
86 ethnl_ops_complete(dev
);
90 static int privflags_reply_size(const struct ethnl_req_info
*req_base
,
91 const struct ethnl_reply_data
*reply_base
)
93 const struct privflags_reply_data
*data
= PRIVFLAGS_REPDATA(reply_base
);
94 bool compact
= req_base
->flags
& ETHTOOL_FLAG_COMPACT_BITSETS
;
95 const u32 all_flags
= ~(u32
)0 >> (32 - data
->n_priv_flags
);
97 return ethnl_bitset32_size(&data
->priv_flags
, &all_flags
,
99 data
->priv_flag_names
, compact
);
102 static int privflags_fill_reply(struct sk_buff
*skb
,
103 const struct ethnl_req_info
*req_base
,
104 const struct ethnl_reply_data
*reply_base
)
106 const struct privflags_reply_data
*data
= PRIVFLAGS_REPDATA(reply_base
);
107 bool compact
= req_base
->flags
& ETHTOOL_FLAG_COMPACT_BITSETS
;
108 const u32 all_flags
= ~(u32
)0 >> (32 - data
->n_priv_flags
);
110 return ethnl_put_bitset32(skb
, ETHTOOL_A_PRIVFLAGS_FLAGS
,
111 &data
->priv_flags
, &all_flags
,
112 data
->n_priv_flags
, data
->priv_flag_names
,
116 static void privflags_cleanup_data(struct ethnl_reply_data
*reply_data
)
118 struct privflags_reply_data
*data
= PRIVFLAGS_REPDATA(reply_data
);
120 kfree(data
->priv_flag_names
);
123 const struct ethnl_request_ops ethnl_privflags_request_ops
= {
124 .request_cmd
= ETHTOOL_MSG_PRIVFLAGS_GET
,
125 .reply_cmd
= ETHTOOL_MSG_PRIVFLAGS_GET_REPLY
,
126 .hdr_attr
= ETHTOOL_A_PRIVFLAGS_HEADER
,
127 .max_attr
= ETHTOOL_A_PRIVFLAGS_MAX
,
128 .req_info_size
= sizeof(struct privflags_req_info
),
129 .reply_data_size
= sizeof(struct privflags_reply_data
),
130 .request_policy
= privflags_get_policy
,
132 .prepare_data
= privflags_prepare_data
,
133 .reply_size
= privflags_reply_size
,
134 .fill_reply
= privflags_fill_reply
,
135 .cleanup_data
= privflags_cleanup_data
,
140 static const struct nla_policy
141 privflags_set_policy
[ETHTOOL_A_PRIVFLAGS_MAX
+ 1] = {
142 [ETHTOOL_A_PRIVFLAGS_UNSPEC
] = { .type
= NLA_REJECT
},
143 [ETHTOOL_A_PRIVFLAGS_HEADER
] = { .type
= NLA_NESTED
},
144 [ETHTOOL_A_PRIVFLAGS_FLAGS
] = { .type
= NLA_NESTED
},
147 int ethnl_set_privflags(struct sk_buff
*skb
, struct genl_info
*info
)
149 struct nlattr
*tb
[ETHTOOL_A_PRIVFLAGS_MAX
+ 1];
150 const char (*names
)[ETH_GSTRING_LEN
] = NULL
;
151 struct ethnl_req_info req_info
= {};
152 const struct ethtool_ops
*ops
;
153 struct net_device
*dev
;
160 ret
= nlmsg_parse(info
->nlhdr
, GENL_HDRLEN
, tb
,
161 ETHTOOL_A_PRIVFLAGS_MAX
, privflags_set_policy
,
165 if (!tb
[ETHTOOL_A_PRIVFLAGS_FLAGS
])
167 ret
= ethnl_bitset_is_compact(tb
[ETHTOOL_A_PRIVFLAGS_FLAGS
], &compact
);
170 ret
= ethnl_parse_header_dev_get(&req_info
,
171 tb
[ETHTOOL_A_PRIVFLAGS_HEADER
],
172 genl_info_net(info
), info
->extack
,
177 ops
= dev
->ethtool_ops
;
179 if (!ops
->get_priv_flags
|| !ops
->set_priv_flags
||
180 !ops
->get_sset_count
|| !ops
->get_strings
)
184 ret
= ethnl_ops_begin(dev
);
187 ret
= ethnl_get_priv_flags_info(dev
, &nflags
, compact
? NULL
: &names
);
190 flags
= ops
->get_priv_flags(dev
);
192 ret
= ethnl_update_bitset32(&flags
, nflags
,
193 tb
[ETHTOOL_A_PRIVFLAGS_FLAGS
], names
,
197 ret
= ops
->set_priv_flags(dev
, flags
);
200 ethtool_notify(dev
, ETHTOOL_MSG_PRIVFLAGS_NTF
, NULL
);
205 ethnl_ops_complete(dev
);