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