1 /*
2 * Copyright (c) 2016 Fabien Siron <fabien.siron@epita.fr>
3 * Copyright (c) 2017 JingPiao Chen <chenjingpiao@gmail.com>
4 * Copyright (c) 2017-2022 The strace developers.
5 * All rights reserved.
6 *
7 * SPDX-License-Identifier: LGPL-2.1-or-later
8 */
9
10 #include "defs.h"
11 #include "netlink.h"
12 #include "netlink_sock_diag.h"
13 #include "nlattr.h"
14
15 #include <linux/sock_diag.h>
16 #include <linux/netlink_diag.h>
17
18 #include "xlat/netlink_diag_attrs.h"
19 #include "xlat/netlink_diag_show.h"
20 #include "xlat/netlink_socket_flags.h"
21 #include "xlat/netlink_states.h"
22
23 DECL_NETLINK_DIAG_DECODER(decode_netlink_diag_req)
24 {
25 struct netlink_diag_req req = { .sdiag_family = family };
26 const size_t offset = sizeof(req.sdiag_family);
27
28 tprint_struct_begin();
29 PRINT_FIELD_XVAL(req, sdiag_family, addrfams, "AF_???");
30 tprint_struct_next();
31
32 if (len >= sizeof(req)) {
33 if (!umoven_or_printaddr(tcp, addr + offset,
34 sizeof(req) - offset,
35 (char *) &req + offset)) {
36 if (NDIAG_PROTO_ALL == req.sdiag_protocol) {
37 tprints_field_name("sdiag_protocol");
38 print_xlat(NDIAG_PROTO_ALL);
39 } else {
40 PRINT_FIELD_XVAL(req, sdiag_protocol,
41 netlink_protocols,
42 "NETLINK_???");
43 }
44 tprint_struct_next();
45 PRINT_FIELD_U(req, ndiag_ino);
46 tprint_struct_next();
47 PRINT_FIELD_FLAGS(req, ndiag_show,
48 netlink_diag_show, "NDIAG_SHOW_???");
49 tprint_struct_next();
50 PRINT_FIELD_COOKIE(req, ndiag_cookie);
51 }
52 } else
53 tprint_more_data_follows();
54 tprint_struct_end();
55 }
56
57 static bool
58 print_group(struct tcb *const tcp,
59 void *const elem_buf,
60 const size_t elem_size,
61 void *const opaque_data)
62 {
63 if (elem_size < sizeof(kernel_ulong_t)) {
64 unsigned int val = *(unsigned int *) elem_buf;
65 PRINT_VAL_0X(val);
66 } else {
67 kernel_ulong_t val = *(kernel_ulong_t *) elem_buf;
68 PRINT_VAL_0X(val);
69 }
70
71 return true;
72 }
73
74 static bool
75 decode_netlink_diag_groups(struct tcb *const tcp,
76 const kernel_ulong_t addr,
77 const unsigned int len,
78 const void *const opaque_data)
79 {
80 kernel_ulong_t buf;
81 const size_t nmemb = len / current_wordsize;
82
83 if (!nmemb)
84 return false;
85
86 print_array(tcp, addr, nmemb, &buf, current_wordsize,
87 tfetch_mem, print_group, 0);
88
89 return true;
90 }
91
92 static bool
93 decode_netlink_diag_ring(struct tcb *const tcp,
94 const kernel_ulong_t addr,
95 const unsigned int len,
96 const void *const opaque_data)
97 {
98 struct netlink_diag_ring ndr;
99
100 if (len < sizeof(ndr))
101 return false;
102 if (umove_or_printaddr(tcp, addr, &ndr))
103 return true;
104
105 tprint_struct_begin();
106 PRINT_FIELD_U(ndr, ndr_block_size);
107 tprint_struct_next();
108 PRINT_FIELD_U(ndr, ndr_block_nr);
109 tprint_struct_next();
110 PRINT_FIELD_U(ndr, ndr_frame_size);
111 tprint_struct_next();
112 PRINT_FIELD_U(ndr, ndr_frame_nr);
113 tprint_struct_end();
114
115 return true;
116 }
117
118 static bool
119 decode_netlink_diag_flags(struct tcb *const tcp,
120 const kernel_ulong_t addr,
121 const unsigned int len,
122 const void *const opaque_data)
123 {
124 uint32_t flags;
125
126 if (len < sizeof(flags))
127 return false;
128 if (umove_or_printaddr(tcp, addr, &flags))
129 return true;
130
131 printflags(netlink_socket_flags, flags, "NDIAG_FLAG_???");
132
133 return true;
134 }
135
136 static const nla_decoder_t netlink_diag_msg_nla_decoders[] = {
137 [NETLINK_DIAG_MEMINFO] = decode_nla_meminfo,
138 [NETLINK_DIAG_GROUPS] = decode_netlink_diag_groups,
139 [NETLINK_DIAG_RX_RING] = decode_netlink_diag_ring,
140 [NETLINK_DIAG_TX_RING] = decode_netlink_diag_ring,
141 [NETLINK_DIAG_FLAGS] = decode_netlink_diag_flags
142 };
143
144 DECL_NETLINK_DIAG_DECODER(decode_netlink_diag_msg)
145 {
146 struct netlink_diag_msg msg = { .ndiag_family = family };
147 size_t offset = sizeof(msg.ndiag_family);
148 bool decode_nla = false;
149
150 tprint_struct_begin();
151 PRINT_FIELD_XVAL(msg, ndiag_family, addrfams, "AF_???");
152 tprint_struct_next();
153
154 if (len >= sizeof(msg)) {
155 if (!umoven_or_printaddr(tcp, addr + offset,
156 sizeof(msg) - offset,
157 (char *) &msg + offset)) {
158 PRINT_FIELD_XVAL(msg, ndiag_type,
159 socktypes, "SOCK_???");
160 tprint_struct_next();
161 PRINT_FIELD_XVAL(msg, ndiag_protocol,
162 netlink_protocols, "NETLINK_???");
163 tprint_struct_next();
164 PRINT_FIELD_XVAL(msg, ndiag_state,
165 netlink_states, "NETLINK_???");
166 tprint_struct_next();
167 PRINT_FIELD_U(msg, ndiag_portid);
168 tprint_struct_next();
169 PRINT_FIELD_U(msg, ndiag_dst_portid);
170 tprint_struct_next();
171 PRINT_FIELD_U(msg, ndiag_dst_group);
172 tprint_struct_next();
173 PRINT_FIELD_U(msg, ndiag_ino);
174 tprint_struct_next();
175 PRINT_FIELD_COOKIE(msg, ndiag_cookie);
176 decode_nla = true;
177 }
178 } else
179 tprint_more_data_follows();
180 tprint_struct_end();
181
182 offset = NLMSG_ALIGN(sizeof(msg));
183 if (decode_nla && len > offset) {
184 tprint_array_next();
185 decode_nlattr(tcp, addr + offset, len - offset,
186 netlink_diag_attrs, "NETLINK_DIAG_???",
187 netlink_diag_msg_nla_decoders,
188 ARRAY_SIZE(netlink_diag_msg_nla_decoders), NULL);
189 }
190 }