1*1b481fc3SMaciej Żenczykowski /*
2*1b481fc3SMaciej Żenczykowski * plca.c - netlink implementation of plca command
3*1b481fc3SMaciej Żenczykowski *
4*1b481fc3SMaciej Żenczykowski * Implementation of "ethtool --show-plca <dev>" and
5*1b481fc3SMaciej Żenczykowski * "ethtool --set-plca <dev> ..."
6*1b481fc3SMaciej Żenczykowski */
7*1b481fc3SMaciej Żenczykowski
8*1b481fc3SMaciej Żenczykowski #include <errno.h>
9*1b481fc3SMaciej Żenczykowski #include <string.h>
10*1b481fc3SMaciej Żenczykowski #include <stdio.h>
11*1b481fc3SMaciej Żenczykowski
12*1b481fc3SMaciej Żenczykowski #include "../internal.h"
13*1b481fc3SMaciej Żenczykowski #include "../common.h"
14*1b481fc3SMaciej Żenczykowski #include "netlink.h"
15*1b481fc3SMaciej Żenczykowski #include "bitset.h"
16*1b481fc3SMaciej Żenczykowski #include "parser.h"
17*1b481fc3SMaciej Żenczykowski
18*1b481fc3SMaciej Żenczykowski /* PLCA_GET_CFG */
19*1b481fc3SMaciej Żenczykowski
plca_get_cfg_reply_cb(const struct nlmsghdr * nlhdr,void * data)20*1b481fc3SMaciej Żenczykowski int plca_get_cfg_reply_cb(const struct nlmsghdr *nlhdr, void *data)
21*1b481fc3SMaciej Żenczykowski {
22*1b481fc3SMaciej Żenczykowski const struct nlattr *tb[ETHTOOL_A_PLCA_MAX + 1] = {};
23*1b481fc3SMaciej Żenczykowski DECLARE_ATTR_TB_INFO(tb);
24*1b481fc3SMaciej Żenczykowski struct nl_context *nlctx = data;
25*1b481fc3SMaciej Żenczykowski bool silent;
26*1b481fc3SMaciej Żenczykowski int idv = 255;
27*1b481fc3SMaciej Żenczykowski int err_ret;
28*1b481fc3SMaciej Żenczykowski int val;
29*1b481fc3SMaciej Żenczykowski int ret;
30*1b481fc3SMaciej Żenczykowski
31*1b481fc3SMaciej Żenczykowski silent = nlctx->is_dump || nlctx->is_monitor;
32*1b481fc3SMaciej Żenczykowski err_ret = silent ? MNL_CB_OK : MNL_CB_ERROR;
33*1b481fc3SMaciej Żenczykowski ret = mnl_attr_parse(nlhdr, GENL_HDRLEN, attr_cb, &tb_info);
34*1b481fc3SMaciej Żenczykowski if (ret < 0)
35*1b481fc3SMaciej Żenczykowski return err_ret;
36*1b481fc3SMaciej Żenczykowski
37*1b481fc3SMaciej Żenczykowski nlctx->devname = get_dev_name(tb[ETHTOOL_A_PLCA_HEADER]);
38*1b481fc3SMaciej Żenczykowski if (!dev_ok(nlctx))
39*1b481fc3SMaciej Żenczykowski return err_ret;
40*1b481fc3SMaciej Żenczykowski
41*1b481fc3SMaciej Żenczykowski if (silent)
42*1b481fc3SMaciej Żenczykowski putchar('\n');
43*1b481fc3SMaciej Żenczykowski
44*1b481fc3SMaciej Żenczykowski printf("PLCA settings for %s:\n", nlctx->devname);
45*1b481fc3SMaciej Żenczykowski
46*1b481fc3SMaciej Żenczykowski // check if PLCA is enabled
47*1b481fc3SMaciej Żenczykowski printf("\tEnabled: ");
48*1b481fc3SMaciej Żenczykowski
49*1b481fc3SMaciej Żenczykowski if (!tb[ETHTOOL_A_PLCA_ENABLED]) {
50*1b481fc3SMaciej Żenczykowski printf("not supported");
51*1b481fc3SMaciej Żenczykowski } else {
52*1b481fc3SMaciej Żenczykowski val = mnl_attr_get_u8(tb[ETHTOOL_A_PLCA_ENABLED]);
53*1b481fc3SMaciej Żenczykowski printf(val ? "Yes" : "No");
54*1b481fc3SMaciej Żenczykowski }
55*1b481fc3SMaciej Żenczykowski putchar('\n');
56*1b481fc3SMaciej Żenczykowski
57*1b481fc3SMaciej Żenczykowski // get node ID
58*1b481fc3SMaciej Żenczykowski printf("\tlocal node ID: ");
59*1b481fc3SMaciej Żenczykowski
60*1b481fc3SMaciej Żenczykowski if (!tb[ETHTOOL_A_PLCA_NODE_ID]) {
61*1b481fc3SMaciej Żenczykowski printf("not supported");
62*1b481fc3SMaciej Żenczykowski } else {
63*1b481fc3SMaciej Żenczykowski idv = mnl_attr_get_u32(tb[ETHTOOL_A_PLCA_NODE_ID]);
64*1b481fc3SMaciej Żenczykowski printf("%u (%s)", idv,
65*1b481fc3SMaciej Żenczykowski idv == 0 ? "coordinator" :
66*1b481fc3SMaciej Żenczykowski idv == 255 ? "unconfigured" : "follower");
67*1b481fc3SMaciej Żenczykowski }
68*1b481fc3SMaciej Żenczykowski putchar('\n');
69*1b481fc3SMaciej Żenczykowski
70*1b481fc3SMaciej Żenczykowski // get node count
71*1b481fc3SMaciej Żenczykowski printf("\tNode count: ");
72*1b481fc3SMaciej Żenczykowski if (!tb[ETHTOOL_A_PLCA_NODE_CNT]) {
73*1b481fc3SMaciej Żenczykowski printf("not supported");
74*1b481fc3SMaciej Żenczykowski } else {
75*1b481fc3SMaciej Żenczykowski val = mnl_attr_get_u32(tb[ETHTOOL_A_PLCA_NODE_CNT]);
76*1b481fc3SMaciej Żenczykowski printf("%u", val);
77*1b481fc3SMaciej Żenczykowski
78*1b481fc3SMaciej Żenczykowski // The node count is ignored by follower nodes. However, it can
79*1b481fc3SMaciej Żenczykowski // be pre-set to enable fast coordinator role switchover.
80*1b481fc3SMaciej Żenczykowski // Therefore, on a follower node we still wanto to show it,
81*1b481fc3SMaciej Żenczykowski // indicating it is not currently used.
82*1b481fc3SMaciej Żenczykowski if (tb[ETHTOOL_A_PLCA_NODE_ID] && idv != 0)
83*1b481fc3SMaciej Żenczykowski printf(" (ignored)");
84*1b481fc3SMaciej Żenczykowski }
85*1b481fc3SMaciej Żenczykowski putchar('\n');
86*1b481fc3SMaciej Żenczykowski
87*1b481fc3SMaciej Żenczykowski // get TO timer (transmit opportunity timer)
88*1b481fc3SMaciej Żenczykowski printf("\tTO timer: ");
89*1b481fc3SMaciej Żenczykowski if (!tb[ETHTOOL_A_PLCA_TO_TMR]) {
90*1b481fc3SMaciej Żenczykowski printf("not supported");
91*1b481fc3SMaciej Żenczykowski } else {
92*1b481fc3SMaciej Żenczykowski val = mnl_attr_get_u32(tb[ETHTOOL_A_PLCA_TO_TMR]);
93*1b481fc3SMaciej Żenczykowski printf("%u BT", val);
94*1b481fc3SMaciej Żenczykowski }
95*1b481fc3SMaciej Żenczykowski putchar('\n');
96*1b481fc3SMaciej Żenczykowski
97*1b481fc3SMaciej Żenczykowski // get burst count
98*1b481fc3SMaciej Żenczykowski printf("\tBurst count: ");
99*1b481fc3SMaciej Żenczykowski if (!tb[ETHTOOL_A_PLCA_BURST_CNT]) {
100*1b481fc3SMaciej Żenczykowski printf("not supported");
101*1b481fc3SMaciej Żenczykowski } else {
102*1b481fc3SMaciej Żenczykowski val = mnl_attr_get_u32(tb[ETHTOOL_A_PLCA_BURST_CNT]);
103*1b481fc3SMaciej Żenczykowski printf("%u (%s)", val,
104*1b481fc3SMaciej Żenczykowski val > 0 ? "enabled" : "disabled");
105*1b481fc3SMaciej Żenczykowski }
106*1b481fc3SMaciej Żenczykowski putchar('\n');
107*1b481fc3SMaciej Żenczykowski
108*1b481fc3SMaciej Żenczykowski // get burst timer
109*1b481fc3SMaciej Żenczykowski printf("\tBurst timer: ");
110*1b481fc3SMaciej Żenczykowski if (!tb[ETHTOOL_A_PLCA_BURST_TMR]) {
111*1b481fc3SMaciej Żenczykowski printf("not supported");
112*1b481fc3SMaciej Żenczykowski } else {
113*1b481fc3SMaciej Żenczykowski val = mnl_attr_get_u32(tb[ETHTOOL_A_PLCA_BURST_TMR]);
114*1b481fc3SMaciej Żenczykowski printf("%u BT", val);
115*1b481fc3SMaciej Żenczykowski }
116*1b481fc3SMaciej Żenczykowski putchar('\n');
117*1b481fc3SMaciej Żenczykowski
118*1b481fc3SMaciej Żenczykowski return MNL_CB_OK;
119*1b481fc3SMaciej Żenczykowski }
120*1b481fc3SMaciej Żenczykowski
121*1b481fc3SMaciej Żenczykowski
nl_plca_get_cfg(struct cmd_context * ctx)122*1b481fc3SMaciej Żenczykowski int nl_plca_get_cfg(struct cmd_context *ctx)
123*1b481fc3SMaciej Żenczykowski {
124*1b481fc3SMaciej Żenczykowski struct nl_context *nlctx = ctx->nlctx;
125*1b481fc3SMaciej Żenczykowski struct nl_socket *nlsk = nlctx->ethnl_socket;
126*1b481fc3SMaciej Żenczykowski int ret;
127*1b481fc3SMaciej Żenczykowski
128*1b481fc3SMaciej Żenczykowski if (netlink_cmd_check(ctx, ETHTOOL_MSG_PLCA_GET_CFG, true))
129*1b481fc3SMaciej Żenczykowski return -EOPNOTSUPP;
130*1b481fc3SMaciej Żenczykowski
131*1b481fc3SMaciej Żenczykowski if (ctx->argc > 0) {
132*1b481fc3SMaciej Żenczykowski fprintf(stderr, "ethtool: unexpected parameter '%s'\n",
133*1b481fc3SMaciej Żenczykowski *ctx->argp);
134*1b481fc3SMaciej Żenczykowski return 1;
135*1b481fc3SMaciej Żenczykowski }
136*1b481fc3SMaciej Żenczykowski
137*1b481fc3SMaciej Żenczykowski ret = nlsock_prep_get_request(nlsk, ETHTOOL_MSG_PLCA_GET_CFG,
138*1b481fc3SMaciej Żenczykowski ETHTOOL_A_PLCA_HEADER, 0);
139*1b481fc3SMaciej Żenczykowski
140*1b481fc3SMaciej Żenczykowski if (ret < 0)
141*1b481fc3SMaciej Żenczykowski return ret;
142*1b481fc3SMaciej Żenczykowski
143*1b481fc3SMaciej Żenczykowski return nlsock_send_get_request(nlsk, plca_get_cfg_reply_cb);
144*1b481fc3SMaciej Żenczykowski }
145*1b481fc3SMaciej Żenczykowski
146*1b481fc3SMaciej Żenczykowski /* PLCA_SET_CFG */
147*1b481fc3SMaciej Żenczykowski
148*1b481fc3SMaciej Żenczykowski static const struct param_parser set_plca_params[] = {
149*1b481fc3SMaciej Żenczykowski {
150*1b481fc3SMaciej Żenczykowski .arg = "enable",
151*1b481fc3SMaciej Żenczykowski .type = ETHTOOL_A_PLCA_ENABLED,
152*1b481fc3SMaciej Żenczykowski .handler = nl_parse_u8bool,
153*1b481fc3SMaciej Żenczykowski .min_argc = 1,
154*1b481fc3SMaciej Żenczykowski },
155*1b481fc3SMaciej Żenczykowski {
156*1b481fc3SMaciej Żenczykowski .arg = "node-id",
157*1b481fc3SMaciej Żenczykowski .type = ETHTOOL_A_PLCA_NODE_ID,
158*1b481fc3SMaciej Żenczykowski .handler = nl_parse_direct_u32,
159*1b481fc3SMaciej Żenczykowski .min_argc = 1,
160*1b481fc3SMaciej Żenczykowski },
161*1b481fc3SMaciej Żenczykowski {
162*1b481fc3SMaciej Żenczykowski .arg = "node-cnt",
163*1b481fc3SMaciej Żenczykowski .type = ETHTOOL_A_PLCA_NODE_CNT,
164*1b481fc3SMaciej Żenczykowski .handler = nl_parse_direct_u32,
165*1b481fc3SMaciej Żenczykowski .min_argc = 1,
166*1b481fc3SMaciej Żenczykowski },
167*1b481fc3SMaciej Żenczykowski {
168*1b481fc3SMaciej Żenczykowski .arg = "to-tmr",
169*1b481fc3SMaciej Żenczykowski .type = ETHTOOL_A_PLCA_TO_TMR,
170*1b481fc3SMaciej Żenczykowski .handler = nl_parse_direct_u32,
171*1b481fc3SMaciej Żenczykowski .min_argc = 1,
172*1b481fc3SMaciej Żenczykowski },
173*1b481fc3SMaciej Żenczykowski {
174*1b481fc3SMaciej Żenczykowski .arg = "burst-cnt",
175*1b481fc3SMaciej Żenczykowski .type = ETHTOOL_A_PLCA_BURST_CNT,
176*1b481fc3SMaciej Żenczykowski .handler = nl_parse_direct_u32,
177*1b481fc3SMaciej Żenczykowski .min_argc = 1,
178*1b481fc3SMaciej Żenczykowski },
179*1b481fc3SMaciej Żenczykowski {
180*1b481fc3SMaciej Żenczykowski .arg = "burst-tmr",
181*1b481fc3SMaciej Żenczykowski .type = ETHTOOL_A_PLCA_BURST_TMR,
182*1b481fc3SMaciej Żenczykowski .handler = nl_parse_direct_u32,
183*1b481fc3SMaciej Żenczykowski .min_argc = 1,
184*1b481fc3SMaciej Żenczykowski },
185*1b481fc3SMaciej Żenczykowski {}
186*1b481fc3SMaciej Żenczykowski };
187*1b481fc3SMaciej Żenczykowski
nl_plca_set_cfg(struct cmd_context * ctx)188*1b481fc3SMaciej Żenczykowski int nl_plca_set_cfg(struct cmd_context *ctx)
189*1b481fc3SMaciej Żenczykowski {
190*1b481fc3SMaciej Żenczykowski struct nl_context *nlctx = ctx->nlctx;
191*1b481fc3SMaciej Żenczykowski struct nl_msg_buff *msgbuff;
192*1b481fc3SMaciej Żenczykowski struct nl_socket *nlsk;
193*1b481fc3SMaciej Żenczykowski int ret;
194*1b481fc3SMaciej Żenczykowski
195*1b481fc3SMaciej Żenczykowski if (netlink_cmd_check(ctx, ETHTOOL_MSG_PLCA_SET_CFG, false))
196*1b481fc3SMaciej Żenczykowski return -EOPNOTSUPP;
197*1b481fc3SMaciej Żenczykowski if (!ctx->argc) {
198*1b481fc3SMaciej Żenczykowski fprintf(stderr,
199*1b481fc3SMaciej Żenczykowski "ethtool (--set-plca-cfg): parameters missing\n");
200*1b481fc3SMaciej Żenczykowski return 1;
201*1b481fc3SMaciej Żenczykowski }
202*1b481fc3SMaciej Żenczykowski
203*1b481fc3SMaciej Żenczykowski nlctx->cmd = "--set-plca-cfg";
204*1b481fc3SMaciej Żenczykowski nlctx->argp = ctx->argp;
205*1b481fc3SMaciej Żenczykowski nlctx->argc = ctx->argc;
206*1b481fc3SMaciej Żenczykowski nlctx->devname = ctx->devname;
207*1b481fc3SMaciej Żenczykowski nlsk = nlctx->ethnl_socket;
208*1b481fc3SMaciej Żenczykowski msgbuff = &nlsk->msgbuff;
209*1b481fc3SMaciej Żenczykowski
210*1b481fc3SMaciej Żenczykowski ret = msg_init(nlctx, msgbuff, ETHTOOL_MSG_PLCA_SET_CFG,
211*1b481fc3SMaciej Żenczykowski NLM_F_REQUEST | NLM_F_ACK);
212*1b481fc3SMaciej Żenczykowski if (ret < 0)
213*1b481fc3SMaciej Żenczykowski return 2;
214*1b481fc3SMaciej Żenczykowski if (ethnla_fill_header(msgbuff, ETHTOOL_A_PLCA_HEADER,
215*1b481fc3SMaciej Żenczykowski ctx->devname, 0))
216*1b481fc3SMaciej Żenczykowski return -EMSGSIZE;
217*1b481fc3SMaciej Żenczykowski
218*1b481fc3SMaciej Żenczykowski ret = nl_parser(nlctx, set_plca_params, NULL, PARSER_GROUP_NONE, NULL);
219*1b481fc3SMaciej Żenczykowski if (ret < 0)
220*1b481fc3SMaciej Żenczykowski return 1;
221*1b481fc3SMaciej Żenczykowski
222*1b481fc3SMaciej Żenczykowski ret = nlsock_sendmsg(nlsk, NULL);
223*1b481fc3SMaciej Żenczykowski if (ret < 0)
224*1b481fc3SMaciej Żenczykowski return 76;
225*1b481fc3SMaciej Żenczykowski ret = nlsock_process_reply(nlsk, nomsg_reply_cb, nlctx);
226*1b481fc3SMaciej Żenczykowski if (ret == 0)
227*1b481fc3SMaciej Żenczykowski return 0;
228*1b481fc3SMaciej Żenczykowski else
229*1b481fc3SMaciej Żenczykowski return nlctx->exit_code ?: 76;
230*1b481fc3SMaciej Żenczykowski }
231*1b481fc3SMaciej Żenczykowski
232*1b481fc3SMaciej Żenczykowski /* PLCA_GET_STATUS */
233*1b481fc3SMaciej Żenczykowski
plca_get_status_reply_cb(const struct nlmsghdr * nlhdr,void * data)234*1b481fc3SMaciej Żenczykowski int plca_get_status_reply_cb(const struct nlmsghdr *nlhdr, void *data)
235*1b481fc3SMaciej Żenczykowski {
236*1b481fc3SMaciej Żenczykowski const struct nlattr *tb[ETHTOOL_A_PLCA_MAX + 1] = {};
237*1b481fc3SMaciej Żenczykowski DECLARE_ATTR_TB_INFO(tb);
238*1b481fc3SMaciej Żenczykowski struct nl_context *nlctx = data;
239*1b481fc3SMaciej Żenczykowski bool silent;
240*1b481fc3SMaciej Żenczykowski int err_ret;
241*1b481fc3SMaciej Żenczykowski int ret;
242*1b481fc3SMaciej Żenczykowski u8 val;
243*1b481fc3SMaciej Żenczykowski
244*1b481fc3SMaciej Żenczykowski silent = nlctx->is_dump || nlctx->is_monitor;
245*1b481fc3SMaciej Żenczykowski err_ret = silent ? MNL_CB_OK : MNL_CB_ERROR;
246*1b481fc3SMaciej Żenczykowski ret = mnl_attr_parse(nlhdr, GENL_HDRLEN, attr_cb, &tb_info);
247*1b481fc3SMaciej Żenczykowski if (ret < 0)
248*1b481fc3SMaciej Żenczykowski return err_ret;
249*1b481fc3SMaciej Żenczykowski
250*1b481fc3SMaciej Żenczykowski nlctx->devname = get_dev_name(tb[ETHTOOL_A_PLCA_HEADER]);
251*1b481fc3SMaciej Żenczykowski if (!dev_ok(nlctx))
252*1b481fc3SMaciej Żenczykowski return err_ret;
253*1b481fc3SMaciej Żenczykowski
254*1b481fc3SMaciej Żenczykowski if (silent)
255*1b481fc3SMaciej Żenczykowski putchar('\n');
256*1b481fc3SMaciej Żenczykowski
257*1b481fc3SMaciej Żenczykowski printf("PLCA status of %s:\n", nlctx->devname);
258*1b481fc3SMaciej Żenczykowski
259*1b481fc3SMaciej Żenczykowski // check whether the Open Alliance TC14 standard memory map is supported
260*1b481fc3SMaciej Żenczykowski printf("\tStatus: ");
261*1b481fc3SMaciej Żenczykowski
262*1b481fc3SMaciej Żenczykowski if (!tb[ETHTOOL_A_PLCA_STATUS]) {
263*1b481fc3SMaciej Żenczykowski printf("not supported");
264*1b481fc3SMaciej Żenczykowski } else {
265*1b481fc3SMaciej Żenczykowski val = mnl_attr_get_u8(tb[ETHTOOL_A_PLCA_STATUS]);
266*1b481fc3SMaciej Żenczykowski printf(val ? "on" : "off");
267*1b481fc3SMaciej Żenczykowski }
268*1b481fc3SMaciej Żenczykowski putchar('\n');
269*1b481fc3SMaciej Żenczykowski
270*1b481fc3SMaciej Żenczykowski return MNL_CB_OK;
271*1b481fc3SMaciej Żenczykowski }
272*1b481fc3SMaciej Żenczykowski
273*1b481fc3SMaciej Żenczykowski
nl_plca_get_status(struct cmd_context * ctx)274*1b481fc3SMaciej Żenczykowski int nl_plca_get_status(struct cmd_context *ctx)
275*1b481fc3SMaciej Żenczykowski {
276*1b481fc3SMaciej Żenczykowski struct nl_context *nlctx = ctx->nlctx;
277*1b481fc3SMaciej Żenczykowski struct nl_socket *nlsk = nlctx->ethnl_socket;
278*1b481fc3SMaciej Żenczykowski int ret;
279*1b481fc3SMaciej Żenczykowski
280*1b481fc3SMaciej Żenczykowski if (netlink_cmd_check(ctx, ETHTOOL_MSG_PLCA_GET_STATUS, true))
281*1b481fc3SMaciej Żenczykowski return -EOPNOTSUPP;
282*1b481fc3SMaciej Żenczykowski
283*1b481fc3SMaciej Żenczykowski if (ctx->argc > 0) {
284*1b481fc3SMaciej Żenczykowski fprintf(stderr, "ethtool: unexpected parameter '%s'\n",
285*1b481fc3SMaciej Żenczykowski *ctx->argp);
286*1b481fc3SMaciej Żenczykowski return 1;
287*1b481fc3SMaciej Żenczykowski }
288*1b481fc3SMaciej Żenczykowski
289*1b481fc3SMaciej Żenczykowski ret = nlsock_prep_get_request(nlsk, ETHTOOL_MSG_PLCA_GET_STATUS,
290*1b481fc3SMaciej Żenczykowski ETHTOOL_A_PLCA_HEADER, 0);
291*1b481fc3SMaciej Żenczykowski
292*1b481fc3SMaciej Żenczykowski if (ret < 0)
293*1b481fc3SMaciej Żenczykowski return ret;
294*1b481fc3SMaciej Żenczykowski
295*1b481fc3SMaciej Żenczykowski return nlsock_send_get_request(nlsk, plca_get_status_reply_cb);
296*1b481fc3SMaciej Żenczykowski }
297