]> granicus.if.org Git - strace/blob - netlink_sock_diag.c
Introduce generic STRINGIFY and STRINGIFY_VAL macros
[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/inet_diag.h>
37 #include <linux/netlink_diag.h>
38 #include <linux/packet_diag.h>
39 #ifdef AF_SMC
40 # include <linux/smc_diag.h>
41 #endif
42 #include <linux/sock_diag.h>
43 #include <linux/unix_diag.h>
44
45 #include "xlat/inet_diag_attrs.h"
46 #include "xlat/inet_diag_extended_flags.h"
47 #include "xlat/inet_diag_req_attrs.h"
48
49 #include "xlat/tcp_states.h"
50 #include "xlat/tcp_state_flags.h"
51
52 #include "xlat/netlink_diag_attrs.h"
53 #include "xlat/netlink_diag_show.h"
54 #include "xlat/netlink_socket_flags.h"
55 #include "xlat/netlink_states.h"
56
57 #include "xlat/packet_diag_attrs.h"
58 #include "xlat/packet_diag_show.h"
59
60 #ifdef AF_SMC
61 # include "xlat/smc_diag_attrs.h"
62 # include "xlat/smc_diag_extended_flags.h"
63 # include "xlat/smc_states.h"
64 #endif
65
66 #include "xlat/unix_diag_attrs.h"
67 #include "xlat/unix_diag_show.h"
68
69 static void
70 decode_family(struct tcb *const tcp, const uint8_t family,
71               const kernel_ulong_t addr, const kernel_ulong_t len)
72 {
73         tprints("{family=");
74         printxval(addrfams, family, "AF_???");
75         if (len > sizeof(family)) {
76                 tprints(", ");
77                 printstrn(tcp, addr + sizeof(family),
78                           len - sizeof(family));
79         }
80         tprints("}");
81 }
82
83 static void
84 decode_unix_diag_req(struct tcb *const tcp,
85                      const struct nlmsghdr *const nlmsghdr,
86                      const uint8_t family,
87                      const kernel_ulong_t addr,
88                      const kernel_ulong_t len)
89 {
90         struct unix_diag_req req = { .sdiag_family = family };
91         const size_t offset = sizeof(req.sdiag_family);
92
93         PRINT_FIELD_XVAL("{", req, sdiag_family, addrfams, "AF_???");
94         tprints(", ");
95         if (len >= sizeof(req)) {
96                 if (!umoven_or_printaddr(tcp, addr + offset,
97                                          sizeof(req) - offset,
98                                          (void *) &req + offset)) {
99                         PRINT_FIELD_U("", req, sdiag_protocol);
100                         PRINT_FIELD_FLAGS(", ", req, udiag_states,
101                                           tcp_state_flags, "1<<TCP_???");
102                         PRINT_FIELD_U(", ", req, udiag_ino);
103                         PRINT_FIELD_FLAGS(", ", req, udiag_show,
104                                           unix_diag_show, "UDIAG_SHOW_???");
105                         PRINT_FIELD_COOKIE(", ", req, udiag_cookie);
106                 }
107         } else
108                 tprints("...");
109         tprints("}");
110 }
111
112 static bool
113 print_meminfo(struct tcb *const tcp,
114               void *const elem_buf,
115               const size_t elem_size,
116               void *const opaque_data)
117 {
118         tprintf("%" PRIu32, *(uint32_t *) elem_buf);
119
120         return true;
121 }
122
123 static bool
124 decode_meminfo(struct tcb *const tcp,
125                const kernel_ulong_t addr,
126                const kernel_ulong_t len,
127                const void *const opaque_data)
128 {
129         uint32_t mem;
130         size_t nmemb = len / sizeof(mem);
131
132         if (!nmemb)
133                 return false;
134
135         if (nmemb > SK_MEMINFO_VARS)
136                 nmemb = SK_MEMINFO_VARS;
137
138         print_array(tcp, addr, nmemb, &mem, sizeof(mem),
139                     umoven_or_printaddr, print_meminfo, 0);
140
141         return true;
142 }
143
144 static bool
145 decode_unix_diag_vfs(struct tcb *const tcp,
146                      const kernel_ulong_t addr,
147                      const kernel_ulong_t len,
148                      const void *const opaque_data)
149 {
150         struct unix_diag_vfs uv;
151
152         if (len < sizeof(uv))
153                 return false;
154         if (umove_or_printaddr(tcp, addr, &uv))
155                 return true;
156
157         tprints("{udiag_vfs_dev=");
158         print_dev_t(uv.udiag_vfs_dev);
159         PRINT_FIELD_U(", ", uv, udiag_vfs_ino);
160         tprints("}");
161
162         return true;
163 }
164
165 static bool
166 print_inode(struct tcb *const tcp,
167             void *const elem_buf,
168             const size_t elem_size,
169             void *const opaque_data)
170 {
171         tprintf("%" PRIu32, *(uint32_t *) elem_buf);
172
173         return true;
174 }
175
176 static bool
177 decode_unix_diag_inode(struct tcb *const tcp,
178                        const kernel_ulong_t addr,
179                        const kernel_ulong_t len,
180                        const void *const opaque_data)
181 {
182         uint32_t inode;
183         const size_t nmemb = len / sizeof(inode);
184
185         if (!nmemb)
186                 return false;
187
188         print_array(tcp, addr, nmemb, &inode, sizeof(inode),
189                     umoven_or_printaddr, print_inode, 0);
190
191         return true;
192 }
193
194 static bool
195 decode_unix_diag_rqlen(struct tcb *const tcp,
196                        const kernel_ulong_t addr,
197                        const kernel_ulong_t len,
198                        const void *const opaque_data)
199 {
200         struct unix_diag_rqlen rql;
201
202         if (len < sizeof(rql))
203                 return false;
204         if (umove_or_printaddr(tcp, addr, &rql))
205                 return true;
206
207         PRINT_FIELD_U("{", rql, udiag_rqueue);
208         PRINT_FIELD_U(", ", rql, udiag_wqueue);
209         tprints("}");
210
211         return true;
212 }
213
214 static const nla_decoder_t unix_diag_msg_nla_decoders[] = {
215         [UNIX_DIAG_NAME]        = decode_nla_str,
216         [UNIX_DIAG_VFS]         = decode_unix_diag_vfs,
217         [UNIX_DIAG_PEER]        = decode_nla_u32,
218         [UNIX_DIAG_ICONS]       = decode_unix_diag_inode,
219         [UNIX_DIAG_RQLEN]       = decode_unix_diag_rqlen,
220         [UNIX_DIAG_MEMINFO]     = decode_meminfo,
221         [UNIX_DIAG_SHUTDOWN]    = decode_nla_u8
222 };
223
224 static void
225 decode_unix_diag_msg(struct tcb *const tcp,
226                      const struct nlmsghdr *const nlmsghdr,
227                      const uint8_t family,
228                      const kernel_ulong_t addr,
229                      const kernel_ulong_t len)
230 {
231         struct unix_diag_msg msg = { .udiag_family = family };
232         size_t offset = sizeof(msg.udiag_family);
233         bool decode_nla = false;
234
235         PRINT_FIELD_XVAL("{", msg, udiag_family, addrfams, "AF_???");
236         tprints(", ");
237         if (len >= sizeof(msg)) {
238                 if (!umoven_or_printaddr(tcp, addr + offset,
239                                          sizeof(msg) - offset,
240                                          (void *) &msg + offset)) {
241                         PRINT_FIELD_XVAL("", msg, udiag_type,
242                                          socktypes, "SOCK_???");
243                         PRINT_FIELD_XVAL(", ", msg, udiag_state,
244                                          tcp_states, "TCP_???");
245                         PRINT_FIELD_U(", ", msg, udiag_ino);
246                         PRINT_FIELD_COOKIE(", ", msg, udiag_cookie);
247                         decode_nla = true;
248                 }
249         } else
250                 tprints("...");
251         tprints("}");
252
253         offset = NLMSG_ALIGN(sizeof(msg));
254         if (decode_nla && len > offset) {
255                 tprints(", ");
256                 decode_nlattr(tcp, addr + offset, len - offset,
257                               unix_diag_attrs, "UNIX_DIAG_???",
258                               unix_diag_msg_nla_decoders,
259                               ARRAY_SIZE(unix_diag_msg_nla_decoders), NULL);
260         }
261 }
262
263 static void
264 decode_netlink_diag_req(struct tcb *const tcp,
265                         const struct nlmsghdr *const nlmsghdr,
266                         const uint8_t family,
267                         const kernel_ulong_t addr,
268                         const kernel_ulong_t len)
269 {
270         struct netlink_diag_req req = { .sdiag_family = family };
271         const size_t offset = sizeof(req.sdiag_family);
272
273         PRINT_FIELD_XVAL("{", req, sdiag_family, addrfams, "AF_???");
274         tprints(", ");
275         if (len >= sizeof(req)) {
276                 if (!umoven_or_printaddr(tcp, addr + offset,
277                                          sizeof(req) - offset,
278                                          (void *) &req + offset)) {
279                         if (NDIAG_PROTO_ALL == req.sdiag_protocol)
280                                 tprintf("%s=%s",
281                                         "sdiag_protocol", "NDIAG_PROTO_ALL");
282                         else
283                                 PRINT_FIELD_XVAL("", req, sdiag_protocol,
284                                                  netlink_protocols,
285                                                  "NETLINK_???");
286                         PRINT_FIELD_U(", ", req, ndiag_ino);
287                         PRINT_FIELD_FLAGS(", ", req, ndiag_show,
288                                           netlink_diag_show, "NDIAG_SHOW_???");
289                         PRINT_FIELD_COOKIE(", ", req, ndiag_cookie);
290                 }
291         } else
292                 tprints("...");
293         tprints("}");
294 }
295
296 static bool
297 print_group(struct tcb *const tcp,
298             void *const elem_buf,
299             const size_t elem_size,
300             void *const opaque_data)
301 {
302         if (elem_size < sizeof(kernel_ulong_t))
303                 tprintf("%#0*x", (int) elem_size * 2 + 2,
304                         *(unsigned int *) elem_buf);
305         else
306                 tprintf("%#0*" PRI_klx, (int) elem_size * 2 + 2,
307                         *(kernel_ulong_t *) elem_buf);
308
309         return true;
310 }
311
312 static bool
313 decode_netlink_diag_groups(struct tcb *const tcp,
314                            const kernel_ulong_t addr,
315                            const kernel_ulong_t len,
316                            const void *const opaque_data)
317 {
318         kernel_ulong_t buf;
319         const size_t nmemb = len / current_wordsize;
320
321         if (!nmemb)
322                 return false;
323
324         print_array(tcp, addr, nmemb, &buf, current_wordsize,
325                     umoven_or_printaddr, print_group, 0);
326
327         return true;
328 }
329
330 static bool
331 decode_netlink_diag_ring(struct tcb *const tcp,
332                          const kernel_ulong_t addr,
333                          const kernel_ulong_t len,
334                          const void *const opaque_data)
335 {
336         struct netlink_diag_ring ndr;
337
338         if (len < sizeof(ndr))
339                 return false;
340         if (umove_or_printaddr(tcp, addr, &ndr))
341                 return true;
342
343         PRINT_FIELD_U("{", ndr, ndr_block_size);
344         PRINT_FIELD_U(", ", ndr, ndr_block_nr);
345         PRINT_FIELD_U(", ", ndr, ndr_frame_size);
346         PRINT_FIELD_U(", ", ndr, ndr_frame_nr);
347         tprints("}");
348
349         return true;
350 }
351
352 static bool
353 decode_netlink_diag_flags(struct tcb *const tcp,
354                           const kernel_ulong_t addr,
355                           const kernel_ulong_t len,
356                           const void *const opaque_data)
357 {
358         uint32_t flags;
359
360         if (len < sizeof(flags))
361                 return false;
362         if (umove_or_printaddr(tcp, addr, &flags))
363                 return true;
364
365         printflags(netlink_socket_flags, flags, "NDIAG_FLAG_???");
366
367         return true;
368 }
369
370 static const nla_decoder_t netlink_diag_msg_nla_decoders[] = {
371         [NETLINK_DIAG_MEMINFO]  = decode_meminfo,
372         [NETLINK_DIAG_GROUPS]   = decode_netlink_diag_groups,
373         [NETLINK_DIAG_RX_RING]  = decode_netlink_diag_ring,
374         [NETLINK_DIAG_TX_RING]  = decode_netlink_diag_ring,
375         [NETLINK_DIAG_FLAGS]    = decode_netlink_diag_flags
376 };
377
378 static void
379 decode_netlink_diag_msg(struct tcb *const tcp,
380                         const struct nlmsghdr *const nlmsghdr,
381                         const uint8_t family,
382                         const kernel_ulong_t addr,
383                         const kernel_ulong_t len)
384 {
385         struct netlink_diag_msg msg = { .ndiag_family = family };
386         size_t offset = sizeof(msg.ndiag_family);
387         bool decode_nla = false;
388
389         PRINT_FIELD_XVAL("{", msg, ndiag_family, addrfams, "AF_???");
390         tprints(", ");
391         if (len >= sizeof(msg)) {
392                 if (!umoven_or_printaddr(tcp, addr + offset,
393                                          sizeof(msg) - offset,
394                                          (void *) &msg + offset)) {
395                         PRINT_FIELD_XVAL("", msg, ndiag_type,
396                                          socktypes, "SOCK_???");
397                         PRINT_FIELD_XVAL(", ", msg, ndiag_protocol,
398                                          netlink_protocols, "NETLINK_???");
399                         PRINT_FIELD_XVAL(", ", msg, ndiag_state,
400                                          netlink_states, "NETLINK_???");
401                         PRINT_FIELD_U(", ", msg, ndiag_portid);
402                         PRINT_FIELD_U(", ", msg, ndiag_dst_portid);
403                         PRINT_FIELD_U(", ", msg, ndiag_dst_group);
404                         PRINT_FIELD_U(", ", msg, ndiag_ino);
405                         PRINT_FIELD_COOKIE(", ", msg, ndiag_cookie);
406                         decode_nla = true;
407                 }
408         } else
409                 tprints("...");
410         tprints("}");
411
412         offset = NLA_ALIGN(sizeof(msg));
413         if (decode_nla && len > offset) {
414                 tprints(", ");
415                 decode_nlattr(tcp, addr + offset, len - offset,
416                               netlink_diag_attrs, "NETLINK_DIAG_???",
417                               netlink_diag_msg_nla_decoders,
418                               ARRAY_SIZE(netlink_diag_msg_nla_decoders), NULL);
419         }
420 }
421
422 static void
423 decode_packet_diag_req(struct tcb *const tcp,
424                        const struct nlmsghdr *const nlmsghdr,
425                        const uint8_t family,
426                        const kernel_ulong_t addr,
427                        const kernel_ulong_t len)
428 {
429         struct packet_diag_req req = { .sdiag_family = family };
430         const size_t offset = sizeof(req.sdiag_family);
431
432         PRINT_FIELD_XVAL("{", req, sdiag_family, addrfams, "AF_???");
433         tprints(", ");
434         if (len >= sizeof(req)) {
435                 if (!umoven_or_printaddr(tcp, addr + offset,
436                                          sizeof(req) - offset,
437                                          (void *) &req + offset)) {
438                         PRINT_FIELD_XVAL("", req, sdiag_protocol,
439                                          ethernet_protocols, "ETH_P_???");
440                         PRINT_FIELD_U(", ", req, pdiag_ino);
441                         PRINT_FIELD_FLAGS(", ", req, pdiag_show,
442                                           packet_diag_show, "PACKET_SHOW_???");
443                         PRINT_FIELD_COOKIE(", ", req, pdiag_cookie);
444                 }
445         } else
446                 tprints("...");
447         tprints("}");
448 }
449
450 static void
451 decode_packet_diag_msg(struct tcb *const tcp,
452                        const struct nlmsghdr *const nlmsghdr,
453                        const uint8_t family,
454                        const kernel_ulong_t addr,
455                        const kernel_ulong_t len)
456 {
457         struct packet_diag_msg msg = { .pdiag_family = family };
458         size_t offset = sizeof(msg.pdiag_family);
459         bool decode_nla = false;
460
461         PRINT_FIELD_XVAL("{", msg, pdiag_family, addrfams, "AF_???");
462         tprints(", ");
463         if (len >= sizeof(msg)) {
464                 if (!umoven_or_printaddr(tcp, addr + offset,
465                                          sizeof(msg) - offset,
466                                          (void *) &msg + offset)) {
467                         PRINT_FIELD_XVAL("", msg, pdiag_type,
468                                          socktypes, "SOCK_???");
469                         PRINT_FIELD_U(", ", msg, pdiag_num);
470                         PRINT_FIELD_U(", ", msg, pdiag_ino);
471                         PRINT_FIELD_COOKIE(", ", msg, pdiag_cookie);
472                         decode_nla = true;
473                 }
474         } else
475                 tprints("...");
476         tprints("}");
477
478         offset = NLA_ALIGN(sizeof(msg));
479         if (decode_nla && len > offset) {
480                 tprints(", ");
481                 decode_nlattr(tcp, addr + offset, len - offset,
482                               packet_diag_attrs, "PACKET_DIAG_???",
483                               NULL, 0, NULL);
484         }
485 }
486
487 static void
488 print_inet_diag_sockid(const struct inet_diag_sockid *id, const uint8_t family)
489 {
490         tprintf("{idiag_sport=htons(%u), idiag_dport=htons(%u)",
491                 ntohs(id->idiag_sport), ntohs(id->idiag_dport));
492
493         tprints(", ");
494         print_inet_addr(family, id->idiag_src,
495                         sizeof(id->idiag_src), "idiag_src");
496         tprints(", ");
497         print_inet_addr(family, id->idiag_dst,
498                         sizeof(id->idiag_dst), "idiag_dst");
499
500         tprints(", idiag_if=");
501         print_ifindex(id->idiag_if);
502
503         PRINT_FIELD_COOKIE(", ", *id, idiag_cookie);
504
505         tprints("}");
506 }
507
508 static void
509 decode_inet_diag_req_compat(struct tcb *const tcp,
510                             const struct nlmsghdr *const nlmsghdr,
511                             const uint8_t family,
512                             const kernel_ulong_t addr,
513                             const kernel_ulong_t len)
514 {
515         struct inet_diag_req req = { .idiag_family = family };
516         size_t offset = sizeof(req.idiag_family);
517         bool decode_nla = false;
518
519         PRINT_FIELD_XVAL("{", req, idiag_family, addrfams, "AF_???");
520         tprints(", ");
521         if (len >= sizeof(req)) {
522                 if (!umoven_or_printaddr(tcp, addr + offset,
523                                          sizeof(req) - offset,
524                                          (void *) &req + offset)) {
525                         PRINT_FIELD_U("", req, idiag_src_len);
526                         PRINT_FIELD_U(", ", req, idiag_dst_len);
527                         PRINT_FIELD_FLAGS(", ", req, idiag_ext,
528                                           inet_diag_extended_flags,
529                                           "1<<INET_DIAG_\?\?\?-1");
530                         tprints(", id=");
531                         print_inet_diag_sockid(&req.id, req.idiag_family);
532                         PRINT_FIELD_FLAGS(", ", req, idiag_states,
533                                           tcp_state_flags, "1<<TCP_???");
534                         PRINT_FIELD_U(", ", req, idiag_dbs);
535                         decode_nla = true;
536                 }
537         } else
538                 tprints("...");
539         tprints("}");
540
541         offset = NLA_ALIGN(sizeof(req));
542         if (decode_nla && len > offset) {
543                 tprints(", ");
544                 decode_nlattr(tcp, addr + offset, len - offset,
545                               inet_diag_req_attrs, "INET_DIAG_REQ_???",
546                               NULL, 0, NULL);
547         }
548 }
549
550 static void
551 decode_inet_diag_req_v2(struct tcb *const tcp,
552                         const struct nlmsghdr *const nlmsghdr,
553                         const uint8_t family,
554                         const kernel_ulong_t addr,
555                         const kernel_ulong_t len)
556 {
557         struct inet_diag_req_v2 req = { .sdiag_family = family };
558         size_t offset = sizeof(req.sdiag_family);
559         bool decode_nla = false;
560
561         PRINT_FIELD_XVAL("{", req, sdiag_family, addrfams, "AF_???");
562         tprints(", ");
563         if (len >= sizeof(req)) {
564                 if (!umoven_or_printaddr(tcp, addr + offset,
565                                          sizeof(req) - offset,
566                                          (void *) &req + offset)) {
567                         PRINT_FIELD_XVAL("", req, sdiag_protocol,
568                                          inet_protocols, "IPPROTO_???");
569                         PRINT_FIELD_FLAGS(", ", req, idiag_ext,
570                                           inet_diag_extended_flags,
571                                           "1<<INET_DIAG_\?\?\?-1");
572                         PRINT_FIELD_FLAGS(", ", req, idiag_states,
573                                           tcp_state_flags, "1<<TCP_???");
574                         tprints(", id=");
575                         print_inet_diag_sockid(&req.id, req.sdiag_family);
576                         decode_nla = true;
577                 }
578         } else
579                 tprints("...");
580         tprints("}");
581
582         offset = NLA_ALIGN(sizeof(req));
583         if (decode_nla && len > offset) {
584                 tprints(", ");
585                 decode_nlattr(tcp, addr + offset, len - offset,
586                               inet_diag_req_attrs, "INET_DIAG_REQ_???",
587                               NULL, 0, NULL);
588         }
589 }
590
591 static void
592 decode_inet_diag_req(struct tcb *const tcp,
593                      const struct nlmsghdr *const nlmsghdr,
594                      const uint8_t family,
595                      const kernel_ulong_t addr,
596                      const kernel_ulong_t len)
597 {
598         if (nlmsghdr->nlmsg_type == TCPDIAG_GETSOCK
599             || nlmsghdr->nlmsg_type == DCCPDIAG_GETSOCK)
600                 return decode_inet_diag_req_compat(tcp, nlmsghdr,
601                                                    family, addr, len);
602         else
603                 return decode_inet_diag_req_v2(tcp, nlmsghdr,
604                                                family, addr, len);
605 }
606
607 static bool
608 decode_inet_diag_meminfo(struct tcb *const tcp,
609                          const kernel_ulong_t addr,
610                          const kernel_ulong_t len,
611                          const void *const opaque_data)
612 {
613         struct inet_diag_meminfo minfo;
614
615         if (len < sizeof(minfo))
616                 return false;
617         if (umove_or_printaddr(tcp, addr, &minfo))
618                 return true;
619
620         PRINT_FIELD_U("{", minfo, idiag_rmem);
621         PRINT_FIELD_U(", ", minfo, idiag_wmem);
622         PRINT_FIELD_U(", ", minfo, idiag_fmem);
623         PRINT_FIELD_U(", ", minfo, idiag_tmem);
624         tprints("}");
625
626         return true;
627 }
628
629 static bool
630 decode_tcpvegas_info(struct tcb *const tcp,
631                      const kernel_ulong_t addr,
632                      const kernel_ulong_t len,
633                      const void *const opaque_data)
634 {
635         struct tcpvegas_info vegas;
636
637         if (len < sizeof(vegas))
638                 return false;
639         if (umove_or_printaddr(tcp, addr, &vegas))
640                 return true;
641
642         PRINT_FIELD_U("{", vegas, tcpv_enabled);
643         PRINT_FIELD_U(", ", vegas, tcpv_rttcnt);
644         PRINT_FIELD_U(", ", vegas, tcpv_rtt);
645         PRINT_FIELD_U(", ", vegas, tcpv_minrtt);
646         tprints("}");
647
648         return true;
649 }
650
651 static bool
652 decode_tcp_dctcp_info(struct tcb *const tcp,
653                       const kernel_ulong_t addr,
654                       const kernel_ulong_t len,
655                       const void *const opaque_data)
656 {
657         struct tcp_dctcp_info dctcp;
658
659         if (len < sizeof(dctcp))
660                 return false;
661         if (umove_or_printaddr(tcp, addr, &dctcp))
662                 return true;
663
664         PRINT_FIELD_U("{", dctcp, dctcp_enabled);
665         PRINT_FIELD_U(", ", dctcp, dctcp_ce_state);
666         PRINT_FIELD_U(", ", dctcp, dctcp_alpha);
667         PRINT_FIELD_U(", ", dctcp, dctcp_ab_ecn);
668         PRINT_FIELD_U(", ", dctcp, dctcp_ab_tot);
669         tprints("}");
670
671         return true;
672 }
673
674 static bool
675 decode_tcp_bbr_info(struct tcb *const tcp,
676                     const kernel_ulong_t addr,
677                     const kernel_ulong_t len,
678                     const void *const opaque_data)
679 {
680         struct tcp_bbr_info bbr;
681
682         if (len < sizeof(bbr))
683                 return false;
684         if (umove_or_printaddr(tcp, addr, &bbr))
685                 return true;
686
687         PRINT_FIELD_X("{", bbr, bbr_bw_lo);
688         PRINT_FIELD_X(", ", bbr, bbr_bw_hi);
689         PRINT_FIELD_U(", ", bbr, bbr_min_rtt);
690         PRINT_FIELD_U(", ", bbr, bbr_pacing_gain);
691         PRINT_FIELD_U(", ", bbr, bbr_cwnd_gain);
692         tprints("}");
693
694         return true;
695 }
696
697 static const nla_decoder_t inet_diag_msg_nla_decoders[] = {
698         [INET_DIAG_MEMINFO]     = decode_inet_diag_meminfo,
699         [INET_DIAG_INFO]        = NULL,                 /* unimplemented */
700         [INET_DIAG_VEGASINFO]   = decode_tcpvegas_info,
701         [INET_DIAG_CONG]        = decode_nla_str,
702         [INET_DIAG_TOS]         = decode_nla_u8,
703         [INET_DIAG_TCLASS]      = decode_nla_u8,
704         [INET_DIAG_SKMEMINFO]   = decode_meminfo,
705         [INET_DIAG_SHUTDOWN]    = decode_nla_u8,
706         [INET_DIAG_DCTCPINFO]   = decode_tcp_dctcp_info,
707         [INET_DIAG_PROTOCOL]    = decode_nla_u8,
708         [INET_DIAG_SKV6ONLY]    = decode_nla_u8,
709         [INET_DIAG_LOCALS]      = NULL,                 /* unimplemented */
710         [INET_DIAG_PEERS]       = NULL,                 /* unimplemented */
711         [INET_DIAG_PAD]         = NULL,
712         [INET_DIAG_MARK]        = decode_nla_u32,
713         [INET_DIAG_BBRINFO]     = decode_tcp_bbr_info
714 };
715
716 static void
717 decode_inet_diag_msg(struct tcb *const tcp,
718                      const struct nlmsghdr *const nlmsghdr,
719                      const uint8_t family,
720                      const kernel_ulong_t addr,
721                      const kernel_ulong_t len)
722 {
723         struct inet_diag_msg msg = { .idiag_family = family };
724         size_t offset = sizeof(msg.idiag_family);
725         bool decode_nla = false;
726
727         PRINT_FIELD_XVAL("{", msg, idiag_family, addrfams, "AF_???");
728         tprints(", ");
729         if (len >= sizeof(msg)) {
730                 if (!umoven_or_printaddr(tcp, addr + offset,
731                                          sizeof(msg) - offset,
732                                          (void *) &msg + offset)) {
733                         PRINT_FIELD_XVAL("", msg, idiag_state,
734                                          tcp_states, "TCP_???");
735                         PRINT_FIELD_U(", ", msg, idiag_timer);
736                         PRINT_FIELD_U(", ", msg, idiag_retrans);
737                         tprints(", id=");
738                         print_inet_diag_sockid(&msg.id, msg.idiag_family);
739                         PRINT_FIELD_U(", ", msg, idiag_expires);
740                         PRINT_FIELD_U(", ", msg, idiag_rqueue);
741                         PRINT_FIELD_U(", ", msg, idiag_wqueue);
742                         PRINT_FIELD_U(", ", msg, idiag_uid);
743                         PRINT_FIELD_U(", ", msg, idiag_inode);
744                         decode_nla = true;
745                 }
746         } else
747                 tprints("...");
748         tprints("}");
749
750         offset = NLA_ALIGN(sizeof(msg));
751         if (decode_nla && len > offset) {
752                 tprints(", ");
753                 decode_nlattr(tcp, addr + offset, len - offset,
754                               inet_diag_attrs, "INET_DIAG_???",
755                               inet_diag_msg_nla_decoders,
756                               ARRAY_SIZE(inet_diag_msg_nla_decoders), NULL);
757         }
758 }
759
760 #ifdef AF_SMC
761 static void
762 decode_smc_diag_req(struct tcb *const tcp,
763                     const struct nlmsghdr *const nlmsghdr,
764                     const uint8_t family,
765                     const kernel_ulong_t addr,
766                     const kernel_ulong_t len)
767 {
768         struct smc_diag_req req = { .diag_family = family };
769         const size_t offset = sizeof(req.diag_family);
770
771         PRINT_FIELD_XVAL("{", req, diag_family, addrfams, "AF_???");
772         tprints(", ");
773         if (len >= sizeof(req)) {
774                 if (!umoven_or_printaddr(tcp, addr + offset,
775                                          sizeof(req) - offset,
776                                          (void *) &req + offset)) {
777                         PRINT_FIELD_FLAGS("", req, diag_ext,
778                                           smc_diag_extended_flags,
779                                           "1<<SMC_DIAG_\?\?\?-1");
780                         tprints(", id=");
781                         /*
782                          * AF_SMC protocol family socket handler
783                          * keeping the AF_INET sock address.
784                          */
785                         print_inet_diag_sockid(&req.id, AF_INET);
786                 }
787         } else
788                 tprints("...");
789         tprints("}");
790 }
791
792 static void
793 decode_smc_diag_msg(struct tcb *const tcp,
794                     const struct nlmsghdr *const nlmsghdr,
795                     const uint8_t family,
796                     const kernel_ulong_t addr,
797                     const kernel_ulong_t len)
798 {
799         struct smc_diag_msg msg = { .diag_family = family };
800         size_t offset = sizeof(msg.diag_family);
801         bool decode_nla = false;
802
803         PRINT_FIELD_XVAL("{", msg, diag_family, addrfams, "AF_???");
804         tprints(", ");
805         if (len >= sizeof(msg)) {
806                 if (!umoven_or_printaddr(tcp, addr + offset,
807                                          sizeof(msg) - offset,
808                                          (void *) &msg + offset)) {
809                         PRINT_FIELD_XVAL("", msg, diag_state,
810                                          smc_states, "SMC_???");
811                         PRINT_FIELD_U(", ", msg, diag_fallback);
812                         PRINT_FIELD_U(", ", msg, diag_shutdown);
813                         tprints(", id=");
814                         /*
815                          * AF_SMC protocol family socket handler
816                          * keeping the AF_INET sock address.
817                          */
818                         print_inet_diag_sockid(&msg.id, AF_INET);
819                         PRINT_FIELD_U(", ", msg, diag_uid);
820                         PRINT_FIELD_U(", ", msg, diag_inode);
821                         decode_nla = true;
822                 }
823         } else
824                 tprints("...");
825         tprints("}");
826
827         offset = NLA_ALIGN(sizeof(msg));
828         if (decode_nla && len > offset) {
829                 tprints(", ");
830                 decode_nlattr(tcp, addr + offset, len - offset,
831                               smc_diag_attrs, "SMC_DIAG_???",
832                               NULL, 0, NULL);
833         }
834 }
835 #endif
836
837 typedef void (*netlink_diag_decoder_t)(struct tcb *,
838                                        const struct nlmsghdr *,
839                                        uint8_t family,
840                                        kernel_ulong_t addr,
841                                        kernel_ulong_t len);
842
843 static const struct {
844         const netlink_diag_decoder_t request, response;
845 } diag_decoders[] = {
846         [AF_INET] = { decode_inet_diag_req, decode_inet_diag_msg },
847         [AF_INET6] = { decode_inet_diag_req, decode_inet_diag_msg },
848         [AF_NETLINK] = { decode_netlink_diag_req, decode_netlink_diag_msg },
849         [AF_PACKET] = { decode_packet_diag_req, decode_packet_diag_msg },
850 #ifdef AF_SMC
851         [AF_SMC] = { decode_smc_diag_req, decode_smc_diag_msg },
852 #endif
853         [AF_UNIX] = { decode_unix_diag_req, decode_unix_diag_msg }
854 };
855
856 bool
857 decode_netlink_sock_diag(struct tcb *const tcp,
858                          const struct nlmsghdr *const nlmsghdr,
859                          const kernel_ulong_t addr,
860                          const kernel_ulong_t len)
861 {
862         uint8_t family;
863
864         if (nlmsghdr->nlmsg_type == NLMSG_DONE)
865                 return false;
866
867         if (!umove_or_printaddr(tcp, addr, &family)) {
868                 if (family < ARRAY_SIZE(diag_decoders)
869                     && len > sizeof(family)) {
870                         const netlink_diag_decoder_t decoder =
871                                 (nlmsghdr->nlmsg_flags & NLM_F_REQUEST)
872                                 ? diag_decoders[family].request
873                                 : diag_decoders[family].response;
874
875                         if (decoder) {
876                                 decoder(tcp, nlmsghdr, family, addr, len);
877                                 return true;
878                         }
879                 }
880
881                 decode_family(tcp, family, addr, len);
882         }
883
884         return true;
885 }