]> granicus.if.org Git - strace/blob - netlink_sock_diag.c
Intorduce PRINT_FIELD_NET_PORT
[strace] / netlink_sock_diag.c
1 /*
2  * Copyright (c) 2016 Fabien Siron <fabien.siron@epita.fr>
3  * Copyright (c) 2017 JingPiao Chen <chenjingpiao@gmail.com>
4  * Copyright (c) 2017 The strace developers.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. The name of the author may not be used to endorse or promote products
16  *    derived from this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29
30 #include "defs.h"
31 #include "netlink.h"
32 #include "nlattr.h"
33 #include "print_fields.h"
34
35 #include <arpa/inet.h>
36 #include <linux/filter.h>
37
38 #include <linux/inet_diag.h>
39 #include <linux/netlink_diag.h>
40 #include <linux/packet_diag.h>
41 #ifdef AF_SMC
42 # include <linux/smc_diag.h>
43 #endif
44 #include <linux/sock_diag.h>
45 #include <linux/unix_diag.h>
46
47 #include "xlat/inet_diag_attrs.h"
48 #include "xlat/inet_diag_extended_flags.h"
49 #include "xlat/inet_diag_req_attrs.h"
50
51 #include "xlat/tcp_states.h"
52 #include "xlat/tcp_state_flags.h"
53
54 #include "xlat/netlink_diag_attrs.h"
55 #include "xlat/netlink_diag_show.h"
56 #include "xlat/netlink_socket_flags.h"
57 #include "xlat/netlink_states.h"
58
59 #include "xlat/packet_diag_attrs.h"
60 #include "xlat/packet_diag_info_flags.h"
61 #include "xlat/packet_diag_show.h"
62
63 #ifdef AF_SMC
64 # include "xlat/smc_diag_attrs.h"
65 # include "xlat/smc_diag_extended_flags.h"
66 # include "xlat/smc_states.h"
67 #endif
68
69 #include "xlat/unix_diag_attrs.h"
70 #include "xlat/unix_diag_show.h"
71
72 static void
73 decode_family(struct tcb *const tcp, const uint8_t family,
74               const kernel_ulong_t addr, const kernel_ulong_t len)
75 {
76         tprints("{family=");
77         printxval(addrfams, family, "AF_???");
78         if (len > sizeof(family)) {
79                 tprints(", ");
80                 printstr_ex(tcp, addr + sizeof(family),
81                             len - sizeof(family), QUOTE_FORCE_HEX);
82         }
83         tprints("}");
84 }
85
86 static void
87 decode_unix_diag_req(struct tcb *const tcp,
88                      const struct nlmsghdr *const nlmsghdr,
89                      const uint8_t family,
90                      const kernel_ulong_t addr,
91                      const kernel_ulong_t len)
92 {
93         struct unix_diag_req req = { .sdiag_family = family };
94         const size_t offset = sizeof(req.sdiag_family);
95
96         PRINT_FIELD_XVAL("{", req, sdiag_family, addrfams, "AF_???");
97         tprints(", ");
98         if (len >= sizeof(req)) {
99                 if (!umoven_or_printaddr(tcp, addr + offset,
100                                          sizeof(req) - offset,
101                                          (void *) &req + offset)) {
102                         PRINT_FIELD_U("", req, sdiag_protocol);
103                         PRINT_FIELD_FLAGS(", ", req, udiag_states,
104                                           tcp_state_flags, "1<<TCP_???");
105                         PRINT_FIELD_U(", ", req, udiag_ino);
106                         PRINT_FIELD_FLAGS(", ", req, udiag_show,
107                                           unix_diag_show, "UDIAG_SHOW_???");
108                         PRINT_FIELD_COOKIE(", ", req, udiag_cookie);
109                 }
110         } else
111                 tprints("...");
112         tprints("}");
113 }
114
115 static bool
116 print_meminfo(struct tcb *const tcp,
117               void *const elem_buf,
118               const size_t elem_size,
119               void *const opaque_data)
120 {
121         tprintf("%" PRIu32, *(uint32_t *) elem_buf);
122
123         return true;
124 }
125
126 static bool
127 decode_meminfo(struct tcb *const tcp,
128                const kernel_ulong_t addr,
129                const kernel_ulong_t len,
130                const void *const opaque_data)
131 {
132         uint32_t mem;
133         size_t nmemb = len / sizeof(mem);
134
135         if (!nmemb)
136                 return false;
137
138         if (nmemb > SK_MEMINFO_VARS)
139                 nmemb = SK_MEMINFO_VARS;
140
141         print_array(tcp, addr, nmemb, &mem, sizeof(mem),
142                     umoven_or_printaddr, print_meminfo, 0);
143
144         return true;
145 }
146
147 static bool
148 decode_unix_diag_vfs(struct tcb *const tcp,
149                      const kernel_ulong_t addr,
150                      const kernel_ulong_t len,
151                      const void *const opaque_data)
152 {
153         struct unix_diag_vfs uv;
154
155         if (len < sizeof(uv))
156                 return false;
157         if (umove_or_printaddr(tcp, addr, &uv))
158                 return true;
159
160         tprints("{udiag_vfs_dev=");
161         print_dev_t(uv.udiag_vfs_dev);
162         PRINT_FIELD_U(", ", uv, udiag_vfs_ino);
163         tprints("}");
164
165         return true;
166 }
167
168 static bool
169 print_inode(struct tcb *const tcp,
170             void *const elem_buf,
171             const size_t elem_size,
172             void *const opaque_data)
173 {
174         tprintf("%" PRIu32, *(uint32_t *) elem_buf);
175
176         return true;
177 }
178
179 static bool
180 decode_unix_diag_inode(struct tcb *const tcp,
181                        const kernel_ulong_t addr,
182                        const kernel_ulong_t len,
183                        const void *const opaque_data)
184 {
185         uint32_t inode;
186         const size_t nmemb = len / sizeof(inode);
187
188         if (!nmemb)
189                 return false;
190
191         print_array(tcp, addr, nmemb, &inode, sizeof(inode),
192                     umoven_or_printaddr, print_inode, 0);
193
194         return true;
195 }
196
197 static bool
198 decode_unix_diag_rqlen(struct tcb *const tcp,
199                        const kernel_ulong_t addr,
200                        const kernel_ulong_t len,
201                        const void *const opaque_data)
202 {
203         struct unix_diag_rqlen rql;
204
205         if (len < sizeof(rql))
206                 return false;
207         if (umove_or_printaddr(tcp, addr, &rql))
208                 return true;
209
210         PRINT_FIELD_U("{", rql, udiag_rqueue);
211         PRINT_FIELD_U(", ", rql, udiag_wqueue);
212         tprints("}");
213
214         return true;
215 }
216
217 static const nla_decoder_t unix_diag_msg_nla_decoders[] = {
218         [UNIX_DIAG_NAME]        = decode_nla_str,
219         [UNIX_DIAG_VFS]         = decode_unix_diag_vfs,
220         [UNIX_DIAG_PEER]        = decode_nla_u32,
221         [UNIX_DIAG_ICONS]       = decode_unix_diag_inode,
222         [UNIX_DIAG_RQLEN]       = decode_unix_diag_rqlen,
223         [UNIX_DIAG_MEMINFO]     = decode_meminfo,
224         [UNIX_DIAG_SHUTDOWN]    = decode_nla_u8
225 };
226
227 static void
228 decode_unix_diag_msg(struct tcb *const tcp,
229                      const struct nlmsghdr *const nlmsghdr,
230                      const uint8_t family,
231                      const kernel_ulong_t addr,
232                      const kernel_ulong_t len)
233 {
234         struct unix_diag_msg msg = { .udiag_family = family };
235         size_t offset = sizeof(msg.udiag_family);
236         bool decode_nla = false;
237
238         PRINT_FIELD_XVAL("{", msg, udiag_family, addrfams, "AF_???");
239         tprints(", ");
240         if (len >= sizeof(msg)) {
241                 if (!umoven_or_printaddr(tcp, addr + offset,
242                                          sizeof(msg) - offset,
243                                          (void *) &msg + offset)) {
244                         PRINT_FIELD_XVAL("", msg, udiag_type,
245                                          socktypes, "SOCK_???");
246                         PRINT_FIELD_XVAL(", ", msg, udiag_state,
247                                          tcp_states, "TCP_???");
248                         PRINT_FIELD_U(", ", msg, udiag_ino);
249                         PRINT_FIELD_COOKIE(", ", msg, udiag_cookie);
250                         decode_nla = true;
251                 }
252         } else
253                 tprints("...");
254         tprints("}");
255
256         offset = NLMSG_ALIGN(sizeof(msg));
257         if (decode_nla && len > offset) {
258                 tprints(", ");
259                 decode_nlattr(tcp, addr + offset, len - offset,
260                               unix_diag_attrs, "UNIX_DIAG_???",
261                               unix_diag_msg_nla_decoders,
262                               ARRAY_SIZE(unix_diag_msg_nla_decoders), NULL);
263         }
264 }
265
266 static void
267 decode_netlink_diag_req(struct tcb *const tcp,
268                         const struct nlmsghdr *const nlmsghdr,
269                         const uint8_t family,
270                         const kernel_ulong_t addr,
271                         const kernel_ulong_t len)
272 {
273         struct netlink_diag_req req = { .sdiag_family = family };
274         const size_t offset = sizeof(req.sdiag_family);
275
276         PRINT_FIELD_XVAL("{", req, sdiag_family, addrfams, "AF_???");
277         tprints(", ");
278         if (len >= sizeof(req)) {
279                 if (!umoven_or_printaddr(tcp, addr + offset,
280                                          sizeof(req) - offset,
281                                          (void *) &req + offset)) {
282                         if (NDIAG_PROTO_ALL == req.sdiag_protocol)
283                                 tprintf("%s=%s",
284                                         "sdiag_protocol", "NDIAG_PROTO_ALL");
285                         else
286                                 PRINT_FIELD_XVAL("", req, sdiag_protocol,
287                                                  netlink_protocols,
288                                                  "NETLINK_???");
289                         PRINT_FIELD_U(", ", req, ndiag_ino);
290                         PRINT_FIELD_FLAGS(", ", req, ndiag_show,
291                                           netlink_diag_show, "NDIAG_SHOW_???");
292                         PRINT_FIELD_COOKIE(", ", req, ndiag_cookie);
293                 }
294         } else
295                 tprints("...");
296         tprints("}");
297 }
298
299 static bool
300 print_group(struct tcb *const tcp,
301             void *const elem_buf,
302             const size_t elem_size,
303             void *const opaque_data)
304 {
305         if (elem_size < sizeof(kernel_ulong_t))
306                 tprintf("%#0*x", (int) elem_size * 2 + 2,
307                         *(unsigned int *) elem_buf);
308         else
309                 tprintf("%#0*" PRI_klx, (int) elem_size * 2 + 2,
310                         *(kernel_ulong_t *) elem_buf);
311
312         return true;
313 }
314
315 static bool
316 decode_netlink_diag_groups(struct tcb *const tcp,
317                            const kernel_ulong_t addr,
318                            const kernel_ulong_t len,
319                            const void *const opaque_data)
320 {
321         kernel_ulong_t buf;
322         const size_t nmemb = len / current_wordsize;
323
324         if (!nmemb)
325                 return false;
326
327         print_array(tcp, addr, nmemb, &buf, current_wordsize,
328                     umoven_or_printaddr, print_group, 0);
329
330         return true;
331 }
332
333 static bool
334 decode_netlink_diag_ring(struct tcb *const tcp,
335                          const kernel_ulong_t addr,
336                          const kernel_ulong_t len,
337                          const void *const opaque_data)
338 {
339         struct netlink_diag_ring ndr;
340
341         if (len < sizeof(ndr))
342                 return false;
343         if (umove_or_printaddr(tcp, addr, &ndr))
344                 return true;
345
346         PRINT_FIELD_U("{", ndr, ndr_block_size);
347         PRINT_FIELD_U(", ", ndr, ndr_block_nr);
348         PRINT_FIELD_U(", ", ndr, ndr_frame_size);
349         PRINT_FIELD_U(", ", ndr, ndr_frame_nr);
350         tprints("}");
351
352         return true;
353 }
354
355 static bool
356 decode_netlink_diag_flags(struct tcb *const tcp,
357                           const kernel_ulong_t addr,
358                           const kernel_ulong_t len,
359                           const void *const opaque_data)
360 {
361         uint32_t flags;
362
363         if (len < sizeof(flags))
364                 return false;
365         if (umove_or_printaddr(tcp, addr, &flags))
366                 return true;
367
368         printflags(netlink_socket_flags, flags, "NDIAG_FLAG_???");
369
370         return true;
371 }
372
373 static const nla_decoder_t netlink_diag_msg_nla_decoders[] = {
374         [NETLINK_DIAG_MEMINFO]  = decode_meminfo,
375         [NETLINK_DIAG_GROUPS]   = decode_netlink_diag_groups,
376         [NETLINK_DIAG_RX_RING]  = decode_netlink_diag_ring,
377         [NETLINK_DIAG_TX_RING]  = decode_netlink_diag_ring,
378         [NETLINK_DIAG_FLAGS]    = decode_netlink_diag_flags
379 };
380
381 static void
382 decode_netlink_diag_msg(struct tcb *const tcp,
383                         const struct nlmsghdr *const nlmsghdr,
384                         const uint8_t family,
385                         const kernel_ulong_t addr,
386                         const kernel_ulong_t len)
387 {
388         struct netlink_diag_msg msg = { .ndiag_family = family };
389         size_t offset = sizeof(msg.ndiag_family);
390         bool decode_nla = false;
391
392         PRINT_FIELD_XVAL("{", msg, ndiag_family, addrfams, "AF_???");
393         tprints(", ");
394         if (len >= sizeof(msg)) {
395                 if (!umoven_or_printaddr(tcp, addr + offset,
396                                          sizeof(msg) - offset,
397                                          (void *) &msg + offset)) {
398                         PRINT_FIELD_XVAL("", msg, ndiag_type,
399                                          socktypes, "SOCK_???");
400                         PRINT_FIELD_XVAL(", ", msg, ndiag_protocol,
401                                          netlink_protocols, "NETLINK_???");
402                         PRINT_FIELD_XVAL(", ", msg, ndiag_state,
403                                          netlink_states, "NETLINK_???");
404                         PRINT_FIELD_U(", ", msg, ndiag_portid);
405                         PRINT_FIELD_U(", ", msg, ndiag_dst_portid);
406                         PRINT_FIELD_U(", ", msg, ndiag_dst_group);
407                         PRINT_FIELD_U(", ", msg, ndiag_ino);
408                         PRINT_FIELD_COOKIE(", ", msg, ndiag_cookie);
409                         decode_nla = true;
410                 }
411         } else
412                 tprints("...");
413         tprints("}");
414
415         offset = NLA_ALIGN(sizeof(msg));
416         if (decode_nla && len > offset) {
417                 tprints(", ");
418                 decode_nlattr(tcp, addr + offset, len - offset,
419                               netlink_diag_attrs, "NETLINK_DIAG_???",
420                               netlink_diag_msg_nla_decoders,
421                               ARRAY_SIZE(netlink_diag_msg_nla_decoders), NULL);
422         }
423 }
424
425 static void
426 decode_packet_diag_req(struct tcb *const tcp,
427                        const struct nlmsghdr *const nlmsghdr,
428                        const uint8_t family,
429                        const kernel_ulong_t addr,
430                        const kernel_ulong_t len)
431 {
432         struct packet_diag_req req = { .sdiag_family = family };
433         const size_t offset = sizeof(req.sdiag_family);
434
435         PRINT_FIELD_XVAL("{", req, sdiag_family, addrfams, "AF_???");
436         tprints(", ");
437         if (len >= sizeof(req)) {
438                 if (!umoven_or_printaddr(tcp, addr + offset,
439                                          sizeof(req) - offset,
440                                          (void *) &req + offset)) {
441                         PRINT_FIELD_XVAL("", req, sdiag_protocol,
442                                          ethernet_protocols, "ETH_P_???");
443                         PRINT_FIELD_U(", ", req, pdiag_ino);
444                         PRINT_FIELD_FLAGS(", ", req, pdiag_show,
445                                           packet_diag_show, "PACKET_SHOW_???");
446                         PRINT_FIELD_COOKIE(", ", req, pdiag_cookie);
447                 }
448         } else
449                 tprints("...");
450         tprints("}");
451 }
452
453 static bool
454 decode_packet_diag_info(struct tcb *const tcp,
455                         const kernel_ulong_t addr,
456                         const kernel_ulong_t len,
457                         const void *const opaque_data)
458 {
459         struct packet_diag_info pinfo;
460
461         if (len < sizeof(pinfo))
462                 return false;
463         if (umove_or_printaddr(tcp, addr, &pinfo))
464                 return true;
465
466         PRINT_FIELD_U("{", pinfo, pdi_index);
467         PRINT_FIELD_U(", ", pinfo, pdi_version);
468         PRINT_FIELD_U(", ", pinfo, pdi_reserve);
469         PRINT_FIELD_U(", ", pinfo, pdi_copy_thresh);
470         PRINT_FIELD_U(", ", pinfo, pdi_tstamp);
471         PRINT_FIELD_FLAGS(", ", pinfo, pdi_flags,
472                           packet_diag_info_flags, "PDI_???");
473         tprints("}");
474
475         return true;
476 }
477
478 static bool
479 print_packet_diag_mclist(struct tcb *const tcp, void *const elem_buf,
480                          const size_t elem_size, void *const opaque_data)
481 {
482         struct packet_diag_mclist *dml = elem_buf;
483         uint16_t alen = dml->pdmc_alen > sizeof(dml->pdmc_addr) ?
484                 sizeof(dml->pdmc_addr) : dml->pdmc_alen;
485
486         PRINT_FIELD_IFINDEX("{", *dml, pdmc_index);
487         PRINT_FIELD_U(", ", *dml, pdmc_count);
488         PRINT_FIELD_U(", ", *dml, pdmc_type);
489         PRINT_FIELD_U(", ", *dml, pdmc_alen);
490         PRINT_FIELD_QUOTED_STRING(", ", *dml, pdmc_addr, alen, QUOTE_FORCE_HEX);
491         tprints("}");
492
493         return true;
494 }
495
496 static bool
497 decode_packet_diag_mclist(struct tcb *const tcp,
498                           const kernel_ulong_t addr,
499                           const kernel_ulong_t len,
500                           const void *const opaque_data)
501 {
502         struct packet_diag_mclist dml;
503         const size_t nmemb = len / sizeof(dml);
504
505         if (!nmemb)
506                 return false;
507
508         print_array(tcp, addr, nmemb, &dml, sizeof(dml),
509                     umoven_or_printaddr, print_packet_diag_mclist, 0);
510
511         return true;
512 }
513
514 static bool
515 decode_packet_diag_ring(struct tcb *const tcp,
516                         const kernel_ulong_t addr,
517                         const kernel_ulong_t len,
518                         const void *const opaque_data)
519 {
520         struct packet_diag_ring pdr;
521
522         if (len < sizeof(pdr))
523                 return false;
524         if (umove_or_printaddr(tcp, addr, &pdr))
525                 return true;
526
527         PRINT_FIELD_U("{", pdr, pdr_block_size);
528         PRINT_FIELD_U(", ", pdr, pdr_block_nr);
529         PRINT_FIELD_U(", ", pdr, pdr_frame_size);
530         PRINT_FIELD_U(", ", pdr, pdr_frame_nr);
531         PRINT_FIELD_U(", ", pdr, pdr_retire_tmo);
532         PRINT_FIELD_U(", ", pdr, pdr_sizeof_priv);
533         PRINT_FIELD_U(", ", pdr, pdr_features);
534         tprints("}");
535
536         return true;
537 }
538
539 static bool
540 decode_packet_diag_filter(struct tcb *const tcp,
541                           const kernel_ulong_t addr,
542                           const kernel_ulong_t len,
543                           const void *const opaque_data)
544 {
545         const kernel_ulong_t nmemb = len / sizeof(struct sock_filter);
546         if (!nmemb || (unsigned short) nmemb != nmemb)
547                 return false;
548
549         print_sock_fprog(tcp, addr, nmemb);
550
551         return true;
552 }
553
554 static const nla_decoder_t packet_diag_msg_nla_decoders[] = {
555         [PACKET_DIAG_INFO]      = decode_packet_diag_info,
556         [PACKET_DIAG_MCLIST]    = decode_packet_diag_mclist,
557         [PACKET_DIAG_RX_RING]   = decode_packet_diag_ring,
558         [PACKET_DIAG_TX_RING]   = decode_packet_diag_ring,
559         [PACKET_DIAG_FANOUT]    = decode_nla_u32,
560         [PACKET_DIAG_UID]       = decode_nla_u32,
561         [PACKET_DIAG_MEMINFO]   = decode_meminfo,
562         [PACKET_DIAG_FILTER]    = decode_packet_diag_filter
563 };
564
565 static void
566 decode_packet_diag_msg(struct tcb *const tcp,
567                        const struct nlmsghdr *const nlmsghdr,
568                        const uint8_t family,
569                        const kernel_ulong_t addr,
570                        const kernel_ulong_t len)
571 {
572         struct packet_diag_msg msg = { .pdiag_family = family };
573         size_t offset = sizeof(msg.pdiag_family);
574         bool decode_nla = false;
575
576         PRINT_FIELD_XVAL("{", msg, pdiag_family, addrfams, "AF_???");
577         tprints(", ");
578         if (len >= sizeof(msg)) {
579                 if (!umoven_or_printaddr(tcp, addr + offset,
580                                          sizeof(msg) - offset,
581                                          (void *) &msg + offset)) {
582                         PRINT_FIELD_XVAL("", msg, pdiag_type,
583                                          socktypes, "SOCK_???");
584                         PRINT_FIELD_U(", ", msg, pdiag_num);
585                         PRINT_FIELD_U(", ", msg, pdiag_ino);
586                         PRINT_FIELD_COOKIE(", ", msg, pdiag_cookie);
587                         decode_nla = true;
588                 }
589         } else
590                 tprints("...");
591         tprints("}");
592
593         offset = NLA_ALIGN(sizeof(msg));
594         if (decode_nla && len > offset) {
595                 tprints(", ");
596                 decode_nlattr(tcp, addr + offset, len - offset,
597                               packet_diag_attrs, "PACKET_DIAG_???",
598                               packet_diag_msg_nla_decoders,
599                               ARRAY_SIZE(packet_diag_msg_nla_decoders), NULL);
600         }
601 }
602
603 static void
604 print_inet_diag_sockid(const struct inet_diag_sockid *id, const uint8_t family)
605 {
606         PRINT_FIELD_NET_PORT("{", *id, idiag_sport);
607         PRINT_FIELD_NET_PORT(", ", *id, idiag_dport);
608         PRINT_FIELD_INET_ADDR(", ", *id, idiag_src, family);
609         PRINT_FIELD_INET_ADDR(", ", *id, idiag_dst, family);
610         PRINT_FIELD_IFINDEX(", ", *id, idiag_if);
611         PRINT_FIELD_COOKIE(", ", *id, idiag_cookie);
612         tprints("}");
613 }
614
615 static void
616 decode_inet_diag_req_compat(struct tcb *const tcp,
617                             const struct nlmsghdr *const nlmsghdr,
618                             const uint8_t family,
619                             const kernel_ulong_t addr,
620                             const kernel_ulong_t len)
621 {
622         struct inet_diag_req req = { .idiag_family = family };
623         size_t offset = sizeof(req.idiag_family);
624         bool decode_nla = false;
625
626         PRINT_FIELD_XVAL("{", req, idiag_family, addrfams, "AF_???");
627         tprints(", ");
628         if (len >= sizeof(req)) {
629                 if (!umoven_or_printaddr(tcp, addr + offset,
630                                          sizeof(req) - offset,
631                                          (void *) &req + offset)) {
632                         PRINT_FIELD_U("", req, idiag_src_len);
633                         PRINT_FIELD_U(", ", req, idiag_dst_len);
634                         PRINT_FIELD_FLAGS(", ", req, idiag_ext,
635                                           inet_diag_extended_flags,
636                                           "1<<INET_DIAG_\?\?\?-1");
637                         tprints(", id=");
638                         print_inet_diag_sockid(&req.id, req.idiag_family);
639                         PRINT_FIELD_FLAGS(", ", req, idiag_states,
640                                           tcp_state_flags, "1<<TCP_???");
641                         PRINT_FIELD_U(", ", req, idiag_dbs);
642                         decode_nla = true;
643                 }
644         } else
645                 tprints("...");
646         tprints("}");
647
648         offset = NLA_ALIGN(sizeof(req));
649         if (decode_nla && len > offset) {
650                 tprints(", ");
651                 decode_nlattr(tcp, addr + offset, len - offset,
652                               inet_diag_req_attrs, "INET_DIAG_REQ_???",
653                               NULL, 0, NULL);
654         }
655 }
656
657 static void
658 decode_inet_diag_req_v2(struct tcb *const tcp,
659                         const struct nlmsghdr *const nlmsghdr,
660                         const uint8_t family,
661                         const kernel_ulong_t addr,
662                         const kernel_ulong_t len)
663 {
664         struct inet_diag_req_v2 req = { .sdiag_family = family };
665         size_t offset = sizeof(req.sdiag_family);
666         bool decode_nla = false;
667
668         PRINT_FIELD_XVAL("{", req, sdiag_family, addrfams, "AF_???");
669         tprints(", ");
670         if (len >= sizeof(req)) {
671                 if (!umoven_or_printaddr(tcp, addr + offset,
672                                          sizeof(req) - offset,
673                                          (void *) &req + offset)) {
674                         PRINT_FIELD_XVAL("", req, sdiag_protocol,
675                                          inet_protocols, "IPPROTO_???");
676                         PRINT_FIELD_FLAGS(", ", req, idiag_ext,
677                                           inet_diag_extended_flags,
678                                           "1<<INET_DIAG_\?\?\?-1");
679                         PRINT_FIELD_FLAGS(", ", req, idiag_states,
680                                           tcp_state_flags, "1<<TCP_???");
681                         tprints(", id=");
682                         print_inet_diag_sockid(&req.id, req.sdiag_family);
683                         decode_nla = true;
684                 }
685         } else
686                 tprints("...");
687         tprints("}");
688
689         offset = NLA_ALIGN(sizeof(req));
690         if (decode_nla && len > offset) {
691                 tprints(", ");
692                 decode_nlattr(tcp, addr + offset, len - offset,
693                               inet_diag_req_attrs, "INET_DIAG_REQ_???",
694                               NULL, 0, NULL);
695         }
696 }
697
698 static void
699 decode_inet_diag_req(struct tcb *const tcp,
700                      const struct nlmsghdr *const nlmsghdr,
701                      const uint8_t family,
702                      const kernel_ulong_t addr,
703                      const kernel_ulong_t len)
704 {
705         if (nlmsghdr->nlmsg_type == TCPDIAG_GETSOCK
706             || nlmsghdr->nlmsg_type == DCCPDIAG_GETSOCK)
707                 return decode_inet_diag_req_compat(tcp, nlmsghdr,
708                                                    family, addr, len);
709         else
710                 return decode_inet_diag_req_v2(tcp, nlmsghdr,
711                                                family, addr, len);
712 }
713
714 static bool
715 decode_inet_diag_meminfo(struct tcb *const tcp,
716                          const kernel_ulong_t addr,
717                          const kernel_ulong_t len,
718                          const void *const opaque_data)
719 {
720         struct inet_diag_meminfo minfo;
721
722         if (len < sizeof(minfo))
723                 return false;
724         if (umove_or_printaddr(tcp, addr, &minfo))
725                 return true;
726
727         PRINT_FIELD_U("{", minfo, idiag_rmem);
728         PRINT_FIELD_U(", ", minfo, idiag_wmem);
729         PRINT_FIELD_U(", ", minfo, idiag_fmem);
730         PRINT_FIELD_U(", ", minfo, idiag_tmem);
731         tprints("}");
732
733         return true;
734 }
735
736 static bool
737 decode_tcpvegas_info(struct tcb *const tcp,
738                      const kernel_ulong_t addr,
739                      const kernel_ulong_t len,
740                      const void *const opaque_data)
741 {
742         struct tcpvegas_info vegas;
743
744         if (len < sizeof(vegas))
745                 return false;
746         if (umove_or_printaddr(tcp, addr, &vegas))
747                 return true;
748
749         PRINT_FIELD_U("{", vegas, tcpv_enabled);
750         PRINT_FIELD_U(", ", vegas, tcpv_rttcnt);
751         PRINT_FIELD_U(", ", vegas, tcpv_rtt);
752         PRINT_FIELD_U(", ", vegas, tcpv_minrtt);
753         tprints("}");
754
755         return true;
756 }
757
758 static bool
759 decode_tcp_dctcp_info(struct tcb *const tcp,
760                       const kernel_ulong_t addr,
761                       const kernel_ulong_t len,
762                       const void *const opaque_data)
763 {
764         struct tcp_dctcp_info dctcp;
765
766         if (len < sizeof(dctcp))
767                 return false;
768         if (umove_or_printaddr(tcp, addr, &dctcp))
769                 return true;
770
771         PRINT_FIELD_U("{", dctcp, dctcp_enabled);
772         PRINT_FIELD_U(", ", dctcp, dctcp_ce_state);
773         PRINT_FIELD_U(", ", dctcp, dctcp_alpha);
774         PRINT_FIELD_U(", ", dctcp, dctcp_ab_ecn);
775         PRINT_FIELD_U(", ", dctcp, dctcp_ab_tot);
776         tprints("}");
777
778         return true;
779 }
780
781 static bool
782 decode_tcp_bbr_info(struct tcb *const tcp,
783                     const kernel_ulong_t addr,
784                     const kernel_ulong_t len,
785                     const void *const opaque_data)
786 {
787         struct tcp_bbr_info bbr;
788
789         if (len < sizeof(bbr))
790                 return false;
791         if (umove_or_printaddr(tcp, addr, &bbr))
792                 return true;
793
794         PRINT_FIELD_X("{", bbr, bbr_bw_lo);
795         PRINT_FIELD_X(", ", bbr, bbr_bw_hi);
796         PRINT_FIELD_U(", ", bbr, bbr_min_rtt);
797         PRINT_FIELD_U(", ", bbr, bbr_pacing_gain);
798         PRINT_FIELD_U(", ", bbr, bbr_cwnd_gain);
799         tprints("}");
800
801         return true;
802 }
803
804 static const nla_decoder_t inet_diag_msg_nla_decoders[] = {
805         [INET_DIAG_MEMINFO]     = decode_inet_diag_meminfo,
806         [INET_DIAG_INFO]        = NULL,                 /* unimplemented */
807         [INET_DIAG_VEGASINFO]   = decode_tcpvegas_info,
808         [INET_DIAG_CONG]        = decode_nla_str,
809         [INET_DIAG_TOS]         = decode_nla_u8,
810         [INET_DIAG_TCLASS]      = decode_nla_u8,
811         [INET_DIAG_SKMEMINFO]   = decode_meminfo,
812         [INET_DIAG_SHUTDOWN]    = decode_nla_u8,
813         [INET_DIAG_DCTCPINFO]   = decode_tcp_dctcp_info,
814         [INET_DIAG_PROTOCOL]    = decode_nla_u8,
815         [INET_DIAG_SKV6ONLY]    = decode_nla_u8,
816         [INET_DIAG_LOCALS]      = NULL,                 /* unimplemented */
817         [INET_DIAG_PEERS]       = NULL,                 /* unimplemented */
818         [INET_DIAG_PAD]         = NULL,
819         [INET_DIAG_MARK]        = decode_nla_u32,
820         [INET_DIAG_BBRINFO]     = decode_tcp_bbr_info
821 };
822
823 static void
824 decode_inet_diag_msg(struct tcb *const tcp,
825                      const struct nlmsghdr *const nlmsghdr,
826                      const uint8_t family,
827                      const kernel_ulong_t addr,
828                      const kernel_ulong_t len)
829 {
830         struct inet_diag_msg msg = { .idiag_family = family };
831         size_t offset = sizeof(msg.idiag_family);
832         bool decode_nla = false;
833
834         PRINT_FIELD_XVAL("{", msg, idiag_family, addrfams, "AF_???");
835         tprints(", ");
836         if (len >= sizeof(msg)) {
837                 if (!umoven_or_printaddr(tcp, addr + offset,
838                                          sizeof(msg) - offset,
839                                          (void *) &msg + offset)) {
840                         PRINT_FIELD_XVAL("", msg, idiag_state,
841                                          tcp_states, "TCP_???");
842                         PRINT_FIELD_U(", ", msg, idiag_timer);
843                         PRINT_FIELD_U(", ", msg, idiag_retrans);
844                         tprints(", id=");
845                         print_inet_diag_sockid(&msg.id, msg.idiag_family);
846                         PRINT_FIELD_U(", ", msg, idiag_expires);
847                         PRINT_FIELD_U(", ", msg, idiag_rqueue);
848                         PRINT_FIELD_U(", ", msg, idiag_wqueue);
849                         PRINT_FIELD_U(", ", msg, idiag_uid);
850                         PRINT_FIELD_U(", ", msg, idiag_inode);
851                         decode_nla = true;
852                 }
853         } else
854                 tprints("...");
855         tprints("}");
856
857         offset = NLA_ALIGN(sizeof(msg));
858         if (decode_nla && len > offset) {
859                 tprints(", ");
860                 decode_nlattr(tcp, addr + offset, len - offset,
861                               inet_diag_attrs, "INET_DIAG_???",
862                               inet_diag_msg_nla_decoders,
863                               ARRAY_SIZE(inet_diag_msg_nla_decoders), NULL);
864         }
865 }
866
867 #ifdef AF_SMC
868 static void
869 decode_smc_diag_req(struct tcb *const tcp,
870                     const struct nlmsghdr *const nlmsghdr,
871                     const uint8_t family,
872                     const kernel_ulong_t addr,
873                     const kernel_ulong_t len)
874 {
875         struct smc_diag_req req = { .diag_family = family };
876         const size_t offset = sizeof(req.diag_family);
877
878         PRINT_FIELD_XVAL("{", req, diag_family, addrfams, "AF_???");
879         tprints(", ");
880         if (len >= sizeof(req)) {
881                 if (!umoven_or_printaddr(tcp, addr + offset,
882                                          sizeof(req) - offset,
883                                          (void *) &req + offset)) {
884                         PRINT_FIELD_FLAGS("", req, diag_ext,
885                                           smc_diag_extended_flags,
886                                           "1<<SMC_DIAG_\?\?\?-1");
887                         tprints(", id=");
888                         /*
889                          * AF_SMC protocol family socket handler
890                          * keeping the AF_INET sock address.
891                          */
892                         print_inet_diag_sockid(&req.id, AF_INET);
893                 }
894         } else
895                 tprints("...");
896         tprints("}");
897 }
898
899 static void
900 decode_smc_diag_msg(struct tcb *const tcp,
901                     const struct nlmsghdr *const nlmsghdr,
902                     const uint8_t family,
903                     const kernel_ulong_t addr,
904                     const kernel_ulong_t len)
905 {
906         struct smc_diag_msg msg = { .diag_family = family };
907         size_t offset = sizeof(msg.diag_family);
908         bool decode_nla = false;
909
910         PRINT_FIELD_XVAL("{", msg, diag_family, addrfams, "AF_???");
911         tprints(", ");
912         if (len >= sizeof(msg)) {
913                 if (!umoven_or_printaddr(tcp, addr + offset,
914                                          sizeof(msg) - offset,
915                                          (void *) &msg + offset)) {
916                         PRINT_FIELD_XVAL("", msg, diag_state,
917                                          smc_states, "SMC_???");
918                         PRINT_FIELD_U(", ", msg, diag_fallback);
919                         PRINT_FIELD_U(", ", msg, diag_shutdown);
920                         tprints(", id=");
921                         /*
922                          * AF_SMC protocol family socket handler
923                          * keeping the AF_INET sock address.
924                          */
925                         print_inet_diag_sockid(&msg.id, AF_INET);
926                         PRINT_FIELD_U(", ", msg, diag_uid);
927                         PRINT_FIELD_U(", ", msg, diag_inode);
928                         decode_nla = true;
929                 }
930         } else
931                 tprints("...");
932         tprints("}");
933
934         offset = NLA_ALIGN(sizeof(msg));
935         if (decode_nla && len > offset) {
936                 tprints(", ");
937                 decode_nlattr(tcp, addr + offset, len - offset,
938                               smc_diag_attrs, "SMC_DIAG_???",
939                               NULL, 0, NULL);
940         }
941 }
942 #endif
943
944 typedef void (*netlink_diag_decoder_t)(struct tcb *,
945                                        const struct nlmsghdr *,
946                                        uint8_t family,
947                                        kernel_ulong_t addr,
948                                        kernel_ulong_t len);
949
950 static const struct {
951         const netlink_diag_decoder_t request, response;
952 } diag_decoders[] = {
953         [AF_INET] = { decode_inet_diag_req, decode_inet_diag_msg },
954         [AF_INET6] = { decode_inet_diag_req, decode_inet_diag_msg },
955         [AF_NETLINK] = { decode_netlink_diag_req, decode_netlink_diag_msg },
956         [AF_PACKET] = { decode_packet_diag_req, decode_packet_diag_msg },
957 #ifdef AF_SMC
958         [AF_SMC] = { decode_smc_diag_req, decode_smc_diag_msg },
959 #endif
960         [AF_UNIX] = { decode_unix_diag_req, decode_unix_diag_msg }
961 };
962
963 bool
964 decode_netlink_sock_diag(struct tcb *const tcp,
965                          const struct nlmsghdr *const nlmsghdr,
966                          const kernel_ulong_t addr,
967                          const kernel_ulong_t len)
968 {
969         uint8_t family;
970
971         if (nlmsghdr->nlmsg_type == NLMSG_DONE)
972                 return false;
973
974         if (!umove_or_printaddr(tcp, addr, &family)) {
975                 if (family < ARRAY_SIZE(diag_decoders)
976                     && len > sizeof(family)) {
977                         const netlink_diag_decoder_t decoder =
978                                 (nlmsghdr->nlmsg_flags & NLM_F_REQUEST)
979                                 ? diag_decoders[family].request
980                                 : diag_decoders[family].response;
981
982                         if (decoder) {
983                                 decoder(tcp, nlmsghdr, family, addr, len);
984                                 return true;
985                         }
986                 }
987
988                 decode_family(tcp, family, addr, len);
989         }
990
991         return true;
992 }