• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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