2 * Routines for the disassembly of the Mikrotik Neighbor Discovery Protocol
6 * Copyright 2011 Joerg Mayer (see AUTHORS file)
8 * Wireshark - Network traffic analyzer
9 * By Gerald Combs <gerald@wireshark.org>
10 * Copyright 1998 Gerald Combs
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
28 http://wiki.mikrotik.com/wiki/Manual:IP/Neighbor_discovery
30 - Find out about first 4 bytes
31 - Find out about additional TLVs
32 - Find out about unpack values
38 #include <epan/packet.h>
39 #include <epan/wmem/wmem.h>
41 /* protocol handles */
42 static int proto_mndp
= -1;
45 static int ett_mndp
= -1;
46 static int ett_mndp_tlv_header
= -1;
50 static int hf_mndp_tlv_type
= -1;
51 static int hf_mndp_tlv_length
= -1;
52 static int hf_mndp_tlv_data
= -1;
54 static int hf_mndp_header_unknown
= -1;
55 static int hf_mndp_header_seqno
= -1;
57 static int hf_mndp_mac
= -1;
58 static int hf_mndp_softwareid
= -1;
59 static int hf_mndp_version
= -1;
60 static int hf_mndp_identity
= -1;
61 static int hf_mndp_uptime
= -1;
62 static int hf_mndp_platform
= -1;
63 static int hf_mndp_board
= -1;
64 static int hf_mndp_unpack
= -1;
65 static int hf_mndp_ipv6address
= -1;
67 #define PROTO_SHORT_NAME "MNDP"
68 #define PROTO_LONG_NAME "Mikrotik Neighbor Discovery Protocol"
70 #define PORT_MNDP 5678
72 /* ============= copy/paste/modify from value_string.[hc] ============== */
73 typedef struct _ext_value_string
{
77 int (*specialfunction
)(tvbuff_t
*, packet_info
*, proto_tree
*, guint32
,
78 guint32
, const struct _ext_value_string
*);
79 const struct _ext_value_string
*evs
;
84 match_strextval_idx(guint32 val
, const ext_value_string
*vs
, gint
*idx
) {
88 while (vs
[i
].strptr
) {
89 if (vs
[i
].value
== val
) {
104 extval_to_str_idx(guint32 val
, const ext_value_string
*vs
, gint
*idx
, const char *fmt
) {
110 ret
= match_strextval_idx(val
, vs
, idx
);
114 return wmem_strdup_printf(wmem_packet_scope(), fmt
, val
);
116 /* ============= end copy/paste/modify ============== */
118 /* Forward decls needed by mndp_tunnel_tlv_vals et al */
119 static int dissect_tlv(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*mndp_tree
,
120 guint32 offset
, guint32 length
, const ext_value_string
*value_array
);
122 static const ext_value_string mndp_body_tlv_vals
[] = {
123 { 1, "MAC-Address", &hf_mndp_mac
, NULL
, NULL
},
124 { 5, "Identity", &hf_mndp_identity
, NULL
, NULL
},
125 { 7, "Version", &hf_mndp_version
, NULL
, NULL
},
126 { 8, "Platform", &hf_mndp_platform
, NULL
, NULL
},
127 { 10, "Uptime", &hf_mndp_uptime
, NULL
, (ext_value_string
*)TRUE
},
128 { 11, "Software-ID", &hf_mndp_softwareid
, NULL
, NULL
},
129 { 12, "Board", &hf_mndp_board
, NULL
, NULL
},
130 { 14, "Unpack", &hf_mndp_unpack
, NULL
, NULL
},
131 { 15, "IPv6-Address", &hf_mndp_ipv6address
, NULL
, NULL
},
133 { 0, NULL
, NULL
, NULL
, NULL
}
136 static const value_string mndp_unpack_vals
[] = {
137 /* none|simple|uncompressed-headers|uncompressed-all */
144 dissect_tlv(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*mndp_tree
,
145 guint32 offset
, guint32 length _U_
, const ext_value_string
*value_array
)
149 proto_item
*tlv_item
;
150 proto_item
*tlv_tree
;
151 proto_item
*type_item
;
156 tlv_type
= tvb_get_ntohs(tvb
, offset
);
157 tlv_length
= tvb_get_ntohs(tvb
, offset
+ 2);
158 /* DISSECTOR_ASSERT(tlv_length >= 4); */
159 tlv_item
= proto_tree_add_text(mndp_tree
, tvb
,
160 offset
, tlv_length
+4,
164 extval_to_str_idx(tlv_type
, value_array
, NULL
, "Unknown"));
165 tlv_tree
= proto_item_add_subtree(tlv_item
,
166 ett_mndp_tlv_header
);
167 type_item
= proto_tree_add_item(tlv_tree
, hf_mndp_tlv_type
,
168 tvb
, offset
, 2, ENC_BIG_ENDIAN
);
169 proto_item_append_text(type_item
, " = %s",
170 extval_to_str_idx(tlv_type
, value_array
,
171 &type_index
, "Unknown"));
173 proto_tree_add_item(tlv_tree
, hf_mndp_tlv_length
,
174 tvb
, offset
, 2, ENC_BIG_ENDIAN
);
177 /* tlv_length -= 4; */
182 tlv_end
= offset
+ tlv_length
;
184 /* Make hf_ handling independent of specialfuncion */
185 /* FIXME: Properly handle encoding info */
186 if ( type_index
!= -1
187 && !value_array
[type_index
].specialfunction
188 && value_array
[type_index
].evs
!= NULL
190 encoding_info
= value_array
[type_index
].evs
? TRUE
: FALSE
;
192 encoding_info
= FALSE
;
194 if ( type_index
!= -1 && value_array
[type_index
].hf_element
) {
195 proto_tree_add_item(tlv_tree
,
196 *(value_array
[type_index
].hf_element
),
197 tvb
, offset
, tlv_length
, encoding_info
);
199 proto_tree_add_item(tlv_tree
, hf_mndp_tlv_data
,
200 tvb
, offset
, tlv_length
, ENC_NA
);
202 if ( type_index
!= -1 && value_array
[type_index
].specialfunction
) {
205 while (offset
< tlv_end
) {
206 newoffset
= value_array
[type_index
].specialfunction (
207 tvb
, pinfo
, tlv_tree
, offset
, tlv_length
,
208 value_array
[type_index
].evs
);
209 DISSECTOR_ASSERT(newoffset
> offset
);
217 dissect_mndp(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
)
220 proto_tree
*mndp_tree
;
222 guint32 packet_length
;
224 col_set_str(pinfo
->cinfo
, COL_PROTOCOL
, PROTO_SHORT_NAME
);
226 packet_length
= tvb_length(tvb
);
228 /* Header dissection */
229 ti
= proto_tree_add_item(tree
, proto_mndp
, tvb
, offset
, -1,
231 mndp_tree
= proto_item_add_subtree(ti
, ett_mndp
);
233 proto_tree_add_item(mndp_tree
, hf_mndp_header_unknown
, tvb
, offset
, 2,
236 proto_tree_add_item(mndp_tree
, hf_mndp_header_seqno
, tvb
, offset
, 2,
240 while (offset
< packet_length
) {
241 offset
= dissect_tlv(tvb
, pinfo
, mndp_tree
,
242 offset
, 0, mndp_body_tlv_vals
);
249 test_mndp(tvbuff_t
*tvb
)
251 /* Minimum of 8 bytes, 4 Bytes header + 1 TLV-header */
252 if ( tvb_length(tvb
) < 8
253 || tvb_get_guint8(tvb
, 4) != 0
254 || tvb_get_guint8(tvb
, 6) != 0
263 dissect_mndp_heur(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
)
265 if ( !test_mndp(tvb
) ) {
268 dissect_mndp(tvb
, pinfo
, tree
);
274 dissect_mndp_static(tvbuff_t
*tvb
, packet_info
*pinfo
, proto_tree
*tree
, void *data _U_
)
276 if ( !test_mndp(tvb
) ) {
279 return dissect_mndp(tvb
, pinfo
, tree
);
283 proto_register_mndp(void)
285 static hf_register_info hf
[] = {
289 { "TlvType", "mndp.tlv.type", FT_UINT16
, BASE_DEC
, NULL
,
292 { &hf_mndp_tlv_length
,
293 { "TlvLength", "mndp.tlv.length", FT_UINT16
, BASE_DEC
, NULL
,
297 { "TlvData", "mndp.tlv.data", FT_BYTES
, BASE_NONE
, NULL
,
300 /* MNDP tunnel header */
301 { &hf_mndp_header_unknown
,
302 { "Header Unknown", "mndp.header.unknown", FT_BYTES
, BASE_NONE
, NULL
,
305 { &hf_mndp_header_seqno
,
306 { "SeqNo", "mndp.header.seqno", FT_UINT16
, BASE_DEC
, NULL
,
309 /* MNDP tunnel data */
311 { "MAC-Address", "mndp.mac", FT_ETHER
, BASE_NONE
, NULL
,
314 { &hf_mndp_softwareid
,
315 { "Software-ID", "mndp.softwareid", FT_STRING
, BASE_NONE
, NULL
,
319 { "Version", "mndp.version", FT_STRING
, BASE_NONE
, NULL
,
323 { "Identity", "mndp.identity", FT_STRING
, BASE_NONE
, NULL
,
327 { "Uptime", "mndp.uptime", FT_RELATIVE_TIME
, BASE_NONE
, NULL
,
331 { "Platform", "mndp.platform", FT_STRING
, BASE_NONE
, NULL
,
335 { "Board", "mndp.board", FT_STRING
, BASE_NONE
, NULL
,
339 { "Unpack", "mndp.unpack", FT_UINT8
, BASE_DEC
, VALS(mndp_unpack_vals
),
342 { &hf_mndp_ipv6address
,
343 { "IPv6-Address", "mndp.ipv6address", FT_IPv6
, BASE_NONE
, NULL
,
347 static gint
*ett
[] = {
349 &ett_mndp_tlv_header
,
352 proto_mndp
= proto_register_protocol(PROTO_LONG_NAME
, PROTO_SHORT_NAME
, "mndp");
353 proto_register_field_array(proto_mndp
, hf
, array_length(hf
));
354 proto_register_subtree_array(ett
, array_length(ett
));
358 proto_reg_handoff_mndp(void)
360 dissector_handle_t mndp_handle
;
362 mndp_handle
= new_create_dissector_handle(dissect_mndp_static
, proto_mndp
);
363 dissector_add_uint("udp.port", PORT_MNDP
, mndp_handle
);
364 /* heur_dissector_add("udp", dissect_mndp_heur, proto_mndp); */