3 * Wireshark - Network traffic analyzer
4 * By Gerald Combs <gerald@wireshark.org>
5 * Copyright 1998 Gerald Combs
7 * SPDX-License-Identifier: GPL-2.0-or-later
10 /* http://www.tcpdump.org/linktypes/LINKTYPE_NETLINK.html */
14 #include <epan/packet.h>
15 #include <epan/arptypes.h>
16 #include <epan/exceptions.h>
17 #include <epan/prefs.h>
19 #include <wiretap/wtap.h>
20 #include <wsutil/ws_roundup.h>
22 #include "packet-netlink.h"
24 void proto_register_netlink(void);
25 void proto_reg_handoff_netlink(void);
28 * A DLT_LINUX_SLL fake link-layer header.
30 #define SLL_HEADER_SIZE 16 /* total header length */
32 static const value_string netlink_family_vals
[] = {
33 { WS_NETLINK_ROUTE
, "Route" },
34 { WS_NETLINK_UNUSED
, "Unused" },
35 { WS_NETLINK_USERSOCK
, "User-mode socket protocols" },
36 { WS_NETLINK_FIREWALL
, "Unused (formerly: ip_queue)" },
37 { WS_NETLINK_SOCK_DIAG
, "Socket monitoring" },
38 { WS_NETLINK_NFLOG
, "Netfilter ULOG" },
39 { WS_NETLINK_XFRM
, "IPsec" },
40 { WS_NETLINK_SELINUX
, "SELinux events" },
41 { WS_NETLINK_ISCSI
, "Open-iSCSI" },
42 { WS_NETLINK_AUDIT
, "Auditing" },
43 { WS_NETLINK_FIB_LOOKUP
, "FIB lookup" },
44 { WS_NETLINK_CONNECTOR
, "Kernel connector" },
45 { WS_NETLINK_NETFILTER
, "Netfilter" },
46 { WS_NETLINK_IP6_FW
, "Unused (formerly: ip6_queue)" },
47 { WS_NETLINK_DNRTMSG
, "DECnet routing messages" },
48 { WS_NETLINK_KOBJECT_UEVENT
, "Kernel messages to userspace" },
49 { WS_NETLINK_GENERIC
, "Generic" },
50 { WS_NETLINK_SCSITRANSPORT
, "SCSI Transports" },
51 { WS_NETLINK_ECRYPTFS
, "ecryptfs" },
52 { WS_NETLINK_RDMA
, "RDMA" },
53 { WS_NETLINK_CRYPTO
, "Crypto layer" },
54 { WS_NETLINK_SMC
, "SMC monitoring" },
58 value_string_ext netlink_family_vals_ext
= VALUE_STRING_EXT_INIT(netlink_family_vals
);
60 static const value_string type_vals
[] = {
61 { WS_NLMSG_NOOP
, "Nothing" },
62 { WS_NLMSG_ERROR
, "Error" },
63 { WS_NLMSG_DONE
, "End of a dump" },
64 { WS_NLMSG_OVERRUN
, "Data lost" },
68 static const value_string ha_types
[] = {
69 { ARPHRD_NETLINK
, "Netlink" },
73 extern value_string_ext linux_negative_errno_vals_ext
;
75 static dissector_handle_t netlink_handle
;
77 static int proto_netlink
;
79 static int hf_netlink_attr_data
;
80 static int hf_netlink_attr_index
;
81 static int hf_netlink_attr_len
;
82 static int hf_netlink_attr_type
;
83 static int hf_netlink_attr_type_nested
;
84 static int hf_netlink_attr_type_net_byteorder
;
85 static int hf_netlink_error
;
86 static int hf_netlink_family
;
87 static int hf_netlink_hatype
;
88 static int hf_netlink_hdr_flag_ack
;
89 static int hf_netlink_hdr_flag_append
;
90 static int hf_netlink_hdr_flag_atomic
;
91 static int hf_netlink_hdr_flag_create
;
92 static int hf_netlink_hdr_flag_dumpfiltered
;
93 static int hf_netlink_hdr_flag_dumpintr
;
94 static int hf_netlink_hdr_flag_echo
;
95 static int hf_netlink_hdr_flag_excl
;
96 static int hf_netlink_hdr_flag_match
;
97 static int hf_netlink_hdr_flag_multi
;
98 static int hf_netlink_hdr_flag_replace
;
99 static int hf_netlink_hdr_flag_request
;
100 static int hf_netlink_hdr_flag_root
;
101 static int hf_netlink_hdr_flags
;
102 static int hf_netlink_hdr_len
;
103 static int hf_netlink_hdr_pid
;
104 static int hf_netlink_hdr_seq
;
105 static int hf_netlink_hdr_type
;
106 static int hf_netlink_padding
;
108 static int ett_netlink_cooked
;
109 static int ett_netlink_msghdr
;
110 static int ett_netlink_msg
;
111 static int ett_netlink_hdr_flags
;
112 static int ett_netlink_attr_type
;
114 static dissector_table_t netlink_dissector_table
;
117 static int * const netlink_header_get_flags
[] = {
118 &hf_netlink_hdr_flag_request
,
119 &hf_netlink_hdr_flag_multi
,
120 &hf_netlink_hdr_flag_ack
,
121 &hf_netlink_hdr_flag_echo
,
122 &hf_netlink_hdr_flag_dumpintr
,
123 &hf_netlink_hdr_flag_dumpfiltered
,
125 &hf_netlink_hdr_flag_root
,
126 &hf_netlink_hdr_flag_match
,
127 &hf_netlink_hdr_flag_atomic
,
131 static int * const netlink_header_new_flags
[] = {
132 &hf_netlink_hdr_flag_request
,
133 &hf_netlink_hdr_flag_multi
,
134 &hf_netlink_hdr_flag_ack
,
135 &hf_netlink_hdr_flag_echo
,
136 &hf_netlink_hdr_flag_dumpintr
,
137 &hf_netlink_hdr_flag_dumpfiltered
,
139 &hf_netlink_hdr_flag_replace
,
140 &hf_netlink_hdr_flag_excl
,
141 &hf_netlink_hdr_flag_create
,
142 &hf_netlink_hdr_flag_append
,
146 static int * const netlink_header_standard_flags
[] = {
147 &hf_netlink_hdr_flag_request
,
148 &hf_netlink_hdr_flag_multi
,
149 &hf_netlink_hdr_flag_ack
,
150 &hf_netlink_hdr_flag_echo
,
151 &hf_netlink_hdr_flag_dumpintr
,
152 &hf_netlink_hdr_flag_dumpfiltered
,
158 // NOLINTNEXTLINE(misc-no-recursion)
159 dissect_netlink_attributes_common(tvbuff_t
*tvb
, int hf_type
, int ett_tree
, int ett_attrib
, void *data
, struct packet_netlink_data
*nl_data
, proto_tree
*tree
, int offset
, int length
, netlink_attributes_cb_t cb
)
162 int padding
= (4 - offset
) & 3;
163 unsigned data_length
;
164 header_field_info
*hfi_type
;
166 DISSECTOR_ASSERT(nl_data
);
168 encoding
= nl_data
->encoding
;
171 * A "negative" length is really a very large positive
172 * length, which we presume to go past the end of the
176 THROW(ReportedBoundsError
);
180 if (length
< padding
)
181 THROW(ReportedBoundsError
);
184 data_length
= length
;
186 while (data_length
>= 4) {
187 unsigned rta_len
, rta_type
, type
;
189 proto_item
*ti
, *type_item
;
190 proto_tree
*attr_tree
, *type_tree
;
192 rta_len
= tvb_get_uint16(tvb
, offset
, encoding
);
194 /* XXX invalid expert */
198 /* XXX expert info when rta_len < data_length? */
199 rta_len
= MIN(rta_len
, data_length
);
201 attr_tree
= proto_tree_add_subtree(tree
, tvb
, offset
, rta_len
, ett_tree
, &ti
, "Attribute");
203 proto_tree_add_item(attr_tree
, hf_netlink_attr_len
, tvb
, offset
, 2, encoding
);
206 rta_type
= tvb_get_uint16(tvb
, offset
, encoding
);
207 if (ett_attrib
<= 0) {
208 /* List of attributes */
209 type
= rta_type
& NLA_TYPE_MASK
;
210 type_item
= proto_tree_add_item(attr_tree
, hf_netlink_attr_type
, tvb
, offset
, 2, encoding
);
211 type_tree
= proto_item_add_subtree(type_item
, ett_netlink_attr_type
);
212 proto_tree_add_item(type_tree
, hf_netlink_attr_type_nested
, tvb
, offset
, 2, encoding
);
213 proto_tree_add_item(type_tree
, hf_netlink_attr_type_net_byteorder
, tvb
, offset
, 2, encoding
);
214 /* The hf_type _must_ have NLA_TYPE_MASK in it's definition, otherwise the nested/net_byteorder
215 * flags influence the retrieved value. Since this is impossible to enforce (apart from using
216 * a nasty DISSECTOR_ASSERT perhaps) we'll just have to make sure to feed in the properly
217 * masked value. Luckily we already have it: 'type' is the value we need.
219 proto_tree_add_uint(type_tree
, hf_type
, tvb
, offset
, 2, type
);
222 if (rta_type
& NLA_F_NESTED
)
223 proto_item_append_text(type_item
, ", Nested");
225 hfi_type
= proto_registrar_get_nth(hf_type
);
226 if (hfi_type
->strings
) {
227 /* XXX, export hf_try_val_to_str */
230 if (hfi_type
->display
& BASE_EXT_STRING
) {
231 rta_str
= try_val_to_str_ext(type
, (value_string_ext
*)hfi_type
->strings
);
233 rta_str
= try_val_to_str(type
, (const value_string
*) hfi_type
->strings
);
237 proto_item_append_text(type_item
, ", %s (%d)", rta_str
, type
);
238 proto_item_append_text(ti
, ": %s", rta_str
);
242 /* The callback needs to be passed the netlink_attr_type_net_byteorder as dissected,
243 * to properly dissect the attribute value, which byte order may differ from the
244 * capture host native byte order, as heuristically established in 'encoding'.
245 * We pass in the encoding through nl_data, so we temporarily modify it to match
246 * the NLA_F_NET_BYTEORDER flag.
248 if (rta_type
& NLA_F_NET_BYTEORDER
)
249 nl_data
->encoding
= ENC_BIG_ENDIAN
;
251 if (!cb(tvb
, data
, nl_data
, attr_tree
, rta_type
, offset
, rta_len
- 4)) {
252 proto_tree_add_item(attr_tree
, hf_netlink_attr_data
, tvb
, offset
, rta_len
- 4, ENC_NA
);
255 /* Restore the originally established encoding. */
256 if (rta_type
& NLA_F_NET_BYTEORDER
)
257 nl_data
->encoding
= encoding
;
260 * Nested attributes, constructing an array (list of
261 * attributes where its type is the array index and its
262 * value is the actual list of interesting attributes).
264 proto_tree_add_item(attr_tree
, hf_netlink_attr_index
, tvb
, offset
, 2, encoding
);
266 proto_item_append_text(ti
, " %u", rta_type
);
268 // In theory we should use increment_dissection_depth here, but that
269 // requires adding pinfo all over packet-netlink*.[ch] and we're limited
270 // to 262144 bytes (WTAP_MAX_PACKET_SIZE_STANDARD).
271 dissect_netlink_attributes(tvb
, hf_type
, ett_attrib
, data
, nl_data
, attr_tree
, offset
, rta_len
- 4, cb
);
274 /* Assume offset already aligned, next offset is rta_len plus alignment. */
275 unsigned signalled_len
= rta_len
;
276 rta_len
= MIN(WS_ROUNDUP_4(rta_len
), data_length
);
277 /* Possible padding following attr */
278 if (rta_len
> signalled_len
) {
279 proto_tree_add_item(tree
, hf_netlink_padding
, tvb
, offset
+1, rta_len
-signalled_len
, ENC_NA
);
282 offset
+= rta_len
- 4; /* Header was already skipped */
285 if (data_length
< rta_len
)
286 THROW(ReportedBoundsError
);
287 data_length
-= rta_len
;
294 // NOLINTNEXTLINE(misc-no-recursion)
295 dissect_netlink_attributes(tvbuff_t
*tvb
, int hf_type
, int ett
, void *data
, struct packet_netlink_data
*nl_data
, proto_tree
*tree
, int offset
, int length
, netlink_attributes_cb_t cb
)
297 return dissect_netlink_attributes_common(tvb
, hf_type
, ett
, -1, data
, nl_data
, tree
, offset
, length
, cb
);
301 dissect_netlink_attributes_to_end(tvbuff_t
*tvb
, int hf_type
, int ett
, void *data
, struct packet_netlink_data
*nl_data
, proto_tree
*tree
, int offset
, netlink_attributes_cb_t cb
)
303 return dissect_netlink_attributes_common(tvb
, hf_type
, ett
, -1, data
, nl_data
, tree
, offset
, tvb_ensure_reported_length_remaining(tvb
, offset
), cb
);
307 dissect_netlink_attributes_array(tvbuff_t
*tvb
, int hf_type
, int ett_array
, int ett_attrib
, void *data
, struct packet_netlink_data
*nl_data
, proto_tree
*tree
, int offset
, int length
, netlink_attributes_cb_t cb
)
309 DISSECTOR_ASSERT(ett_attrib
> 0);
310 return dissect_netlink_attributes_common(tvb
, hf_type
, ett_array
, ett_attrib
, data
, nl_data
, tree
, offset
, length
, cb
);
314 dissect_netlink_header(tvbuff_t
*tvb
, proto_tree
*tree
, int offset
, int encoding
, int hf_type
, proto_item
**pi_type
)
320 header_field_info
*hfi_type
;
322 fh_hdr
= proto_tree_add_subtree(tree
, tvb
, offset
, 16, ett_netlink_msghdr
, NULL
, "Netlink message header");
324 proto_tree_add_item(fh_hdr
, hf_netlink_hdr_len
, tvb
, offset
, 4, encoding
);
327 hdr_type
= tvb_get_uint16(tvb
, offset
, encoding
);
328 if (hdr_type
< WS_NLMSG_MIN_TYPE
) {
329 /* Reserved control messages. */
330 hf_type
= hf_netlink_hdr_type
;
331 pi
= proto_tree_add_item(fh_hdr
, hf_type
, tvb
, offset
, 2, encoding
);
334 pi
= proto_tree_add_item(fh_hdr
, hf_type
, tvb
, offset
, 2, encoding
);
336 hf_type
= hf_netlink_hdr_type
;
337 pi
= proto_tree_add_item(fh_hdr
, hf_type
, tvb
, offset
, 2, encoding
);
338 proto_item_set_text(pi
, "Message type: Protocol-specific (0x%04x)", hdr_type
);
341 hfi_type
= proto_registrar_get_nth(hf_type
);
346 /* TODO export hf_try_val_to_str? */
347 if (hfi_type
->strings
&& hfi_type
->display
& BASE_EXT_STRING
) {
348 proto_item_append_text(fh_hdr
, " (type: %s)", val_to_str_ext(hdr_type
, (value_string_ext
*)hfi_type
->strings
, "0x%04x"));
349 } else if (hfi_type
->strings
) {
350 proto_item_append_text(fh_hdr
, " (type: %s)", val_to_str(hdr_type
, (const value_string
*)hfi_type
->strings
, "0x%04x"));
352 proto_item_append_text(fh_hdr
, " (type: 0x%04x)", hdr_type
);
356 hdr_flags
= tvb_get_uint16(tvb
, offset
, encoding
);
357 if ((hdr_flags
& WS_NLM_F_REQUEST
) && (hdr_flags
& 0x0f00)) {
358 /* TODO detect based on the protocol family and message type
359 * whether this is a GET, NEW or regular request. */
360 proto_tree_add_bitmask(fh_hdr
, tvb
, offset
, hf_netlink_hdr_flags
,
361 ett_netlink_hdr_flags
, netlink_header_get_flags
, encoding
);
362 proto_tree_add_bitmask(fh_hdr
, tvb
, offset
, hf_netlink_hdr_flags
,
363 ett_netlink_hdr_flags
, netlink_header_new_flags
, encoding
);
365 proto_tree_add_bitmask(fh_hdr
, tvb
, offset
, hf_netlink_hdr_flags
,
366 ett_netlink_hdr_flags
, netlink_header_standard_flags
, encoding
);
371 proto_tree_add_item(fh_hdr
, hf_netlink_hdr_seq
, tvb
, offset
, 4, encoding
);
374 proto_tree_add_item(fh_hdr
, hf_netlink_hdr_pid
, tvb
, offset
, 4, encoding
);
381 dissect_netlink_error(tvbuff_t
*tvb
, proto_tree
*tree
, int offset
, int encoding
)
384 * XXX - this should make sure we don't run past the end of the
389 * Assume sizeof(int) == 4; RFC 3549 doesn't say "32 bits", it
390 * says "integer (typically 32 bits)".
392 proto_tree_add_item(tree
, hf_netlink_error
, tvb
, offset
, 4, encoding
);
395 dissect_netlink_header(tvb
, tree
, offset
, encoding
, -1, NULL
);
399 dissect_netlink(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
)
401 uint16_t protocol
, hatype
;
408 unsigned len_rem
, len_le
, len_be
;
410 hatype
= tvb_get_ntohs(tvb
, 2);
411 if (hatype
!= ARPHRD_NETLINK
)
414 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, "Netlink");
415 col_clear(pinfo
->cinfo
, COL_INFO
);
417 ti
= proto_tree_add_protocol_format(tree
, proto_netlink
, tvb
, offset
,
418 SLL_HEADER_SIZE
, "Linux netlink (cooked header)");
419 fh_tree
= proto_item_add_subtree(ti
, ett_netlink_cooked
);
422 * Since this packet, coming from the monitor port, is always outgoing we skip this
426 proto_tree_add_item(fh_tree
, hf_netlink_hatype
, tvb
, offset
, 2, ENC_BIG_ENDIAN
);
429 /* Hardware address length plus spare space, unused 10B */
432 /* Protocol, used as netlink family identifier */
433 protocol
= tvb_get_ntohs(tvb
, offset
);
434 proto_tree_add_item(fh_tree
, hf_netlink_family
, tvb
, offset
, 2, ENC_BIG_ENDIAN
);
437 /* End of cooked header */
440 * We do not know the endianness of the capture host, we have to guess.
441 * Compare the size of the message with the reported size of the TVB,
442 * take the endianness in which the messsage length is closer to
443 * the size of the TVB. Normally we have messages with less
444 * than 10KiB here so the sizes are very huge in the wrong endianness.
446 len_rem
= tvb_reported_length_remaining(tvb
, offset
);
447 len_le
= tvb_get_letohl(tvb
, offset
);
448 len_be
= tvb_get_ntohl(tvb
, offset
);
449 #define abs_diff(a, b) ((a) > (b) ? (a) - (b) : (b) - (a))
450 if (abs_diff(len_be
, len_rem
) < abs_diff(len_le
, len_rem
)) {
451 encoding
= ENC_BIG_ENDIAN
;
453 encoding
= ENC_LITTLE_ENDIAN
;
456 while (tvb_reported_length_remaining(tvb
, offset
) >= 16) {
462 bool dissected
= false;
464 pkt_len
= tvb_get_uint32(tvb
, offset
, encoding
);
466 pkt_end_offset
= offset
+ pkt_len
;
470 * This field includes the length of the 16-byte header,
471 * so its value is invalid. Add it, report an error,
472 * and stop trying to dissect.
476 fh_hdr
= proto_tree_add_subtree(tree
, tvb
, offset
, 4, ett_netlink_msghdr
, NULL
, "Netlink message header");
478 proto_tree_add_item(fh_hdr
, hf_netlink_hdr_len
, tvb
, offset
, 4, encoding
);
479 /* XXX invalid expert */
483 /* message type field comes after length field. */
484 msg_type
= tvb_get_uint16(tvb
, offset
+ 4, encoding
);
485 port_id
= tvb_get_uint32(tvb
, offset
+ 12, encoding
);
487 /* Since we have no original direction in the packet coming from
488 * the monitor port we have to derive it from the port_id
491 pinfo
->p2p_dir
= P2P_DIR_SENT
; /* userspace -> kernel */
493 pinfo
->p2p_dir
= P2P_DIR_RECV
; /* userspace or kernel -> userspace */
496 * Try to invoke subdissectors for non-control messages.
498 if (msg_type
>= WS_NLMSG_MIN_TYPE
&& pkt_len
> 16) {
499 struct packet_netlink_data nl_data
;
501 nl_data
.magic
= PACKET_NETLINK_MAGIC
;
502 nl_data
.encoding
= encoding
;
503 nl_data
.type
= msg_type
;
505 next_tvb
= tvb_new_subset_length(tvb
, offset
, pkt_len
);
507 if (dissector_try_uint_with_data(netlink_dissector_table
, protocol
, next_tvb
, pinfo
, tree
, true, &nl_data
)) {
514 * No subdissector was called, add a new layer with the
515 * header and the payload. Note that pkt_len>=16.
517 fh_msg
= proto_tree_add_subtree(tree
, tvb
, offset
, pkt_len
, ett_netlink_msg
, NULL
, "Netlink message");
518 offset
= dissect_netlink_header(tvb
, fh_msg
, offset
, encoding
, -1, NULL
);
520 if (msg_type
== WS_NLMSG_ERROR
) {
521 dissect_netlink_error(tvb
, fh_msg
, offset
, encoding
);
522 } else if (pkt_len
> 16) {
523 next_tvb
= tvb_new_subset_length(tvb
, offset
, pkt_len
- 16);
524 call_data_dissector(next_tvb
, pinfo
, fh_msg
);
528 offset
= pkt_end_offset
;
535 proto_register_netlink(void)
537 static hf_register_info hf
[] = {
538 { &hf_netlink_hatype
,
539 { "Link-layer address type", "netlink.hatype",
540 FT_UINT16
, BASE_DEC
, VALS(ha_types
), 0x0,
543 { &hf_netlink_family
,
544 { "Family", "netlink.family",
545 FT_UINT16
, BASE_HEX
| BASE_EXT_STRING
, &netlink_family_vals_ext
, 0x0,
548 { &hf_netlink_hdr_len
,
549 { "Length", "netlink.hdr_len",
550 FT_UINT32
, BASE_DEC
, NULL
, 0x0,
551 "Length of message including header", HFILL
}
553 { &hf_netlink_hdr_type
,
554 { "Message type", "netlink.hdr_type",
555 FT_UINT16
, BASE_HEX
, VALS(type_vals
), 0x0,
556 "Type of message content", HFILL
}
558 { &hf_netlink_hdr_flags
,
559 { "Flags", "netlink.hdr_flags",
560 FT_UINT16
, BASE_HEX
, NULL
, 0x0,
561 "Additional flags", HFILL
}
563 { &hf_netlink_hdr_flag_dumpfiltered
,
564 { "Dump filtered", "netlink.hdr_flags.dump_filtered",
565 FT_UINT16
, BASE_DEC
, NULL
, WS_NLM_F_DUMP_FILTERED
,
566 "Dump was filtered as requested", HFILL
}
568 { &hf_netlink_hdr_flag_dumpintr
,
569 { "Dump inconsistent", "netlink.hdr_flags.dump_intr",
570 FT_UINT16
, BASE_DEC
, NULL
, WS_NLM_F_DUMP_INTR
,
571 "Dump was inconsistent due to sequence change", HFILL
}
573 { &hf_netlink_hdr_flag_echo
,
574 { "Echo", "netlink.hdr_flags.echo",
575 FT_UINT16
, BASE_DEC
, NULL
, WS_NLM_F_ECHO
,
576 "Echo this request", HFILL
}
578 { &hf_netlink_hdr_flag_ack
,
579 { "Ack", "netlink.hdr_flags.ack",
580 FT_UINT16
, BASE_DEC
, NULL
, WS_NLM_F_ACK
,
581 "Asking for an ack", HFILL
}
583 { &hf_netlink_hdr_flag_multi
,
584 { "Multipart message", "netlink.hdr_flags.multi",
585 FT_UINT16
, BASE_DEC
, NULL
, WS_NLM_F_MULTI
,
586 "Part of multi-part message terminated by NLMSG_DONE", HFILL
}
588 { &hf_netlink_hdr_flag_request
,
589 { "Request", "netlink.hdr_flags.request",
590 FT_UINT16
, BASE_DEC
, NULL
, WS_NLM_F_REQUEST
,
591 "It is a request message", HFILL
}
593 { &hf_netlink_hdr_flag_root
,
594 { "Specify tree root", "netlink.hdr_flags.root",
595 FT_UINT16
, BASE_DEC
, NULL
, WS_NLM_F_ROOT
,
596 "Return the complete table instead of a single entry", HFILL
}
598 { &hf_netlink_hdr_flag_match
,
599 { "Return all matching", "netlink.hdr_flags.match",
600 FT_UINT16
, BASE_DEC
, NULL
, WS_NLM_F_MATCH
,
601 "Return all entries matching criteria in request", HFILL
}
603 { &hf_netlink_hdr_flag_atomic
,
604 { "Atomic", "netlink.hdr_flags.atomic",
605 FT_UINT16
, BASE_DEC
, NULL
, WS_NLM_F_ATOMIC
,
606 "Return an atomic snapshot of the table", HFILL
}
608 { &hf_netlink_hdr_flag_replace
,
609 { "Replace", "netlink.hdr_flags.replace",
610 FT_UINT16
, BASE_DEC
, NULL
, WS_NLM_F_REPLACE
,
611 "Replace existing objects", HFILL
}
613 { &hf_netlink_hdr_flag_excl
,
614 { "Excl", "netlink.hdr_flags.excl",
615 FT_UINT16
, BASE_DEC
, NULL
, WS_NLM_F_EXCL
,
616 "Do not replace existing objects", HFILL
}
618 { &hf_netlink_hdr_flag_create
,
619 { "Create", "netlink.hdr_flags.create",
620 FT_UINT16
, BASE_DEC
, NULL
, WS_NLM_F_CREATE
,
621 "Create objects if it does not already exist", HFILL
}
623 { &hf_netlink_hdr_flag_append
,
624 { "Append", "netlink.hdr_flags.append",
625 FT_UINT16
, BASE_DEC
, NULL
, WS_NLM_F_APPEND
,
626 "Add to end of object list", HFILL
}
628 { &hf_netlink_hdr_seq
,
629 { "Sequence", "netlink.hdr_seq",
630 FT_UINT32
, BASE_DEC
, NULL
, 0x0,
631 "Sequence number", HFILL
}
633 { &hf_netlink_hdr_pid
,
634 { "Port ID", "netlink.hdr_pid",
635 FT_UINT32
, BASE_DEC
, NULL
, 0x0,
636 "Sender port ID", HFILL
}
638 { &hf_netlink_attr_len
,
639 { "Len", "netlink.attr_len",
640 FT_UINT16
, BASE_DEC
, NULL
, 0x0,
643 { &hf_netlink_attr_type
,
644 { "Type", "netlink.attr_type",
645 FT_UINT16
, BASE_HEX
, NULL
, 0x0,
646 "Netlink Attribute type", HFILL
}
648 { &hf_netlink_attr_type_nested
,
649 { "Nested", "netlink.attr_type.nested",
650 FT_BOOLEAN
, 16, NULL
, NLA_F_NESTED
,
651 "Carries nested attributes", HFILL
}
653 { &hf_netlink_attr_type_net_byteorder
,
654 { "Network byte order", "netlink.attr_type.net_byteorder",
655 FT_BOOLEAN
, 16, NULL
, NLA_F_NET_BYTEORDER
,
656 "Payload stored in host or network byte order", HFILL
}
658 { &hf_netlink_attr_index
,
659 { "Index", "netlink.attr_index",
660 FT_UINT16
, BASE_DEC
, NULL
, 0x0,
661 "Netlink Attribute type (array index)", HFILL
}
663 { &hf_netlink_attr_data
,
664 { "Data", "netlink.attr_data",
665 FT_BYTES
, BASE_NONE
, NULL
, 0x0,
669 { "Error code", "netlink.error",
670 FT_INT32
, BASE_DEC
| BASE_EXT_STRING
, &linux_negative_errno_vals_ext
, 0x0,
671 "Negative errno or 0 for acknowledgements", HFILL
}
673 { &hf_netlink_padding
,
674 { "Padding", "netlink.padding",
675 FT_BYTES
, BASE_NONE
, NULL
, 0x0,
680 static int *ett
[] = {
684 &ett_netlink_hdr_flags
,
685 &ett_netlink_attr_type
,
688 proto_netlink
= proto_register_protocol("Linux netlink protocol", "NETLINK", "netlink" );
689 proto_register_field_array(proto_netlink
, hf
, array_length(hf
));
690 proto_register_subtree_array(ett
, array_length(ett
));
692 netlink_handle
= register_dissector("netlink", dissect_netlink
, proto_netlink
);
694 netlink_dissector_table
= register_dissector_table(
696 "Linux netlink protocol type",
697 proto_netlink
, FT_UINT16
,
703 proto_reg_handoff_netlink(void)
705 dissector_add_uint("wtap_encap", WTAP_ENCAP_NETLINK
, netlink_handle
);
709 * Editor modelines - https://www.wireshark.org/tools/modelines.html
714 * indent-tabs-mode: t
717 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
718 * :indentSize=8:tabSize=8:noTabs=false: