xref: /aosp_15_r20/external/ethtool/netlink/prettymsg.c (revision 1b481fc3bb1b45d4cf28d1ec12969dc1055f555d)
1*1b481fc3SMaciej Żenczykowski /*
2*1b481fc3SMaciej Żenczykowski  * prettymsg.c - human readable message dump
3*1b481fc3SMaciej Żenczykowski  *
4*1b481fc3SMaciej Żenczykowski  * Support for pretty print of an ethtool netlink message
5*1b481fc3SMaciej Żenczykowski  */
6*1b481fc3SMaciej Żenczykowski 
7*1b481fc3SMaciej Żenczykowski #include <stdio.h>
8*1b481fc3SMaciej Żenczykowski #include <string.h>
9*1b481fc3SMaciej Żenczykowski #include <errno.h>
10*1b481fc3SMaciej Żenczykowski #include <stdint.h>
11*1b481fc3SMaciej Żenczykowski #include <limits.h>
12*1b481fc3SMaciej Żenczykowski #include <inttypes.h>
13*1b481fc3SMaciej Żenczykowski #include <linux/genetlink.h>
14*1b481fc3SMaciej Żenczykowski #include <linux/rtnetlink.h>
15*1b481fc3SMaciej Żenczykowski #include <linux/if_link.h>
16*1b481fc3SMaciej Żenczykowski #include <libmnl/libmnl.h>
17*1b481fc3SMaciej Żenczykowski 
18*1b481fc3SMaciej Żenczykowski #include "prettymsg.h"
19*1b481fc3SMaciej Żenczykowski 
20*1b481fc3SMaciej Żenczykowski #define __INDENT 4
21*1b481fc3SMaciej Żenczykowski #define __DUMP_LINE 16
22*1b481fc3SMaciej Żenczykowski #define __DUMP_BLOCK 4
23*1b481fc3SMaciej Żenczykowski 
__print_binary_short(uint8_t * adata,unsigned int alen)24*1b481fc3SMaciej Żenczykowski static void __print_binary_short(uint8_t *adata, unsigned int alen)
25*1b481fc3SMaciej Żenczykowski {
26*1b481fc3SMaciej Żenczykowski 	unsigned int i;
27*1b481fc3SMaciej Żenczykowski 
28*1b481fc3SMaciej Żenczykowski 	if (!alen)
29*1b481fc3SMaciej Żenczykowski 		return;
30*1b481fc3SMaciej Żenczykowski 	printf("%02x", adata[0]);
31*1b481fc3SMaciej Żenczykowski 	for (i = 1; i < alen; i++)
32*1b481fc3SMaciej Żenczykowski 		printf("%c%02x", (i % __DUMP_BLOCK) ? ':' : ' ',  adata[i]);
33*1b481fc3SMaciej Żenczykowski }
34*1b481fc3SMaciej Żenczykowski 
__print_binary_long(uint8_t * adata,unsigned int alen,unsigned int level)35*1b481fc3SMaciej Żenczykowski static void __print_binary_long(uint8_t *adata, unsigned int alen,
36*1b481fc3SMaciej Żenczykowski 				unsigned int level)
37*1b481fc3SMaciej Żenczykowski {
38*1b481fc3SMaciej Żenczykowski 	unsigned int i;
39*1b481fc3SMaciej Żenczykowski 
40*1b481fc3SMaciej Żenczykowski 	for (i = 0; i < alen; i++) {
41*1b481fc3SMaciej Żenczykowski 		if (i % __DUMP_LINE == 0)
42*1b481fc3SMaciej Żenczykowski 			printf("\n%*s", __INDENT * (level + 2), "");
43*1b481fc3SMaciej Żenczykowski 		else if (i % __DUMP_BLOCK == 0)
44*1b481fc3SMaciej Żenczykowski 			printf("  ");
45*1b481fc3SMaciej Żenczykowski 		else
46*1b481fc3SMaciej Żenczykowski 			putchar(' ');
47*1b481fc3SMaciej Żenczykowski 		printf("%02x", adata[i]);
48*1b481fc3SMaciej Żenczykowski 	}
49*1b481fc3SMaciej Żenczykowski }
50*1b481fc3SMaciej Żenczykowski 
pretty_print_attr(const struct nlattr * attr,const struct pretty_nla_desc * desc,unsigned int ndesc,unsigned int level,int err_offset,bool in_array)51*1b481fc3SMaciej Żenczykowski static int pretty_print_attr(const struct nlattr *attr,
52*1b481fc3SMaciej Żenczykowski 			     const struct pretty_nla_desc *desc,
53*1b481fc3SMaciej Żenczykowski 			     unsigned int ndesc, unsigned int level,
54*1b481fc3SMaciej Żenczykowski 			     int err_offset, bool in_array)
55*1b481fc3SMaciej Żenczykowski {
56*1b481fc3SMaciej Żenczykowski 	unsigned int alen = mnl_attr_get_payload_len(attr);
57*1b481fc3SMaciej Żenczykowski 	unsigned int atype = mnl_attr_get_type(attr);
58*1b481fc3SMaciej Żenczykowski 	unsigned int desc_idx = in_array ? 0 : atype;
59*1b481fc3SMaciej Żenczykowski 	void *adata = mnl_attr_get_payload(attr);
60*1b481fc3SMaciej Żenczykowski 	const struct pretty_nla_desc *adesc;
61*1b481fc3SMaciej Żenczykowski 	const char *prefix = "    ";
62*1b481fc3SMaciej Żenczykowski 	bool nested;
63*1b481fc3SMaciej Żenczykowski 
64*1b481fc3SMaciej Żenczykowski 	adesc = (desc && desc_idx < ndesc) ? &desc[desc_idx] : NULL;
65*1b481fc3SMaciej Żenczykowski 	nested = (adesc && (adesc->format == NLA_NESTED ||
66*1b481fc3SMaciej Żenczykowski 			    adesc->format == NLA_ARRAY)) ||
67*1b481fc3SMaciej Żenczykowski 		 (attr->nla_type & NLA_F_NESTED);
68*1b481fc3SMaciej Żenczykowski 	if (err_offset >= 0 &&
69*1b481fc3SMaciej Żenczykowski 	    err_offset < (nested ? NLA_HDRLEN : attr->nla_len)) {
70*1b481fc3SMaciej Żenczykowski 		prefix = "===>";
71*1b481fc3SMaciej Żenczykowski 		if (err_offset)
72*1b481fc3SMaciej Żenczykowski 			fprintf(stderr,
73*1b481fc3SMaciej Żenczykowski 				"ethtool: bad_attr inside an attribute (offset %d)\n",
74*1b481fc3SMaciej Żenczykowski 				err_offset);
75*1b481fc3SMaciej Żenczykowski 	}
76*1b481fc3SMaciej Żenczykowski 	if (adesc && adesc->name && !in_array)
77*1b481fc3SMaciej Żenczykowski 		printf("%s%*s%s", prefix, level * __INDENT, "", adesc->name);
78*1b481fc3SMaciej Żenczykowski 	else
79*1b481fc3SMaciej Żenczykowski 		printf("%s%*s[%u]", prefix, level * __INDENT, "", atype);
80*1b481fc3SMaciej Żenczykowski 
81*1b481fc3SMaciej Żenczykowski 	if (nested) {
82*1b481fc3SMaciej Żenczykowski 		struct nlattr *child;
83*1b481fc3SMaciej Żenczykowski 		int ret = 0;
84*1b481fc3SMaciej Żenczykowski 
85*1b481fc3SMaciej Żenczykowski 		putchar('\n');
86*1b481fc3SMaciej Żenczykowski 		mnl_attr_for_each_nested(child, attr) {
87*1b481fc3SMaciej Żenczykowski 			bool array = adesc && adesc->format == NLA_ARRAY;
88*1b481fc3SMaciej Żenczykowski 			unsigned int child_off;
89*1b481fc3SMaciej Żenczykowski 
90*1b481fc3SMaciej Żenczykowski 			child_off = (const char *)child - (const char *)attr;
91*1b481fc3SMaciej Żenczykowski 			ret = pretty_print_attr(child,
92*1b481fc3SMaciej Żenczykowski 						adesc ? adesc->children : NULL,
93*1b481fc3SMaciej Żenczykowski 						adesc ? adesc->n_children : 0,
94*1b481fc3SMaciej Żenczykowski 						level + 1,
95*1b481fc3SMaciej Żenczykowski 						err_offset - child_off, array);
96*1b481fc3SMaciej Żenczykowski 			if (ret < 0)
97*1b481fc3SMaciej Żenczykowski 				break;
98*1b481fc3SMaciej Żenczykowski 		}
99*1b481fc3SMaciej Żenczykowski 
100*1b481fc3SMaciej Żenczykowski 		return ret;
101*1b481fc3SMaciej Żenczykowski 	}
102*1b481fc3SMaciej Żenczykowski 
103*1b481fc3SMaciej Żenczykowski 	printf(" = ");
104*1b481fc3SMaciej Żenczykowski 	switch(adesc ? adesc->format : NLA_BINARY) {
105*1b481fc3SMaciej Żenczykowski 	case NLA_U8:
106*1b481fc3SMaciej Żenczykowski 		printf("%u", mnl_attr_get_u8(attr));
107*1b481fc3SMaciej Żenczykowski 		break;
108*1b481fc3SMaciej Żenczykowski 	case NLA_U16:
109*1b481fc3SMaciej Żenczykowski 		printf("%u", mnl_attr_get_u16(attr));
110*1b481fc3SMaciej Żenczykowski 		break;
111*1b481fc3SMaciej Żenczykowski 	case NLA_U32:
112*1b481fc3SMaciej Żenczykowski 		printf("%u", mnl_attr_get_u32(attr));
113*1b481fc3SMaciej Żenczykowski 		break;
114*1b481fc3SMaciej Żenczykowski 	case NLA_U64:
115*1b481fc3SMaciej Żenczykowski 		printf("%" PRIu64, mnl_attr_get_u64(attr));
116*1b481fc3SMaciej Żenczykowski 		break;
117*1b481fc3SMaciej Żenczykowski 	case NLA_X8:
118*1b481fc3SMaciej Żenczykowski 		printf("0x%02x", mnl_attr_get_u8(attr));
119*1b481fc3SMaciej Żenczykowski 		break;
120*1b481fc3SMaciej Żenczykowski 	case NLA_X16:
121*1b481fc3SMaciej Żenczykowski 		printf("0x%04x", mnl_attr_get_u16(attr));
122*1b481fc3SMaciej Żenczykowski 		break;
123*1b481fc3SMaciej Żenczykowski 	case NLA_X32:
124*1b481fc3SMaciej Żenczykowski 		printf("0x%08x", mnl_attr_get_u32(attr));
125*1b481fc3SMaciej Żenczykowski 		break;
126*1b481fc3SMaciej Żenczykowski 	case NLA_X64:
127*1b481fc3SMaciej Żenczykowski 		printf("%" PRIx64, mnl_attr_get_u64(attr));
128*1b481fc3SMaciej Żenczykowski 		break;
129*1b481fc3SMaciej Żenczykowski 	case NLA_S8:
130*1b481fc3SMaciej Żenczykowski 		printf("%d", (int)mnl_attr_get_u8(attr));
131*1b481fc3SMaciej Żenczykowski 		break;
132*1b481fc3SMaciej Żenczykowski 	case NLA_S16:
133*1b481fc3SMaciej Żenczykowski 		printf("%d", (int)mnl_attr_get_u16(attr));
134*1b481fc3SMaciej Żenczykowski 		break;
135*1b481fc3SMaciej Żenczykowski 	case NLA_S32:
136*1b481fc3SMaciej Żenczykowski 		printf("%d", (int)mnl_attr_get_u32(attr));
137*1b481fc3SMaciej Żenczykowski 		break;
138*1b481fc3SMaciej Żenczykowski 	case NLA_S64:
139*1b481fc3SMaciej Żenczykowski 		printf("%" PRId64, (int64_t)mnl_attr_get_u64(attr));
140*1b481fc3SMaciej Żenczykowski 		break;
141*1b481fc3SMaciej Żenczykowski 	case NLA_STRING:
142*1b481fc3SMaciej Żenczykowski 		printf("\"%.*s\"", alen, (const char *)adata);
143*1b481fc3SMaciej Żenczykowski 		break;
144*1b481fc3SMaciej Żenczykowski 	case NLA_FLAG:
145*1b481fc3SMaciej Żenczykowski 		printf("true");
146*1b481fc3SMaciej Żenczykowski 		break;
147*1b481fc3SMaciej Żenczykowski 	case NLA_BOOL:
148*1b481fc3SMaciej Żenczykowski 		printf("%s", mnl_attr_get_u8(attr) ? "on" : "off");
149*1b481fc3SMaciej Żenczykowski 		break;
150*1b481fc3SMaciej Żenczykowski 	case NLA_U8_ENUM:
151*1b481fc3SMaciej Żenczykowski 	case NLA_U32_ENUM: {
152*1b481fc3SMaciej Żenczykowski 		uint32_t val;
153*1b481fc3SMaciej Żenczykowski 
154*1b481fc3SMaciej Żenczykowski 		if (adesc->format == NLA_U8_ENUM)
155*1b481fc3SMaciej Żenczykowski 			val = mnl_attr_get_u8(attr);
156*1b481fc3SMaciej Żenczykowski 		else
157*1b481fc3SMaciej Żenczykowski 			val = mnl_attr_get_u32(attr);
158*1b481fc3SMaciej Żenczykowski 
159*1b481fc3SMaciej Żenczykowski 		if (adesc && val < adesc->n_names && adesc->names[val])
160*1b481fc3SMaciej Żenczykowski 			printf("%s", adesc->names[val]);
161*1b481fc3SMaciej Żenczykowski 		else
162*1b481fc3SMaciej Żenczykowski 			printf("%u", val);
163*1b481fc3SMaciej Żenczykowski 		break;
164*1b481fc3SMaciej Żenczykowski 	}
165*1b481fc3SMaciej Żenczykowski 	default:
166*1b481fc3SMaciej Żenczykowski 		if (alen <= __DUMP_LINE)
167*1b481fc3SMaciej Żenczykowski 			__print_binary_short(adata, alen);
168*1b481fc3SMaciej Żenczykowski 		else
169*1b481fc3SMaciej Żenczykowski 			__print_binary_long(adata, alen, level);
170*1b481fc3SMaciej Żenczykowski 	}
171*1b481fc3SMaciej Żenczykowski 	putchar('\n');
172*1b481fc3SMaciej Żenczykowski 
173*1b481fc3SMaciej Żenczykowski 	return 0;
174*1b481fc3SMaciej Żenczykowski }
175*1b481fc3SMaciej Żenczykowski 
pretty_print_nlmsg(const struct nlmsghdr * nlhdr,unsigned int payload_offset,const struct pretty_nla_desc * desc,unsigned int ndesc,unsigned int err_offset)176*1b481fc3SMaciej Żenczykowski static int pretty_print_nlmsg(const struct nlmsghdr *nlhdr,
177*1b481fc3SMaciej Żenczykowski 			      unsigned int payload_offset,
178*1b481fc3SMaciej Żenczykowski 			      const struct pretty_nla_desc *desc,
179*1b481fc3SMaciej Żenczykowski 			      unsigned int ndesc, unsigned int err_offset)
180*1b481fc3SMaciej Żenczykowski {
181*1b481fc3SMaciej Żenczykowski 	const struct nlattr *attr;
182*1b481fc3SMaciej Żenczykowski 	int attr_offset;
183*1b481fc3SMaciej Żenczykowski 	int ret;
184*1b481fc3SMaciej Żenczykowski 
185*1b481fc3SMaciej Żenczykowski 	mnl_attr_for_each(attr, nlhdr, payload_offset) {
186*1b481fc3SMaciej Żenczykowski 		attr_offset = (const char *)attr - (const char *)nlhdr;
187*1b481fc3SMaciej Żenczykowski 		ret = pretty_print_attr(attr, desc, ndesc, 1,
188*1b481fc3SMaciej Żenczykowski 					err_offset - attr_offset, false);
189*1b481fc3SMaciej Żenczykowski 		if (ret < 0)
190*1b481fc3SMaciej Żenczykowski 			return ret;
191*1b481fc3SMaciej Żenczykowski 	}
192*1b481fc3SMaciej Żenczykowski 
193*1b481fc3SMaciej Żenczykowski 	return 0;
194*1b481fc3SMaciej Żenczykowski }
195*1b481fc3SMaciej Żenczykowski 
pretty_print_genlmsg(const struct nlmsghdr * nlhdr,const struct pretty_nlmsg_desc * desc,unsigned int ndesc,unsigned int err_offset)196*1b481fc3SMaciej Żenczykowski int pretty_print_genlmsg(const struct nlmsghdr *nlhdr,
197*1b481fc3SMaciej Żenczykowski 			 const struct pretty_nlmsg_desc *desc,
198*1b481fc3SMaciej Żenczykowski 			 unsigned int ndesc, unsigned int err_offset)
199*1b481fc3SMaciej Żenczykowski {
200*1b481fc3SMaciej Żenczykowski 	const struct pretty_nlmsg_desc *msg_desc;
201*1b481fc3SMaciej Żenczykowski 	const struct genlmsghdr *genlhdr;
202*1b481fc3SMaciej Żenczykowski 
203*1b481fc3SMaciej Żenczykowski 	if (mnl_nlmsg_get_payload_len(nlhdr) < GENL_HDRLEN) {
204*1b481fc3SMaciej Żenczykowski 		fprintf(stderr, "ethtool: message too short (%u bytes)\n",
205*1b481fc3SMaciej Żenczykowski 			nlhdr->nlmsg_len);
206*1b481fc3SMaciej Żenczykowski 		return -EINVAL;
207*1b481fc3SMaciej Żenczykowski 	}
208*1b481fc3SMaciej Żenczykowski 	genlhdr = mnl_nlmsg_get_payload(nlhdr);
209*1b481fc3SMaciej Żenczykowski 	msg_desc = (desc && genlhdr->cmd < ndesc) ? &desc[genlhdr->cmd] : NULL;
210*1b481fc3SMaciej Żenczykowski 	if (msg_desc && msg_desc->name)
211*1b481fc3SMaciej Żenczykowski 		printf("    %s\n", msg_desc->name);
212*1b481fc3SMaciej Żenczykowski 	else
213*1b481fc3SMaciej Żenczykowski 		printf("    [%u]\n", genlhdr->cmd);
214*1b481fc3SMaciej Żenczykowski 
215*1b481fc3SMaciej Żenczykowski 	return pretty_print_nlmsg(nlhdr, GENL_HDRLEN,
216*1b481fc3SMaciej Żenczykowski 				  msg_desc ? msg_desc->attrs : NULL,
217*1b481fc3SMaciej Żenczykowski 				  msg_desc ? msg_desc->n_attrs : 0, err_offset);
218*1b481fc3SMaciej Żenczykowski }
219*1b481fc3SMaciej Żenczykowski 
rtm_link_summary(const struct ifinfomsg * ifinfo)220*1b481fc3SMaciej Żenczykowski static void rtm_link_summary(const struct ifinfomsg *ifinfo)
221*1b481fc3SMaciej Żenczykowski {
222*1b481fc3SMaciej Żenczykowski 	if (ifinfo->ifi_family)
223*1b481fc3SMaciej Żenczykowski 		printf(" family=%u", ifinfo->ifi_family);
224*1b481fc3SMaciej Żenczykowski 	if (ifinfo->ifi_type)
225*1b481fc3SMaciej Żenczykowski 		printf(" type=0x%04x", ifinfo->ifi_type);
226*1b481fc3SMaciej Żenczykowski 	if (ifinfo->ifi_index)
227*1b481fc3SMaciej Żenczykowski 		printf(" ifindex=%d", ifinfo->ifi_index);
228*1b481fc3SMaciej Żenczykowski 	if (ifinfo->ifi_flags)
229*1b481fc3SMaciej Żenczykowski 		printf(" flags=0x%x", ifinfo->ifi_flags);
230*1b481fc3SMaciej Żenczykowski 	if (ifinfo->ifi_change)
231*1b481fc3SMaciej Żenczykowski 		printf(" change=0x%x", ifinfo->ifi_change);
232*1b481fc3SMaciej Żenczykowski }
233*1b481fc3SMaciej Żenczykowski 
pretty_print_rtnlmsg(const struct nlmsghdr * nlhdr,unsigned int err_offset)234*1b481fc3SMaciej Żenczykowski int pretty_print_rtnlmsg(const struct nlmsghdr *nlhdr, unsigned int err_offset)
235*1b481fc3SMaciej Żenczykowski {
236*1b481fc3SMaciej Żenczykowski 	const unsigned int idx = (nlhdr->nlmsg_type - RTM_BASE) / 4;
237*1b481fc3SMaciej Żenczykowski 	const struct pretty_nlmsg_desc *msg_desc = NULL;
238*1b481fc3SMaciej Żenczykowski 	unsigned int hdrlen = USHRT_MAX;
239*1b481fc3SMaciej Żenczykowski 
240*1b481fc3SMaciej Żenczykowski 	if (nlhdr->nlmsg_type < rtnl_msg_n_desc)
241*1b481fc3SMaciej Żenczykowski 		msg_desc = &rtnl_msg_desc[nlhdr->nlmsg_type];
242*1b481fc3SMaciej Żenczykowski 	if (idx < rtnl_msghdr_n_len)
243*1b481fc3SMaciej Żenczykowski 		hdrlen = rtnl_msghdr_lengths[idx];
244*1b481fc3SMaciej Żenczykowski 	if (hdrlen < USHRT_MAX && mnl_nlmsg_get_payload_len(nlhdr) < hdrlen) {
245*1b481fc3SMaciej Żenczykowski 		fprintf(stderr, "ethtool: message too short (%u bytes)\n",
246*1b481fc3SMaciej Żenczykowski 			nlhdr->nlmsg_len);
247*1b481fc3SMaciej Żenczykowski 		return -EINVAL;
248*1b481fc3SMaciej Żenczykowski 	}
249*1b481fc3SMaciej Żenczykowski 	if (msg_desc && msg_desc->name)
250*1b481fc3SMaciej Żenczykowski 		printf("    %s", msg_desc->name);
251*1b481fc3SMaciej Żenczykowski 	else
252*1b481fc3SMaciej Żenczykowski 		printf("    [%u]", nlhdr->nlmsg_type);
253*1b481fc3SMaciej Żenczykowski 	if (idx == (RTM_NEWLINK - RTM_BASE) / 4)
254*1b481fc3SMaciej Żenczykowski 		rtm_link_summary(mnl_nlmsg_get_payload(nlhdr));
255*1b481fc3SMaciej Żenczykowski 	putchar('\n');
256*1b481fc3SMaciej Żenczykowski 	if (hdrlen == USHRT_MAX)
257*1b481fc3SMaciej Żenczykowski 		return 0;
258*1b481fc3SMaciej Żenczykowski 
259*1b481fc3SMaciej Żenczykowski 	return pretty_print_nlmsg(nlhdr, hdrlen,
260*1b481fc3SMaciej Żenczykowski 				  msg_desc ? msg_desc->attrs : NULL,
261*1b481fc3SMaciej Żenczykowski 				  msg_desc ? msg_desc->n_attrs : 0, err_offset);
262*1b481fc3SMaciej Żenczykowski }
263