1*1b481fc3SMaciej Żenczykowski /*
2*1b481fc3SMaciej Żenczykowski * module.c - netlink implementation of module commands
3*1b481fc3SMaciej Żenczykowski *
4*1b481fc3SMaciej Żenczykowski * Implementation of "ethtool --show-module <dev>" and
5*1b481fc3SMaciej Żenczykowski * "ethtool --set-module <dev> ..."
6*1b481fc3SMaciej Żenczykowski */
7*1b481fc3SMaciej Żenczykowski
8*1b481fc3SMaciej Żenczykowski #include <errno.h>
9*1b481fc3SMaciej Żenczykowski #include <ctype.h>
10*1b481fc3SMaciej Żenczykowski #include <inttypes.h>
11*1b481fc3SMaciej Żenczykowski #include <string.h>
12*1b481fc3SMaciej Żenczykowski #include <stdio.h>
13*1b481fc3SMaciej Żenczykowski
14*1b481fc3SMaciej Żenczykowski #include "../internal.h"
15*1b481fc3SMaciej Żenczykowski #include "../common.h"
16*1b481fc3SMaciej Żenczykowski #include "netlink.h"
17*1b481fc3SMaciej Żenczykowski #include "parser.h"
18*1b481fc3SMaciej Żenczykowski
19*1b481fc3SMaciej Żenczykowski /* MODULE_GET */
20*1b481fc3SMaciej Żenczykowski
module_power_mode_policy_name(u8 val)21*1b481fc3SMaciej Żenczykowski static const char *module_power_mode_policy_name(u8 val)
22*1b481fc3SMaciej Żenczykowski {
23*1b481fc3SMaciej Żenczykowski switch (val) {
24*1b481fc3SMaciej Żenczykowski case ETHTOOL_MODULE_POWER_MODE_POLICY_HIGH:
25*1b481fc3SMaciej Żenczykowski return "high";
26*1b481fc3SMaciej Żenczykowski case ETHTOOL_MODULE_POWER_MODE_POLICY_AUTO:
27*1b481fc3SMaciej Żenczykowski return "auto";
28*1b481fc3SMaciej Żenczykowski default:
29*1b481fc3SMaciej Żenczykowski return "unknown";
30*1b481fc3SMaciej Żenczykowski }
31*1b481fc3SMaciej Żenczykowski }
32*1b481fc3SMaciej Żenczykowski
module_power_mode_name(u8 val)33*1b481fc3SMaciej Żenczykowski static const char *module_power_mode_name(u8 val)
34*1b481fc3SMaciej Żenczykowski {
35*1b481fc3SMaciej Żenczykowski switch (val) {
36*1b481fc3SMaciej Żenczykowski case ETHTOOL_MODULE_POWER_MODE_LOW:
37*1b481fc3SMaciej Żenczykowski return "low";
38*1b481fc3SMaciej Żenczykowski case ETHTOOL_MODULE_POWER_MODE_HIGH:
39*1b481fc3SMaciej Żenczykowski return "high";
40*1b481fc3SMaciej Żenczykowski default:
41*1b481fc3SMaciej Żenczykowski return "unknown";
42*1b481fc3SMaciej Żenczykowski }
43*1b481fc3SMaciej Żenczykowski }
44*1b481fc3SMaciej Żenczykowski
module_reply_cb(const struct nlmsghdr * nlhdr,void * data)45*1b481fc3SMaciej Żenczykowski int module_reply_cb(const struct nlmsghdr *nlhdr, void *data)
46*1b481fc3SMaciej Żenczykowski {
47*1b481fc3SMaciej Żenczykowski const struct nlattr *tb[ETHTOOL_A_MODULE_MAX + 1] = {};
48*1b481fc3SMaciej Żenczykowski struct nl_context *nlctx = data;
49*1b481fc3SMaciej Żenczykowski DECLARE_ATTR_TB_INFO(tb);
50*1b481fc3SMaciej Żenczykowski bool silent;
51*1b481fc3SMaciej Żenczykowski int err_ret;
52*1b481fc3SMaciej Żenczykowski int ret;
53*1b481fc3SMaciej Żenczykowski
54*1b481fc3SMaciej Żenczykowski silent = nlctx->is_dump || nlctx->is_monitor;
55*1b481fc3SMaciej Żenczykowski err_ret = silent ? MNL_CB_OK : MNL_CB_ERROR;
56*1b481fc3SMaciej Żenczykowski ret = mnl_attr_parse(nlhdr, GENL_HDRLEN, attr_cb, &tb_info);
57*1b481fc3SMaciej Żenczykowski if (ret < 0)
58*1b481fc3SMaciej Żenczykowski return err_ret;
59*1b481fc3SMaciej Żenczykowski nlctx->devname = get_dev_name(tb[ETHTOOL_A_MODULE_HEADER]);
60*1b481fc3SMaciej Żenczykowski if (!dev_ok(nlctx))
61*1b481fc3SMaciej Żenczykowski return err_ret;
62*1b481fc3SMaciej Żenczykowski
63*1b481fc3SMaciej Żenczykowski if (silent)
64*1b481fc3SMaciej Żenczykowski print_nl();
65*1b481fc3SMaciej Żenczykowski
66*1b481fc3SMaciej Żenczykowski open_json_object(NULL);
67*1b481fc3SMaciej Żenczykowski
68*1b481fc3SMaciej Żenczykowski print_string(PRINT_ANY, "ifname", "Module parameters for %s:\n",
69*1b481fc3SMaciej Żenczykowski nlctx->devname);
70*1b481fc3SMaciej Żenczykowski
71*1b481fc3SMaciej Żenczykowski if (tb[ETHTOOL_A_MODULE_POWER_MODE_POLICY]) {
72*1b481fc3SMaciej Żenczykowski u8 val;
73*1b481fc3SMaciej Żenczykowski
74*1b481fc3SMaciej Żenczykowski val = mnl_attr_get_u8(tb[ETHTOOL_A_MODULE_POWER_MODE_POLICY]);
75*1b481fc3SMaciej Żenczykowski print_string(PRINT_ANY, "power-mode-policy",
76*1b481fc3SMaciej Żenczykowski "power-mode-policy: %s\n",
77*1b481fc3SMaciej Żenczykowski module_power_mode_policy_name(val));
78*1b481fc3SMaciej Żenczykowski }
79*1b481fc3SMaciej Żenczykowski
80*1b481fc3SMaciej Żenczykowski if (tb[ETHTOOL_A_MODULE_POWER_MODE]) {
81*1b481fc3SMaciej Żenczykowski u8 val;
82*1b481fc3SMaciej Żenczykowski
83*1b481fc3SMaciej Żenczykowski val = mnl_attr_get_u8(tb[ETHTOOL_A_MODULE_POWER_MODE]);
84*1b481fc3SMaciej Żenczykowski print_string(PRINT_ANY, "power-mode",
85*1b481fc3SMaciej Żenczykowski "power-mode: %s\n", module_power_mode_name(val));
86*1b481fc3SMaciej Żenczykowski }
87*1b481fc3SMaciej Żenczykowski
88*1b481fc3SMaciej Żenczykowski close_json_object();
89*1b481fc3SMaciej Żenczykowski
90*1b481fc3SMaciej Żenczykowski return MNL_CB_OK;
91*1b481fc3SMaciej Żenczykowski }
92*1b481fc3SMaciej Żenczykowski
nl_gmodule(struct cmd_context * ctx)93*1b481fc3SMaciej Żenczykowski int nl_gmodule(struct cmd_context *ctx)
94*1b481fc3SMaciej Żenczykowski {
95*1b481fc3SMaciej Żenczykowski struct nl_context *nlctx = ctx->nlctx;
96*1b481fc3SMaciej Żenczykowski struct nl_socket *nlsk;
97*1b481fc3SMaciej Żenczykowski int ret;
98*1b481fc3SMaciej Żenczykowski
99*1b481fc3SMaciej Żenczykowski if (netlink_cmd_check(ctx, ETHTOOL_MSG_MODULE_GET, true))
100*1b481fc3SMaciej Żenczykowski return -EOPNOTSUPP;
101*1b481fc3SMaciej Żenczykowski if (ctx->argc > 0) {
102*1b481fc3SMaciej Żenczykowski fprintf(stderr, "ethtool: unexpected parameter '%s'\n",
103*1b481fc3SMaciej Żenczykowski *ctx->argp);
104*1b481fc3SMaciej Żenczykowski return 1;
105*1b481fc3SMaciej Żenczykowski }
106*1b481fc3SMaciej Żenczykowski
107*1b481fc3SMaciej Żenczykowski nlsk = nlctx->ethnl_socket;
108*1b481fc3SMaciej Żenczykowski ret = nlsock_prep_get_request(nlsk, ETHTOOL_MSG_MODULE_GET,
109*1b481fc3SMaciej Żenczykowski ETHTOOL_A_MODULE_HEADER, 0);
110*1b481fc3SMaciej Żenczykowski if (ret < 0)
111*1b481fc3SMaciej Żenczykowski return ret;
112*1b481fc3SMaciej Żenczykowski
113*1b481fc3SMaciej Żenczykowski new_json_obj(ctx->json);
114*1b481fc3SMaciej Żenczykowski ret = nlsock_send_get_request(nlsk, module_reply_cb);
115*1b481fc3SMaciej Żenczykowski delete_json_obj();
116*1b481fc3SMaciej Żenczykowski return ret;
117*1b481fc3SMaciej Żenczykowski }
118*1b481fc3SMaciej Żenczykowski
119*1b481fc3SMaciej Żenczykowski /* MODULE_SET */
120*1b481fc3SMaciej Żenczykowski
121*1b481fc3SMaciej Żenczykowski static const struct lookup_entry_u8 power_mode_policy_values[] = {
122*1b481fc3SMaciej Żenczykowski { .arg = "high", .val = ETHTOOL_MODULE_POWER_MODE_POLICY_HIGH },
123*1b481fc3SMaciej Żenczykowski { .arg = "auto", .val = ETHTOOL_MODULE_POWER_MODE_POLICY_AUTO },
124*1b481fc3SMaciej Żenczykowski {}
125*1b481fc3SMaciej Żenczykowski };
126*1b481fc3SMaciej Żenczykowski
127*1b481fc3SMaciej Żenczykowski static const struct param_parser smodule_params[] = {
128*1b481fc3SMaciej Żenczykowski {
129*1b481fc3SMaciej Żenczykowski .arg = "power-mode-policy",
130*1b481fc3SMaciej Żenczykowski .type = ETHTOOL_A_MODULE_POWER_MODE_POLICY,
131*1b481fc3SMaciej Żenczykowski .handler = nl_parse_lookup_u8,
132*1b481fc3SMaciej Żenczykowski .handler_data = power_mode_policy_values,
133*1b481fc3SMaciej Żenczykowski .min_argc = 1,
134*1b481fc3SMaciej Żenczykowski },
135*1b481fc3SMaciej Żenczykowski {}
136*1b481fc3SMaciej Żenczykowski };
137*1b481fc3SMaciej Żenczykowski
nl_smodule(struct cmd_context * ctx)138*1b481fc3SMaciej Żenczykowski int nl_smodule(struct cmd_context *ctx)
139*1b481fc3SMaciej Żenczykowski {
140*1b481fc3SMaciej Żenczykowski struct nl_context *nlctx = ctx->nlctx;
141*1b481fc3SMaciej Żenczykowski struct nl_msg_buff *msgbuff;
142*1b481fc3SMaciej Żenczykowski struct nl_socket *nlsk;
143*1b481fc3SMaciej Żenczykowski int ret;
144*1b481fc3SMaciej Żenczykowski
145*1b481fc3SMaciej Żenczykowski if (netlink_cmd_check(ctx, ETHTOOL_MSG_MODULE_SET, false))
146*1b481fc3SMaciej Żenczykowski return -EOPNOTSUPP;
147*1b481fc3SMaciej Żenczykowski if (!ctx->argc) {
148*1b481fc3SMaciej Żenczykowski fprintf(stderr, "ethtool (--set-module): parameters missing\n");
149*1b481fc3SMaciej Żenczykowski return 1;
150*1b481fc3SMaciej Żenczykowski }
151*1b481fc3SMaciej Żenczykowski
152*1b481fc3SMaciej Żenczykowski nlctx->cmd = "--set-module";
153*1b481fc3SMaciej Żenczykowski nlctx->argp = ctx->argp;
154*1b481fc3SMaciej Żenczykowski nlctx->argc = ctx->argc;
155*1b481fc3SMaciej Żenczykowski nlctx->devname = ctx->devname;
156*1b481fc3SMaciej Żenczykowski nlsk = nlctx->ethnl_socket;
157*1b481fc3SMaciej Żenczykowski msgbuff = &nlsk->msgbuff;
158*1b481fc3SMaciej Żenczykowski
159*1b481fc3SMaciej Żenczykowski ret = msg_init(nlctx, msgbuff, ETHTOOL_MSG_MODULE_SET,
160*1b481fc3SMaciej Żenczykowski NLM_F_REQUEST | NLM_F_ACK);
161*1b481fc3SMaciej Żenczykowski if (ret < 0)
162*1b481fc3SMaciej Żenczykowski return 2;
163*1b481fc3SMaciej Żenczykowski if (ethnla_fill_header(msgbuff, ETHTOOL_A_MODULE_HEADER,
164*1b481fc3SMaciej Żenczykowski ctx->devname, 0))
165*1b481fc3SMaciej Żenczykowski return -EMSGSIZE;
166*1b481fc3SMaciej Żenczykowski
167*1b481fc3SMaciej Żenczykowski ret = nl_parser(nlctx, smodule_params, NULL, PARSER_GROUP_NONE, NULL);
168*1b481fc3SMaciej Żenczykowski if (ret < 0)
169*1b481fc3SMaciej Żenczykowski return 1;
170*1b481fc3SMaciej Żenczykowski
171*1b481fc3SMaciej Żenczykowski ret = nlsock_sendmsg(nlsk, NULL);
172*1b481fc3SMaciej Żenczykowski if (ret < 0)
173*1b481fc3SMaciej Żenczykowski return 83;
174*1b481fc3SMaciej Żenczykowski ret = nlsock_process_reply(nlsk, nomsg_reply_cb, nlctx);
175*1b481fc3SMaciej Żenczykowski if (ret == 0)
176*1b481fc3SMaciej Żenczykowski return 0;
177*1b481fc3SMaciej Żenczykowski else
178*1b481fc3SMaciej Żenczykowski return nlctx->exit_code ?: 83;
179*1b481fc3SMaciej Żenczykowski }
180