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