1 /*
2 * eee.c - netlink implementation of eee commands
3 *
4 * Implementation of "ethtool --show-eee <dev>" and
5 * "ethtool --set-eee <dev> ..."
6 */
7
8 #include <errno.h>
9 #include <string.h>
10 #include <stdio.h>
11
12 #include "../internal.h"
13 #include "../common.h"
14 #include "netlink.h"
15 #include "bitset.h"
16 #include "parser.h"
17 #include "../json_writer.h"
18
19 /* EEE_GET */
20
eee_reply_cb(const struct nlmsghdr * nlhdr,void * data)21 int eee_reply_cb(const struct nlmsghdr *nlhdr, void *data)
22 {
23 const struct nlattr *tb[ETHTOOL_A_EEE_MAX + 1] = {};
24 DECLARE_ATTR_TB_INFO(tb);
25 bool enabled, active, tx_lpi_enabled, status_support;
26 struct nl_context *nlctx = data;
27 bool silent;
28 int err_ret;
29 int ret;
30
31 silent = nlctx->is_dump || nlctx->is_monitor || is_json_context();
32 err_ret = silent ? MNL_CB_OK : MNL_CB_ERROR;
33 ret = mnl_attr_parse(nlhdr, GENL_HDRLEN, attr_cb, &tb_info);
34 if (ret < 0)
35 return err_ret;
36 nlctx->devname = get_dev_name(tb[ETHTOOL_A_EEE_HEADER]);
37 if (!dev_ok(nlctx))
38 return err_ret;
39
40 if (!tb[ETHTOOL_A_EEE_MODES_OURS] ||
41 !tb[ETHTOOL_A_EEE_ACTIVE] || !tb[ETHTOOL_A_EEE_ENABLED] ||
42 !tb[ETHTOOL_A_EEE_TX_LPI_ENABLED] ||
43 !tb[ETHTOOL_A_EEE_TX_LPI_TIMER]) {
44 fprintf(stderr, "Malformed response from kernel\n");
45 return err_ret;
46 }
47 active = mnl_attr_get_u8(tb[ETHTOOL_A_EEE_ACTIVE]);
48 enabled = mnl_attr_get_u8(tb[ETHTOOL_A_EEE_ENABLED]);
49 tx_lpi_enabled = mnl_attr_get_u8(tb[ETHTOOL_A_EEE_TX_LPI_ENABLED]);
50 status_support = bitset_is_empty(tb[ETHTOOL_A_EEE_MODES_OURS], true, &ret);
51
52 if (silent)
53 putchar('\n');
54 print_string(PRINT_ANY, "ifname", "EEE settings for %s:\n", nlctx->devname);
55 print_string(PRINT_FP, NULL, "\tEEE status: ", NULL);
56 if (status_support) {
57 print_string(PRINT_ANY, "status", "%s\n", "not supported");
58 return MNL_CB_OK;
59 }
60 if (!enabled)
61 print_string(PRINT_ANY, "status", "%s\n", "disabled");
62 else
63 print_string(PRINT_ANY, "status", "enabled - %s\n", active ? "active" : "inactive");
64 print_string(PRINT_FP, NULL, "\tTx LPI: ", NULL);
65 if (tx_lpi_enabled)
66 print_uint(PRINT_ANY, "tx-lpi", "%u (us)\n",
67 mnl_attr_get_u32(tb[ETHTOOL_A_EEE_TX_LPI_TIMER]));
68 else
69 print_string(PRINT_FP, NULL, "%s\n", "disabled");
70
71 ret = dump_link_modes(nlctx, tb[ETHTOOL_A_EEE_MODES_OURS], true,
72 LM_CLASS_REAL,
73 "Supported EEE link modes: ", NULL, "\n",
74 "Not reported", "supported-eee-link-modes");
75 if (ret < 0)
76 return err_ret;
77 ret = dump_link_modes(nlctx, tb[ETHTOOL_A_EEE_MODES_OURS], false,
78 LM_CLASS_REAL,
79 "Advertised EEE link modes: ", NULL, "\n",
80 "Not reported", "advertised-eee-link-modes");
81 if (ret < 0)
82 return err_ret;
83 ret = dump_link_modes(nlctx, tb[ETHTOOL_A_EEE_MODES_PEER], false,
84 LM_CLASS_REAL,
85 "Link partner advertised EEE link modes: ", NULL,
86 "\n", "Not reported", "link-partner-advertised-eee-link-modes");
87 if (ret < 0)
88 return err_ret;
89
90 return MNL_CB_OK;
91 }
92
nl_geee(struct cmd_context * ctx)93 int nl_geee(struct cmd_context *ctx)
94 {
95 struct nl_context *nlctx = ctx->nlctx;
96 struct nl_socket *nlsk = nlctx->ethnl_socket;
97 int ret;
98
99 if (netlink_cmd_check(ctx, ETHTOOL_MSG_EEE_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 new_json_obj(ctx->json);
108 open_json_object(NULL);
109
110 ret = nlsock_prep_get_request(nlsk, ETHTOOL_MSG_EEE_GET,
111 ETHTOOL_A_EEE_HEADER, 0);
112 if (ret < 0)
113 goto out;
114 ret = nlsock_send_get_request(nlsk, eee_reply_cb);
115 out:
116 close_json_object();
117 delete_json_obj();
118 return ret;
119 }
120
121 /* EEE_SET */
122
123 static const struct bitset_parser_data advertise_parser_data = {
124 .no_mask = false,
125 .force_hex = true,
126 };
127
128 static const struct param_parser seee_params[] = {
129 {
130 .arg = "advertise",
131 .type = ETHTOOL_A_EEE_MODES_OURS,
132 .handler = nl_parse_bitset,
133 .handler_data = &advertise_parser_data,
134 .min_argc = 1,
135 },
136 {
137 .arg = "tx-lpi",
138 .type = ETHTOOL_A_EEE_TX_LPI_ENABLED,
139 .handler = nl_parse_u8bool,
140 .min_argc = 1,
141 },
142 {
143 .arg = "tx-timer",
144 .type = ETHTOOL_A_EEE_TX_LPI_TIMER,
145 .handler = nl_parse_direct_u32,
146 .min_argc = 1,
147 },
148 {
149 .arg = "eee",
150 .type = ETHTOOL_A_EEE_ENABLED,
151 .handler = nl_parse_u8bool,
152 .min_argc = 1,
153 },
154 {}
155 };
156
nl_seee(struct cmd_context * ctx)157 int nl_seee(struct cmd_context *ctx)
158 {
159 struct nl_context *nlctx = ctx->nlctx;
160 struct nl_msg_buff *msgbuff;
161 struct nl_socket *nlsk;
162 int ret;
163
164 if (netlink_cmd_check(ctx, ETHTOOL_MSG_EEE_SET, false))
165 return -EOPNOTSUPP;
166 if (!ctx->argc) {
167 fprintf(stderr, "ethtool (--set-eee): parameters missing\n");
168 return 1;
169 }
170
171 nlctx->cmd = "--set-eee";
172 nlctx->argp = ctx->argp;
173 nlctx->argc = ctx->argc;
174 nlctx->devname = ctx->devname;
175 nlsk = nlctx->ethnl_socket;
176 msgbuff = &nlsk->msgbuff;
177
178 ret = msg_init(nlctx, msgbuff, ETHTOOL_MSG_EEE_SET,
179 NLM_F_REQUEST | NLM_F_ACK);
180 if (ret < 0)
181 return 2;
182 if (ethnla_fill_header(msgbuff, ETHTOOL_A_EEE_HEADER,
183 ctx->devname, 0))
184 return -EMSGSIZE;
185
186 ret = nl_parser(nlctx, seee_params, NULL, PARSER_GROUP_NONE, NULL);
187 if (ret < 0)
188 return 1;
189
190 ret = nlsock_sendmsg(nlsk, NULL);
191 if (ret < 0)
192 return 76;
193 ret = nlsock_process_reply(nlsk, nomsg_reply_cb, nlctx);
194 if (ret == 0)
195 return 0;
196 else
197 return nlctx->exit_code ?: 76;
198 }
199