summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Wu <peter@lekensteyn.nl>2017-04-04 21:30:45 +0200
committerMichael Mann <mmann78@netscape.net>2017-04-09 01:50:27 +0000
commit92ebd6389203448168a2769fa473bbbad95ec159 (patch)
tree811503a22c39f5d3c7ad093122956922ffca0d24
parent0add542dbfc6d0467d14ebb2abbde0ebd1427ce1 (diff)
downloadwireshark-92ebd6389203448168a2769fa473bbbad95ec159.tar.gz
netlink: let subdissectors handle the netlink header
Let subdissectors handle parsing and addition of the Netlink header instead of doing this before calling subdissectors. After this patch: - Protocol filters like "netlink-netfilter" can be used to match packets (previously only a text item was added to the tree). - Subdissectors have more freedom in modifying the type field, so now it shows the correct type directly rather than "Message type: Protocol-specific". - netfilter: the type fields are now actually linked to a tvb, previously it was linked to a NULL tvb. - netfilter: fix unintended rejection of packets (the length should have been added to the offset, otherwise it would fallback to the data dissector). - Now subdissectors will not be called for control messages (so the netlink-conntrack.pcap sample now shows "Netlink" instead of "Netlink route" for the "End of dump" control message). Change-Id: I2ab1bef91fb0080664195b281a6a45c9702914e5 Reviewed-on: https://code.wireshark.org/review/20910 Petri-Dish: Peter Wu <peter@lekensteyn.nl> Tested-by: Petri Dish Buildbot <buildbot-no-reply@wireshark.org> Reviewed-by: Michael Mann <mmann78@netscape.net>
-rw-r--r--epan/dissectors/packet-netlink-netfilter.c49
-rw-r--r--epan/dissectors/packet-netlink-route.c44
-rw-r--r--epan/dissectors/packet-netlink-sock_diag.c28
-rw-r--r--epan/dissectors/packet-netlink.c82
-rw-r--r--epan/dissectors/packet-netlink.h6
5 files changed, 121 insertions, 88 deletions
diff --git a/epan/dissectors/packet-netlink-netfilter.c b/epan/dissectors/packet-netlink-netfilter.c
index 40c554a8ee..64136bcb4b 100644
--- a/epan/dissectors/packet-netlink-netfilter.c
+++ b/epan/dissectors/packet-netlink-netfilter.c
@@ -239,6 +239,8 @@ enum ws_ipset_ip_attr {
};
+static int proto_netlink_netfilter;
+
static int ett_netlink_netfilter = -1;
static int ett_nfq_config_attr = -1;
static int ett_nfq_attr = -1;
@@ -735,11 +737,14 @@ static int
dissect_netfilter_ulog(tvbuff_t *tvb, netlink_netfilter_info_t *info, proto_tree *tree, int offset)
{
enum ws_nfulnl_msg_types type = (enum ws_nfulnl_msg_types) (info->data->type & 0xff);
+ tvbuff_t *next_tvb;
switch (type) {
case WS_NFULNL_MSG_PACKET:
/* Note that NFLOG dissects the nfgenmsg header */
- call_dissector(nflog_handle, tvb, info->pinfo, tree);
+ next_tvb = tvb_new_subset_remaining(tvb, offset);
+ call_dissector(nflog_handle, next_tvb, info->pinfo, tree);
+ offset = tvb_reported_length(tvb);
break;
default:
@@ -1117,35 +1122,34 @@ static header_field_info hfi_netlink_netfilter_subsys NETLINK_NETFILTER_HFI_INIT
static int
dissect_netlink_netfilter(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *_data)
{
- struct packet_netlink_data *data = NULL;
+ struct packet_netlink_data *data = (struct packet_netlink_data *)_data;
netlink_netfilter_info_t info;
- int offset;
-
- if (_data) {
- if (((struct packet_netlink_data *) _data)->magic == PACKET_NETLINK_MAGIC)
- data = (struct packet_netlink_data *) _data;
- }
+ proto_tree *nlmsg_tree;
+ proto_item *pi;
+ int offset = 0;
- DISSECTOR_ASSERT(data);
+ DISSECTOR_ASSERT(data && data->magic == PACKET_NETLINK_MAGIC);
col_set_str(pinfo->cinfo, COL_PROTOCOL, "Netlink netfilter");
col_clear(pinfo->cinfo, COL_INFO);
- proto_item_set_text(tree, "Linux netlink netfilter message");
+ pi = proto_tree_add_item(tree, proto_registrar_get_nth(proto_netlink_netfilter), tvb, 0, -1, ENC_NA);
+ nlmsg_tree = proto_item_add_subtree(pi, ett_netlink_netfilter);
- /* XXX, from header tvb */
- proto_tree_add_uint(tree, &hfi_netlink_netfilter_subsys, NULL, 0, 0, data->type);
+ /* Netlink message header (nlmsghdr) */
+ offset = dissect_netlink_header(tvb, nlmsg_tree, offset, data->encoding, NULL, NULL);
+ proto_tree_add_item(nlmsg_tree, &hfi_netlink_netfilter_subsys, tvb, 4, 2, data->encoding);
switch (data->type >> 8) {
case WS_NFNL_SUBSYS_QUEUE:
- proto_tree_add_uint(tree, &hfi_nfq_type, NULL, 0, 0, data->type);
+ proto_tree_add_item(nlmsg_tree, &hfi_nfq_type, tvb, 4, 2, data->encoding);
break;
case WS_NFNL_SUBSYS_ULOG:
- proto_tree_add_uint(tree, &hfi_netlink_netfilter_ulog_type, NULL, 0, 0, data->type);
+ proto_tree_add_item(nlmsg_tree, &hfi_netlink_netfilter_ulog_type, tvb, 4, 2, data->encoding);
break;
case WS_NFNL_SUBSYS_IPSET:
- proto_tree_add_uint(tree, &hfi_ipset_command, NULL, 0, 0, data->type);
+ proto_tree_add_item(nlmsg_tree, &hfi_ipset_command, tvb, 4, 2, data->encoding);
break;
}
@@ -1154,19 +1158,22 @@ dissect_netlink_netfilter(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, v
info.data = data;
info.hw_protocol = 0;
- offset = 0;
-
switch (data->type >> 8) {
case WS_NFNL_SUBSYS_QUEUE:
- offset = dissect_netfilter_queue(tvb, &info, tree, offset);
+ offset = dissect_netfilter_queue(tvb, &info, nlmsg_tree, offset);
break;
case WS_NFNL_SUBSYS_ULOG:
- offset = dissect_netfilter_ulog(tvb, &info, tree, offset);
+ offset = dissect_netfilter_ulog(tvb, &info, nlmsg_tree, offset);
break;
case WS_NFNL_SUBSYS_IPSET:
- offset = dissect_netfilter_ipset(tvb, &info, tree, offset);
+ offset = dissect_netfilter_ipset(tvb, &info, nlmsg_tree, offset);
+ break;
+
+ default:
+ call_data_dissector(tvb_new_subset_remaining(tvb, offset), pinfo, nlmsg_tree);
+ offset = tvb_reported_length(tvb);
break;
}
@@ -1242,8 +1249,6 @@ proto_register_netlink_netfilter(void)
&ett_ipset_ip_attr,
};
- int proto_netlink_netfilter;
-
proto_netlink_netfilter = proto_register_protocol("Linux netlink netfilter protocol", "netfilter", "netlink-netfilter" );
hfi_netlink_netfilter = proto_registrar_get_nth(proto_netlink_netfilter);
diff --git a/epan/dissectors/packet-netlink-route.c b/epan/dissectors/packet-netlink-route.c
index c00090e0e3..0c328b0b2d 100644
--- a/epan/dissectors/packet-netlink-route.c
+++ b/epan/dissectors/packet-netlink-route.c
@@ -287,6 +287,8 @@ enum {
WS_NUD_PERMANENT = 0x80
};
+static int proto_netlink_route;
+
static dissector_handle_t netlink_route_handle;
static header_field_info *hfi_netlink_route = NULL;
@@ -970,32 +972,24 @@ static header_field_info hfi_netlink_route_nltype NETLINK_ROUTE_HFI_INIT =
static int
dissect_netlink_route(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *_data)
{
- int offset;
-
struct netlink_route_info info;
- struct packet_netlink_data *data = NULL;
-
- if (_data) {
- if (((struct packet_netlink_data *) _data)->magic == PACKET_NETLINK_MAGIC)
- data = (struct packet_netlink_data *) _data;
- }
+ struct packet_netlink_data *data = (struct packet_netlink_data *)_data;
+ proto_tree *nlmsg_tree;
+ proto_item *pi;
+ int offset = 0;
- DISSECTOR_ASSERT(data);
+ DISSECTOR_ASSERT(data && data->magic == PACKET_NETLINK_MAGIC);
col_set_str(pinfo->cinfo, COL_PROTOCOL, "Netlink route");
col_clear(pinfo->cinfo, COL_INFO);
- offset = 0;
+ pi = proto_tree_add_item(tree, proto_registrar_get_nth(proto_netlink_route), tvb, 0, -1, ENC_NA);
+ nlmsg_tree = proto_item_add_subtree(pi, ett_netlink_route);
- if (tree) {
- proto_item_set_text(tree, "Linux rtnetlink (route netlink) message");
-
- /* XXX, from header tvb */
- proto_tree_add_uint(tree, &hfi_netlink_route_nltype, NULL, 0, 0, data->type);
- }
+ /* Netlink message header (nlmsghdr) */
+ offset = dissect_netlink_header(tvb, nlmsg_tree, offset, data->encoding, &hfi_netlink_route_nltype, NULL);
info.encoding = data->encoding;
-
info.pinfo = pinfo;
info.data = data;
@@ -1005,9 +999,9 @@ dissect_netlink_route(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void
case WS_RTM_GETLINK:
/* backward compatibility with legacy tools; 16 is sizeof(struct ifinfomsg) */
info.legacy = (data->type == WS_RTM_GETLINK) && (tvb_reported_length_remaining(tvb, offset) < 16);
- offset = dissect_netlink_route_ifinfomsg(tvb, &info, tree, offset);
+ offset = dissect_netlink_route_ifinfomsg(tvb, &info, nlmsg_tree, offset);
/* Optional attributes */
- offset = dissect_netlink_route_attributes(tvb, &hfi_netlink_route_ifla_attr_type, &info, tree, offset, dissect_netlink_route_ifla_attrs);
+ offset = dissect_netlink_route_attributes(tvb, &hfi_netlink_route_ifla_attr_type, &info, nlmsg_tree, offset, dissect_netlink_route_ifla_attrs);
break;
case WS_RTM_NEWADDR:
@@ -1015,9 +1009,9 @@ dissect_netlink_route(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void
case WS_RTM_GETADDR:
/* backward compatibility with legacy tools; 8 is sizeof(struct ifaddrmsg) */
info.legacy = (data->type == WS_RTM_GETADDR) && (tvb_reported_length_remaining(tvb, offset) < 8);
- offset = dissect_netlink_route_ifaddrmsg(tvb, &info, tree, offset);
+ offset = dissect_netlink_route_ifaddrmsg(tvb, &info, nlmsg_tree, offset);
/* Optional attributes */
- offset = dissect_netlink_route_attributes(tvb, &hfi_netlink_route_ifa_attr_type, &info, tree, offset, dissect_netlink_route_ifa_attrs);
+ offset = dissect_netlink_route_attributes(tvb, &hfi_netlink_route_ifa_attr_type, &info, nlmsg_tree, offset, dissect_netlink_route_ifa_attrs);
break;
case WS_RTM_NEWROUTE:
@@ -1025,9 +1019,9 @@ dissect_netlink_route(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void
case WS_RTM_GETROUTE:
/* backward compatibility with legacy tools; 12 is sizeof(struct rtmsg) */
info.legacy = (data->type == WS_RTM_GETROUTE) && (tvb_reported_length_remaining(tvb, offset) < 12);
- offset = dissect_netlink_route_rtmsg(tvb, &info, tree, offset);
+ offset = dissect_netlink_route_rtmsg(tvb, &info, nlmsg_tree, offset);
/* Optional attributes */
- offset = dissect_netlink_route_attributes(tvb, &hfi_netlink_route_rta_attr_type, &info, tree, offset, dissect_netlink_route_route_attrs);
+ offset = dissect_netlink_route_attributes(tvb, &hfi_netlink_route_rta_attr_type, &info, nlmsg_tree, offset, dissect_netlink_route_route_attrs);
break;
case WS_RTM_NEWNEIGH:
@@ -1035,7 +1029,7 @@ dissect_netlink_route(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void
case WS_RTM_GETNEIGH:
/* backward compatibility with legacy tools; 12 is sizeof(struct ndmsg) */
info.legacy = (data->type == WS_RTM_GETNEIGH) && (tvb_reported_length_remaining(tvb, offset) < 12);
- offset = dissect_netlink_route_ndmsg(tvb, &info, tree, offset);
+ offset = dissect_netlink_route_ndmsg(tvb, &info, nlmsg_tree, offset);
break;
}
@@ -1103,8 +1097,6 @@ proto_register_netlink_route(void)
&ett_netlink_route_if_flags
};
- int proto_netlink_route;
-
proto_netlink_route = proto_register_protocol("Linux rtnetlink (route netlink) protocol", "rtnetlink", "netlink-route" );
hfi_netlink_route = proto_registrar_get_nth(proto_netlink_route);
diff --git a/epan/dissectors/packet-netlink-sock_diag.c b/epan/dissectors/packet-netlink-sock_diag.c
index b118a0f87e..1592072c9d 100644
--- a/epan/dissectors/packet-netlink-sock_diag.c
+++ b/epan/dissectors/packet-netlink-sock_diag.c
@@ -39,6 +39,8 @@ typedef struct {
int encoding; /* copy of data->encoding */
} netlink_sock_diag_info_t;
+static int proto_netlink_sock_diag;
+
static dissector_handle_t netlink_sock_diag_handle;
static header_field_info *hfi_netlink_sock_diag = NULL;
@@ -1103,26 +1105,22 @@ static header_field_info hfi_netlink_sock_diag_nltype NETLINK_SOCK_DIAG_HFI_INIT
static int
dissect_netlink_sock_diag(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *_data)
{
- struct packet_netlink_data *data = NULL;
+ struct packet_netlink_data *data = (struct packet_netlink_data *)_data;
netlink_sock_diag_info_t info;
- int offset;
-
- if (_data) {
- if (((struct packet_netlink_data *) _data)->magic == PACKET_NETLINK_MAGIC)
- data = (struct packet_netlink_data *) _data;
- }
+ proto_tree *nlmsg_tree;
+ proto_item *pi;
+ int offset = 0;
- DISSECTOR_ASSERT(data);
+ DISSECTOR_ASSERT(data && data->magic == PACKET_NETLINK_MAGIC);
col_set_str(pinfo->cinfo, COL_PROTOCOL, "Netlink sock diag");
col_clear(pinfo->cinfo, COL_INFO);
- if (tree) {
- proto_item_set_text(tree, "Linux netlink sock diag message");
+ pi = proto_tree_add_item(tree, proto_registrar_get_nth(proto_netlink_sock_diag), tvb, 0, -1, ENC_NA);
+ nlmsg_tree = proto_item_add_subtree(pi, ett_netlink_sock_diag);
- /* XXX, from header tvb */
- proto_tree_add_uint(tree, &hfi_netlink_sock_diag_nltype, NULL, 0, 0, data->type);
- }
+ /* Netlink message header (nlmsghdr) */
+ offset = dissect_netlink_header(tvb, nlmsg_tree, offset, data->encoding, &hfi_netlink_sock_diag_nltype, NULL);
info.encoding = data->encoding;
info.pinfo = pinfo;
@@ -1137,7 +1135,7 @@ dissect_netlink_sock_diag(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, v
break;
case WS_SOCK_DIAG_BY_FAMILY:
- offset = dissect_sock_diag_by_family(tvb, &info, tree, offset);
+ offset = dissect_sock_diag_by_family(tvb, &info, nlmsg_tree, offset);
break;
}
@@ -1221,8 +1219,6 @@ proto_register_netlink_sock_diag(void)
&ett_netlink_sock_diag_attr
};
- int proto_netlink_sock_diag;
-
proto_netlink_sock_diag = proto_register_protocol("Linux netlink sock diag protocol", "sock_diag", "netlink-sock_diag" );
hfi_netlink_sock_diag = proto_registrar_get_nth(proto_netlink_sock_diag);
diff --git a/epan/dissectors/packet-netlink.c b/epan/dissectors/packet-netlink.c
index 06cb9ec154..3d73982eea 100644
--- a/epan/dissectors/packet-netlink.c
+++ b/epan/dissectors/packet-netlink.c
@@ -340,27 +340,43 @@ dissect_netlink_attributes_array(tvbuff_t *tvb, header_field_info *hfi_type, int
return dissect_netlink_attributes_common(tvb, hfi_type, ett_array, ett_attrib, data, nl_data, tree, offset, length, cb);
}
-static int
-dissect_netlink_hdr(tvbuff_t *tvb, proto_tree *tree, int offset, int encoding, guint16 *type, guint32 *port_id)
+int
+dissect_netlink_header(tvbuff_t *tvb, proto_tree *tree, int offset, int encoding, header_field_info *hfi_type, proto_item **pi_type)
{
guint16 hdr_flags;
guint16 hdr_type;
-
proto_tree *fh_hdr;
- proto_item *pi_type;
+ proto_item *pi;
fh_hdr = proto_tree_add_subtree(tree, tvb, offset, 16, ett_netlink_msghdr, NULL, "Header");
proto_tree_add_item(fh_hdr, &hfi_netlink_hdr_len, tvb, offset, 4, encoding);
offset += 4;
- pi_type = proto_tree_add_item(fh_hdr, &hfi_netlink_hdr_type, tvb, offset, 2, encoding);
hdr_type = tvb_get_guint16(tvb, offset, encoding);
- if (hdr_type >= WS_NLMSG_MIN_TYPE) {
- proto_item_set_text(pi_type, "Message type: Protocol-specific (0x%04x)", hdr_type);
+ if (hdr_type < WS_NLMSG_MIN_TYPE) {
+ /* Reserved control messages. */
+ hfi_type = &hfi_netlink_hdr_type;
+ pi = proto_tree_add_item(fh_hdr, hfi_type, tvb, offset, 2, encoding);
+ } else {
+ if (hfi_type) {
+ pi = proto_tree_add_item(fh_hdr, hfi_type, tvb, offset, 2, encoding);
+ } else {
+ hfi_type = &hfi_netlink_hdr_type;
+ pi = proto_tree_add_item(fh_hdr, hfi_type, tvb, offset, 2, encoding);
+ proto_item_set_text(pi, "Message type: Protocol-specific (0x%04x)", hdr_type);
+ }
}
- if (type) {
- *type = hdr_type;
+ if (pi_type) {
+ *pi_type = pi;
+ }
+ /* TODO export hf_try_val_to_str? */
+ if (hfi_type->strings && hfi_type->display & BASE_EXT_STRING) {
+ proto_item_append_text(fh_hdr, " (type: %s)", val_to_str_ext(hdr_type, (value_string_ext *)hfi_type->strings, "0x%04x"));
+ } else if (hfi_type->strings) {
+ proto_item_append_text(fh_hdr, " (type: %s)", val_to_str(hdr_type, (const value_string *)hfi_type->strings, "0x%04x"));
+ } else {
+ proto_item_append_text(fh_hdr, " (type: 0x%04x)", hdr_type);
}
offset += 2;
@@ -382,7 +398,7 @@ dissect_netlink_hdr(tvbuff_t *tvb, proto_tree *tree, int offset, int encoding, g
proto_tree_add_item(fh_hdr, &hfi_netlink_hdr_seq, tvb, offset, 4, encoding);
offset += 4;
- proto_tree_add_item_ret_uint(fh_hdr, hfi_netlink_hdr_pid.id, tvb, offset, 4, encoding, port_id);
+ proto_tree_add_item(fh_hdr, &hfi_netlink_hdr_pid, tvb, offset, 4, encoding);
offset += 4;
return offset;
@@ -403,7 +419,7 @@ dissect_netlink_error(tvbuff_t *tvb, proto_tree *tree, int offset, int encoding)
proto_tree_add_item(tree, &hfi_netlink_error, tvb, offset, 4, encoding);
offset += 4;
- dissect_netlink_hdr(tvb, tree, offset, encoding, NULL, NULL);
+ dissect_netlink_header(tvb, tree, offset, encoding, NULL, NULL);
}
static int
@@ -462,21 +478,17 @@ dissect_netlink(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *_data
}
while (tvb_reported_length_remaining(tvb, offset) >= 16) {
- struct packet_netlink_data data;
-
int pkt_end_offset;
+ guint16 msg_type;
guint32 pkt_len;
guint32 port_id;
-
proto_tree *fh_msg;
-
+ gboolean dissected = FALSE;
pkt_len = tvb_get_guint32(tvb, offset, encoding);
pkt_end_offset = offset + pkt_len;
- fh_msg = proto_tree_add_subtree(tree, tvb, offset, pkt_len, ett_netlink_msg, NULL, "Netlink message");
-
if (pkt_len < 16) {
/*
* This field includes the length of the 16-byte header,
@@ -492,7 +504,9 @@ dissect_netlink(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *_data
break;
}
- offset = dissect_netlink_hdr(tvb, fh_msg, offset, encoding, &data.type, &port_id);
+ /* message type field comes after length field. */
+ msg_type = tvb_get_guint16(tvb, offset + 4, encoding);
+ port_id = tvb_get_guint32(tvb, offset + 12, encoding);
/* XXX */
if (port_id == 0x00)
@@ -500,17 +514,37 @@ dissect_netlink(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *_data
else
pinfo->p2p_dir = P2P_DIR_RECV; /* userspace or kernel -> userspace */
- if (data.type == WS_NLMSG_ERROR) {
- dissect_netlink_error(tvb, fh_msg, offset, encoding);
- } else if (pkt_len > 16) {
+ /*
+ * Try to invoke subdissectors for non-control messages.
+ */
+ if (msg_type >= WS_NLMSG_MIN_TYPE && pkt_len > 16) {
+ struct packet_netlink_data data;
+
data.magic = PACKET_NETLINK_MAGIC;
data.encoding = encoding;
+ data.type = msg_type;
- next_tvb = tvb_new_subset_length(tvb, offset, pkt_len-16);
+ next_tvb = tvb_new_subset_length(tvb, offset, pkt_len);
- if (!dissector_try_uint_new(netlink_dissector_table, protocol, next_tvb, pinfo, fh_msg, TRUE, &data))
- call_data_dissector(next_tvb, pinfo, fh_msg);
+ if (dissector_try_uint_new(netlink_dissector_table, protocol, next_tvb, pinfo, tree, TRUE, &data)) {
+ dissected = TRUE;
+ }
+ }
+ if (!dissected) {
+ /*
+ * No subdissector was called, add a new layer with the
+ * header and the payload. Note that pkt_len>=16.
+ */
+ fh_msg = proto_tree_add_subtree(tree, tvb, offset, pkt_len, ett_netlink_msg, NULL, "Netlink message");
+ offset = dissect_netlink_header(tvb, fh_msg, offset, encoding, NULL, NULL);
+
+ if (msg_type == WS_NLMSG_ERROR) {
+ dissect_netlink_error(tvb, fh_msg, offset, encoding);
+ } else if (pkt_len > 16) {
+ next_tvb = tvb_new_subset_length(tvb, offset, pkt_len - 16);
+ call_data_dissector(next_tvb, pinfo, fh_msg);
+ }
}
offset = pkt_end_offset;
diff --git a/epan/dissectors/packet-netlink.h b/epan/dissectors/packet-netlink.h
index e02cd685fe..fd379fe507 100644
--- a/epan/dissectors/packet-netlink.h
+++ b/epan/dissectors/packet-netlink.h
@@ -105,6 +105,12 @@ struct packet_netlink_data {
guint16 type;
};
+/**
+ * Dissects the Netlink message header (struct nlmsghdr). The "hfi_type" field
+ * is added for the "nlmsg_type" field and returned into pi_type.
+ */
+int dissect_netlink_header(tvbuff_t *tvb, proto_tree *tree, int offset, int encoding, header_field_info *hfi_type, proto_item **pi_type);
+
typedef int netlink_attributes_cb_t(tvbuff_t *, void *data, proto_tree *, int nla_type, int offset, int len);
int dissect_netlink_attributes(tvbuff_t *tvb, header_field_info *hfi_type, int ett, void *data, struct packet_netlink_data *nl_data, proto_tree *tree, int offset, int length, netlink_attributes_cb_t cb);