• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * phy.c - List PHYs on an interface and their parameters
3  *
4  * Implementation of "ethtool --show-phys <dev>"
5  */
6 
7 #include <errno.h>
8 #include <inttypes.h>
9 #include <string.h>
10 #include <stdio.h>
11 
12 #include "../internal.h"
13 #include "../common.h"
14 #include "netlink.h"
15 
16 /* PHY_GET / PHY_DUMP */
17 
phy_upstream_type_to_str(uint8_t upstream_type)18 static const char * phy_upstream_type_to_str(uint8_t upstream_type)
19 {
20 	switch (upstream_type) {
21 	case PHY_UPSTREAM_PHY: return "phy";
22 	case PHY_UPSTREAM_MAC: return "mac";
23 	default: return "Unknown";
24 	}
25 }
26 
phy_reply_cb(const struct nlmsghdr * nlhdr,void * data)27 int phy_reply_cb(const struct nlmsghdr *nlhdr, void *data)
28 {
29 	const struct nlattr *tb[ETHTOOL_A_PHY_MAX + 1] = {};
30 	struct nl_context *nlctx = data;
31 	DECLARE_ATTR_TB_INFO(tb);
32 	uint8_t upstream_type;
33 	bool silent;
34 	int err_ret;
35 	int ret;
36 
37 	silent = nlctx->is_dump || nlctx->is_monitor;
38 	err_ret = silent ? MNL_CB_OK : MNL_CB_ERROR;
39 	ret = mnl_attr_parse(nlhdr, GENL_HDRLEN, attr_cb, &tb_info);
40 	if (ret < 0)
41 		return err_ret;
42 	nlctx->devname = get_dev_name(tb[ETHTOOL_A_PHY_HEADER]);
43 	if (!dev_ok(nlctx))
44 		return err_ret;
45 
46 	if (silent)
47 		print_nl();
48 
49 	open_json_object(NULL);
50 
51 	print_string(PRINT_ANY, "ifname", "PHY for %s:\n", nlctx->devname);
52 
53 	show_u32("phy_index", "PHY index: ", tb[ETHTOOL_A_PHY_INDEX]);
54 
55 	if (tb[ETHTOOL_A_PHY_DRVNAME])
56 		print_string(PRINT_ANY, "drvname", "Driver name: %s\n",
57 		     mnl_attr_get_str(tb[ETHTOOL_A_PHY_DRVNAME]));
58 
59 	if (tb[ETHTOOL_A_PHY_NAME])
60 		print_string(PRINT_ANY, "name", "PHY device name: %s\n",
61 		     mnl_attr_get_str(tb[ETHTOOL_A_PHY_NAME]));
62 
63 	if (tb[ETHTOOL_A_PHY_DOWNSTREAM_SFP_NAME])
64 		print_string(PRINT_ANY, "downstream_sfp_name",
65 			     "Downstream SFP bus name: %s\n",
66 			     mnl_attr_get_str(tb[ETHTOOL_A_PHY_DOWNSTREAM_SFP_NAME]));
67 
68 	if (tb[ETHTOOL_A_PHY_UPSTREAM_TYPE]) {
69 		upstream_type = mnl_attr_get_u8(tb[ETHTOOL_A_PHY_UPSTREAM_TYPE]);
70 		print_string(PRINT_ANY, "upstream_type", "Upstream type: %s\n",
71 			     phy_upstream_type_to_str(upstream_type));
72 	}
73 
74 	if (tb[ETHTOOL_A_PHY_UPSTREAM_INDEX])
75 		show_u32("upstream_index", "Upstream PHY index: ",
76 			 tb[ETHTOOL_A_PHY_UPSTREAM_INDEX]);
77 
78 	if (tb[ETHTOOL_A_PHY_UPSTREAM_SFP_NAME])
79 		print_string(PRINT_ANY, "upstream_sfp_name", "Upstream SFP name: %s\n",
80 			     mnl_attr_get_str(tb[ETHTOOL_A_PHY_UPSTREAM_SFP_NAME]));
81 
82 	if (!silent)
83 		print_nl();
84 
85 	close_json_object();
86 
87 	return MNL_CB_OK;
88 
89 	close_json_object();
90 	return err_ret;
91 }
92 
nl_get_phy(struct cmd_context * ctx)93 int nl_get_phy(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_PHY_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 	ret = nlsock_prep_filtered_dump_request(nlsk, ETHTOOL_MSG_PHY_GET,
108 						ETHTOOL_A_PHY_HEADER, 0);
109 	if (ret)
110 		return ret;
111 
112 	new_json_obj(ctx->json);
113 	ret = nlsock_send_get_request(nlsk, phy_reply_cb);
114 	delete_json_obj();
115 	return ret;
116 }
117