1 /*
2 * Copyright (c) 2016 Fabien Siron <fabien.siron@epita.fr>
3 * Copyright (c) 2017 JingPiao Chen <chenjingpiao@gmail.com>
4 * Copyright (c) 2016-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_route.h"
12 #include "nlattr.h"
13
14 #include "netlink.h"
15 #include <linux/neighbour.h>
16
17 #include "xlat/fdb_notify_flags.h"
18 #include "xlat/neighbor_cache_entry_ext_flags.h"
19 #include "xlat/neighbor_cache_entry_flags.h"
20 #include "xlat/neighbor_cache_entry_states.h"
21 #include "xlat/rtnl_neigh_attrs.h"
22 #include "xlat/rtnl_neigh_fdb_ext_attrs.h"
23
24 static bool
25 decode_neigh_addr(struct tcb *const tcp,
26 const kernel_ulong_t addr,
27 const unsigned int len,
28 const void *const opaque_data)
29 {
30 const struct ndmsg *const ndmsg = opaque_data;
31
32 decode_inet_addr(tcp, addr, len, ndmsg->ndm_family, NULL);
33
34 return true;
35 }
36
37 static bool
38 decode_nda_cacheinfo(struct tcb *const tcp,
39 const kernel_ulong_t addr,
40 const unsigned int len,
41 const void *const opaque_data)
42 {
43 struct nda_cacheinfo ci;
44
45 if (len < sizeof(ci))
46 return false;
47 else if (!umove_or_printaddr(tcp, addr, &ci)) {
48 tprint_struct_begin();
49 PRINT_FIELD_U(ci, ndm_confirmed);
50 tprint_struct_next();
51 PRINT_FIELD_U(ci, ndm_used);
52 tprint_struct_next();
53 PRINT_FIELD_U(ci, ndm_updated);
54 tprint_struct_next();
55 PRINT_FIELD_U(ci, ndm_refcnt);
56 tprint_struct_end();
57 }
58
59 return true;
60 }
61
62 static bool
63 decode_fdb_notify_flags(struct tcb *const tcp,
64 const kernel_ulong_t addr,
65 const unsigned int len,
66 const void *const opaque_data)
67 {
68 static const struct decode_nla_xlat_opts opts = {
69 fdb_notify_flags, "FDB_NOTIFY_???",
70 .size = 1,
71 };
72
73 return decode_nla_flags(tcp, addr, len, &opts);
74 }
75
76 static const nla_decoder_t nda_fdb_ext_attrs_nla_decoders[] = {
77 [NFEA_UNSPEC] = NULL,
78 [NFEA_ACTIVITY_NOTIFY] = decode_fdb_notify_flags,
79 [NFEA_DONT_REFRESH] = NULL, /* flag attr, no payload is expected */
80 };
81
82 static bool
83 decode_nda_fdb_ext_attrs(struct tcb *const tcp,
84 const kernel_ulong_t addr,
85 const unsigned int len,
86 const void *const opaque_data)
87 {
88 decode_nlattr(tcp, addr, len, rtnl_neigh_fdb_ext_attrs,
89 "NFEA_???", ARRSZ_PAIR(nda_fdb_ext_attrs_nla_decoders),
90 opaque_data);
91
92 return true;
93 }
94
95 static bool
96 decode_nda_ext_flags(struct tcb *const tcp,
97 const kernel_ulong_t addr,
98 const unsigned int len,
99 const void *const opaque_data)
100 {
101 static const struct decode_nla_xlat_opts opts = {
102 neighbor_cache_entry_ext_flags, "NTF_EXT_???",
103 .size = 4,
104 };
105
106 return decode_nla_flags(tcp, addr, len, &opts);
107 }
108
109 static bool
110 decode_nda_ndm_states(struct tcb *const tcp,
111 const kernel_ulong_t addr,
112 const unsigned int len,
113 const void *const opaque_data)
114 {
115 static const struct decode_nla_xlat_opts opts = {
116 neighbor_cache_entry_states, "NUD_???",
117 .size = 2,
118 };
119
120 return decode_nla_flags(tcp, addr, len, &opts);
121 }
122
123 static bool
124 decode_nda_ndm_flags(struct tcb *const tcp,
125 const kernel_ulong_t addr,
126 const unsigned int len,
127 const void *const opaque_data)
128 {
129 static const struct decode_nla_xlat_opts opts = {
130 neighbor_cache_entry_flags, "NTF_???",
131 .size = 1,
132 };
133
134 return decode_nla_flags(tcp, addr, len, &opts);
135 }
136
137 static const nla_decoder_t ndmsg_nla_decoders[] = {
138 [NDA_DST] = decode_neigh_addr,
139 [NDA_LLADDR] = decode_nla_hwaddr_nofamily,
140 [NDA_CACHEINFO] = decode_nda_cacheinfo,
141 [NDA_PROBES] = decode_nla_u32,
142 [NDA_VLAN] = decode_nla_u16,
143 [NDA_PORT] = decode_nla_be16,
144 [NDA_VNI] = decode_nla_u32,
145 [NDA_IFINDEX] = decode_nla_ifindex,
146 [NDA_MASTER] = decode_nla_ifindex,
147 [NDA_LINK_NETNSID] = decode_nla_u32,
148 [NDA_SRC_VNI] = decode_nla_u32,
149 [NDA_PROTOCOL] = decode_nla_ip_proto,
150 [NDA_NH_ID] = decode_nla_u32,
151 [NDA_FDB_EXT_ATTRS] = decode_nda_fdb_ext_attrs,
152 [NDA_FLAGS_EXT] = decode_nda_ext_flags,
153 [NDA_NDM_STATE_MASK] = decode_nda_ndm_states,
154 [NDA_NDM_FLAGS_MASK] = decode_nda_ndm_flags,
155 };
156
157 DECL_NETLINK_ROUTE_DECODER(decode_ndmsg)
158 {
159 struct ndmsg ndmsg = { .ndm_family = family };
160 size_t offset = sizeof(ndmsg.ndm_family);
161 bool decode_nla = false;
162
163 tprint_struct_begin();
164 PRINT_FIELD_XVAL(ndmsg, ndm_family, addrfams, "AF_???");
165 tprint_struct_next();
166
167 if (len >= sizeof(ndmsg)) {
168 if (!umoven_or_printaddr(tcp, addr + offset,
169 sizeof(ndmsg) - offset,
170 (char *) &ndmsg + offset)) {
171 PRINT_FIELD_IFINDEX(ndmsg, ndm_ifindex);
172 tprint_struct_next();
173 PRINT_FIELD_FLAGS(ndmsg, ndm_state,
174 neighbor_cache_entry_states,
175 "NUD_???");
176 tprint_struct_next();
177 PRINT_FIELD_FLAGS(ndmsg, ndm_flags,
178 neighbor_cache_entry_flags,
179 "NTF_???");
180 tprint_struct_next();
181 PRINT_FIELD_XVAL(ndmsg, ndm_type,
182 routing_types, "RTN_???");
183 decode_nla = true;
184 }
185 } else
186 tprint_more_data_follows();
187 tprint_struct_end();
188
189 offset = NLMSG_ALIGN(sizeof(ndmsg));
190 if (decode_nla && len > offset) {
191 tprint_array_next();
192 decode_nlattr(tcp, addr + offset, len - offset,
193 rtnl_neigh_attrs, "NDA_???",
194 ndmsg_nla_decoders,
195 ARRAY_SIZE(ndmsg_nla_decoders), &ndmsg);
196 }
197 }
198
199 DECL_NETLINK_ROUTE_DECODER(decode_rtm_getneigh)
200 {
201 if (family == AF_BRIDGE)
202 decode_ifinfomsg(tcp, nlmsghdr, family, addr, len);
203 else
204 decode_ndmsg(tcp, nlmsghdr, family, addr, len);
205 }