Revert "TODO epan/dissectors/asn1/kerberos/packet-kerberos-template.c new GSS flags"
[wireshark-sm.git] / epan / dissectors / packet-netlink.c
blob570ffe249158ed55d2e4e1ce6f695e72508eff43
1 /* packet-netlink.c
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
8 */
10 /* http://www.tcpdump.org/linktypes/LINKTYPE_NETLINK.html */
12 #include "config.h"
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" },
55 { 0, NULL }
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" },
65 { 0, NULL }
68 static const value_string ha_types[] = {
69 { ARPHRD_NETLINK, "Netlink" },
70 { 0, NULL }
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,
128 NULL
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,
143 NULL
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,
153 NULL
157 static int
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)
161 int encoding;
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
173 * packet.
175 if (length < 0)
176 THROW(ReportedBoundsError);
178 /* align to 4 */
179 offset += padding;
180 if (length < padding)
181 THROW(ReportedBoundsError);
182 length -= padding;
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);
193 if (rta_len < 4) {
194 /* XXX invalid expert */
195 break;
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);
204 offset += 2;
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);
220 offset += 2;
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 */
228 const char *rta_str;
230 if (hfi_type->display & BASE_EXT_STRING) {
231 rta_str = try_val_to_str_ext(type, (value_string_ext *)hfi_type->strings);
232 } else {
233 rta_str = try_val_to_str(type, (const value_string *) hfi_type->strings);
236 if (rta_str) {
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;
258 } else {
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);
265 offset += 2;
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;
290 return offset;
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)
316 uint16_t hdr_flags;
317 uint16_t hdr_type;
318 proto_tree *fh_hdr;
319 proto_item *pi;
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);
325 offset += 4;
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);
332 } else {
333 if (hf_type > 0) {
334 pi = proto_tree_add_item(fh_hdr, hf_type, tvb, offset, 2, encoding);
335 } else {
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);
343 if (pi_type) {
344 *pi_type = pi;
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"));
351 } else {
352 proto_item_append_text(fh_hdr, " (type: 0x%04x)", hdr_type);
354 offset += 2;
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);
364 } else {
365 proto_tree_add_bitmask(fh_hdr, tvb, offset, hf_netlink_hdr_flags,
366 ett_netlink_hdr_flags, netlink_header_standard_flags, encoding);
369 offset += 2;
371 proto_tree_add_item(fh_hdr, hf_netlink_hdr_seq, tvb, offset, 4, encoding);
372 offset += 4;
374 proto_tree_add_item(fh_hdr, hf_netlink_hdr_pid, tvb, offset, 4, encoding);
375 offset += 4;
377 return offset;
380 static void
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
385 * message.
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);
393 offset += 4;
395 dissect_netlink_header(tvb, tree, offset, encoding, -1, NULL);
398 static int
399 dissect_netlink(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
401 uint16_t protocol, hatype;
402 proto_item *ti;
403 tvbuff_t *next_tvb;
404 proto_tree *fh_tree;
406 int offset = 0;
407 int encoding;
408 unsigned len_rem, len_le, len_be;
410 hatype = tvb_get_ntohs(tvb, 2);
411 if (hatype != ARPHRD_NETLINK)
412 return 0;
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);
421 /* Packet type
422 * Since this packet, coming from the monitor port, is always outgoing we skip this
424 offset += 2;
426 proto_tree_add_item(fh_tree, hf_netlink_hatype, tvb, offset, 2, ENC_BIG_ENDIAN);
427 offset += 2;
429 /* Hardware address length plus spare space, unused 10B */
430 offset += 10;
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);
435 offset += 2;
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;
452 } else {
453 encoding = ENC_LITTLE_ENDIAN;
456 while (tvb_reported_length_remaining(tvb, offset) >= 16) {
457 int pkt_end_offset;
458 uint16_t msg_type;
459 uint32_t pkt_len;
460 uint32_t port_id;
461 proto_tree *fh_msg;
462 bool dissected = false;
464 pkt_len = tvb_get_uint32(tvb, offset, encoding);
466 pkt_end_offset = offset + pkt_len;
468 if (pkt_len < 16) {
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.
474 proto_tree *fh_hdr;
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 */
480 break;
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
490 if (port_id == 0x00)
491 pinfo->p2p_dir = P2P_DIR_SENT; /* userspace -> kernel */
492 else
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)) {
508 dissected = true;
512 if (!dissected) {
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;
531 return offset;
534 void
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,
541 NULL, HFILL }
543 { &hf_netlink_family,
544 { "Family", "netlink.family",
545 FT_UINT16, BASE_HEX | BASE_EXT_STRING, &netlink_family_vals_ext, 0x0,
546 NULL, HFILL }
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,
641 NULL, HFILL }
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,
666 NULL, HFILL }
668 { &hf_netlink_error,
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,
676 NULL, HFILL }
680 static int *ett[] = {
681 &ett_netlink_cooked,
682 &ett_netlink_msghdr,
683 &ett_netlink_msg,
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(
695 "netlink.protocol",
696 "Linux netlink protocol type",
697 proto_netlink, FT_UINT16,
698 BASE_HEX
702 void
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
711 * Local variables:
712 * c-basic-offset: 8
713 * tab-width: 8
714 * indent-tabs-mode: t
715 * End:
717 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
718 * :indentSize=8:tabSize=8:noTabs=false: