netfilter: nf_tables: disallow updates of anonymous sets
[linux-2.6-block.git] / net / ethtool / plca.c
CommitLineData
8580e16c
PB
1// SPDX-License-Identifier: GPL-2.0-only
2
3#include <linux/phy.h>
4#include <linux/ethtool_netlink.h>
5
6#include "netlink.h"
7#include "common.h"
8
9struct plca_req_info {
10 struct ethnl_req_info base;
11};
12
13struct plca_reply_data {
14 struct ethnl_reply_data base;
15 struct phy_plca_cfg plca_cfg;
16 struct phy_plca_status plca_st;
17};
18
19// Helpers ------------------------------------------------------------------ //
20
21#define PLCA_REPDATA(__reply_base) \
22 container_of(__reply_base, struct plca_reply_data, base)
23
24static void plca_update_sint(int *dst, const struct nlattr *attr,
25 bool *mod)
26{
27 if (!attr)
28 return;
29
30 *dst = nla_get_u32(attr);
31 *mod = true;
32}
33
34// PLCA get configuration message ------------------------------------------- //
35
36const struct nla_policy ethnl_plca_get_cfg_policy[] = {
37 [ETHTOOL_A_PLCA_HEADER] =
38 NLA_POLICY_NESTED(ethnl_header_policy),
39};
40
41static int plca_get_cfg_prepare_data(const struct ethnl_req_info *req_base,
42 struct ethnl_reply_data *reply_base,
43 struct genl_info *info)
44{
45 struct plca_reply_data *data = PLCA_REPDATA(reply_base);
46 struct net_device *dev = reply_base->dev;
47 const struct ethtool_phy_ops *ops;
48 int ret;
49
50 // check that the PHY device is available and connected
51 if (!dev->phydev) {
52 ret = -EOPNOTSUPP;
53 goto out;
54 }
55
56 // note: rtnl_lock is held already by ethnl_default_doit
57 ops = ethtool_phy_ops;
58 if (!ops || !ops->get_plca_cfg) {
59 ret = -EOPNOTSUPP;
60 goto out;
61 }
62
63 ret = ethnl_ops_begin(dev);
28dbf774 64 if (ret < 0)
8580e16c
PB
65 goto out;
66
67 memset(&data->plca_cfg, 0xff,
68 sizeof_field(struct plca_reply_data, plca_cfg));
69
70 ret = ops->get_plca_cfg(dev->phydev, &data->plca_cfg);
71 ethnl_ops_complete(dev);
72
73out:
74 return ret;
75}
76
77static int plca_get_cfg_reply_size(const struct ethnl_req_info *req_base,
78 const struct ethnl_reply_data *reply_base)
79{
80 return nla_total_size(sizeof(u16)) + /* _VERSION */
81 nla_total_size(sizeof(u8)) + /* _ENABLED */
82 nla_total_size(sizeof(u32)) + /* _NODE_CNT */
83 nla_total_size(sizeof(u32)) + /* _NODE_ID */
84 nla_total_size(sizeof(u32)) + /* _TO_TIMER */
85 nla_total_size(sizeof(u32)) + /* _BURST_COUNT */
86 nla_total_size(sizeof(u32)); /* _BURST_TIMER */
87}
88
89static int plca_get_cfg_fill_reply(struct sk_buff *skb,
90 const struct ethnl_req_info *req_base,
91 const struct ethnl_reply_data *reply_base)
92{
93 const struct plca_reply_data *data = PLCA_REPDATA(reply_base);
94 const struct phy_plca_cfg *plca = &data->plca_cfg;
95
96 if ((plca->version >= 0 &&
97 nla_put_u16(skb, ETHTOOL_A_PLCA_VERSION, plca->version)) ||
98 (plca->enabled >= 0 &&
99 nla_put_u8(skb, ETHTOOL_A_PLCA_ENABLED, !!plca->enabled)) ||
100 (plca->node_id >= 0 &&
101 nla_put_u32(skb, ETHTOOL_A_PLCA_NODE_ID, plca->node_id)) ||
102 (plca->node_cnt >= 0 &&
103 nla_put_u32(skb, ETHTOOL_A_PLCA_NODE_CNT, plca->node_cnt)) ||
104 (plca->to_tmr >= 0 &&
105 nla_put_u32(skb, ETHTOOL_A_PLCA_TO_TMR, plca->to_tmr)) ||
106 (plca->burst_cnt >= 0 &&
107 nla_put_u32(skb, ETHTOOL_A_PLCA_BURST_CNT, plca->burst_cnt)) ||
108 (plca->burst_tmr >= 0 &&
109 nla_put_u32(skb, ETHTOOL_A_PLCA_BURST_TMR, plca->burst_tmr)))
110 return -EMSGSIZE;
111
112 return 0;
113};
114
8580e16c
PB
115// PLCA set configuration message ------------------------------------------- //
116
117const struct nla_policy ethnl_plca_set_cfg_policy[] = {
118 [ETHTOOL_A_PLCA_HEADER] =
119 NLA_POLICY_NESTED(ethnl_header_policy),
120 [ETHTOOL_A_PLCA_ENABLED] = NLA_POLICY_MAX(NLA_U8, 1),
121 [ETHTOOL_A_PLCA_NODE_ID] = NLA_POLICY_MAX(NLA_U32, 255),
122 [ETHTOOL_A_PLCA_NODE_CNT] = NLA_POLICY_RANGE(NLA_U32, 1, 255),
123 [ETHTOOL_A_PLCA_TO_TMR] = NLA_POLICY_MAX(NLA_U32, 255),
124 [ETHTOOL_A_PLCA_BURST_CNT] = NLA_POLICY_MAX(NLA_U32, 255),
125 [ETHTOOL_A_PLCA_BURST_TMR] = NLA_POLICY_MAX(NLA_U32, 255),
126};
127
04007961
JK
128static int
129ethnl_set_plca(struct ethnl_req_info *req_info, struct genl_info *info)
8580e16c 130{
04007961 131 struct net_device *dev = req_info->dev;
8580e16c 132 const struct ethtool_phy_ops *ops;
04007961 133 struct nlattr **tb = info->attrs;
8580e16c 134 struct phy_plca_cfg plca_cfg;
8580e16c
PB
135 bool mod = false;
136 int ret;
137
8580e16c 138 // check that the PHY device is available and connected
04007961
JK
139 if (!dev->phydev)
140 return -EOPNOTSUPP;
8580e16c
PB
141
142 ops = ethtool_phy_ops;
04007961
JK
143 if (!ops || !ops->set_plca_cfg)
144 return -EOPNOTSUPP;
8580e16c
PB
145
146 memset(&plca_cfg, 0xff, sizeof(plca_cfg));
147 plca_update_sint(&plca_cfg.enabled, tb[ETHTOOL_A_PLCA_ENABLED], &mod);
148 plca_update_sint(&plca_cfg.node_id, tb[ETHTOOL_A_PLCA_NODE_ID], &mod);
149 plca_update_sint(&plca_cfg.node_cnt, tb[ETHTOOL_A_PLCA_NODE_CNT], &mod);
150 plca_update_sint(&plca_cfg.to_tmr, tb[ETHTOOL_A_PLCA_TO_TMR], &mod);
151 plca_update_sint(&plca_cfg.burst_cnt, tb[ETHTOOL_A_PLCA_BURST_CNT],
152 &mod);
153 plca_update_sint(&plca_cfg.burst_tmr, tb[ETHTOOL_A_PLCA_BURST_TMR],
154 &mod);
8580e16c 155 if (!mod)
04007961 156 return 0;
8580e16c
PB
157
158 ret = ops->set_plca_cfg(dev->phydev, &plca_cfg, info->extack);
04007961
JK
159 return ret < 0 ? ret : 1;
160}
8580e16c 161
04007961
JK
162const struct ethnl_request_ops ethnl_plca_cfg_request_ops = {
163 .request_cmd = ETHTOOL_MSG_PLCA_GET_CFG,
164 .reply_cmd = ETHTOOL_MSG_PLCA_GET_CFG_REPLY,
165 .hdr_attr = ETHTOOL_A_PLCA_HEADER,
166 .req_info_size = sizeof(struct plca_req_info),
167 .reply_data_size = sizeof(struct plca_reply_data),
8580e16c 168
04007961
JK
169 .prepare_data = plca_get_cfg_prepare_data,
170 .reply_size = plca_get_cfg_reply_size,
171 .fill_reply = plca_get_cfg_fill_reply,
8580e16c 172
04007961
JK
173 .set = ethnl_set_plca,
174 .set_ntf_cmd = ETHTOOL_MSG_PLCA_NTF,
175};
8580e16c
PB
176
177// PLCA get status message -------------------------------------------------- //
178
179const struct nla_policy ethnl_plca_get_status_policy[] = {
180 [ETHTOOL_A_PLCA_HEADER] =
181 NLA_POLICY_NESTED(ethnl_header_policy),
182};
183
184static int plca_get_status_prepare_data(const struct ethnl_req_info *req_base,
185 struct ethnl_reply_data *reply_base,
186 struct genl_info *info)
187{
188 struct plca_reply_data *data = PLCA_REPDATA(reply_base);
189 struct net_device *dev = reply_base->dev;
190 const struct ethtool_phy_ops *ops;
191 int ret;
192
193 // check that the PHY device is available and connected
194 if (!dev->phydev) {
195 ret = -EOPNOTSUPP;
196 goto out;
197 }
198
199 // note: rtnl_lock is held already by ethnl_default_doit
200 ops = ethtool_phy_ops;
201 if (!ops || !ops->get_plca_status) {
202 ret = -EOPNOTSUPP;
203 goto out;
204 }
205
206 ret = ethnl_ops_begin(dev);
28dbf774 207 if (ret < 0)
8580e16c
PB
208 goto out;
209
210 memset(&data->plca_st, 0xff,
211 sizeof_field(struct plca_reply_data, plca_st));
212
213 ret = ops->get_plca_status(dev->phydev, &data->plca_st);
214 ethnl_ops_complete(dev);
215out:
216 return ret;
217}
218
219static int plca_get_status_reply_size(const struct ethnl_req_info *req_base,
220 const struct ethnl_reply_data *reply_base)
221{
222 return nla_total_size(sizeof(u8)); /* _STATUS */
223}
224
225static int plca_get_status_fill_reply(struct sk_buff *skb,
226 const struct ethnl_req_info *req_base,
227 const struct ethnl_reply_data *reply_base)
228{
229 const struct plca_reply_data *data = PLCA_REPDATA(reply_base);
230 const u8 status = data->plca_st.pst;
231
232 if (nla_put_u8(skb, ETHTOOL_A_PLCA_STATUS, !!status))
233 return -EMSGSIZE;
234
235 return 0;
236};
237
238const struct ethnl_request_ops ethnl_plca_status_request_ops = {
239 .request_cmd = ETHTOOL_MSG_PLCA_GET_STATUS,
240 .reply_cmd = ETHTOOL_MSG_PLCA_GET_STATUS_REPLY,
241 .hdr_attr = ETHTOOL_A_PLCA_HEADER,
242 .req_info_size = sizeof(struct plca_req_info),
243 .reply_data_size = sizeof(struct plca_reply_data),
244
245 .prepare_data = plca_get_status_prepare_data,
246 .reply_size = plca_get_status_reply_size,
247 .fill_reply = plca_get_status_fill_reply,
248};