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