Add initial dissectors for netlink, and netlink route subsystem.
[metze/wireshark/wip.git] / epan / dissectors / packet-netlink.c
1 /* packet-netlink.c
2  *
3  * $Id$
4  *
5  * Wireshark - Network traffic analyzer
6  * By Gerald Combs <gerald@wireshark.org>
7  * Copyright 1998 Gerald Combs
8  *
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public License
11  * as published by the Free Software Foundation; either version 2
12  * of the License, or (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22  */
23
24 /* http://www.tcpdump.org/linktypes/LINKTYPE_NETLINK.html */
25
26 #define NEW_PROTO_TREE_API
27
28 #include "config.h"
29
30 #include <glib.h>
31
32 #include <epan/arptypes.h>
33 #include <epan/packet.h>
34 #include <wiretap/wtap.h>
35
36 #include "packet-netlink.h"
37
38 /*
39  * A DLT_LINUX_SLL fake link-layer header.
40  */
41 #define SLL_HEADER_SIZE 16              /* total header length */
42
43 static const value_string ltype_vals[] = {
44         { WS_NETLINK_ROUTE,       "Route" },
45         { WS_NETLINK_UNUSED,      "Unused" },
46         { WS_NETLINK_USERSOCK,    "user-mode" },
47         { WS_NETLINK_FIREWALL,    "Unused (formerly: ip_queue)" },
48         { WS_NETLINK_SOCK_DIAG,   "socket monitoring" },
49         { WS_NETLINK_NFLOG,       "Netfilter ULOG" },
50         { WS_NETLINK_XFRM,        "IPsec" },
51         { WS_NETLINK_SELINUX,     "SELinux events" },
52         { WS_NETLINK_ISCSI,       "Open-iSCSI" },
53         { WS_NETLINK_AUDIT,       "Auditing" },
54         { WS_NETLINK_FIB_LOOKUP,  "FIB lookup" },
55         { WS_NETLINK_CONNECTOR,   "Kernel connector" },
56         { WS_NETLINK_NETFILTER,   "Netfilter" },
57         { WS_NETLINK_IP6_FW,      "Unused (formerly: ip6_queue)" },
58         { WS_NETLINK_DNRTMSG,     "DECnet routing messages" },
59         { WS_NETLINK_KOBJECT_UEVENT, "Kernel messages" },
60         { WS_NETLINK_GENERIC,      "Generic" },
61         { WS_NETLINK_SCSITRANSPORT, "SCSI Transports" },
62         { WS_NETLINK_ECRYPTFS,     "ecryptfs" },
63         { WS_NETLINK_RDMA,         "RDMA" },
64         { WS_NETLINK_CRYPTO,       "Crypto layer" },
65         { 0, NULL }
66 };
67
68
69 static dissector_handle_t netlink_handle;
70
71 static header_field_info *hfi_netlink = NULL;
72
73 #define NETLINK_HFI_INIT HFI_INIT(proto_netlink)
74
75 static header_field_info hfi_netlink_hatype NETLINK_HFI_INIT =
76         { "Link-layer address type",    "netlink.hatype", FT_UINT16, BASE_DEC,
77           NULL, 0x0, NULL, HFILL };
78
79 /* Linux netlink protocol type */
80 static header_field_info hfi_netlink_family NETLINK_HFI_INIT =
81         { "Family",     "netlink.family", FT_UINT16, BASE_HEX,
82           VALS(ltype_vals), 0x00, NULL, HFILL };
83
84
85 static header_field_info hfi_netlink_hdr_len NETLINK_HFI_INIT =
86         { "Length", "netlink.hdr_len", FT_UINT32, BASE_DEC,
87           NULL, 0x00, NULL, HFILL };
88
89 static header_field_info hfi_netlink_hdr_type NETLINK_HFI_INIT =
90         { "Type", "netlink.hdr_type", FT_UINT16, BASE_HEX,
91           NULL, 0x00, NULL, HFILL };
92
93 static header_field_info hfi_netlink_hdr_flags NETLINK_HFI_INIT =
94         { "Flags", "netlink.hdr_flags", FT_UINT16, BASE_HEX,
95           NULL, 0x00, NULL, HFILL };
96
97 static header_field_info hfi_netlink_hdr_seq NETLINK_HFI_INIT =
98         { "Sequence", "netlink.hdr_seq", FT_UINT32, BASE_HEX,
99           NULL, 0x00, NULL, HFILL };
100
101 static header_field_info hfi_netlink_hdr_pid NETLINK_HFI_INIT =
102         { "Port ID", "netlink.hdr_pid", FT_UINT32, BASE_HEX,
103           NULL, 0x00, NULL, HFILL };
104
105 static gint ett_netlink_cooked = -1;
106 static gint ett_netlink_msghdr = -1;
107 static gint ett_netlink_msg = -1;
108
109 static dissector_table_t netlink_dissector_table;
110 static dissector_handle_t data_handle;
111
112 static int
113 dissect_netlink(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *_data _U_)
114 {
115         guint16 protocol, hatype;
116         proto_item *ti;
117         tvbuff_t *next_tvb;
118         proto_tree *fh_tree = NULL;
119
120         int offset;
121
122         hatype = tvb_get_ntohs(tvb, 2);
123         if (hatype != ARPHRD_NETLINK)
124                 return 0;
125
126         col_set_str(pinfo->cinfo, COL_PROTOCOL, "Netlink");
127         col_clear(pinfo->cinfo, COL_INFO);
128
129         if (tree) {
130                 ti = proto_tree_add_protocol_format(tree, hfi_netlink->id, tvb, 0,
131                     SLL_HEADER_SIZE, "Linux netlink (cooked header)");
132                 fh_tree = proto_item_add_subtree(ti, ett_netlink_cooked);
133         }
134
135         /* Unused 2B */
136         offset = 2;
137
138         proto_tree_add_item(fh_tree, &hfi_netlink_hatype, tvb, offset, 2, ENC_BIG_ENDIAN);
139         offset += 2;
140
141         /* Unused 10B */
142         offset += 10;
143
144         protocol = tvb_get_ntohs(tvb, offset);
145         proto_tree_add_item(fh_tree, &hfi_netlink_family, tvb, offset, 2, ENC_BIG_ENDIAN);
146         offset += 2;
147
148         /* DISSECTOR_ASSERT(offset == 16); */
149
150         while (tvb_reported_length_remaining(tvb, offset) >= 16) {
151                 struct packet_netlink_data data;
152
153                 int pkt_end_offset;
154                 guint32 pkt_len;
155
156                 proto_tree *fh_msg;
157                 proto_tree *fh_hdr;
158
159                 int encoding = ENC_LITTLE_ENDIAN; /* XXX */
160
161                 pkt_len = tvb_get_letohl(tvb, offset);
162
163                 pkt_end_offset = offset + pkt_len;
164
165                 ti = proto_tree_add_text(tree, tvb, offset, pkt_len, "Netlink message");
166                 fh_msg = proto_item_add_subtree(ti, ett_netlink_msg);
167
168                 ti = proto_tree_add_text(fh_msg, tvb, offset, 16, "Header");
169                 fh_hdr = proto_item_add_subtree(ti, ett_netlink_msghdr);
170
171                 proto_tree_add_item(fh_hdr, &hfi_netlink_hdr_len, tvb, offset, 4, encoding);
172                 offset += 4;
173
174                 proto_tree_add_item(fh_hdr, &hfi_netlink_hdr_type, tvb, offset, 2, encoding);
175                 data.type = tvb_get_letohs(tvb, offset);
176                 offset += 2;
177
178                 proto_tree_add_item(fh_hdr, &hfi_netlink_hdr_flags, tvb, offset, 2, encoding);
179                 offset += 2;
180
181                 proto_tree_add_item(fh_hdr, &hfi_netlink_hdr_seq, tvb, offset, 4, encoding);
182                 offset += 4;
183
184                 proto_tree_add_item(fh_hdr, &hfi_netlink_hdr_pid, tvb, offset, 4, encoding);
185                 offset += 4;
186
187                 if (pkt_len > 16) {
188                         data.magic = PACKET_NETLINK_MAGIC;
189                         data.encoding = encoding;
190
191                         next_tvb = tvb_new_subset_length(tvb, offset, pkt_len-16);
192
193                         if (!dissector_try_uint_new(netlink_dissector_table, protocol, next_tvb, pinfo, fh_msg, TRUE, &data))
194                                 call_dissector(data_handle, next_tvb, pinfo, fh_msg);
195
196                 } else if (pkt_len != 16) {
197                         /* XXX, expert info */
198                         break;
199                 }
200
201                 offset = pkt_end_offset;
202         }
203
204         return offset;
205 }
206
207 void
208 proto_register_netlink(void)
209 {
210 #ifndef HAVE_HFI_SECTION_INIT
211         static header_field_info *hfi[] = {
212         /* Cooked header */
213                 &hfi_netlink_hatype,
214                 &hfi_netlink_family,
215
216         /* Netlink message header */
217                 &hfi_netlink_hdr_len,
218                 &hfi_netlink_hdr_type,
219                 &hfi_netlink_hdr_flags,
220                 &hfi_netlink_hdr_seq,
221                 &hfi_netlink_hdr_pid,
222         };
223 #endif
224
225         static gint *ett[] = {
226                 &ett_netlink_cooked,
227                 &ett_netlink_msghdr,
228                 &ett_netlink_msg
229         };
230
231         int proto_netlink;
232
233         proto_netlink = proto_register_protocol("Linux netlink protocol",  "NETLINK", "netlink" );
234         hfi_netlink = proto_registrar_get_nth(proto_netlink);
235
236         proto_register_fields(proto_netlink, hfi, array_length(hfi));
237         proto_register_subtree_array(ett, array_length(ett));
238
239         netlink_handle = new_create_dissector_handle(dissect_netlink, proto_netlink);
240
241         netlink_dissector_table = register_dissector_table(
242                 "netlink.protocol",
243                 "Linux netlink protocol type",
244                 FT_UINT16,
245                 BASE_HEX
246         );
247 }
248
249 void
250 proto_reg_handoff_netlink(void)
251 {
252         data_handle = find_dissector("data");
253
254         dissector_add_uint("wtap_encap", WTAP_ENCAP_NETLINK, netlink_handle);
255 }