1 /*
2 * tsinfo.c - netlink implementation of timestamping commands
3 *
4 * Implementation of "ethtool -T <dev>"
5 */
6
7 #include <errno.h>
8 #include <string.h>
9 #include <stdio.h>
10
11 #include "../internal.h"
12 #include "../common.h"
13 #include "netlink.h"
14 #include "bitset.h"
15
16 /* TSINFO_GET */
17
tsinfo_dump_cb(unsigned int idx,const char * name,bool val,void * data __maybe_unused)18 static void tsinfo_dump_cb(unsigned int idx, const char *name, bool val,
19 void *data __maybe_unused)
20 {
21 if (!val)
22 return;
23
24 if (name)
25 printf("\t%s\n", name);
26 else
27 printf("\tbit%u\n", idx);
28 }
29
tsinfo_dump_list(struct nl_context * nlctx,const struct nlattr * attr,const char * label,const char * if_empty,unsigned int stringset_id)30 static int tsinfo_dump_list(struct nl_context *nlctx, const struct nlattr *attr,
31 const char *label, const char *if_empty,
32 unsigned int stringset_id)
33 {
34 const struct stringset *strings = NULL;
35 int ret;
36
37 printf("%s:", label);
38 ret = 0;
39 if (!attr || bitset_is_empty(attr, false, &ret)) {
40 printf("%s\n", if_empty);
41 return ret;
42 }
43 putchar('\n');
44 if (ret < 0)
45 return ret;
46
47 if (bitset_is_compact(attr)) {
48 ret = netlink_init_ethnl2_socket(nlctx);
49 if (ret < 0)
50 return ret;
51 strings = global_stringset(stringset_id, nlctx->ethnl2_socket);
52 }
53 return walk_bitset(attr, strings, tsinfo_dump_cb, NULL);
54 }
55
tsinfo_reply_cb(const struct nlmsghdr * nlhdr,void * data)56 int tsinfo_reply_cb(const struct nlmsghdr *nlhdr, void *data)
57 {
58 const struct nlattr *tb[ETHTOOL_A_TSINFO_MAX + 1] = {};
59 DECLARE_ATTR_TB_INFO(tb);
60 struct nl_context *nlctx = data;
61 bool silent;
62 int err_ret;
63 int ret;
64
65 silent = nlctx->is_dump;
66 err_ret = silent ? MNL_CB_OK : MNL_CB_ERROR;
67 ret = mnl_attr_parse(nlhdr, GENL_HDRLEN, attr_cb, &tb_info);
68 if (ret < 0)
69 return err_ret;
70 nlctx->devname = get_dev_name(tb[ETHTOOL_A_TSINFO_HEADER]);
71 if (!dev_ok(nlctx))
72 return err_ret;
73
74 if (silent)
75 putchar('\n');
76 printf("Time stamping parameters for %s:\n", nlctx->devname);
77
78 ret = tsinfo_dump_list(nlctx, tb[ETHTOOL_A_TSINFO_TIMESTAMPING],
79 "Capabilities", "", ETH_SS_SOF_TIMESTAMPING);
80 if (ret < 0)
81 return err_ret;
82
83 printf("PTP Hardware Clock: ");
84 if (tb[ETHTOOL_A_TSINFO_PHC_INDEX])
85 printf("%d\n",
86 mnl_attr_get_u32(tb[ETHTOOL_A_TSINFO_PHC_INDEX]));
87 else
88 printf("none\n");
89
90 ret = tsinfo_dump_list(nlctx, tb[ETHTOOL_A_TSINFO_TX_TYPES],
91 "Hardware Transmit Timestamp Modes", " none",
92 ETH_SS_TS_TX_TYPES);
93 if (ret < 0)
94 return err_ret;
95
96 ret = tsinfo_dump_list(nlctx, tb[ETHTOOL_A_TSINFO_RX_FILTERS],
97 "Hardware Receive Filter Modes", " none",
98 ETH_SS_TS_RX_FILTERS);
99 if (ret < 0)
100 return err_ret;
101
102 return MNL_CB_OK;
103 }
104
nl_tsinfo(struct cmd_context * ctx)105 int nl_tsinfo(struct cmd_context *ctx)
106 {
107 struct nl_context *nlctx = ctx->nlctx;
108 struct nl_socket *nlsk = nlctx->ethnl_socket;
109 int ret;
110
111 if (netlink_cmd_check(ctx, ETHTOOL_MSG_TSINFO_GET, true))
112 return -EOPNOTSUPP;
113 if (ctx->argc > 0) {
114 fprintf(stderr, "ethtool: unexpected parameter '%s'\n",
115 *ctx->argp);
116 return 1;
117 }
118
119 ret = nlsock_prep_get_request(nlsk, ETHTOOL_MSG_TSINFO_GET,
120 ETHTOOL_A_TSINFO_HEADER, 0);
121 if (ret < 0)
122 return ret;
123 return nlsock_send_get_request(nlsk, tsinfo_reply_cb);
124 }
125