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