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