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