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