xref: /aosp_15_r20/external/ethtool/netlink/eee.c (revision 1b481fc3bb1b45d4cf28d1ec12969dc1055f555d)
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