Move 3 ASN1 dissectors to 'clean' group; move 1 PIDL dissector to 'dirty' group.
[metze/wireshark/wip.git] / epan / dissectors / packet-nhrp.c
1 /* packet-nhrp.c
2  * Routines for NBMA Next Hop Resolution Protocol
3  * RFC 2332 plus Cisco extensions (documented where?), plus extensions from:
4  *     RFC 2520: NHRP with Mobile NHCs
5  *     RFC 2735: NHRP Support for Virtual Private Networks
6  *
7  * $Id$
8  *
9  * Wireshark - Network traffic analyzer
10  * By Gerald Combs <gerald@wireshark.org>
11  * Copyright 1998 Gerald Combs
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software
25  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
26  *
27  * CIE decoding for extensions and Cisco 12.4T extensions
28  * added by Timo Teras <timo.teras@iki.fi>
29  */
30
31 #include "config.h"
32
33 #include <string.h>
34
35 #include <glib.h>
36
37 #include <epan/packet.h>
38 #include <epan/addr_resolv.h>
39 #include <epan/expert.h>
40 #include <epan/etypes.h>
41 #include <epan/ipproto.h>
42 #include <epan/greproto.h>
43 #include <epan/nlpid.h>
44 #include <epan/oui.h>
45 #include <epan/afn.h>
46 #include <epan/in_cksum.h>
47 #include <epan/iana_snap_pid.h>
48 #include <epan/dissectors/packet-llc.h>
49 #include "packet-nhrp.h"
50
51 /* forward reference */
52 static void _dissect_nhrp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
53     gboolean nested, gboolean codeinfo);
54
55 static int proto_nhrp = -1;
56 static int hf_nhrp_hdr_afn = -1;
57 static int hf_nhrp_hdr_pro_type = -1;
58 static int hf_nhrp_hdr_pro_snap_oui = -1;
59 static int hf_nhrp_hdr_pro_snap_pid = -1;
60 static int hf_nhrp_hdr_hopcnt = -1;
61 static int hf_nhrp_hdr_pktsz = -1;
62 static int hf_nhrp_hdr_chksum = -1;
63 static int hf_nhrp_hdr_extoff = -1;
64 static int hf_nhrp_hdr_version = -1;
65 static int hf_nhrp_hdr_op_type = -1;
66 static int hf_nhrp_hdr_shtl = -1;
67 static int hf_nhrp_hdr_shtl_type = -1;
68 static int hf_nhrp_hdr_shtl_len = -1;
69 static int hf_nhrp_hdr_sstl = -1;
70 static int hf_nhrp_hdr_sstl_type = -1;
71 static int hf_nhrp_hdr_sstl_len = -1;
72
73 static int hf_nhrp_src_proto_len = -1;
74 static int hf_nhrp_dst_proto_len = -1;
75 static int hf_nhrp_flags = -1;
76 static int hf_nhrp_flag_Q = -1;
77 static int hf_nhrp_flag_N = -1;
78 static int hf_nhrp_flag_A = -1;
79 static int hf_nhrp_flag_D = -1;
80 static int hf_nhrp_flag_U1 = -1;
81 static int hf_nhrp_flag_U2 = -1;
82 static int hf_nhrp_flag_S = -1;
83 static int hf_nhrp_flag_NAT = -1;
84 static int hf_nhrp_src_nbma_addr = -1;
85 #if 0
86 static int hf_nhrp_src_nbma_saddr = -1;     /* TBD: Not used */
87 #endif
88 static int hf_nhrp_src_prot_addr = -1;
89 static int hf_nhrp_dst_prot_addr = -1;
90 static int hf_nhrp_request_id = -1;
91
92 static int hf_nhrp_code = -1;
93 static int hf_nhrp_prefix_len = -1;
94 static int hf_nhrp_unused = -1;
95 static int hf_nhrp_mtu = -1;
96 static int hf_nhrp_holding_time = -1;
97 static int hf_nhrp_cli_addr_tl = -1;
98 static int hf_nhrp_cli_addr_tl_type = -1;
99 static int hf_nhrp_cli_addr_tl_len = -1;
100 static int hf_nhrp_cli_saddr_tl = -1;
101 static int hf_nhrp_cli_saddr_tl_type = -1;
102 static int hf_nhrp_cli_saddr_tl_len = -1;
103 static int hf_nhrp_cli_prot_len = -1;
104 static int hf_nhrp_pref = -1;
105 static int hf_nhrp_client_nbma_addr = -1;
106 #if 0
107 static int hf_nhrp_client_nbma_saddr = -1;  /* TBD: Not used */
108 #endif
109 static int hf_nhrp_client_prot_addr = -1;
110 static int hf_nhrp_ext_C = -1;
111 static int hf_nhrp_ext_type = -1;
112 static int hf_nhrp_ext_len = -1;
113 #if 0
114 static int hf_nhrp_ext_value = -1;          /* TBD: Not used */
115 #endif
116 static int hf_nhrp_error_code = -1;
117 static int hf_nhrp_error_offset = -1;
118 #if 0
119 static int hf_nhrp_error_packet = -1;       /* TBD: Not used */
120 #endif
121
122 static int hf_nhrp_auth_ext_reserved = -1;
123 static int hf_nhrp_auth_ext_spi = -1;
124 static int hf_nhrp_auth_ext_src_addr = -1;
125 static int hf_nhrp_vendor_ext_id = -1;
126 static int hf_nhrp_devcap_ext_srccap = -1;
127 static int hf_nhrp_devcap_ext_srccap_V = -1;
128 static int hf_nhrp_devcap_ext_dstcap = -1;
129 static int hf_nhrp_devcap_ext_dstcap_V = -1;
130 static int hf_nhrp_unknown_ext_value = -1;
131
132 static gint ett_nhrp = -1;
133 static gint ett_nhrp_hdr = -1;
134 static gint ett_nhrp_hdr_shtl = -1;
135 static gint ett_nhrp_hdr_sstl = -1;
136 static gint ett_nhrp_mand = -1;
137 static gint ett_nhrp_ext = -1;
138 static gint ett_nhrp_mand_flag = -1;
139 static gint ett_nhrp_cie = -1;
140 static gint ett_nhrp_cie_cli_addr_tl = -1;
141 static gint ett_nhrp_cie_cli_saddr_tl = -1;
142 static gint ett_nhrp_indication = -1;
143 static gint ett_nhrp_auth_ext = -1;
144 static gint ett_nhrp_vendor_ext = -1;
145 static gint ett_nhrp_devcap_ext = -1;
146 static gint ett_nhrp_devcap_ext_srccap = -1;
147 static gint ett_nhrp_devcap_ext_dstcap = -1;
148
149 /* NHRP Packet Types */
150 #define NHRP_RESOLUTION_REQ     1
151 #define NHRP_RESOLUTION_REPLY   2
152 #define NHRP_REGISTRATION_REQ   3
153 #define NHRP_REGISTRATION_REPLY 4
154 #define NHRP_PURGE_REQ          5
155 #define NHRP_PURGE_REPLY        6
156 #define NHRP_ERROR_INDICATION   7
157 #define NHRP_TRAFFIC_INDICATION 8
158
159 /* NHRP Extension Types */
160 #define NHRP_EXT_NULL              0   /* End of Extension */
161 #define NHRP_EXT_RESP_ADDR         3   /* Responder Address Extension */
162 #define NHRP_EXT_FWD_RECORD        4   /* NHRP Forward Transit NHS Record Extension */
163 #define NHRP_EXT_REV_RECORD        5   /* NHRP Reverse Transit NHS Record Extension */
164 #define NHRP_EXT_AUTH              7   /* NHRP Authentication Extension */
165 #define NHRP_EXT_VENDOR_PRIV       8   /* NHRP Vendor Private Extension */
166 #define NHRP_EXT_NAT_ADDRESS       9   /* Cisco NAT Address Extension */
167 #define NHRP_EXT_DEV_CAPABILITIES  9   /* RFC 2735: Device Capabilities Extension */
168 #define NHRP_EXT_MOBILE_AUTH      10   /* RFC 2520: NHRP Mobile NHC Authentication Extension */
169
170 /* NHRP Error Codes */
171 #define NHRP_ERR_UNRECOGNIZED_EXT       0x0001
172 #define NHRP_ERR_NHRP_LOOP_DETECT       0x0003
173 #define NHRP_ERR_PROT_ADDR_UNREACHABLE  0x0006
174 #define NHRP_ERR_PROT_ERROR             0x0007
175 #define NHRP_ERR_SDU_SIZE_EXCEEDED      0x0008
176 #define NHRP_ERR_INV_EXT                0x0009
177 #define NHRP_ERR_INV_RESOLUTION_REPLY   0x000a
178 #define NHRP_ERR_AUTH_FAILURE           0x000b
179 #define NHRP_ERR_HOP_COUNT_EXCEEDED     0x000f
180 #define NHRP_ERR_VPN_MISMATCH           0x0010  /* RFC 2735 */
181 #define NHRP_ERR_VPN_UNSUPPORTED        0x0011  /* RFC 2735 */
182
183 /* NHRP CIE codes */
184 #define NHRP_CODE_SUCCESS                   0x00
185 #define NHRP_CODE_ADMIN_PROHIBITED          0x04
186 #define NHRP_CODE_INSUFFICIENT_RESOURCES    0x05
187 #define NHRP_CODE_NO_BINDING_EXISTS         0x0c
188 #define NHRP_CODE_NON_UNIQUE_BINDING        0x0d
189 #define NHRP_CODE_ALREADY_REGISTERED        0x0e
190
191 /* NHRP Subnetwork layer address type/length */
192 #define NHRP_SHTL_TYPE_MASK 0x40
193 #define NHRP_SHTL_LEN_MASK  0x3F
194 #define NHRP_SHTL_TYPE(val) (((val) & (NHRP_SHTL_TYPE_MASK)) >> 6)
195 #define NHRP_SHTL_LEN(val)  ((val) & (NHRP_SHTL_LEN_MASK))
196
197 #define NHRP_SHTL_TYPE_NSAP 0
198 #define NHRP_SHTL_TYPE_E164 1
199
200 static const value_string nhrp_shtl_type_vals[] = {
201     { NHRP_SHTL_TYPE_NSAP, "NSAP format" },
202     { NHRP_SHTL_TYPE_E164, "Native E.164 format" },
203     { 0, NULL }
204 };
205
206 static const value_string nhrp_op_type_vals[] = {
207     { NHRP_RESOLUTION_REQ,      "NHRP Resolution Request" },
208     { NHRP_RESOLUTION_REPLY,    "NHRP Resolution Reply" },
209     { NHRP_REGISTRATION_REQ,    "NHRP Registration Request" },
210     { NHRP_REGISTRATION_REPLY,  "NHRP Registration Reply" },
211     { NHRP_PURGE_REQ,           "NHRP Purge Request" },
212     { NHRP_PURGE_REPLY,         "NHRP Purge Reply" },
213     { NHRP_ERROR_INDICATION,    "NHRP Error Indication" },
214     { NHRP_TRAFFIC_INDICATION,  "NHRP Traffic Indication" },
215     { 0,                        NULL }
216 };
217
218 static const value_string ext_type_vals[] = {
219     { NHRP_EXT_NULL,            "End of Extension" },
220     { NHRP_EXT_RESP_ADDR,       "Responder Address Extension" },
221     { NHRP_EXT_FWD_RECORD,      "Forward Transit NHS Record Extension" },
222     { NHRP_EXT_REV_RECORD,      "Reverse Transit NHS Record Extension" },
223     { NHRP_EXT_AUTH,            "NHRP Authentication Extension" },
224     { NHRP_EXT_VENDOR_PRIV,     "NHRP Vendor Private Extension" },
225     { NHRP_EXT_NAT_ADDRESS,     "Cisco NAT Address Extension" },
226 #if 0 /* Dup (which is handled in the code) */
227     { NHRP_EXT_DEV_CAPABILITIES,"Device Capabilities Extension" },
228 #endif
229     { NHRP_EXT_MOBILE_AUTH,     "Mobile NHC Authentication Extension" },
230     { 0,                        NULL }
231 };
232
233 static const value_string nhrp_error_code_vals[] = {
234     { NHRP_ERR_UNRECOGNIZED_EXT,        "Unrecognized Extension" },
235     { NHRP_ERR_NHRP_LOOP_DETECT,        "NHRP Loop Detected" },
236     { NHRP_ERR_PROT_ADDR_UNREACHABLE,   "Protocol Address Unreachable" },
237     { NHRP_ERR_PROT_ERROR,              "Protocol Error" },
238     { NHRP_ERR_SDU_SIZE_EXCEEDED,       "NHRP SDU Size Exceeded" },
239     { NHRP_ERR_INV_EXT,                 "Invalid Extension" },
240     { NHRP_ERR_INV_RESOLUTION_REPLY,    "Invalid NHRP Resolution Reply Received" },
241     { NHRP_ERR_AUTH_FAILURE,            "Authentication Failure" },
242     { NHRP_ERR_HOP_COUNT_EXCEEDED,      "Hop Count Exceeded" },
243     { NHRP_ERR_VPN_MISMATCH,            "VPN Mismatch" },
244     { NHRP_ERR_VPN_UNSUPPORTED,         "VPN Unsupported" },
245     { 0,                                NULL }
246 };
247
248 static const value_string nhrp_cie_code_vals[] = {
249     { NHRP_CODE_SUCCESS,                "Success" },
250     { NHRP_CODE_ADMIN_PROHIBITED,       "Administratively Prohibited" },
251     { NHRP_CODE_INSUFFICIENT_RESOURCES, "Insufficient Resources" },
252     { NHRP_CODE_NO_BINDING_EXISTS,      "No Interworking Layer Address to NBMA Address Binding Exists" },
253     { NHRP_CODE_NON_UNIQUE_BINDING,     "Binding Exists But Is Not Unique" },
254     { NHRP_CODE_ALREADY_REGISTERED,     "Unique Internetworking Layer Address Already Registered" },
255     { 0,                                NULL }
256 };
257
258 static dissector_table_t osinl_subdissector_table;
259 static dissector_table_t osinl_excl_subdissector_table;
260 static dissector_table_t ethertype_subdissector_table;
261
262 static dissector_handle_t data_handle;
263
264 typedef struct _e_nhrp {
265     guint16 ar_afn;
266     guint16 ar_pro_type;
267     guint32 ar_pro_type_oui;
268     guint16 ar_pro_type_pid;
269     guint8  ar_hopCnt;
270     guint16 ar_pktsz;
271     guint16 ar_chksum;
272     guint16 ar_extoff;
273     guint8  ar_op_version;
274     guint8  ar_op_type;
275     guint8  ar_shtl;
276     guint8  ar_sstl;
277 } e_nhrp_hdr;
278
279 static guint16 nhrp_checksum(const guint8 *ptr, int len)
280 {
281     vec_t cksum_vec[1];
282
283     cksum_vec[0].ptr = ptr;
284     cksum_vec[0].len = len;
285     return in_cksum(&cksum_vec[0], 1);
286 }
287
288 void dissect_nhrp_hdr(tvbuff_t     *tvb,
289                       packet_info  *pinfo,
290                       proto_tree   *tree,
291                       gint         *pOffset,
292                       gint         *pMandLen,
293                       gint         *pExtLen,
294                       oui_info_t  **pOuiInfo,
295                       e_nhrp_hdr   *hdr)
296 {
297     gint         offset    = *pOffset;
298     const gchar *pro_type_str;
299     guint        total_len = tvb_reported_length(tvb);
300     guint16      ipcsum, rx_chksum;
301
302     proto_item *nhrp_tree_item;
303     proto_tree *nhrp_tree;
304     proto_item *shtl_tree_item;
305     proto_tree *shtl_tree;
306     proto_item *sstl_tree_item;
307     proto_tree *sstl_tree;
308     proto_item *ti;
309
310     nhrp_tree_item = proto_tree_add_text(tree, tvb, offset, 20, "NHRP Fixed Header");
311     nhrp_tree = proto_item_add_subtree(nhrp_tree_item, ett_nhrp_hdr);
312
313     hdr->ar_pktsz = tvb_get_ntohs(tvb, 10);
314     if (total_len > hdr->ar_pktsz) {
315         total_len = hdr->ar_pktsz;
316     }
317
318     hdr->ar_afn = tvb_get_ntohs(tvb, offset);
319     proto_tree_add_item(nhrp_tree, hf_nhrp_hdr_afn, tvb, offset, 2, ENC_BIG_ENDIAN);
320     offset += 2;
321
322     hdr->ar_pro_type = tvb_get_ntohs(tvb, offset);
323     if (hdr->ar_pro_type <= 0xFF) {
324         /* It's an NLPID */
325         pro_type_str = val_to_str_const(hdr->ar_pro_type, nlpid_vals,
326             "Unknown NLPID");
327     } else if (hdr->ar_pro_type <= 0x3FF) {
328         /* Reserved for future use by the IETF */
329         pro_type_str = "Reserved for future use by the IETF";
330     } else if (hdr->ar_pro_type <= 0x04FF) {
331         /* Allocated for use by the ATM Forum */
332         pro_type_str = "Allocated for use by the ATM Forum";
333     } else if (hdr->ar_pro_type <= 0x05FF) {
334         /* Experimental/Local use */
335         pro_type_str = "Experimental/Local use";
336     } else {
337         pro_type_str = val_to_str_const(hdr->ar_pro_type, etype_vals,
338             "Unknown Ethertype");
339     }
340     proto_tree_add_uint_format(nhrp_tree, hf_nhrp_hdr_pro_type, tvb, offset, 2,
341         hdr->ar_pro_type, "Protocol Type (short form): %s (0x%04x)",
342         pro_type_str, hdr->ar_pro_type);
343     offset += 2;
344
345     if (hdr->ar_pro_type == NLPID_SNAP) {
346         /*
347          * The long form protocol type is a SNAP OUI and PID.
348          */
349         hdr->ar_pro_type_oui = tvb_get_ntoh24(tvb, offset);
350         proto_tree_add_uint(nhrp_tree, hf_nhrp_hdr_pro_snap_oui,
351             tvb, offset, 3, hdr->ar_pro_type_oui);
352         offset += 3;
353
354         hdr->ar_pro_type_pid = tvb_get_ntohs(tvb, offset);
355         *pOuiInfo = get_snap_oui_info(hdr->ar_pro_type_oui);
356         if (*pOuiInfo != NULL) {
357             proto_tree_add_uint(nhrp_tree,
358                 *(*pOuiInfo)->field_info->p_id,
359                 tvb, offset, 2, hdr->ar_pro_type_pid);
360         } else {
361             proto_tree_add_uint(nhrp_tree, hf_nhrp_hdr_pro_snap_pid,
362                 tvb, offset, 2, hdr->ar_pro_type_pid);
363         }
364     } else {
365         /*
366          * XXX - we should check that this is zero, as RFC 2332
367          * says it should be zero.
368          */
369         proto_tree_add_text(nhrp_tree, tvb, offset, 5,
370                         "Protocol Type (long form): %s",
371                         tvb_bytes_to_str(tvb, offset, 5));
372         offset += 5;
373     }
374
375     proto_tree_add_item(nhrp_tree, hf_nhrp_hdr_hopcnt, tvb, offset, 1, ENC_BIG_ENDIAN);
376     offset += 1;
377
378     proto_tree_add_item(nhrp_tree, hf_nhrp_hdr_pktsz, tvb, offset, 2, ENC_BIG_ENDIAN);
379     offset += 2;
380
381     rx_chksum = tvb_get_ntohs(tvb, offset);
382     if (tvb_bytes_exist(tvb, 0, total_len)) {
383         ipcsum = nhrp_checksum(tvb_get_ptr(tvb, 0, total_len),
384             total_len);
385         if (ipcsum == 0) {
386             proto_tree_add_uint_format(nhrp_tree, hf_nhrp_hdr_chksum, tvb, offset, 2, rx_chksum,
387                 "NHRP Packet checksum: 0x%04x [correct]", rx_chksum);
388         } else {
389             proto_tree_add_uint_format(nhrp_tree, hf_nhrp_hdr_chksum, tvb, offset, 2, rx_chksum,
390                 "NHRP Packet checksum: 0x%04x [incorrect, should be 0x%04x]", rx_chksum,
391                 in_cksum_shouldbe(rx_chksum, ipcsum));
392         }
393     } else {
394         proto_tree_add_uint_format(nhrp_tree, hf_nhrp_hdr_chksum, tvb, offset, 2, rx_chksum,
395             "NHRP Packet checksum: 0x%04x [not all data available]", rx_chksum);
396     }
397     offset += 2;
398
399     hdr->ar_extoff = tvb_get_ntohs(tvb, offset);
400     ti = proto_tree_add_item(nhrp_tree, hf_nhrp_hdr_extoff, tvb, offset, 2, ENC_BIG_ENDIAN);
401     if (hdr->ar_extoff != 0 && hdr->ar_extoff < 20) {
402         expert_add_info_format(pinfo, ti, PI_MALFORMED, PI_ERROR,
403             "Extension offset is less than the fixed header length");
404     }
405     offset += 2;
406
407     hdr->ar_op_version = tvb_get_guint8(tvb, offset);
408     proto_tree_add_uint_format(nhrp_tree, hf_nhrp_hdr_version, tvb, offset, 1,
409         hdr->ar_op_version, "Version : %u (%s)", hdr->ar_op_version,
410         (hdr->ar_op_version == 1) ? "NHRP - rfc2332" : "Unknown");
411     offset += 1;
412     proto_tree_add_item(nhrp_tree, hf_nhrp_hdr_op_type, tvb, offset, 1, ENC_BIG_ENDIAN);
413     offset += 1;
414
415     hdr->ar_shtl = tvb_get_guint8(tvb, offset);
416     shtl_tree_item = proto_tree_add_uint_format(nhrp_tree, hf_nhrp_hdr_shtl,
417         tvb, offset, 1, hdr->ar_shtl, "Source Address Type/Len: %s/%u",
418         val_to_str_const(NHRP_SHTL_TYPE(hdr->ar_shtl), nhrp_shtl_type_vals, "Unknown Type"),
419         NHRP_SHTL_LEN(hdr->ar_shtl));
420     shtl_tree = proto_item_add_subtree(shtl_tree_item, ett_nhrp_hdr_shtl);
421     proto_tree_add_item(shtl_tree, hf_nhrp_hdr_shtl_type, tvb, offset, 1, ENC_BIG_ENDIAN);
422     proto_tree_add_item(shtl_tree, hf_nhrp_hdr_shtl_len, tvb, offset, 1, ENC_BIG_ENDIAN);
423     offset += 1;
424
425     hdr->ar_sstl = tvb_get_guint8(tvb, offset);
426     sstl_tree_item = proto_tree_add_uint_format(nhrp_tree, hf_nhrp_hdr_sstl,
427         tvb, offset, 1, hdr->ar_sstl, "Source SubAddress Type/Len: %s/%u",
428         val_to_str_const(NHRP_SHTL_TYPE(hdr->ar_sstl), nhrp_shtl_type_vals, "Unknown Type"),
429         NHRP_SHTL_LEN(hdr->ar_sstl));
430     sstl_tree = proto_item_add_subtree(sstl_tree_item, ett_nhrp_hdr_sstl);
431     proto_tree_add_item(sstl_tree, hf_nhrp_hdr_sstl_type, tvb, offset, 1, ENC_BIG_ENDIAN);
432     proto_tree_add_item(sstl_tree, hf_nhrp_hdr_sstl_len, tvb, offset, 1, ENC_BIG_ENDIAN);
433     offset += 1;
434
435     *pOffset = offset;
436     if (hdr->ar_extoff != 0) {
437         if (hdr->ar_extoff >= 20) {
438             *pMandLen = hdr->ar_extoff - 20;
439             *pExtLen = total_len - hdr->ar_extoff;
440         } else {
441             /* Error */
442             *pMandLen = 0;
443             *pExtLen = 0;
444         }
445     }
446     else {
447         if (total_len >= 20)
448             *pMandLen = total_len - 20;
449         else {
450             /* "Can't happen" - we would have thrown an exception */
451             *pMandLen = 0;
452         }
453         *pExtLen = 0;
454     }
455 }
456
457 void dissect_cie_list(tvbuff_t    *tvb,
458                       packet_info *pinfo,
459                       proto_tree  *tree,
460                       gint         offset,
461                       gint         cieEnd,
462                       e_nhrp_hdr  *hdr,
463                       gint         isReq,
464                       gboolean     codeinfo)
465 {
466     proto_item *cli_addr_tree_item;
467     proto_tree *cli_addr_tree;
468     proto_item *cli_saddr_tree_item;
469     proto_tree *cli_saddr_tree;
470     guint8      val;
471
472     while ((offset + 12)          <= cieEnd) {
473         guint       cli_addr_len   = tvb_get_guint8(tvb, offset + 8);
474         guint       cli_saddr_len  = tvb_get_guint8(tvb, offset + 9);
475         guint       cli_prot_len   = tvb_get_guint8(tvb, offset + 10);
476         guint       cie_len        = 12 + cli_addr_len + cli_saddr_len + cli_prot_len;
477         proto_item *cie_tree_item  = proto_tree_add_text(tree, tvb, offset, cie_len, "Client Information Entry");
478         proto_tree *cie_tree       = proto_item_add_subtree(cie_tree_item, ett_nhrp_cie);
479
480         if (isReq) {
481             proto_tree_add_item(cie_tree, hf_nhrp_code, tvb, offset, 1, ENC_BIG_ENDIAN);
482         }
483         else {
484             guint8 code = tvb_get_guint8(tvb, offset);
485             if ( codeinfo ) {
486                 col_append_fstr(pinfo->cinfo, COL_INFO, ", Code=%s",
487                     val_to_str(code, nhrp_cie_code_vals, "Unknown (%u)"));
488             }
489             proto_tree_add_text(cie_tree, tvb, offset, 1, "Code: %s",
490                                 val_to_str(code, nhrp_cie_code_vals, "Unknown (%u)"));
491         }
492         offset += 1;
493
494         proto_tree_add_item(cie_tree, hf_nhrp_prefix_len, tvb, offset, 1, ENC_BIG_ENDIAN);
495         offset += 1;
496
497         proto_tree_add_item(cie_tree, hf_nhrp_unused, tvb, offset, 2, ENC_BIG_ENDIAN);
498         offset += 2;
499
500         proto_tree_add_item(cie_tree, hf_nhrp_mtu, tvb, offset, 2, ENC_BIG_ENDIAN);
501         offset += 2;
502
503         proto_tree_add_item(cie_tree, hf_nhrp_holding_time, tvb, offset, 2, ENC_BIG_ENDIAN);
504         offset += 2;
505
506         val = tvb_get_guint8(tvb, offset);
507         cli_addr_tree_item = proto_tree_add_uint_format(cie_tree,
508             hf_nhrp_cli_addr_tl, tvb, offset, 1, val,
509             "Client Address Type/Len: %s/%u",
510             val_to_str_const(NHRP_SHTL_TYPE(val), nhrp_shtl_type_vals, "Unknown Type"),
511             NHRP_SHTL_LEN(val));
512         cli_addr_tree = proto_item_add_subtree(cli_addr_tree_item, ett_nhrp_cie_cli_addr_tl);
513         proto_tree_add_item(cli_addr_tree, hf_nhrp_cli_addr_tl_type, tvb, offset, 1, ENC_BIG_ENDIAN);
514         proto_tree_add_item(cli_addr_tree, hf_nhrp_cli_addr_tl_len, tvb, offset, 1, ENC_BIG_ENDIAN);
515         offset += 1;
516
517         val = tvb_get_guint8(tvb, offset);
518         cli_saddr_tree_item = proto_tree_add_uint_format(cie_tree,
519             hf_nhrp_cli_saddr_tl, tvb, offset, 1, val,
520             "Client Sub Address Type/Len: %s/%u",
521             val_to_str_const(NHRP_SHTL_TYPE(val), nhrp_shtl_type_vals, "Unknown Type"),
522             NHRP_SHTL_LEN(val));
523         cli_saddr_tree = proto_item_add_subtree(cli_saddr_tree_item, ett_nhrp_cie_cli_saddr_tl);
524         proto_tree_add_item(cli_saddr_tree, hf_nhrp_cli_saddr_tl_type, tvb, offset, 1, ENC_BIG_ENDIAN);
525         proto_tree_add_item(cli_saddr_tree, hf_nhrp_cli_saddr_tl_len, tvb, offset, 1, ENC_BIG_ENDIAN);
526         offset += 1;
527
528         proto_tree_add_item(cie_tree, hf_nhrp_cli_prot_len, tvb, offset, 1, ENC_BIG_ENDIAN);
529         offset += 1;
530
531         proto_tree_add_item(cie_tree, hf_nhrp_pref, tvb, offset, 1, ENC_BIG_ENDIAN);
532         offset += 1;
533
534         if (cli_addr_len) {
535             switch (hdr->ar_afn) {
536
537             case AFNUM_INET:
538                 if (cli_addr_len == 4)
539                     proto_tree_add_item(cie_tree, hf_nhrp_client_nbma_addr, tvb, offset, 4, ENC_BIG_ENDIAN);
540                 else {
541                     proto_tree_add_text(cie_tree, tvb, offset, cli_addr_len,
542                         "Client NBMA Address: %s",
543                         tvb_bytes_to_str(tvb, offset, cli_addr_len));
544                 }
545                 break;
546
547             default:
548                 proto_tree_add_text(cie_tree, tvb, offset, cli_addr_len,
549                     "Client NBMA Address: %s",
550                     tvb_bytes_to_str(tvb, offset, cli_addr_len));
551                 break;
552             }
553             offset += cli_addr_len;
554         }
555
556         if (cli_saddr_len) {
557             proto_tree_add_text(cie_tree, tvb, offset, cli_saddr_len,
558                                 "Client NBMA Sub Address: %s",
559                                 tvb_bytes_to_str(tvb, offset, cli_saddr_len));
560         }
561
562         if (cli_prot_len) {
563             if (cli_prot_len == 4)
564                 proto_tree_add_item(cie_tree, hf_nhrp_client_prot_addr, tvb, offset, 4, ENC_BIG_ENDIAN);
565             else {
566                 proto_tree_add_text(cie_tree, tvb, offset, cli_prot_len,
567                                     "Client Protocol Address: %s",
568                                     tvb_bytes_to_str(tvb, offset, cli_prot_len));
569             }
570             offset += cli_prot_len;
571         }
572     }
573 }
574
575 void dissect_nhrp_mand(tvbuff_t    *tvb,
576                        packet_info *pinfo,
577                        proto_tree  *tree,
578                        gint        *pOffset,
579                        gint         mandLen,
580                        oui_info_t  *oui_info,
581                        e_nhrp_hdr  *hdr,
582                        guint       *srcLen,
583                        gboolean     codeinfo)
584 {
585     gint     offset  = *pOffset;
586     gint     mandEnd = offset + mandLen;
587     guint8   ssl, shl;
588     guint16  flags;
589     guint    dstLen;
590     gboolean isReq   = FALSE;
591     gboolean isErr   = FALSE;
592     gboolean isInd   = FALSE;
593
594     proto_item *nhrp_tree_item;
595     proto_tree *nhrp_tree;
596
597     tvb_ensure_bytes_exist(tvb, offset, mandLen);
598
599     switch (hdr->ar_op_type)
600     {
601     case NHRP_RESOLUTION_REPLY:
602     case NHRP_REGISTRATION_REPLY:
603     case NHRP_PURGE_REPLY:
604         break;
605     case NHRP_RESOLUTION_REQ:
606     case NHRP_REGISTRATION_REQ:
607     case NHRP_PURGE_REQ:
608         isReq = TRUE;
609         break;
610     case NHRP_ERROR_INDICATION: /* This needs special treatment */
611         isErr = TRUE;
612         isInd = TRUE;
613         break;
614     case NHRP_TRAFFIC_INDICATION:
615         isInd = TRUE;
616         break;
617     }
618     nhrp_tree_item = proto_tree_add_text(tree, tvb, offset, mandLen, "NHRP Mandatory Part");
619     nhrp_tree = proto_item_add_subtree(nhrp_tree_item, ett_nhrp_mand);
620
621     *srcLen = tvb_get_guint8(tvb, offset);
622     proto_tree_add_item(nhrp_tree, hf_nhrp_src_proto_len, tvb, offset, 1, ENC_BIG_ENDIAN);
623     offset += 1;
624
625     dstLen = tvb_get_guint8(tvb, offset);
626     proto_tree_add_item(nhrp_tree, hf_nhrp_dst_proto_len, tvb, offset, 1, ENC_BIG_ENDIAN);
627     offset += 1;
628
629     if (!isInd) {
630         proto_item *flag_item;
631         proto_tree *flag_tree;
632         flags = tvb_get_ntohs(tvb, offset);
633         flag_item = proto_tree_add_uint(nhrp_tree, hf_nhrp_flags, tvb, offset, 2, flags);
634         flag_tree = proto_item_add_subtree(flag_item, ett_nhrp_mand_flag);
635
636         switch (hdr->ar_op_type)
637         {
638         case NHRP_RESOLUTION_REQ:
639         case NHRP_RESOLUTION_REPLY:
640             proto_tree_add_boolean(flag_tree, hf_nhrp_flag_Q, tvb, offset, 2, flags);
641             proto_tree_add_boolean(flag_tree, hf_nhrp_flag_A, tvb, offset, 2, flags);
642             proto_tree_add_boolean(flag_tree, hf_nhrp_flag_D, tvb, offset, 2, flags);
643             proto_tree_add_boolean(flag_tree, hf_nhrp_flag_U1, tvb, offset, 2, flags);
644             proto_tree_add_boolean(flag_tree, hf_nhrp_flag_S, tvb, offset, 2, flags);
645             break;
646         case NHRP_REGISTRATION_REQ:
647         case NHRP_REGISTRATION_REPLY:
648             proto_tree_add_boolean(flag_tree, hf_nhrp_flag_U2, tvb, offset, 2, flags);
649             break;
650
651         case NHRP_PURGE_REQ:
652         case NHRP_PURGE_REPLY:
653             proto_tree_add_boolean(flag_tree, hf_nhrp_flag_N, tvb, offset, 2, flags);
654             break;
655         }
656         proto_tree_add_boolean(flag_tree, hf_nhrp_flag_NAT, tvb, offset, 2, flags);
657
658         offset += 2;
659
660         col_append_fstr(pinfo->cinfo, COL_INFO, ", ID=%u", tvb_get_ntohl(tvb, offset));
661         proto_tree_add_item(nhrp_tree, hf_nhrp_request_id, tvb, offset, 4, ENC_BIG_ENDIAN);
662         offset += 4;
663     }
664     else if (isErr) {
665         offset += 2;
666
667         col_append_fstr(pinfo->cinfo, COL_INFO, ", %s",
668             val_to_str(tvb_get_ntohs(tvb, offset), nhrp_error_code_vals, "Unknown Error (%u)"));
669         proto_tree_add_item(nhrp_tree, hf_nhrp_error_code, tvb, offset, 2, ENC_BIG_ENDIAN);
670         offset += 2;
671
672         proto_tree_add_item(nhrp_tree, hf_nhrp_error_offset, tvb, offset, 2, ENC_BIG_ENDIAN);
673         offset += 2;
674     }
675     else {
676         offset += 6;
677     }
678
679     shl = NHRP_SHTL_LEN(hdr->ar_shtl);
680     if (shl) {
681         switch (hdr->ar_afn) {
682
683         case AFNUM_INET:
684             if (shl == 4)
685                 proto_tree_add_item(nhrp_tree, hf_nhrp_src_nbma_addr, tvb, offset, 4, ENC_BIG_ENDIAN);
686             else {
687                 proto_tree_add_text(nhrp_tree, tvb, offset, shl,
688                     "Source NBMA Address: %s",
689                     tvb_bytes_to_str(tvb, offset, shl));
690             }
691             break;
692
693         default:
694             proto_tree_add_text(nhrp_tree, tvb, offset, shl,
695                 "Source NBMA Address: %s",
696                 tvb_bytes_to_str(tvb, offset, shl));
697             break;
698         }
699         offset += shl;
700     }
701
702     ssl = NHRP_SHTL_LEN(hdr->ar_sstl);
703     if (ssl) {
704         proto_tree_add_text(nhrp_tree, tvb, offset, ssl,
705                             "Source NBMA Sub Address: %s",
706                             tvb_bytes_to_str(tvb, offset, ssl));
707         offset += ssl;
708     }
709
710     if (*srcLen == 4) {
711         proto_tree_add_item(nhrp_tree, hf_nhrp_src_prot_addr, tvb, offset, 4, ENC_BIG_ENDIAN);
712         offset += 4;
713     }
714     else if (*srcLen) {
715         proto_tree_add_text(nhrp_tree, tvb, offset, *srcLen,
716                             "Source Protocol Address: %s",
717                             tvb_bytes_to_str(tvb, offset, *srcLen));
718         offset += *srcLen;
719     }
720
721     if (dstLen == 4) {
722         proto_tree_add_item(nhrp_tree, hf_nhrp_dst_prot_addr, tvb, offset, 4, ENC_BIG_ENDIAN);
723         offset += 4;
724     }
725     else if (dstLen) {
726         proto_tree_add_text(nhrp_tree, tvb, offset, dstLen,
727                             "Destination Protocol Address: %s",
728                             tvb_bytes_to_str(tvb, offset, dstLen));
729         offset += dstLen;
730     }
731
732     if (isInd) {
733         gboolean    save_in_error_pkt;
734         gint        pkt_len       = mandEnd - offset;
735         proto_item *ind_tree_item = proto_tree_add_text(tree, tvb, offset, pkt_len, "Packet Causing Indication");
736         proto_tree *ind_tree      = proto_item_add_subtree(ind_tree_item, ett_nhrp_indication);
737         gboolean    dissected;
738         tvbuff_t   *sub_tvb;
739
740         save_in_error_pkt = pinfo->flags.in_error_pkt;
741         pinfo->flags.in_error_pkt = TRUE;
742         sub_tvb = tvb_new_subset_remaining(tvb, offset);
743         if (isErr) {
744             _dissect_nhrp(sub_tvb, pinfo, ind_tree, TRUE, FALSE);
745         }
746         else {
747             if (hdr->ar_pro_type <= 0xFF) {
748                 /* It's an NLPID */
749                 if (hdr->ar_pro_type == NLPID_SNAP) {
750                     /*
751                      * Dissect based on the SNAP OUI
752                      * and PID.
753                      */
754                     if (hdr->ar_pro_type_oui == 0x000000) {
755                         /*
756                          * "Should not happen", as
757                          * the protocol type should
758                          * be the Ethertype, but....
759                          */
760                         dissected = dissector_try_uint(
761                             ethertype_subdissector_table,
762                             hdr->ar_pro_type_pid,
763                             sub_tvb, pinfo, ind_tree);
764                     } else {
765                         /*
766                          * If we have a dissector
767                          * table, use it, otherwise
768                          * just dissect as data.
769                          */
770                         if (oui_info != NULL) {
771                             dissected = dissector_try_uint(
772                                 oui_info->table,
773                                 hdr->ar_pro_type_pid,
774                                 sub_tvb, pinfo,
775                                 ind_tree);
776                         } else
777                             dissected = FALSE;
778                     }
779                 } else {
780                     /*
781                      * Dissect based on the NLPID.
782                      */
783                     dissected = dissector_try_uint(
784                         osinl_subdissector_table,
785                         hdr->ar_pro_type, sub_tvb, pinfo,
786                         ind_tree) ||
787                                 dissector_try_uint(
788                         osinl_excl_subdissector_table,
789                         hdr->ar_pro_type, sub_tvb, pinfo,
790                         ind_tree);
791                 }
792             } else if (hdr->ar_pro_type <= 0x3FF) {
793                 /* Reserved for future use by the IETF */
794                 dissected = FALSE;
795             } else if (hdr->ar_pro_type <= 0x04FF) {
796                 /* Allocated for use by the ATM Forum */
797                 dissected = FALSE;
798             } else if (hdr->ar_pro_type <= 0x05FF) {
799                 /* Experimental/Local use */
800                 dissected = FALSE;
801             } else {
802                 dissected = dissector_try_uint(
803                     ethertype_subdissector_table,
804                     hdr->ar_pro_type, sub_tvb, pinfo, ind_tree);
805             }
806             if (!dissected) {
807                 call_dissector(data_handle, sub_tvb, pinfo,
808                     ind_tree);
809             }
810         }
811         pinfo->flags.in_error_pkt = save_in_error_pkt;
812         offset = mandEnd;
813     }
814
815     /* According to RFC 2332, section 5.2.7, there shouldn't be any extensions
816      * in the Error Indication packet. */
817     if (isErr && tvb_reported_length_remaining(tvb, offset)) {
818         expert_add_info_format(pinfo, tree, PI_MALFORMED, PI_ERROR,
819             "Extensions not allowed per RFC2332 section 5.2.7");
820     }
821
822     dissect_cie_list(tvb, pinfo, nhrp_tree, offset, mandEnd, hdr, isReq, codeinfo);
823
824     *pOffset = mandEnd;
825 }
826
827 void dissect_nhrp_ext(tvbuff_t    *tvb,
828                       packet_info *pinfo,
829                       proto_tree  *tree,
830                       gint        *pOffset,
831                       gint         extLen,
832                       e_nhrp_hdr  *hdr,
833                       guint        srcLen,
834                       gboolean     nested)
835 {
836     gint offset = *pOffset;
837     gint extEnd = offset + extLen;
838
839     proto_item *ti;
840
841     tvb_ensure_bytes_exist(tvb, offset, extLen);
842
843     while ((offset + 4) <= extEnd)
844     {
845         proto_item *nhrp_tree_item;
846         proto_tree *nhrp_tree;
847         gint        extTypeC = tvb_get_ntohs(tvb, offset);
848         gint        extType  = extTypeC & 0x3FFF;
849         guint       len      = tvb_get_ntohs(tvb, offset+2);
850
851         if ((extType == NHRP_EXT_NAT_ADDRESS) && (len == 8)) {
852             /* Assume it's not really a Cisco NAT extension, but a device
853              * capabilities extension instead (see RFC 2735). */
854             nhrp_tree_item =  proto_tree_add_text(tree, tvb, offset,
855                 len + 4, "Device Capabilities Extension");
856         }
857         else {
858             nhrp_tree_item =  proto_tree_add_text(tree, tvb, offset,
859                 len + 4, "%s",
860                 val_to_str(extType, ext_type_vals, "Unknown (%u)"));
861         }
862         nhrp_tree = proto_item_add_subtree(nhrp_tree_item, ett_nhrp_ext);
863         proto_tree_add_boolean(nhrp_tree, hf_nhrp_ext_C, tvb, offset, 2, extTypeC);
864         proto_tree_add_item(nhrp_tree, hf_nhrp_ext_type, tvb, offset, 2, ENC_BIG_ENDIAN);
865         offset += 2;
866
867         proto_tree_add_item(nhrp_tree, hf_nhrp_ext_len, tvb, offset, 2, ENC_BIG_ENDIAN);
868         offset += 2;
869
870         if (len && (extType != NHRP_EXT_NULL)) {
871             tvb_ensure_bytes_exist(tvb, offset, len);
872             if ((extType == NHRP_EXT_NAT_ADDRESS) && (len == 8)) {
873                 /* Assume it's not really a Cisco NAT extension, but a device
874                  * capabilities extension instead (see RFC 2735). */
875                 proto_item *devcap_item;
876                 proto_tree *devcap_tree;
877                 proto_item *cap_item;
878                 proto_tree *cap_tree;
879
880                 devcap_item = proto_tree_add_text(nhrp_tree, tvb, offset, len,
881                     "Extension Data: Src is %sVPN-aware; Dst is %sVPN-aware",
882                     tvb_get_ntohl(tvb, offset) & 1 ? "" : "non-",
883                     tvb_get_ntohl(tvb, offset + 4) & 1 ? "" : "non-");
884                 devcap_tree = proto_item_add_subtree(devcap_item, ett_nhrp_devcap_ext);
885                 cap_item = proto_tree_add_item(devcap_tree, hf_nhrp_devcap_ext_srccap, tvb, offset, 4, ENC_BIG_ENDIAN);
886                 cap_tree = proto_item_add_subtree(cap_item, ett_nhrp_devcap_ext_srccap);
887                 proto_tree_add_item(cap_tree, hf_nhrp_devcap_ext_srccap_V, tvb, offset, 4, ENC_BIG_ENDIAN);
888
889                 cap_item = proto_tree_add_item(devcap_tree, hf_nhrp_devcap_ext_dstcap, tvb, offset + 4, 4, ENC_BIG_ENDIAN);
890                 cap_tree = proto_item_add_subtree(cap_item, ett_nhrp_devcap_ext_dstcap);
891                 proto_tree_add_item(cap_tree, hf_nhrp_devcap_ext_dstcap_V, tvb, offset + 4, 4, ENC_BIG_ENDIAN);
892                 goto skip_switch;
893             }
894
895             switch (extType) {
896             case NHRP_EXT_RESP_ADDR:
897             case NHRP_EXT_FWD_RECORD:
898             case NHRP_EXT_REV_RECORD:
899             case NHRP_EXT_NAT_ADDRESS:
900                 dissect_cie_list(tvb, pinfo, nhrp_tree,
901                     offset, offset + len, hdr, 0, FALSE);
902                 break;
903
904             case NHRP_EXT_AUTH:
905             case NHRP_EXT_MOBILE_AUTH:
906                 if (len < (4 + srcLen)) {
907                     ti = proto_tree_add_text(nhrp_tree, tvb, offset, len,
908                         "Malformed Extension: %s",
909                         tvb_bytes_to_str(tvb, offset, len));
910                     expert_add_info_format(pinfo, ti, PI_MALFORMED, PI_ERROR,
911                         "Incomplete Authentication Extension");
912                 }
913                 else {
914                     proto_item *auth_item;
915                     proto_tree *auth_tree;
916
917                     auth_item = proto_tree_add_text(nhrp_tree, tvb, offset, len,
918                         "Extension Data: SPI=%u: Data=%s", tvb_get_ntohs(tvb, offset + 2),
919                         tvb_bytes_to_str(tvb, offset + 4, len - 4));
920                     auth_tree = proto_item_add_subtree(auth_item, ett_nhrp_auth_ext);
921                     proto_tree_add_item(auth_tree, hf_nhrp_auth_ext_reserved, tvb, offset, 2, ENC_BIG_ENDIAN);
922                     proto_tree_add_item(auth_tree, hf_nhrp_auth_ext_spi, tvb, offset + 2, 2, ENC_BIG_ENDIAN);
923                     if (srcLen == 4)
924                         proto_tree_add_item(auth_tree, hf_nhrp_auth_ext_src_addr, tvb, offset + 4, 4, ENC_BIG_ENDIAN);
925                     else if (srcLen) {
926                         proto_tree_add_text(auth_tree, tvb, offset + 4, srcLen,
927                             "Source Address: %s",
928                             tvb_bytes_to_str(tvb, offset + 4, srcLen));
929                     }
930                     if (len > (4 + srcLen)) {
931                         proto_tree_add_text(auth_tree, tvb, offset + 4 + srcLen, len - (4 + srcLen),
932                             "Data: %s", tvb_bytes_to_str(tvb, offset + 4 + srcLen, len - (4 + srcLen)));
933                     }
934                 }
935                 break;
936
937             case NHRP_EXT_VENDOR_PRIV:
938                 if (len < 3) {
939                     ti = proto_tree_add_text(nhrp_tree, tvb, offset, len,
940                         "Malformed Extension: %s",
941                         tvb_bytes_to_str(tvb, offset, len));
942                     expert_add_info_format(pinfo, ti, PI_MALFORMED, PI_ERROR,
943                         "Incomplete Vendor-Private Extension");
944                 }
945                 else {
946                     proto_item *vendor_item;
947                     proto_tree *vendor_tree;
948                     gchar manuf[3];
949
950                     tvb_memcpy(tvb, manuf, offset, 3);
951                     vendor_item = proto_tree_add_text(nhrp_tree, tvb, offset, len,
952                         "Extension Data: Vendor ID=%s, Data=%s", get_manuf_name(manuf),
953                         tvb_bytes_to_str(tvb, offset + 3, len - 3));
954                     vendor_tree = proto_item_add_subtree(vendor_item, ett_nhrp_vendor_ext);
955                     proto_tree_add_bytes_format(vendor_tree, hf_nhrp_vendor_ext_id, tvb,
956                         offset, 3, manuf, "Vendor ID: %s", get_manuf_name(manuf));
957                     if (len > 3) {
958                         proto_tree_add_text(vendor_tree, tvb, offset + 3, len - 3,
959                             "Data: %s", tvb_bytes_to_str(tvb, offset + 3, len - 3));
960                     }
961                 }
962                 break;
963
964             default:
965                 proto_tree_add_item(nhrp_tree, hf_nhrp_unknown_ext_value, tvb,
966                     offset, len, ENC_NA);
967                 break;
968             }
969 skip_switch:
970             offset += len;
971         }
972
973         if (!nested) {
974             len = tvb_reported_length_remaining(tvb, offset);
975             if ((extType == NHRP_EXT_NULL) && len) {
976                 ti = proto_tree_add_text(tree, tvb, offset, len,
977                     "Unknown Data (%d bytes)", len);
978                 expert_add_info_format(pinfo, ti, PI_MALFORMED, PI_ERROR,
979                     "Superfluous data follows End Extension");
980                 break;
981             }
982         }
983     }
984
985     *pOffset = extEnd;
986 }
987
988 void dissect_nhrp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
989 {
990     _dissect_nhrp(tvb, pinfo, tree, FALSE, TRUE);
991 }
992
993 static void _dissect_nhrp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
994     gboolean nested, gboolean codeinfo)
995 {
996     e_nhrp_hdr  hdr;
997     gint        mandLen  = 0;
998     gint        extLen   = 0;
999     gint        offset   = 0;
1000     proto_item *ti;
1001     proto_tree *nhrp_tree;
1002     oui_info_t *oui_info = NULL;
1003     guint       srcLen   = 0;
1004
1005     if (!nested) {
1006         col_set_str(pinfo->cinfo, COL_PROTOCOL, "NHRP");
1007         col_clear(pinfo->cinfo, COL_INFO);
1008     }
1009
1010     memset(&hdr, 0, sizeof(e_nhrp_hdr));
1011     hdr.ar_op_type = tvb_get_guint8(tvb, 17);
1012
1013     if (!nested) {
1014         col_add_str(pinfo->cinfo, COL_INFO,
1015             val_to_str(hdr.ar_op_type, nhrp_op_type_vals,
1016                 "0x%02X - unknown"));
1017     }
1018
1019     ti = proto_tree_add_protocol_format(tree, proto_nhrp, tvb, 0, -1,
1020         "Next Hop Resolution Protocol (%s)",
1021         val_to_str(hdr.ar_op_type, nhrp_op_type_vals, "0x%02X - unknown"));
1022     nhrp_tree = proto_item_add_subtree(ti, ett_nhrp);
1023
1024     dissect_nhrp_hdr(tvb, pinfo, nhrp_tree, &offset, &mandLen, &extLen,
1025         &oui_info, &hdr);
1026     if (mandLen) {
1027         dissect_nhrp_mand(tvb, pinfo, nhrp_tree, &offset, mandLen,
1028             oui_info, &hdr, &srcLen, codeinfo);
1029     }
1030
1031     if (extLen) {
1032         dissect_nhrp_ext(tvb, pinfo, nhrp_tree, &offset, extLen, &hdr, srcLen, nested);
1033     }
1034 }
1035
1036 void
1037 proto_register_nhrp(void)
1038 {
1039     static hf_register_info hf[] = {
1040
1041         { &hf_nhrp_hdr_afn,
1042           { "Address Family Number", "nhrp.hdr.afn",
1043             FT_UINT16, BASE_HEX_DEC, VALS(afn_vals), 0x0,
1044             NULL, HFILL }
1045         },
1046         { &hf_nhrp_hdr_pro_type,
1047           { "Protocol Type (short form)", "nhrp.hdr.pro.type",
1048             FT_UINT16, BASE_HEX_DEC, NULL, 0x0,
1049             NULL, HFILL }
1050         },
1051         { &hf_nhrp_hdr_pro_snap_oui,
1052           { "Protocol Type (long form) - OUI", "nhrp.hdr.pro.snap.oui",
1053             FT_UINT24, BASE_HEX, VALS(oui_vals), 0x0,
1054             NULL, HFILL }
1055         },
1056         { &hf_nhrp_hdr_pro_snap_pid,
1057           { "Protocol Type (long form) - PID", "nhrp.hdr.pro.snap.pid",
1058             FT_UINT16, BASE_HEX, NULL, 0x0,
1059             NULL, HFILL }
1060         },
1061         { &hf_nhrp_hdr_hopcnt,
1062           { "Hop Count", "nhrp.hdr.hopcnt",
1063             FT_UINT8, BASE_DEC, NULL, 0x0,
1064             NULL, HFILL }
1065         },
1066         { &hf_nhrp_hdr_pktsz,
1067           { "Packet Length", "nhrp.hdr.pktsz",
1068             FT_UINT16, BASE_DEC, NULL, 0x0,
1069             NULL, HFILL }
1070         },
1071         { &hf_nhrp_hdr_chksum,
1072           { "Packet Checksum", "nhrp.hdr.chksum",
1073             FT_UINT16, BASE_HEX, NULL, 0x0,
1074             NULL, HFILL }
1075         },
1076         { &hf_nhrp_hdr_extoff,
1077           { "Extension Offset", "nhrp.hdr.extoff",
1078             FT_UINT16, BASE_DEC, NULL, 0x0,
1079             NULL, HFILL }
1080         },
1081         { &hf_nhrp_hdr_version,
1082           { "Version", "nhrp.hdr.version",
1083             FT_UINT8, BASE_DEC, NULL, 0x0,
1084             NULL, HFILL }
1085         },
1086         { &hf_nhrp_hdr_op_type,
1087           { "NHRP Packet Type", "nhrp.hdr.op.type",
1088             FT_UINT8, BASE_DEC, VALS(nhrp_op_type_vals), 0x0,
1089             NULL, HFILL }
1090         },
1091         { &hf_nhrp_hdr_shtl,
1092           { "Source Address Type/Len", "nhrp.hdr.shtl",
1093             FT_UINT8, BASE_DEC, NULL, 0x0,
1094             NULL, HFILL }
1095         },
1096         { &hf_nhrp_hdr_shtl_type,
1097           { "Type", "nhrp.hdr.shtl.type",
1098             FT_UINT8, BASE_DEC, VALS(nhrp_shtl_type_vals), NHRP_SHTL_TYPE_MASK,
1099             NULL, HFILL }
1100         },
1101         { &hf_nhrp_hdr_shtl_len,
1102           { "Length", "nhrp.hdr.shtl.len",
1103             FT_UINT8, BASE_DEC, NULL, NHRP_SHTL_LEN_MASK,
1104             NULL, HFILL }
1105         },
1106         { &hf_nhrp_hdr_sstl,
1107           { "Source SubAddress Type/Len", "nhrp.hdr.sstl",
1108             FT_UINT8, BASE_DEC, NULL, 0x0,
1109             NULL, HFILL }
1110         },
1111         { &hf_nhrp_hdr_sstl_type,
1112           { "Type", "nhrp.hdr.sstl.type",
1113             FT_UINT8, BASE_DEC, VALS(nhrp_shtl_type_vals), NHRP_SHTL_TYPE_MASK,
1114             NULL, HFILL }
1115         },
1116         { &hf_nhrp_hdr_sstl_len,
1117           { "Length", "nhrp.hdr.sstl.len",
1118             FT_UINT8, BASE_DEC, NULL, NHRP_SHTL_LEN_MASK,
1119             NULL, HFILL }
1120         },
1121
1122         { &hf_nhrp_src_proto_len,
1123           { "Source Protocol Len", "nhrp.src.prot.len",
1124             FT_UINT16, BASE_DEC, NULL, 0x0,
1125             NULL, HFILL }
1126         },
1127         { &hf_nhrp_dst_proto_len,
1128           { "Destination Protocol Len", "nhrp.dst.prot.len",
1129             FT_UINT16, BASE_DEC, NULL, 0x0,
1130             NULL, HFILL }
1131         },
1132         { &hf_nhrp_flags,
1133           { "Flags", "nhrp.flags",
1134             FT_UINT16, BASE_HEX, NULL, 0x0,
1135             NULL, HFILL }
1136         },
1137         { &hf_nhrp_flag_Q,
1138           { "Is Router", "nhrp.flag.q",
1139             FT_BOOLEAN, 16, NULL, 0x8000,
1140             NULL, HFILL }
1141         },
1142         { &hf_nhrp_flag_N,
1143           { "Expected Purge Reply", "nhrp.flag.n",
1144             FT_BOOLEAN, 16, NULL, 0x8000,
1145             NULL, HFILL }
1146         },
1147         { &hf_nhrp_flag_A,
1148           { "Authoritative", "nhrp.flag.a",
1149             FT_BOOLEAN, 16, NULL, 0x4000,
1150             "A bit", HFILL }
1151         },
1152         { &hf_nhrp_flag_D,
1153           { "Stable Association", "nhrp.flag.d",
1154             FT_BOOLEAN, 16, NULL, 0x2000,
1155             "D bit", HFILL }
1156         },
1157         { &hf_nhrp_flag_U1,
1158           { "Uniqueness Bit", "nhrp.flag.u1",
1159             FT_BOOLEAN, 16, NULL, 0x1000,
1160             "U bit", HFILL }
1161         },
1162         { &hf_nhrp_flag_U2,
1163           { "Uniqueness Bit", "nhrp.flag.u1",
1164             FT_BOOLEAN, 16, NULL, 0x8000,
1165             "U bit", HFILL }
1166         },
1167         { &hf_nhrp_flag_S,
1168           { "Stable Binding", "nhrp.flag.s",
1169             FT_BOOLEAN, 16, NULL, 0x0800,
1170             "S bit", HFILL }
1171         },
1172         { &hf_nhrp_flag_NAT,
1173           { "Cisco NAT Supported", "nhrp.flag.nat",
1174             FT_BOOLEAN, 16, NULL, 0x0002,
1175             "NAT bit", HFILL }
1176         },
1177         { &hf_nhrp_request_id,
1178           { "Request ID", "nhrp.reqid",
1179             FT_UINT32, BASE_HEX_DEC, NULL, 0x0,
1180             NULL, HFILL }
1181         },
1182         { &hf_nhrp_src_nbma_addr,
1183           { "Source NBMA Address", "nhrp.src.nbma.addr",
1184             FT_IPv4, BASE_NONE, NULL, 0x0,
1185             NULL, HFILL }
1186         },
1187 #if 0
1188         { &hf_nhrp_src_nbma_saddr,
1189           { "Source NBMA Sub Address", "nhrp.src.nbma.saddr",
1190             FT_UINT_BYTES, BASE_NONE, NULL, 0x0,
1191             NULL, HFILL }
1192         },
1193 #endif
1194         { &hf_nhrp_src_prot_addr,
1195           { "Source Protocol Address", "nhrp.src.prot.addr",
1196             FT_IPv4, BASE_NONE, NULL, 0x0,
1197             NULL, HFILL }
1198         },
1199         { &hf_nhrp_dst_prot_addr,
1200           { "Destination Protocol Address", "nhrp.dst.prot.addr",
1201             FT_IPv4, BASE_NONE, NULL, 0x0,
1202             NULL, HFILL }
1203         },
1204
1205         { &hf_nhrp_code,
1206           { "Code", "nhrp.code",
1207             FT_UINT8, BASE_DEC, NULL, 0x0,
1208             NULL, HFILL }
1209         },
1210         { &hf_nhrp_prefix_len,
1211           { "Prefix Length", "nhrp.prefix",
1212             FT_UINT8, BASE_DEC, NULL, 0x0,
1213             NULL, HFILL }
1214         },
1215         { &hf_nhrp_unused,
1216           { "Unused", "nhrp.unused",
1217             FT_UINT16, BASE_DEC, NULL, 0x0,
1218             NULL, HFILL }
1219         },
1220         { &hf_nhrp_mtu,
1221           { "Max Transmission Unit", "nhrp.mtu",
1222             FT_UINT16, BASE_DEC, NULL, 0x0,
1223             NULL, HFILL }
1224         },
1225         { &hf_nhrp_holding_time,
1226           { "Holding Time (s)", "nhrp.htime",
1227             FT_UINT16, BASE_DEC, NULL, 0x0,
1228             NULL, HFILL }
1229         },
1230         { &hf_nhrp_cli_addr_tl,
1231           { "Client Address Type/Len", "nhrp.cli.addr_tl",
1232             FT_UINT8, BASE_DEC, NULL, 0x0,
1233             NULL, HFILL }
1234         },
1235         { &hf_nhrp_cli_addr_tl_type,
1236           { "Type", "nhrp.cli.addr_tl.type",
1237             FT_UINT8, BASE_DEC, VALS(nhrp_shtl_type_vals), NHRP_SHTL_TYPE_MASK,
1238             NULL, HFILL }
1239         },
1240         { &hf_nhrp_cli_addr_tl_len,
1241           { "Length", "nhrp.cli.addr_tl.len",
1242             FT_UINT8, BASE_DEC, NULL, NHRP_SHTL_LEN_MASK,
1243             NULL, HFILL }
1244         },
1245         { &hf_nhrp_cli_saddr_tl,
1246           { "Client Sub Address Type/Len", "nhrp.cli.saddr_tl",
1247             FT_UINT8, BASE_DEC, NULL, 0x0,
1248             NULL, HFILL }
1249         },
1250         { &hf_nhrp_cli_saddr_tl_type,
1251           { "Type", "nhrp.cli.saddr_tl.type",
1252             FT_UINT8, BASE_DEC, VALS(nhrp_shtl_type_vals), NHRP_SHTL_TYPE_MASK,
1253             NULL, HFILL }
1254         },
1255         { &hf_nhrp_cli_saddr_tl_len,
1256           { "Length", "nhrp.cli.saddr_tl.len",
1257             FT_UINT8, BASE_DEC, NULL, NHRP_SHTL_LEN_MASK,
1258             NULL, HFILL }
1259         },
1260         { &hf_nhrp_cli_prot_len,
1261           { "Client Protocol Length", "nhrp.prot.len",
1262             FT_UINT8, BASE_DEC, NULL, 0x0,
1263             NULL, HFILL }
1264         },
1265         { &hf_nhrp_pref,
1266           { "CIE Preference Value", "nhrp.pref",
1267             FT_UINT8, BASE_DEC, NULL, 0x0,
1268             NULL, HFILL }
1269         },
1270         { &hf_nhrp_client_nbma_addr,
1271           { "Client NBMA Address", "nhrp.client.nbma.addr",
1272             FT_IPv4, BASE_NONE, NULL, 0x0,
1273             NULL, HFILL }
1274         },
1275 #if 0
1276         { &hf_nhrp_client_nbma_saddr,
1277           { "Client NBMA Sub Address", "nhrp.client.nbma.saddr",
1278             FT_UINT_BYTES, BASE_NONE, NULL, 0x0,
1279             NULL, HFILL }
1280         },
1281 #endif
1282         { &hf_nhrp_client_prot_addr,
1283           { "Client Protocol Address", "nhrp.client.prot.addr",
1284             FT_IPv4, BASE_NONE, NULL, 0x0,
1285             NULL, HFILL }
1286         },
1287
1288         { &hf_nhrp_ext_C,
1289           { "Compulsory Flag", "nhrp.ext.c",
1290             FT_BOOLEAN, 16, NULL, 0x8000,
1291             NULL, HFILL }
1292         },
1293         { &hf_nhrp_ext_type,
1294           { "Extension Type", "nhrp.ext.type",
1295             FT_UINT16, BASE_HEX, NULL, 0x3FFF,
1296             NULL, HFILL }
1297         },
1298         { &hf_nhrp_ext_len,
1299           { "Extension length", "nhrp.ext.len",
1300             FT_UINT16, BASE_DEC, NULL, 0x0,
1301             NULL, HFILL }
1302         },
1303 #if 0
1304         { &hf_nhrp_ext_value,
1305           { "Extension Value", "nhrp.ext.val",
1306             FT_UINT_BYTES, BASE_NONE, NULL, 0x0,
1307             NULL, HFILL }
1308         },
1309 #endif
1310
1311         { &hf_nhrp_error_code,
1312           { "Error Code", "nhrp.err.code",
1313             FT_UINT16, BASE_DEC, VALS(nhrp_error_code_vals), 0x0,
1314             NULL, HFILL }
1315         },
1316         { &hf_nhrp_error_offset,
1317           { "Error Offset", "nhrp.err.offset",
1318             FT_UINT16, BASE_DEC, NULL, 0x0,
1319             NULL, HFILL }
1320         },
1321 #if 0
1322         { &hf_nhrp_error_packet,
1323           { "Errored Packet", "nhrp.err.pkt",
1324             FT_UINT_BYTES, BASE_NONE, NULL, 0x0,
1325             NULL, HFILL }
1326         },
1327 #endif
1328         { &hf_nhrp_auth_ext_reserved,
1329           { "Reserved", "nhrp.auth_ext.reserved",
1330             FT_UINT16, BASE_DEC, NULL, 0x0,
1331             NULL, HFILL }
1332         },
1333         { &hf_nhrp_auth_ext_spi,
1334           { "SPI", "nhrp.auth_ext.spi",
1335             FT_UINT16, BASE_DEC, NULL, 0x0,
1336             "Security Parameter Index", HFILL }
1337         },
1338         { &hf_nhrp_auth_ext_src_addr,
1339           { "Source Address", "nhrp.auth_ext.src_addr",
1340             FT_IPv4, BASE_NONE, NULL, 0x0,
1341             NULL, HFILL }
1342         },
1343         { &hf_nhrp_vendor_ext_id      ,
1344           { "Vendor ID", "nhrp.vendor_ext.id",
1345             FT_BYTES, BASE_NONE, NULL, 0x0,
1346             NULL, HFILL }
1347         },
1348         { &hf_nhrp_devcap_ext_srccap,
1349           { "Source Capabilities", "nhrp.devcap_ext.srccap",
1350             FT_UINT32, BASE_HEX, NULL, 0x0,
1351             NULL, HFILL }
1352         },
1353         { &hf_nhrp_devcap_ext_srccap_V,
1354           { "VPN-aware", "nhrp.devcap_ext.srccap.V",
1355             FT_BOOLEAN, 32, NULL, 0x00000001,
1356             NULL, HFILL }
1357         },
1358         { &hf_nhrp_devcap_ext_dstcap,
1359           { "Destination Capabilities", "nhrp.devcap_ext.dstcap",
1360             FT_UINT32, BASE_HEX, NULL, 0x0,
1361             NULL, HFILL }
1362         },
1363         { &hf_nhrp_devcap_ext_dstcap_V,
1364           { "VPN-aware", "nhrp.devcap_ext.dstcap.V",
1365             FT_BOOLEAN, 32, NULL, 0x00000001,
1366             NULL, HFILL }
1367         },
1368         { &hf_nhrp_unknown_ext_value,
1369           { "Extension Value", "nhrp.unknown_ext.value",
1370             FT_BYTES, BASE_NONE, NULL, 0x0,
1371             NULL, HFILL }
1372         },
1373     };
1374
1375     static gint *ett[] = {
1376         &ett_nhrp,
1377         &ett_nhrp_hdr,
1378         &ett_nhrp_hdr_shtl,
1379         &ett_nhrp_hdr_sstl,
1380         &ett_nhrp_mand,
1381         &ett_nhrp_ext,
1382         &ett_nhrp_mand_flag,
1383         &ett_nhrp_cie,
1384         &ett_nhrp_cie_cli_addr_tl,
1385         &ett_nhrp_cie_cli_saddr_tl,
1386         &ett_nhrp_indication,
1387         &ett_nhrp_auth_ext,
1388         &ett_nhrp_vendor_ext,
1389         &ett_nhrp_devcap_ext,
1390         &ett_nhrp_devcap_ext_srccap,
1391         &ett_nhrp_devcap_ext_dstcap
1392     };
1393
1394     proto_nhrp = proto_register_protocol(
1395         "NBMA Next Hop Resolution Protocol",
1396         "NHRP",
1397         "nhrp");
1398     proto_register_field_array(proto_nhrp, hf, array_length(hf));
1399     proto_register_subtree_array(ett, array_length(ett));
1400 }
1401
1402 void
1403 proto_reg_handoff_nhrp(void)
1404 {
1405     dissector_handle_t nhrp_handle;
1406
1407     data_handle = find_dissector("data");
1408
1409     osinl_subdissector_table      = find_dissector_table("osinl");
1410     osinl_excl_subdissector_table = find_dissector_table("osinl.excl");
1411     ethertype_subdissector_table  = find_dissector_table("ethertype");
1412
1413     nhrp_handle = create_dissector_handle(dissect_nhrp, proto_nhrp);
1414     dissector_add_uint("ip.proto", IP_PROTO_NARP, nhrp_handle);
1415     dissector_add_uint("gre.proto", GRE_NHRP, nhrp_handle);
1416     dissector_add_uint("llc.iana_pid", IANA_PID_MARS_NHRP_CONTROL, nhrp_handle);
1417 }