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