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