Use G_GINT64_MODIFIER, rather than the PRI[douxX]64 macros, for GLib
[obnox/wireshark/wip.git] / epan / dissectors / packet-bootp.c
1 /* packet-bootp.c
2  * Routines for BOOTP/DHCP packet disassembly
3  * Copyright 1998, Gilbert Ramirez <gram@alumni.rice.edu>
4  * Copyright 2004, Thomas Anders <thomas.anders [AT] blue-cable.de>
5  *
6  * $Id$
7  *
8  * The information used comes from:
9  * RFC  951: Bootstrap Protocol
10  * RFC 1497: BOOTP extensions
11  * RFC 1542: Clarifications and Extensions for the Bootstrap Protocol
12  * RFC 2131: Dynamic Host Configuration Protocol
13  * RFC 2132: DHCP Options and BOOTP Vendor Extensions
14  * RFC 2241: DHCP Options for Novell Directory Services
15  * RFC 2242: NetWare/IP Domain Name and Information
16  * RFC 2489: Procedure for Defining New DHCP Options
17  * RFC 2610: DHCP Options for Service Location Protocol
18  * RFC 3046: DHCP Relay Agent Information Option
19  * RFC 3118: Authentication for DHCP Messages
20  * RFC 3203: DHCP reconfigure extension
21  * RFC 3495: DHCP Option (122) for CableLabs Client Configuration
22  * RFC 3594: PacketCable Security Ticket Control Sub-Option (122.9)
23  * draft-ietf-dhc-fqdn-option-07.txt
24  * BOOTP and DHCP Parameters
25  *     http://www.iana.org/assignments/bootp-dhcp-parameters
26  * DOCSIS(TM) 2.0 Radio Frequency Interface Specification
27  *     http://www.cablemodem.com/downloads/specs/CM-SP-RFI2.0-I10-051209.pdf
28  * PacketCable(TM) 1.0 MTA Device Provisioning Specification
29  *     http://www.packetcable.com/downloads/specs/PKT-SP-PROV-I11-050812.pdf
30  *     http://www.cablelabs.com/specifications/archives/PKT-SP-PROV-I05-021127.pdf (superseded by above)
31  * PacketCable(TM) 1.5 MTA Device Provisioning Specification
32  *     http://www.packetcable.com/downloads/specs/PKT-SP-PROV1.5-I02-050812.pdf
33  * CableHome(TM) 1.1 Specification
34  *     http://www.cablelabs.com/projects/cablehome/downloads/specs/CH-SP-CH1.1-I11-060407.pdf
35  * DSL Forum TR-111
36  *     http://www.dslforum.org/techwork/tr/TR-111.pdf
37  *
38  * Wireshark - Network traffic analyzer
39  * By Gerald Combs <gerald@wireshark.org>
40  * Copyright 1998 Gerald Combs
41  *
42  * This program is free software; you can redistribute it and/or
43  * modify it under the terms of the GNU General Public License
44  * as published by the Free Software Foundation; either version 2
45  * of the License, or (at your option) any later version.
46  *
47  * This program is distributed in the hope that it will be useful,
48  * but WITHOUT ANY WARRANTY; without even the implied warranty of
49  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
50  * GNU General Public License for more details.
51  *
52  * You should have received a copy of the GNU General Public License
53  * along with this program; if not, write to the Free Software
54  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
55  */
56
57 /*
58  * Some of the development of the BOOTP/DHCP protocol decoder was sponsored by
59  * Cable Television Laboratories, Inc. ("CableLabs") based upon proprietary
60  * CableLabs' specifications. Your license and use of this protocol decoder
61  * does not mean that you are licensed to use the CableLabs'
62  * specifications.  If you have questions about this protocol, contact
63  * jf.mule [AT] cablelabs.com or c.stuart [AT] cablelabs.com for additional
64  * information.
65  */
66
67
68 #ifdef HAVE_CONFIG_H
69 # include "config.h"
70 #endif
71
72 #include <string.h>
73 #include <glib.h>
74 #include <epan/packet.h>
75 #include "packet-arp.h"
76 #include "packet-dns.h"                         /* for get_dns_name() */
77 #include <epan/addr_resolv.h>
78 #include <epan/prefs.h>
79 #include <epan/tap.h>
80 #include <epan/strutil.h>
81 #include <epan/arptypes.h>
82 #include <epan/emem.h>
83 #include <epan/sminmpec.h>
84
85 static int bootp_dhcp_tap = -1;
86 static int proto_bootp = -1;
87 static int hf_bootp_type = -1;
88 static int hf_bootp_hw_type = -1;
89 static int hf_bootp_hw_len = -1;
90 static int hf_bootp_hops = -1;
91 static int hf_bootp_id = -1;
92 static int hf_bootp_secs = -1;
93 static int hf_bootp_flags = -1;
94 static int hf_bootp_flags_broadcast = -1;
95 static int hf_bootp_flags_reserved = -1;
96 static int hf_bootp_ip_client = -1;
97 static int hf_bootp_ip_your = -1;
98 static int hf_bootp_ip_server = -1;
99 static int hf_bootp_ip_relay = -1;
100 static int hf_bootp_hw_addr = -1;
101 static int hf_bootp_server = -1;
102 static int hf_bootp_file = -1;
103 static int hf_bootp_cookie = -1;
104 static int hf_bootp_vendor = -1;
105 static int hf_bootp_dhcp = -1;
106 static int hf_bootp_fqdn_s = -1;
107 static int hf_bootp_fqdn_o = -1;
108 static int hf_bootp_fqdn_e = -1;
109 static int hf_bootp_fqdn_n = -1;
110 static int hf_bootp_fqdn_mbz = -1;
111 static int hf_bootp_fqdn_rcode1 = -1;
112 static int hf_bootp_fqdn_rcode2 = -1;
113 static int hf_bootp_fqdn_name = -1;
114 static int hf_bootp_fqdn_asciiname = -1;
115 static int hf_bootp_pkt_mtacap_len = -1;
116 static int hf_bootp_docsis_cmcap_len = -1;
117 static int hf_bootp_hw_ether_addr = -1;
118 static int hf_bootp_alcatel_vid = -1;
119 static int hf_bootp_client_identifier_uuid = -1;
120 static int hf_bootp_client_network_id_major_ver = -1;
121 static int hf_bootp_client_network_id_minor_ver = -1;
122 static int hf_bootp_option_type = -1;
123 static int hf_bootp_option_length = -1;
124 static int hf_bootp_option_value = -1;
125
126 static gint ett_bootp = -1;
127 static gint ett_bootp_flags = -1;
128 static gint ett_bootp_option = -1;
129 static gint ett_bootp_fqdn = -1;
130
131 gboolean novell_string = FALSE;
132
133 #define UDP_PORT_BOOTPS  67
134 #define UDP_PORT_BOOTPC  68
135
136 #define BOOTP_BC        0x8000
137 #define BOOTP_MBZ       0x7FFF
138
139 /* FQDN stuff */
140 #define F_FQDN_S        0x01
141 #define F_FQDN_O        0x02
142 #define F_FQDN_E        0x04
143 #define F_FQDN_N        0x08
144 #define F_FQDN_MBZ      0xf0
145
146 static const true_false_string tfs_fqdn_s = {
147   "Server",
148   "Client"
149 };
150
151 static const true_false_string tfs_fqdn_o = {
152   "Override",
153   "No override"
154 };
155
156 static const true_false_string tfs_fqdn_e = {
157   "Binary encoding",
158   "ASCII encoding"
159 };
160
161 static const true_false_string tfs_fqdn_n = {
162   "No server updates",
163   "Some server updates"
164 };
165
166 enum field_type {
167         special,
168         none,
169         presence,
170         ipv4,                   /* single IPv4 address */
171         ipv4_list,              /* list of IPv4 addresses */
172         string,
173         bytes,
174         opaque,
175         val_boolean,
176         val_u_byte,
177         val_u_short,
178         val_u_short_list,
179         val_u_le_short,
180         val_u_long,
181         time_in_secs,
182         fqdn,
183         ipv4_or_fqdn
184 };
185
186 struct opt_info {
187         const char      *text;
188         enum field_type ftype;
189         const void      *data;
190 };
191
192 static const true_false_string flag_set_broadcast = {
193   "Broadcast",
194   "Unicast"
195 };
196
197
198 /* PacketCable/DOCSIS definitions */
199 #define PACKETCABLE_MTA_CAP10 "pktc1.0:"
200 #define PACKETCABLE_MTA_CAP15 "pktc1.5:"
201 #define PACKETCABLE_CM_CAP11  "docsis1.1:"
202 #define PACKETCABLE_CM_CAP20  "docsis2.0:"
203
204 #define PACKETCABLE_CCC_I05      1
205 #define PACKETCABLE_CCC_DRAFT5   2
206 #define PACKETCABLE_CCC_RFC_3495 3
207
208 static enum_val_t pkt_ccc_protocol_versions[] = {
209         { "ccc_i05",     "PKT-SP-PROV-I05-021127", PACKETCABLE_CCC_I05 },
210         { "ccc_draft_5", "IETF Draft 5",           PACKETCABLE_CCC_DRAFT5 },
211         { "rfc_3495",    "RFC 3495",               PACKETCABLE_CCC_RFC_3495 },
212         { NULL, NULL, 0 }
213 };
214
215 static gint pkt_ccc_protocol_version = PACKETCABLE_CCC_RFC_3495;
216 static guint pkt_ccc_option = 122;
217
218
219 static int dissect_vendor_pxeclient_suboption(proto_tree *v_tree, tvbuff_t *tvb,
220     int optoff, int optend);
221 static int dissect_vendor_cablelabs_suboption(proto_tree *v_tree, tvbuff_t *tvb,
222     int optoff, int optend);
223 static int dissect_netware_ip_suboption(proto_tree *v_tree, tvbuff_t *tvb,
224     int optoff, int optend);
225 static int dissect_vendor_tr111_suboption(proto_tree *v_tree, tvbuff_t *tvb,
226     int optoff, int optend);
227 static int bootp_dhcp_decode_agent_info(proto_tree *v_tree, tvbuff_t *tvb,
228     int optoff, int optend);
229 static void dissect_packetcable_mta_cap(proto_tree *v_tree, tvbuff_t *tvb,
230        int voff, int len);
231 static void dissect_docsis_cm_cap(proto_tree *v_tree, tvbuff_t *tvb,
232        int voff, int len);
233 static int dissect_packetcable_i05_ccc(proto_tree *v_tree, tvbuff_t *tvb,
234     int optoff, int optend);
235 static int dissect_packetcable_ietf_ccc(proto_tree *v_tree, tvbuff_t *tvb,
236     int optoff, int optend, int revision);
237
238 #define OPT53_DISCOVER "Discover"
239 static const value_string opt53_text[] = {
240         { 1,    OPT53_DISCOVER },
241         { 2,    "Offer" },
242         { 3,    "Request" },
243         { 4,    "Decline" },
244         { 5,    "ACK" },
245         { 6,    "NAK" },
246         { 7,    "Release" },
247         { 8,    "Inform" },
248         { 9,    "Force Renew" },
249         /* draft-ietf-dhc-leasequery-09.txt */
250         { 13,   "Lease query" },
251         { 14,   "Lease known" },
252         { 15,   "Lease unknown" },
253         { 16,   "Lease active" },
254         { 17,   "Unimplemented" },
255
256         { 0,    NULL }
257 };
258
259 /* DHCP Authentication protocols */
260 #define AUTHEN_PROTO_CONFIG_TOKEN       0
261 #define AUTHEN_PROTO_DELAYED_AUTHEN     1
262
263 /* DHCP Authentication algorithms for delayed authentication */
264 #define AUTHEN_DELAYED_ALGO_HMAC_MD5    1
265
266 /* DHCP Authentication Replay Detection Methods */
267 #define AUTHEN_RDM_MONOTONIC_COUNTER    0x00
268
269 /* DHCP Option Overload (option code 52) */
270 #define OPT_OVERLOAD_FILE               1
271 #define OPT_OVERLOAD_SNAME              2
272 #define OPT_OVERLOAD_BOTH               3
273
274 /* Server name and boot file offsets and lengths */
275 #define SERVER_NAME_OFFSET              44
276 #define SERVER_NAME_LEN                 64
277 #define FILE_NAME_OFFSET                108
278 #define FILE_NAME_LEN                   128
279 #define VENDOR_INFO_OFFSET              236
280
281 static const true_false_string toggle_tfs = {
282         "Enabled",
283         "Disabled"
284 };
285
286 static const true_false_string yes_no_tfs = {
287         "Yes",
288         "No"
289 };
290
291 static const value_string bootp_nbnt_vals[] = {
292     {0x1,   "B-node" },
293     {0x2,   "P-node" },
294     {0x4,   "M-node" },
295     {0x8,   "H-node" },
296     {0,     NULL     }
297 };
298
299 static const value_string bootp_client_arch[] = {
300         { 0x0000, "IA x86 PC" },
301         { 0x0001, "NEC/PC98" },
302         { 0x0002, "IA64 PC" },
303         { 0x0003, "DEC Alpha" },
304         { 0x0004, "ArcX86" },
305         { 0x0005, "Intel Lean Client" },
306         { 0,      NULL }
307 };
308
309 static struct opt_info bootp_opt[] = {
310 /*   0 */ { "Padding",                                  none, NULL },
311 /*   1 */ { "Subnet Mask",                              ipv4, NULL },
312 /*   2 */ { "Time Offset",                              time_in_secs, NULL },
313 /*   3 */ { "Router",                                   ipv4_list, NULL },
314 /*   4 */ { "Time Server",                              ipv4_list, NULL },
315 /*   5 */ { "Name Server",                              ipv4_list, NULL },
316 /*   6 */ { "Domain Name Server",                       ipv4_list, NULL },
317 /*   7 */ { "Log Server",                               ipv4_list, NULL },
318 /*   8 */ { "Cookie Server",                            ipv4_list, NULL },
319 /*   9 */ { "LPR Server",                               ipv4_list, NULL },
320 /*  10 */ { "Impress Server",                           ipv4_list, NULL },
321 /*  11 */ { "Resource Location Server",                 ipv4_list, NULL },
322 /*  12 */ { "Host Name",                                string, NULL },
323 /*  13 */ { "Boot File Size",                           val_u_short, NULL },
324 /*  14 */ { "Merit Dump File",                          string, NULL },
325 /*  15 */ { "Domain Name",                              string, NULL },
326 /*  16 */ { "Swap Server",                              ipv4, NULL },
327 /*  17 */ { "Root Path",                                string, NULL },
328 /*  18 */ { "Extensions Path",                          string, NULL },
329 /*  19 */ { "IP Forwarding",                            val_boolean, TFS(&toggle_tfs) },
330 /*  20 */ { "Non-Local Source Routing",                 val_boolean, TFS(&toggle_tfs) },
331 /*  21 */ { "Policy Filter",                            special, NULL },
332 /*  22 */ { "Maximum Datagram Reassembly Size",         val_u_short, NULL },
333 /*  23 */ { "Default IP Time-to-Live",                  val_u_byte, NULL },
334 /*  24 */ { "Path MTU Aging Timeout",                   time_in_secs, NULL },
335 /*  25 */ { "Path MTU Plateau Table",                   val_u_short_list, NULL },
336 /*  26 */ { "Interface MTU",                            val_u_short, NULL },
337 /*  27 */ { "All Subnets are Local",                    val_boolean, TFS(&yes_no_tfs) },
338 /*  28 */ { "Broadcast Address",                        ipv4, NULL },
339 /*  29 */ { "Perform Mask Discovery",                   val_boolean, TFS(&toggle_tfs) },
340 /*  30 */ { "Mask Supplier",                            val_boolean, TFS(&yes_no_tfs) },
341 /*  31 */ { "Perform Router Discover",                  val_boolean, TFS(&toggle_tfs) },
342 /*  32 */ { "Router Solicitation Address",              ipv4, NULL },
343 /*  33 */ { "Static Route",                             special, NULL },
344 /*  34 */ { "Trailer Encapsulation",                    val_boolean, TFS(&toggle_tfs) },
345 /*  35 */ { "ARP Cache Timeout",                        time_in_secs, NULL },
346 /*  36 */ { "Ethernet Encapsulation",                   val_boolean, TFS(&toggle_tfs) },
347 /*  37 */ { "TCP Default TTL",                          val_u_byte, NULL },
348 /*  38 */ { "TCP Keepalive Interval",                   time_in_secs, NULL },
349 /*  39 */ { "TCP Keepalive Garbage",                    val_boolean, TFS(&toggle_tfs) },
350 /*  40 */ { "Network Information Service Domain",       string, NULL },
351 /*  41 */ { "Network Information Service Servers",      ipv4_list, NULL },
352 /*  42 */ { "Network Time Protocol Servers",            ipv4_list, NULL },
353 /*  43 */ { "Vendor-Specific Information",              special, NULL },
354 /*  44 */ { "NetBIOS over TCP/IP Name Server",          ipv4_list, NULL },
355 /*  45 */ { "NetBIOS over TCP/IP Datagram Distribution Name Server", ipv4_list, NULL },
356 /*  46 */ { "NetBIOS over TCP/IP Node Type",            val_u_byte, VALS(bootp_nbnt_vals) },
357 /*  47 */ { "NetBIOS over TCP/IP Scope",                string, NULL },
358 /*  48 */ { "X Window System Font Server",              ipv4_list, NULL },
359 /*  49 */ { "X Window System Display Manager",          ipv4_list, NULL },
360 /*  50 */ { "Requested IP Address",                     ipv4, NULL },
361 /*  51 */ { "IP Address Lease Time",                    time_in_secs, NULL },
362 /*  52 */ { "Option Overload",                          special, NULL },
363 /*  53 */ { "DHCP Message Type",                        special, NULL },
364 /*  54 */ { "Server Identifier",                        ipv4, NULL },
365 /*  55 */ { "Parameter Request List",                   special, NULL },
366 /*  56 */ { "Message",                                  string, NULL },
367 /*  57 */ { "Maximum DHCP Message Size",                val_u_short, NULL },
368 /*  58 */ { "Renewal Time Value",                       time_in_secs, NULL },
369 /*  59 */ { "Rebinding Time Value",                     time_in_secs, NULL },
370 /*  60 */ { "Vendor class identifier",                  special, NULL },
371 /*  61 */ { "Client identifier",                        special, NULL },
372 /*  62 */ { "Novell/Netware IP domain",                 string, NULL },
373 /*  63 */ { "Novell Options",                           special, NULL },
374 /*  64 */ { "Network Information Service+ Domain",      string, NULL },
375 /*  65 */ { "Network Information Service+ Servers",     ipv4_list, NULL },
376 /*  66 */ { "TFTP Server Name",                         string, NULL },
377 /*  67 */ { "Bootfile name",                            string, NULL },
378 /*  68 */ { "Mobile IP Home Agent",                     ipv4_list, NULL },
379 /*  69 */ { "SMTP Server",                              ipv4_list, NULL },
380 /*  70 */ { "POP3 Server",                              ipv4_list, NULL },
381 /*  71 */ { "NNTP Server",                              ipv4_list, NULL },
382 /*  72 */ { "Default WWW Server",                       ipv4_list, NULL },
383 /*  73 */ { "Default Finger Server",                    ipv4_list, NULL },
384 /*  74 */ { "Default IRC Server",                       ipv4_list, NULL },
385 /*  75 */ { "StreetTalk Server",                        ipv4_list, NULL },
386 /*  76 */ { "StreetTalk Directory Assistance Server",   ipv4_list, NULL },
387 /*  77 */ { "User Class Information",                   opaque, NULL },
388 /*  78 */ { "Directory Agent Information",              special, NULL },
389 /*  79 */ { "Service Location Agent Scope",             special, NULL },
390 /*  80 */ { "Naming Authority",                         opaque, NULL },
391 /*  81 */ { "Client Fully Qualified Domain Name",       special, NULL },
392 /*  82 */ { "Agent Information Option",                 special, NULL },
393 /*  83 */ { "Unassigned",                               opaque, NULL },
394 /*  84 */ { "Unassigned",                               opaque, NULL },
395 /*  85 */ { "Novell Directory Services Servers",        special, NULL },
396 /*  86 */ { "Novell Directory Services Tree Name",      string, NULL },
397 /*  87 */ { "Novell Directory Services Context",        string, NULL },
398 /*  88 */ { "IEEE 1003.1 POSIX Timezone",               opaque, NULL },
399 /*  89 */ { "Fully Qualified Domain Name",              opaque, NULL },
400 /*  90 */ { "Authentication",                           special, NULL },
401 /*  91 */ { "Vines TCP/IP Server Option",               opaque, NULL },
402 /*  92 */ { "Server Selection Option",                  opaque, NULL },
403 /*  93 */ { "Client System Architecture",               val_u_short, VALS(bootp_client_arch) },
404 /*  94 */ { "Client Network Device Interface",          special, NULL },
405 /*  95 */ { "Lightweight Directory Access Protocol",    opaque, NULL },
406 /*  96 */ { "IPv6 Transitions",                         opaque, NULL },
407 /*  97 */ { "UUID/GUID-based Client Identifier",        special, NULL },
408 /*  98 */ { "Open Group's User Authentication",         opaque, NULL },
409 /*  99 */ { "Unassigned",                               opaque, NULL },
410 /* 100 */ { "Printer Name",                             opaque, NULL },
411 /* 101 */ { "MDHCP multicast address",                  opaque, NULL },
412 /* 102 */ { "Removed/unassigned",                       opaque, NULL },
413 /* 103 */ { "Removed/unassigned",                       opaque, NULL },
414 /* 104 */ { "Removed/unassigned",                       opaque, NULL },
415 /* 105 */ { "Removed/unassigned",                       opaque, NULL },
416 /* 106 */ { "Removed/unassigned",                       opaque, NULL },
417 /* 107 */ { "Removed/unassigned",                       opaque, NULL },
418 /* 108 */ { "Swap Path Option",                         opaque, NULL },
419 /* 109 */ { "Unassigned",                               opaque, NULL },
420 /* 110 */ { "IPX Compability",                          opaque, NULL },
421 /* 111 */ { "Unassigned",                               opaque, NULL },
422 /* 112 */ { "NetInfo Parent Server Address",            ipv4_list, NULL },
423 /* 113 */ { "NetInfo Parent Server Tag",                string, NULL },
424 /* 114 */ { "URL",                                      opaque, NULL },
425 /* 115 */ { "DHCP Failover Protocol",                   opaque, NULL },
426 /* 116 */ { "DHCP Auto-Configuration",                  opaque, NULL },
427 /* 117 */ { "Name Service Search",                      opaque, NULL },
428 /* 118 */ { "Subnet Selection Option",                  ipv4_list, NULL },
429 /* 119 */ { "Domain Search",                            opaque, NULL },
430 /* 120 */ { "SIP Servers",                              opaque, NULL },
431 /* 121 */ { "Classless Static Route",                   opaque, NULL },
432 /* 122 */ { "CableLabs Client Configuration",           opaque, NULL },
433 /* 123 */ { "Unassigned",                               opaque, NULL },
434 /* 124 */ { "V-I Vendor Class",                         opaque, NULL },
435 /* 125 */ { "V-I Vendor-specific Information",          opaque, NULL },
436 /* 126 */ { "Extension",                                opaque, NULL },
437 /* 127 */ { "Extension",                                opaque, NULL },
438 /* 128 */ { "Private",                                  opaque, NULL },
439 /* 129 */ { "Private",                                  opaque, NULL },
440 /* 130 */ { "Private",                                  opaque, NULL },
441 /* 131 */ { "Private",                                  opaque, NULL },
442 /* 132 */ { "Private",                                  opaque, NULL },
443 /* 133 */ { "Private",                                  opaque, NULL },
444 /* 134 */ { "Private",                                  opaque, NULL },
445 /* 135 */ { "Private",                                  opaque, NULL },
446 /* 136 */ { "Private",                                  opaque, NULL },
447 /* 137 */ { "Private",                                  opaque, NULL },
448 /* 138 */ { "Private",                                  opaque, NULL },
449 /* 139 */ { "Private",                                  opaque, NULL },
450 /* 140 */ { "Private",                                  opaque, NULL },
451 /* 141 */ { "Private",                                  opaque, NULL },
452 /* 142 */ { "Private",                                  opaque, NULL },
453 /* 143 */ { "Private",                                  opaque, NULL },
454 /* 144 */ { "Private",                                  opaque, NULL },
455 /* 145 */ { "Private",                                  opaque, NULL },
456 /* 146 */ { "Private",                                  opaque, NULL },
457 /* 147 */ { "Private",                                  opaque, NULL },
458 /* 148 */ { "Private",                                  opaque, NULL },
459 /* 149 */ { "Private",                                  opaque, NULL },
460 /* 150 */ { "Private",                                  opaque, NULL },
461 /* 151 */ { "Private",                                  opaque, NULL },
462 /* 152 */ { "Private",                                  opaque, NULL },
463 /* 153 */ { "Private",                                  opaque, NULL },
464 /* 154 */ { "Private",                                  opaque, NULL },
465 /* 155 */ { "Private",                                  opaque, NULL },
466 /* 156 */ { "Private",                                  opaque, NULL },
467 /* 157 */ { "Private",                                  opaque, NULL },
468 /* 158 */ { "Private",                                  opaque, NULL },
469 /* 159 */ { "Private",                                  opaque, NULL },
470 /* 160 */ { "Private",                                  opaque, NULL },
471 /* 161 */ { "Private",                                  opaque, NULL },
472 /* 162 */ { "Private",                                  opaque, NULL },
473 /* 163 */ { "Private",                                  opaque, NULL },
474 /* 164 */ { "Private",                                  opaque, NULL },
475 /* 165 */ { "Private",                                  opaque, NULL },
476 /* 166 */ { "Private",                                  opaque, NULL },
477 /* 167 */ { "Private",                                  opaque, NULL },
478 /* 168 */ { "Private",                                  opaque, NULL },
479 /* 169 */ { "Private",                                  opaque, NULL },
480 /* 170 */ { "Private",                                  opaque, NULL },
481 /* 171 */ { "Private",                                  opaque, NULL },
482 /* 172 */ { "Private",                                  opaque, NULL },
483 /* 173 */ { "Private",                                  opaque, NULL },
484 /* 174 */ { "Private",                                  opaque, NULL },
485 /* 175 */ { "Private",                                  opaque, NULL },
486 /* 176 */ { "Private",                                  opaque, NULL },
487 /* 177 */ { "Private",                                  opaque, NULL },
488 /* 178 */ { "Private",                                  opaque, NULL },
489 /* 179 */ { "Private",                                  opaque, NULL },
490 /* 180 */ { "Private",                                  opaque, NULL },
491 /* 181 */ { "Private",                                  opaque, NULL },
492 /* 182 */ { "Private",                                  opaque, NULL },
493 /* 183 */ { "Private",                                  opaque, NULL },
494 /* 184 */ { "Private",                                  opaque, NULL },
495 /* 185 */ { "Private",                                  opaque, NULL },
496 /* 186 */ { "Private",                                  opaque, NULL },
497 /* 187 */ { "Private",                                  opaque, NULL },
498 /* 188 */ { "Private",                                  opaque, NULL },
499 /* 189 */ { "Private",                                  opaque, NULL },
500 /* 190 */ { "Private",                                  opaque, NULL },
501 /* 191 */ { "Private",                                  opaque, NULL },
502 /* 192 */ { "Private",                                  opaque, NULL },
503 /* 193 */ { "Private",                                  opaque, NULL },
504 /* 194 */ { "Private",                                  opaque, NULL },
505 /* 195 */ { "Private",                                  opaque, NULL },
506 /* 196 */ { "Private",                                  opaque, NULL },
507 /* 197 */ { "Private",                                  opaque, NULL },
508 /* 198 */ { "Private",                                  opaque, NULL },
509 /* 199 */ { "Private",                                  opaque, NULL },
510 /* 200 */ { "Private",                                  opaque, NULL },
511 /* 201 */ { "Private",                                  opaque, NULL },
512 /* 202 */ { "Private",                                  opaque, NULL },
513 /* 203 */ { "Private",                                  opaque, NULL },
514 /* 204 */ { "Private",                                  opaque, NULL },
515 /* 205 */ { "Private",                                  opaque, NULL },
516 /* 206 */ { "Private",                                  opaque, NULL },
517 /* 207 */ { "Private",                                  opaque, NULL },
518 /* 208 */ { "Private",                                  opaque, NULL },
519 /* 209 */ { "Private",                                  opaque, NULL },
520 /* 210 */ { "Authentication",                           special, NULL },
521 /* 211 */ { "Private",                                  opaque, NULL },
522 /* 212 */ { "Private",                                  opaque, NULL },
523 /* 213 */ { "Private",                                  opaque, NULL },
524 /* 214 */ { "Private",                                  opaque, NULL },
525 /* 215 */ { "Private",                                  opaque, NULL },
526 /* 216 */ { "Private",                                  opaque, NULL },
527 /* 217 */ { "Private",                                  opaque, NULL },
528 /* 218 */ { "Private",                                  opaque, NULL },
529 /* 219 */ { "Private",                                  opaque, NULL },
530 /* 220 */ { "Private",                                  opaque, NULL },
531 /* 221 */ { "Private",                                  opaque, NULL },
532 /* 222 */ { "Private",                                  opaque, NULL },
533 /* 223 */ { "Private",                                  opaque, NULL },
534 /* 224 */ { "Private",                                  opaque, NULL },
535 /* 225 */ { "Private",                                  opaque, NULL },
536 /* 226 */ { "Private",                                  opaque, NULL },
537 /* 227 */ { "Private",                                  opaque, NULL },
538 /* 228 */ { "Private",                                  opaque, NULL },
539 /* 229 */ { "Private",                                  opaque, NULL },
540 /* 230 */ { "Private",                                  opaque, NULL },
541 /* 231 */ { "Private",                                  opaque, NULL },
542 /* 232 */ { "Private",                                  opaque, NULL },
543 /* 233 */ { "Private",                                  opaque, NULL },
544 /* 234 */ { "Private",                                  opaque, NULL },
545 /* 235 */ { "Private",                                  opaque, NULL },
546 /* 236 */ { "Private",                                  opaque, NULL },
547 /* 237 */ { "Private",                                  opaque, NULL },
548 /* 238 */ { "Private",                                  opaque, NULL },
549 /* 239 */ { "Private",                                  opaque, NULL },
550 /* 240 */ { "Private",                                  opaque, NULL },
551 /* 241 */ { "Private",                                  opaque, NULL },
552 /* 242 */ { "Private",                                  opaque, NULL },
553 /* 243 */ { "Private",                                  opaque, NULL },
554 /* 244 */ { "Private",                                  opaque, NULL },
555 /* 245 */ { "Private",                                  opaque, NULL },
556 /* 246 */ { "Private",                                  opaque, NULL },
557 /* 247 */ { "Private",                                  opaque, NULL },
558 /* 248 */ { "Private",                                  opaque, NULL },
559 /* 249 */ { "Classless static routes",                  opaque, NULL },
560 /* 250 */ { "Private",                                  opaque, NULL },
561 /* 251 */ { "Private",                                  opaque, NULL },
562 /* 252 */ { "Proxy autodiscovery",                      string, NULL },
563 /* 253 */ { "Private",                                  opaque, NULL },
564 /* 254 */ { "Private",                                  opaque, NULL },
565 /* 255 */ { "Private",                                  opaque, NULL }
566 };
567
568 static const char *
569 bootp_get_opt_text(unsigned int index)
570 {
571         if(index>=(sizeof(bootp_opt)/sizeof(struct opt_info)))
572                 return "unknown";
573         return bootp_opt[index].text;
574 }
575
576 static const void *
577 bootp_get_opt_data(unsigned int index)
578 {
579         if(index>=(sizeof(bootp_opt)/sizeof(struct opt_info)))
580                 return NULL;
581         return bootp_opt[index].data;
582 }
583
584 static enum field_type
585 bootp_get_opt_ftype(unsigned int index)
586 {
587         if(index>=(sizeof(bootp_opt)/sizeof(struct opt_info)))
588                 return none;
589         return bootp_opt[index].ftype;
590 }
591
592
593 /* Returns the number of bytes consumed by this option. */
594 static int
595 bootp_option(tvbuff_t *tvb, proto_tree *bp_tree, int voff, int eoff,
596     gboolean first_pass, gboolean *at_end, const char **dhcp_type_p,
597     const guint8 **vendor_class_id_p)
598 {
599         const char              *text;
600         enum field_type         ftype;
601         guchar                  code = tvb_get_guint8(tvb, voff);
602         int                     optlen;
603         const struct true_false_string *tfs;
604         const value_string      *vs;
605         guchar                  byte;
606         int                     i, consumed;
607         int                     optoff, optleft, optend;
608         gulong                  time_secs;
609         proto_tree              *v_tree, *ft;
610         proto_item              *vti;
611         guint8                  protocol;
612         guint8                  algorithm;
613         guint8                  rdm;
614         guint8                  fqdn_flags;
615         int                     o52voff, o52eoff;
616         gboolean                o52at_end;
617         gboolean                skip_opaque = FALSE;
618         int                     s_option;
619         int                     ava_vid;
620
621
622         static const value_string slpda_vals[] = {
623             {0x00,   "Dynamic Discovery" },
624             {0x01,   "Static Discovery" },
625             {0x80,   "Backwards compatibility" },
626             {0,     NULL     } };
627
628         static const value_string slp_scope_vals[] = {
629             {0x00,   "Preferred Scope" },
630             {0x01,   "Mandatory Scope" },
631             {0,     NULL     } };
632
633         static const value_string authen_protocol_vals[] = {
634             {AUTHEN_PROTO_CONFIG_TOKEN,   "configuration token" },
635             {AUTHEN_PROTO_DELAYED_AUTHEN, "delayed authentication" },
636             {0,                           NULL     } };
637
638         static const value_string authen_da_algo_vals[] = {
639             {AUTHEN_DELAYED_ALGO_HMAC_MD5, "HMAC_MD5" },
640             {0,                            NULL     } };
641
642         static const value_string authen_rdm_vals[] = {
643             {AUTHEN_RDM_MONOTONIC_COUNTER, "Monotonically-increasing counter" },
644             {0,                            NULL     } };
645
646         static const value_string opt_overload_vals[] = {
647             { OPT_OVERLOAD_FILE,  "Boot file name holds options",                },
648             { OPT_OVERLOAD_SNAME, "Server host name holds options",              },
649             { OPT_OVERLOAD_BOTH,  "Boot file and server host names hold options" },
650             { 0,                  NULL                                           } };
651
652         /* Options whose length isn't "optlen + 2". */
653         switch (code) {
654
655         case 0:         /* Padding */
656                 /* check how much padding we have */
657                 for (i = voff + 1; i < eoff; i++ ) {
658                         if (tvb_get_guint8(tvb, i) != 0) {
659                                 break;
660                         }
661                 }
662                 i = i - voff;
663                 if (!first_pass) {
664                         if (bp_tree != NULL) {
665                                 proto_tree_add_text(bp_tree, tvb, voff, i,
666                                     "Padding (%d byte%s)", i, (i>1)?"s":"");
667                         }
668                 }
669                 consumed = i;
670                 return consumed;
671                 break;
672
673         case 255:       /* End Option */
674                 if (!first_pass) {
675                         if (bp_tree != NULL) {
676                                 proto_tree_add_text(bp_tree, tvb, voff, 1,
677                                     "End Option");
678                         }
679                 }
680                 *at_end = TRUE;
681                 consumed = 1;
682                 return consumed;
683         }
684
685         /*
686          * Get the length of the option, and the number of bytes it
687          * consumes (the length doesn't include the option code or
688          * length bytes).
689          *
690          * On the first pass, check first whether we have the length
691          * byte, so that we don't throw an exception; if we throw an
692          * exception in the first pass, which is only checking for options
693          * whose values we need in order to properly dissect the packet
694          * on the second pass, we won't actually dissect the options, so
695          * you won't be able to see which option had the problem.
696          */
697         if (first_pass) {
698                 if (!tvb_bytes_exist(tvb, voff+1, 1)) {
699                         /*
700                          * We don't have the length byte; just return 1
701                          * as the number of bytes we consumed, to count
702                          * the code byte.
703                          */
704                         return 1;
705                 }
706         }
707         optlen = tvb_get_guint8(tvb, voff+1);
708         consumed = optlen + 2;
709
710         /*
711          * In the first pass, we don't put anything into the protocol
712          * tree; we just check for some options we have to look at
713          * in order to properly process the packet:
714          *
715          *      53 (DHCP message type) - if this is present, this is DHCP
716          *
717          *      60 (Vendor class identifier) - we need this in order to
718          *         interpret the vendor-specific info
719          *
720          * We also check, before fetching anything, to make sure we
721          * have the entire item we're fetching, so that we don't throw
722          * an exception.
723          */
724         if (first_pass) {
725                 if (tvb_bytes_exist(tvb, voff+2, consumed-2)) {
726                         switch (code) {
727
728                         case 53:
729                                 *dhcp_type_p =
730                                     val_to_str(tvb_get_guint8(tvb, voff+2),
731                                         opt53_text,
732                                         "Unknown Message Type (0x%02x)");
733                                 break;
734
735                         case 60:
736                                 *vendor_class_id_p =
737                                     tvb_get_ptr(tvb, voff+2, consumed-2);
738                                 break;
739                         }
740                 }
741
742                 /*
743                  * We don't do anything else here.
744                  */
745                 return consumed;
746         }
747
748         /*
749          * This is the second pass - if there's a protocol tree to be
750          * built, we put stuff into it, otherwise we just return.
751          */
752         if (bp_tree == NULL) {
753                 /* Don't put anything in the protocol tree. */
754                 return consumed;
755         }
756
757         /* Normal cases */
758         text = bootp_get_opt_text(code);
759         ftype = bootp_get_opt_ftype(code);
760
761         optoff = voff+2;
762
763         vti = proto_tree_add_text(bp_tree, tvb, voff, consumed,
764             "Option: (t=%d,l=%d) %s", code, optlen, text);
765         v_tree = proto_item_add_subtree(vti, ett_bootp_option);
766         proto_tree_add_uint_format_value(v_tree, hf_bootp_option_type,
767                 tvb, voff, 1, code, "(%d) %s", code, text);
768         proto_tree_add_item(v_tree, hf_bootp_option_length, tvb, voff+1, 1, FALSE);
769         if (optlen > 0) {
770                 proto_tree_add_item(v_tree, hf_bootp_option_value, tvb, voff+2, optlen, FALSE);
771         }
772
773         /* Special cases */
774         switch (code) {
775
776         case 21:        /* Policy Filter */
777                 if (optlen == 8) {
778                         /* one IP address pair */
779                         proto_item_append_text(vti, " = %s/%s",
780                                 ip_to_str(tvb_get_ptr(tvb, optoff, 4)),
781                                 ip_to_str(tvb_get_ptr(tvb, optoff+4, 4)));
782                 } else {
783                         /* > 1 IP address pair. Let's make a sub-tree */
784                         for (i = optoff, optleft = optlen;
785                             optleft > 0; i += 8, optleft -= 8) {
786                                 if (optleft < 8) {
787                                         proto_tree_add_text(v_tree, tvb, i, optleft,
788                                             "Option length isn't a multiple of 8");
789                                         break;
790                                 }
791                                 proto_tree_add_text(v_tree, tvb, i, 8, "IP Address/Mask: %s/%s",
792                                         ip_to_str(tvb_get_ptr(tvb, i, 4)),
793                                         ip_to_str(tvb_get_ptr(tvb, i+4, 4)));
794                         }
795                 }
796                 break;
797
798         case 33:        /* Static Route */
799                 if (optlen == 8) {
800                         /* one IP address pair */
801                         proto_item_append_text(vti, " = %s/%s",
802                                 ip_to_str(tvb_get_ptr(tvb, optoff, 4)),
803                                 ip_to_str(tvb_get_ptr(tvb, optoff+4, 4)));
804                 } else {
805                         /* > 1 IP address pair. Let's make a sub-tree */
806                         for (i = optoff, optleft = optlen; optleft > 0;
807                             i += 8, optleft -= 8) {
808                                 if (optleft < 8) {
809                                         proto_tree_add_text(v_tree, tvb, i, optleft,
810                                             "Option length isn't a multiple of 8");
811                                         break;
812                                 }
813                                 proto_tree_add_text(v_tree, tvb, i, 8,
814                                         "Destination IP Address/Router: %s/%s",
815                                         ip_to_str(tvb_get_ptr(tvb, i, 4)),
816                                         ip_to_str(tvb_get_ptr(tvb, i+4, 4)));
817                         }
818                 }
819                 break;
820
821         case 43:        /* Vendor-Specific Info */
822                 s_option = tvb_get_guint8(tvb, optoff);
823
824                 if (optlen == 5 && s_option == 58)
825                 {
826                                 proto_item_append_text(vti, " (Alcatel AVA)");
827                                 ava_vid =  tvb_get_ntohs(tvb, optoff + 2);
828
829                                 proto_tree_add_uint (v_tree, hf_bootp_alcatel_vid, tvb, optoff + 2,
830                                         2, ava_vid);
831
832                                 if (ava_vid == 65535)
833                                 {
834                                         proto_tree_add_text (v_tree, tvb, optoff + 2,
835                                                 2, "Type: Request from TSC IP Phone");
836                                 } else {
837                                         proto_tree_add_text (v_tree, tvb, optoff + 2,
838                                                 2, "Type: Response from Server");
839                                 }
840
841                                 break;
842                 }
843
844                 /* PXE protocol 2.1 as described in the intel specs */
845                 if (*vendor_class_id_p != NULL &&
846                     strncmp((const gchar*)*vendor_class_id_p, "PXEClient", strlen("PXEClient")) == 0) {
847                         proto_item_append_text(vti, " (PXEClient)");
848                         v_tree = proto_item_add_subtree(vti, ett_bootp_option);
849
850                         optend = optoff + optlen;
851                         while (optoff < optend) {
852                                 optoff = dissect_vendor_pxeclient_suboption(v_tree,
853                                         tvb, optoff, optend);
854                         }
855                 } else if (*vendor_class_id_p != NULL &&
856                            ((strncmp((const gchar*)*vendor_class_id_p, "pktc", strlen("pktc")) == 0) ||
857                             (strncmp((const gchar*)*vendor_class_id_p, "docsis", strlen("docsis")) == 0) ||
858                             (strncmp((const gchar*)*vendor_class_id_p, "CableHome", strlen("CableHome")) == 0))) {
859                         /* CableLabs standard - see www.cablelabs.com/projects */
860                         proto_item_append_text(vti, " (CableLabs)");
861
862                         optend = optoff + optlen;
863                         while (optoff < optend) {
864                                 optoff = dissect_vendor_cablelabs_suboption(v_tree,
865                                         tvb, optoff, optend);
866                         }
867                 }
868                 break;
869
870         case 52:        /* Option Overload */
871                 if (optlen < 1) {
872                         proto_item_append_text(vti, " length isn't >= 1");
873                         break;
874                 }
875                 byte = tvb_get_guint8(tvb, optoff);
876                 proto_item_append_text(vti, " = %s",
877                         val_to_str(byte, opt_overload_vals,
878                             "Unknown (0x%02x)"));
879
880                 /* Just in case we find an option 52 in sname or file */
881                 if (voff > VENDOR_INFO_OFFSET && byte >= 1 && byte <= 3) {
882                         v_tree = proto_item_add_subtree(vti, ett_bootp_option);
883                         if (byte == 1 || byte == 3) {   /* 'file' */
884                                 vti = proto_tree_add_text (v_tree, tvb,
885                                         FILE_NAME_OFFSET, FILE_NAME_LEN,
886                                         "Boot file name option overload");
887                                 v_tree = proto_item_add_subtree(vti, ett_bootp_option);
888                                 o52voff = FILE_NAME_OFFSET;
889                                 o52eoff = FILE_NAME_OFFSET + FILE_NAME_LEN;
890                                 o52at_end = FALSE;
891                                 while (o52voff < o52eoff && !o52at_end) {
892                                         o52voff += bootp_option(tvb, v_tree, o52voff,
893                                                 o52eoff, FALSE, &o52at_end,
894                                                 dhcp_type_p, vendor_class_id_p);
895                                 }
896                         }
897                         if (byte == 2 || byte == 3) {   /* 'sname' */
898                                 vti = proto_tree_add_text (v_tree, tvb,
899                                         SERVER_NAME_OFFSET, SERVER_NAME_LEN,
900                                         "Server host name option overload");
901                                 v_tree = proto_item_add_subtree(vti, ett_bootp_option);
902                                 o52voff = SERVER_NAME_OFFSET;
903                                 o52eoff = SERVER_NAME_OFFSET + SERVER_NAME_LEN;
904                                 o52at_end = FALSE;
905                                 while (o52voff < o52eoff && !o52at_end) {
906                                         o52voff += bootp_option(tvb, v_tree, o52voff,
907                                                 o52eoff, FALSE, &o52at_end,
908                                                 dhcp_type_p, vendor_class_id_p);
909                                 }
910                         }
911                 }
912
913 /*              protocol = tvb_get_guint8(tvb, optoff);
914                 proto_tree_add_text(v_tree, tvb, optoff, 1, "Protocol: %s (%u)",
915                                     val_to_str(protocol, authen_protocol_vals, "Unknown"),
916                                     protocol); */
917                 break;
918
919         case 53:        /* DHCP Message Type */
920                 if (optlen != 1) {
921                         proto_item_append_text(vti, " length isn't 1");
922                         break;
923                 }
924                 proto_item_append_text(vti, " = DHCP %s",
925                         val_to_str(tvb_get_guint8(tvb, optoff),
926                                 opt53_text,
927                                 "Unknown Message Type (0x%02x)"));
928                 break;
929
930         case 55:        /* Parameter Request List */
931                 for (i = 0; i < optlen; i++) {
932                         byte = tvb_get_guint8(tvb, optoff+i);
933                         proto_tree_add_text(v_tree, tvb, optoff+i, 1, "%d = %s",
934                                         byte, bootp_get_opt_text(byte));
935                 }
936                 break;
937
938         case 60:        /* Vendor class identifier */
939                 /*
940                  * XXX - RFC 2132 says this is a string of octets;
941                  * should we check for non-printables?
942                  */
943                 proto_item_append_text(vti, " = \"%s\"",
944                         tvb_format_stringzpad(tvb, optoff, consumed-2));
945                 if ((tvb_memeql(tvb, optoff, (const guint8*)PACKETCABLE_MTA_CAP10,
946                                       strlen(PACKETCABLE_MTA_CAP10)) == 0)
947                     ||
948                     (tvb_memeql(tvb, optoff, (const guint8*)PACKETCABLE_MTA_CAP15,
949                                       strlen(PACKETCABLE_MTA_CAP10)) == 0))
950                 {
951                         dissect_packetcable_mta_cap(v_tree, tvb, optoff, optlen);
952                 }
953                 else {
954                   if (tvb_memeql(tvb, optoff, (const guint8*)PACKETCABLE_CM_CAP11,
955                                       strlen(PACKETCABLE_CM_CAP11)) == 0
956                       ||
957                       tvb_memeql(tvb, optoff, (const guint8*)PACKETCABLE_CM_CAP20,
958                                       strlen(PACKETCABLE_CM_CAP20)) == 0 )
959                   {
960                         dissect_docsis_cm_cap(v_tree, tvb, optoff, optlen);
961                   }
962                 }
963                 break;
964
965         case 61:        /* Client Identifier */
966         case 97:        /* Client Identifier (UUID) */
967                 if (optlen > 0)
968                         byte = tvb_get_guint8(tvb, optoff);
969                 else
970                         byte = 0;
971
972                 /* We *MAY* use hwtype/hwaddr. If we have 7 bytes, I'll
973                    guess that the first is the hwtype, and the last 6
974                    are the hw addr */
975                 /* See http://www.iana.org/assignments/arp-parameters */
976                 /* RFC2132 9.14 Client-identifier has the following to say:
977                    A hardware type of 0 (zero) should be used when the value
978                    field contains an identifier other than a hardware address
979                    (e.g. a fully qualified domain name). */
980
981                 if (optlen == 7 && byte > 0 && byte < 48) {
982                         proto_tree_add_text(v_tree, tvb, optoff, 1,
983                                 "Hardware type: %s",
984                                 arphrdtype_to_str(byte,
985                                         "Unknown (0x%02x)"));
986                         if (byte == ARPHRD_ETHER || byte == ARPHRD_IEEE802)
987                                 proto_tree_add_item(v_tree,
988                                     hf_bootp_hw_ether_addr, tvb, optoff+1, 6,
989                                     FALSE);
990                         else
991                                 proto_tree_add_text(v_tree, tvb, optoff+1, 6,
992                                         "Client hardware address: %s",
993                                         arphrdaddr_to_str(tvb_get_ptr(tvb, optoff+1, 6),
994                                         6, byte));
995                 } else if (optlen == 17 && byte == 0) {
996                         /* Identifier is a UUID */
997                         proto_tree_add_item(v_tree, hf_bootp_client_identifier_uuid,
998                                             tvb, optoff + 1, 16, TRUE);
999                 } else {
1000                         /* otherwise, it's opaque data */
1001                 }
1002                 break;
1003
1004         case 63:        /* NetWare/IP options (RFC 2242) */
1005
1006                 optend = optoff + optlen;
1007                 while (optoff < optend)
1008                         optoff = dissect_netware_ip_suboption(v_tree, tvb, optoff, optend);
1009                 break;
1010
1011         case 78:        /* SLP Directory Agent Option RFC2610 Added by Greg Morris (gmorris@novell.com)*/
1012                 if (optlen < 1) {
1013                         proto_item_append_text(vti, " length isn't >= 1");
1014                         break;
1015                 }
1016                 optleft = optlen;
1017                 byte = tvb_get_guint8(tvb, optoff);
1018                 proto_item_append_text(vti, " = %s",
1019                                 val_to_str(byte, slpda_vals,
1020                                         "Unknown (0x%02x)"));
1021                 optoff++;
1022                 optleft--;
1023                 if (byte == 0x80) {
1024                         if (optleft == 0)
1025                                 break;
1026                         optoff++;
1027                         optleft--;
1028                 }
1029                 for (i = optoff; optleft > 0; i += 4, optleft -= 4) {
1030                         if (optleft < 4) {
1031                                 proto_tree_add_text(v_tree, tvb, i, optleft,
1032                                     "Option length isn't a multiple of 4");
1033                                 break;
1034                         }
1035                         proto_tree_add_text(v_tree, tvb, i, 4, "SLPDA Address: %s",
1036                             ip_to_str(tvb_get_ptr(tvb, i, 4)));
1037                 }
1038                 break;
1039
1040         case 79:        /* SLP Service Scope Option RFC2610 Added by Greg Morris (gmorris@novell.com)*/
1041                 byte = tvb_get_guint8(tvb, optoff);
1042                 proto_item_append_text(vti, " = %s",
1043                                 val_to_str(byte, slp_scope_vals,
1044                                     "Unknown (0x%02x)"));
1045                 optoff++;
1046                 optleft = optlen - 1;
1047                 proto_tree_add_text(v_tree, tvb, optoff, optleft,
1048                     "%s = \"%s\"", text,
1049                     tvb_format_stringzpad(tvb, optoff, optleft));
1050                 break;
1051
1052         case 81:        /* Client Fully Qualified Domain Name */
1053                 if (optlen < 3) {
1054                         proto_item_append_text(vti, " length isn't >= 3");
1055                         break;
1056                 }
1057                 fqdn_flags = tvb_get_guint8(tvb, optoff);
1058                 ft = proto_tree_add_text(v_tree, tvb, optoff, 1, "Flags: 0x%02x", fqdn_flags);
1059                 proto_tree_add_item(v_tree, hf_bootp_fqdn_mbz, tvb, optoff, 1, FALSE);
1060                 proto_tree_add_item(v_tree, hf_bootp_fqdn_n, tvb, optoff, 1, FALSE);
1061                 proto_tree_add_item(v_tree, hf_bootp_fqdn_e, tvb, optoff, 1, FALSE);
1062                 proto_tree_add_item(v_tree, hf_bootp_fqdn_o, tvb, optoff, 1, FALSE);
1063                 proto_tree_add_item(v_tree, hf_bootp_fqdn_s, tvb, optoff, 1, FALSE);
1064                 /* XXX: use code from packet-dns for return code decoding */
1065                 proto_tree_add_item(v_tree, hf_bootp_fqdn_rcode1, tvb, optoff+1, 1, FALSE);
1066                 /* XXX: use code from packet-dns for return code decoding */
1067                 proto_tree_add_item(v_tree, hf_bootp_fqdn_rcode2, tvb, optoff+2, 1, FALSE);
1068                 if (optlen > 3) {
1069                         if (fqdn_flags & F_FQDN_E) {
1070                                 /* XXX: use code from packet-dns for binary encoded name */
1071                                 proto_tree_add_item(v_tree, hf_bootp_fqdn_name,
1072                                     tvb, optoff+3, optlen-3, FALSE);
1073
1074                         } else {
1075                                 proto_tree_add_item(v_tree, hf_bootp_fqdn_asciiname,
1076                                     tvb, optoff+3, optlen-3, FALSE);
1077                         }
1078                 }
1079                 break;
1080
1081         case 82:        /* Relay Agent Information Option */
1082                 optend = optoff + optlen;
1083                 while (optoff < optend)
1084                         optoff = bootp_dhcp_decode_agent_info(v_tree, tvb, optoff, optend);
1085                 break;
1086
1087         case 85:        /* Novell Servers (RFC 2241) */
1088                 /* Option 85 can be sent as a string */
1089                 /* Added by Greg Morris (gmorris[AT]novell.com) */
1090                 if (novell_string) {
1091                         proto_item_append_text(vti, " = \"%s\"",
1092                             tvb_format_stringzpad(tvb, optoff, optlen));
1093                 } else {
1094                         if (optlen == 4) {
1095                                 /* one IP address */
1096                                 proto_item_append_text(vti, " = %s",
1097                                         ip_to_str(tvb_get_ptr(tvb, optoff, 4)));
1098                         } else {
1099                                 /* > 1 IP addresses. Let's make a sub-tree */
1100                                 for (i = optoff, optleft = optlen; optleft > 0;
1101                                     i += 4, optleft -= 4) {
1102                                         if (optleft < 4) {
1103                                                 proto_tree_add_text(v_tree, tvb, i, optleft,
1104                                                     "Option length isn't a multiple of 4");
1105                                                 break;
1106                                         }
1107                                         proto_tree_add_text(v_tree, tvb, i, 4, "IP Address: %s",
1108                                                 ip_to_str(tvb_get_ptr(tvb, i, 4)));
1109                                 }
1110                         }
1111                 }
1112                 break;
1113
1114         case 94: {      /* Client network interface identifier */
1115                 guint8 id_type;
1116
1117                 id_type = tvb_get_guint8(tvb, optoff);
1118
1119                 if (id_type == 0x01) {
1120                         proto_tree_add_item(v_tree, hf_bootp_client_network_id_major_ver,
1121                                             tvb, optoff + 1, 1, TRUE);
1122                         proto_tree_add_item(v_tree, hf_bootp_client_network_id_minor_ver,
1123                                             tvb, optoff + 2, 1, TRUE);
1124                 }
1125
1126                 break;
1127         }
1128
1129         case 90:        /* DHCP Authentication */
1130         case 210:       /* Was this used for authentication at one time? */
1131                 if (optlen < 11) {
1132                         proto_item_append_text(vti, " length isn't >= 11");
1133                         break;
1134                 }
1135                 optleft = optlen;
1136                 protocol = tvb_get_guint8(tvb, optoff);
1137                 proto_tree_add_text(v_tree, tvb, optoff, 1, "Protocol: %s (%u)",
1138                                     val_to_str(protocol, authen_protocol_vals, "Unknown"),
1139                                     protocol);
1140                 optoff++;
1141                 optleft--;
1142
1143                 algorithm = tvb_get_guint8(tvb, optoff);
1144                 switch (protocol) {
1145
1146                 case AUTHEN_PROTO_DELAYED_AUTHEN:
1147                         proto_tree_add_text(v_tree, tvb, optoff, 1,
1148                                     "Algorithm: %s (%u)",
1149                                     val_to_str(algorithm, authen_da_algo_vals, "Unknown"),
1150                                     algorithm);
1151                         break;
1152
1153                 default:
1154                         proto_tree_add_text(v_tree, tvb, optoff, 1,
1155                                     "Algorithm: %u", algorithm);
1156                         break;
1157                 }
1158                 optoff++;
1159                 optleft--;
1160
1161                 rdm = tvb_get_guint8(tvb, optoff);
1162                 proto_tree_add_text(v_tree, tvb, optoff, 1,
1163                                     "Replay Detection Method: %s (%u)",
1164                                     val_to_str(rdm, authen_rdm_vals, "Unknown"),
1165                                     rdm);
1166                 optoff++;
1167                 optleft--;
1168
1169                 switch (rdm) {
1170
1171                 case AUTHEN_RDM_MONOTONIC_COUNTER:
1172                         proto_tree_add_text(v_tree, tvb, optoff, 8,
1173                                     "RDM Replay Detection Value: %" G_GINT64_MODIFIER "x",
1174                                     tvb_get_ntoh64(tvb, optoff));
1175                         break;
1176
1177                 default:
1178                         proto_tree_add_text(v_tree, tvb, optoff, 8,
1179                                     "Replay Detection Value: %s",
1180                                     tvb_bytes_to_str(tvb, optoff, 8));
1181                         break;
1182                 }
1183                 optoff += 8;
1184                 optleft -= 8;
1185
1186                 switch (protocol) {
1187
1188                 case AUTHEN_PROTO_DELAYED_AUTHEN:
1189                         switch (algorithm) {
1190
1191                         case AUTHEN_DELAYED_ALGO_HMAC_MD5:
1192                                 if (*dhcp_type_p && !strcmp(*dhcp_type_p, OPT53_DISCOVER)) {
1193                                         /* Discover has no Secret ID nor HMAC MD5 Hash */
1194                                         break;
1195                                 } else {
1196                                         if (optlen < 31) {
1197                                                 proto_item_append_text(vti,
1198                                                         " length isn't >= 31");
1199                                                 break;
1200                                         }
1201                                         proto_tree_add_text(v_tree, tvb, optoff, 4,
1202                                                 "Secret ID: 0x%08x",
1203                                                 tvb_get_ntohl(tvb, optoff));
1204                                         optoff += 4;
1205                                         optleft -= 4;
1206                                         proto_tree_add_text(v_tree, tvb, optoff, 16,
1207                                                 "HMAC MD5 Hash: %s",
1208                                                 tvb_bytes_to_str(tvb, optoff, 16));
1209                                         break;
1210                                 }
1211                         default:
1212                                 if (optleft == 0)
1213                                         break;
1214                                 proto_tree_add_text(v_tree, tvb, optoff, optleft,
1215                                         "Authentication Information: %s",
1216                                         tvb_bytes_to_str(tvb, optoff, optleft));
1217                                 break;
1218                         }
1219                         break;
1220
1221                 default:
1222                         if (optleft == 0)
1223                                 break;
1224                         proto_tree_add_text(v_tree, tvb, optoff, optleft,
1225                                 "Authentication Information: %s",
1226                                 tvb_bytes_to_str(tvb, optoff, optleft));
1227                         break;
1228                 }
1229                 break;
1230
1231         case 125: {     /* V-I Vendor-specific Information */
1232                 int enterprise = 0;
1233                 int s_end = 0;
1234                 int s_option_len = 0;
1235                 proto_tree *e_tree = 0;
1236
1237                 optend = optoff + optlen;
1238
1239                 optleft = optlen;
1240
1241                 while (optleft > 0) {
1242
1243                   if (optleft < 5) {
1244                     proto_tree_add_text(v_tree, tvb, optoff,
1245                                         optleft, "Vendor-specific Information: malformed option");
1246                     break;
1247                   }
1248
1249                   enterprise = tvb_get_ntohl(tvb, optoff);
1250
1251                   vti = proto_tree_add_text(v_tree, tvb, optoff, 4,
1252                                             "Enterprise-number: %s-%u",
1253                                             val_to_str( enterprise, sminmpec_values, "Unknown"),
1254                                             enterprise);
1255
1256                   s_option_len = tvb_get_guint8(tvb, optoff + 4);
1257
1258                   optoff += 5;
1259                   optleft -= 5;
1260
1261                   /* Handle DSL Forum TR-111 Option 125 */
1262                   if ( enterprise == 3561 ) {
1263
1264                     s_end = optoff + s_option_len;
1265                     if ( s_end > optend ) {
1266                       proto_tree_add_text(v_tree, tvb, optoff, 1,
1267                                           "no room left in option for enterprise %u data", enterprise);
1268                       break;
1269                     }
1270
1271
1272                     e_tree = proto_item_add_subtree(vti, ett_bootp_option);
1273                     while (optoff < s_end) {
1274
1275                       optoff = dissect_vendor_tr111_suboption(e_tree,
1276                                                                  tvb, optoff, s_end);
1277                     }
1278                   } else {
1279
1280                     /* skip over the data and look for next enterprise number */
1281                     optoff += s_option_len;
1282                   }
1283
1284                   optleft -= s_option_len;
1285
1286                 }
1287                 break;
1288         }
1289
1290         default:        /* not special */
1291                 /* The PacketCable CCC option number can vary.  If this is a CCC option,
1292                    handle it and skip the "opaque" case below.
1293                  */
1294                 if (code == pkt_ccc_option) {
1295                         skip_opaque = TRUE;
1296                         proto_item_append_text(vti,
1297                                 "CableLabs Client Configuration (%d bytes)",
1298                                 optlen);
1299                         optend = optoff + optlen;
1300                         while (optoff < optend) {
1301                                 switch (pkt_ccc_protocol_version) {
1302                                         case PACKETCABLE_CCC_I05:
1303                                                 optoff = dissect_packetcable_i05_ccc(v_tree, tvb, optoff, optend);
1304                                                 break;
1305                                         case PACKETCABLE_CCC_DRAFT5:
1306                                         case PACKETCABLE_CCC_RFC_3495:
1307                                                 optoff = dissect_packetcable_ietf_ccc(v_tree, tvb, optoff, optend, pkt_ccc_protocol_version);
1308                                                 break;
1309                                         default: /* XXX Should we do something here? */
1310                                                 break;
1311                                 }
1312                         }
1313                 }
1314
1315                 break;
1316         }
1317
1318         if (ftype == special)
1319                 return consumed;
1320         if (ftype == opaque) {
1321                 if (skip_opaque) /* Currently used by PacketCable CCC */
1322                         return consumed;
1323         }
1324
1325         switch (ftype) {
1326         case ipv4:
1327                 if (optlen != 4) {
1328                         proto_item_append_text(vti,
1329                             " - length isn't 4");
1330                         break;
1331                 }
1332                 proto_item_append_text(vti, " = %s",
1333                         ip_to_str(tvb_get_ptr(tvb, optoff, 4)));
1334                 break;
1335
1336         case ipv4_list:
1337                 if (optlen == 4) {
1338                         /* one IP address */
1339                         proto_item_append_text(vti, " = %s",
1340                                 ip_to_str(tvb_get_ptr(tvb, optoff, 4)));
1341                 } else {
1342                         /* > 1 IP addresses. Let's make a sub-tree */
1343                         for (i = optoff, optleft = optlen; optleft > 0;
1344                             i += 4, optleft -= 4) {
1345                                 if (optleft < 4) {
1346                                         proto_tree_add_text(v_tree, tvb, i, voff + consumed - i,
1347                                             "Option length isn't a multiple of 4");
1348                                         break;
1349                                 }
1350                                 proto_tree_add_text(v_tree, tvb, i, 4, "IP Address: %s",
1351                                         ip_to_str(tvb_get_ptr(tvb, i, 4)));
1352                         }
1353                 }
1354                 break;
1355
1356         case string:
1357                 /* Fix for non null-terminated string supplied by
1358                  * John Lines <John.Lines[AT]aeat.co.uk>
1359                  */
1360                 proto_item_append_text(vti, " = \"%s\"",
1361                                 tvb_format_stringzpad(tvb, optoff, consumed-2));
1362                 break;
1363
1364         case opaque:
1365                 break;
1366
1367         case val_boolean:
1368                 if (optlen != 1) {
1369                         proto_item_append_text(vti,
1370                             " - length isn't 1");
1371                         break;
1372                 }
1373                 tfs = (const struct true_false_string *) bootp_get_opt_data(code);
1374                 if(tfs){
1375                         i = tvb_get_guint8(tvb, optoff);
1376                         if (i != 0 && i != 1) {
1377                                 proto_item_append_text(vti,
1378                                     " = Invalid Value %d", i);
1379                         } else {
1380                                 proto_item_append_text(vti, " = %s",
1381                                         i == 0 ? tfs->false_string : tfs->true_string);
1382                         }
1383                 }
1384                 break;
1385
1386         case val_u_byte:
1387                 if (optlen != 1) {
1388                         proto_item_append_text(vti,
1389                             " - length isn't 1");
1390                         break;
1391                 }
1392                 vs = (const value_string *) bootp_get_opt_data(code);
1393                 byte = tvb_get_guint8(tvb, optoff);
1394                 if (vs != NULL) {
1395                         proto_item_append_text(vti, " = %s",
1396                             val_to_str(byte, vs, "Unknown (%u)"));
1397                 } else
1398                         proto_item_append_text(vti, " = %u", byte);
1399                 break;
1400
1401         case val_u_short: {
1402                 gushort vd;
1403
1404                 if (optlen != 2) {
1405                         proto_item_append_text(vti,
1406                             " - length isn't 2");
1407                         break;
1408                 }
1409
1410                 vs = (const value_string *) bootp_get_opt_data(code);
1411                 vd = tvb_get_ntohs(tvb, optoff);
1412
1413                 if (vs != NULL) {
1414                         proto_item_append_text(vti, " = %s",
1415                             val_to_str(vd, vs, "Unknown (%u)"));
1416                 } else
1417                         proto_item_append_text(vti, " = %u", vd);
1418
1419                 break;
1420         }
1421
1422         case val_u_short_list:
1423                 if (optlen == 2) {
1424                         /* one gushort */
1425                         proto_item_append_text(vti, " = %u",
1426                             tvb_get_ntohs(tvb, optoff));
1427                 } else {
1428                         /* > 1 gushort */
1429                         for (i = optoff, optleft = optlen; optleft > 0;
1430                             i += 2, optleft -= 2) {
1431                                 if (optleft < 2) {
1432                                         proto_tree_add_text(v_tree, tvb, i, voff + consumed - i,
1433                                             "Option length isn't a multiple of 2");
1434                                         break;
1435                                 }
1436                                 proto_tree_add_text(v_tree, tvb, i, 4, "Value: %u",
1437                                         tvb_get_ntohs(tvb, i));
1438                         }
1439                 }
1440                 break;
1441
1442         case val_u_long:
1443                 if (optlen != 4) {
1444                         proto_item_append_text(vti,
1445                             " - length isn't 4");
1446                         break;
1447                 }
1448                 proto_item_append_text(vti, " = %u",
1449                     tvb_get_ntohl(tvb, optoff));
1450                 break;
1451
1452         case time_in_secs:
1453                 if (optlen != 4) {
1454                         proto_item_append_text(vti,
1455                             " - length isn't 4");
1456                         break;
1457                 }
1458                 time_secs = tvb_get_ntohl(tvb, optoff);
1459                 proto_item_append_text(vti, " = %s",
1460                     ((time_secs == 0xffffffff) ?
1461                       "infinity" :
1462                       time_secs_to_str(time_secs)));
1463                 break;
1464
1465         default:
1466                 break;
1467         }
1468
1469         return consumed;
1470 }
1471
1472 static int
1473 bootp_dhcp_decode_agent_info(proto_tree *v_tree, tvbuff_t *tvb, int optoff,
1474     int optend)
1475 {
1476         int suboptoff = optoff;
1477         guint8 subopt;
1478         guint8 subopt_len;
1479
1480         subopt = tvb_get_guint8(tvb, optoff);
1481         suboptoff++;
1482
1483         if (suboptoff >= optend) {
1484                 proto_tree_add_text(v_tree, tvb, optoff, 1,
1485                         "Suboption %d: no room left in option for suboption length",
1486                         subopt);
1487                 return (optend);
1488         }
1489         subopt_len = tvb_get_guint8(tvb, suboptoff);
1490         suboptoff++;
1491
1492         if (suboptoff+subopt_len > optend) {
1493                 proto_tree_add_text(v_tree, tvb, optoff, optend-optoff,
1494                         "Suboption %d: no room left in option for suboption value",
1495                         subopt);
1496                 return (optend);
1497         }
1498         switch (subopt) {
1499         case 1:
1500                 proto_tree_add_text(v_tree, tvb, optoff, subopt_len + 2,
1501                                     "Agent Circuit ID: %s",
1502                                     tvb_bytes_to_str(tvb, suboptoff, subopt_len));
1503                 break;
1504         case 2:
1505                 proto_tree_add_text(v_tree, tvb, optoff, subopt_len + 2,
1506                                     "Agent Remote ID: %s",
1507                                     tvb_bytes_to_str(tvb, suboptoff, subopt_len));
1508                 break;
1509         default:
1510                 proto_tree_add_text(v_tree, tvb, optoff, subopt_len + 2,
1511                                     "Invalid agent suboption %d (%d bytes)",
1512                                     subopt, subopt_len);
1513                 break;
1514         }
1515         optoff += (subopt_len + 2);
1516         return optoff;
1517 }
1518
1519 static int
1520 dissect_vendor_pxeclient_suboption(proto_tree *v_tree, tvbuff_t *tvb,
1521     int optoff, int optend)
1522 {
1523         int suboptoff = optoff;
1524         guint8 subopt;
1525         guint8 subopt_len;
1526         int suboptleft;
1527         proto_tree *o43pxeclient_v_tree;
1528         proto_item *vti;
1529
1530         static struct opt_info o43pxeclient_opt[]= {
1531                 /* 0 */ {"nop", special, NULL}, /* dummy */
1532                 /* 1 */ {"PXE mtftp IP", ipv4_list, NULL},
1533                 /* 2 */ {"PXE mtftp client port", val_u_le_short, NULL},
1534                 /* 3 */ {"PXE mtftp server port",val_u_le_short, NULL},
1535                 /* 4 */ {"PXE mtftp timeout", val_u_byte, NULL},
1536                 /* 5 */ {"PXE mtftp delay", val_u_byte, NULL},
1537                 /* 6 */ {"PXE discovery control", val_u_byte, NULL},
1538                         /*
1539                          * Correct: b0 (lsb): disable broadcast discovery
1540                          *      b1: disable multicast discovery
1541                          *      b2: only use/accept servers in boot servers
1542                          *      b3: download bootfile without prompt/menu/disc
1543                          */
1544                 /* 7 */ {"PXE multicast address", ipv4_list, NULL},
1545                 /* 8 */ {"PXE boot servers", special, NULL},
1546                 /* 9 */ {"PXE boot menu", special, NULL},
1547                 /* 10 */ {"PXE menu prompt", special, NULL},
1548                 /* 11 */ {"PXE multicast address alloc", special, NULL},
1549                 /* 12 */ {"PXE credential types", special, NULL},
1550                 /* 71 {"PXE boot item", special, NULL}, */
1551                 /* 255 {"PXE end options", special, NULL} */
1552         };
1553
1554         subopt = tvb_get_guint8(tvb, suboptoff);
1555         suboptoff++;
1556
1557         if (subopt == 0) {
1558                 proto_tree_add_text(v_tree, tvb, optoff, 1, "Padding");
1559                 return (suboptoff);
1560         } else if (subopt == 255) {     /* End Option */
1561                 proto_tree_add_text(v_tree, tvb, optoff, 1, "End PXEClient option");
1562                 /* Make sure we skip any junk left this option */
1563                 return (optend);
1564         }
1565
1566         if (suboptoff >= optend) {
1567                 proto_tree_add_text(v_tree, tvb, optoff, 1,
1568                         "Suboption %d: no room left in option for suboption length",
1569                         subopt);
1570                 return (optend);
1571         }
1572         subopt_len = tvb_get_guint8(tvb, suboptoff);
1573         suboptoff++;
1574
1575         if (suboptoff+subopt_len > optend) {
1576                 proto_tree_add_text(v_tree, tvb, optoff, optend-optoff,
1577                         "Suboption %d: no room left in option for suboption value",
1578                         subopt);
1579                 return (optend);
1580         }
1581         if ( subopt == 71 ) {   /* 71 {"PXE boot item", special} */
1582                 /* case special */
1583                 /* I may need to decode that properly one day */
1584                 proto_tree_add_text(v_tree, tvb, optoff, subopt_len+2,
1585                         "Suboption %d: %s (%d byte%s)" ,
1586                         subopt, "PXE boot item",
1587                         subopt_len, plurality(subopt_len, "", "s"));
1588         } else if ((subopt < 1) || (subopt >= array_length(o43pxeclient_opt))) {
1589                 proto_tree_add_text(v_tree, tvb, optoff, subopt_len+2,
1590                         "Unknown suboption %d (%d byte%s)", subopt, subopt_len,
1591                         plurality(subopt_len, "", "s"));
1592         } else {
1593                 switch (o43pxeclient_opt[subopt].ftype) {
1594
1595                 case special:
1596                         /* I may need to decode that properly one day */
1597                         proto_tree_add_text(v_tree, tvb, optoff, subopt_len+2,
1598                                 "Suboption %d: %s (%d byte%s)",
1599                                 subopt, o43pxeclient_opt[subopt].text,
1600                                 subopt_len, plurality(subopt_len, "", "s"));
1601                         break;
1602
1603                 case ipv4_list:
1604                         if (subopt_len == 4) {
1605                                 /* one IP address */
1606                                 proto_tree_add_text(v_tree, tvb, optoff, 6,
1607                                     "Suboption %d : %s = %s",
1608                                     subopt, o43pxeclient_opt[subopt].text,
1609                                     ip_to_str(tvb_get_ptr(tvb, suboptoff, 4)));
1610                         } else {
1611                                 /* > 1 IP addresses. Let's make a sub-tree */
1612                                 vti = proto_tree_add_text(v_tree, tvb, optoff,
1613                                     subopt_len+2, "Suboption %d: %s",
1614                                     subopt, o43pxeclient_opt[subopt].text);
1615                                 o43pxeclient_v_tree = proto_item_add_subtree(vti, ett_bootp_option);
1616                                 for (suboptleft = subopt_len; suboptleft > 0;
1617                                     suboptoff += 4, suboptleft -= 4) {
1618                                         if (suboptleft < 4) {
1619                                                 proto_tree_add_text(o43pxeclient_v_tree,
1620                                                     tvb, suboptoff, suboptleft,
1621                                                     "Suboption length isn't a multiple of 4");
1622                                                 break;
1623                                         }
1624                                         proto_tree_add_text(o43pxeclient_v_tree,
1625                                             tvb, suboptoff, 4, "IP Address: %s",
1626                                             ip_to_str(tvb_get_ptr(tvb, suboptoff, 4)));
1627                                 }
1628                         }
1629                         break;
1630
1631 /* XXX          case string:
1632                         proto_tree_add_text(v_tree, tvb, optoff, subopt_len+2,
1633                                 "Suboption %d: %s", subopt, o43pxeclient_opt[subopt].text);
1634                         break;
1635    XXX */
1636
1637                 case val_u_byte:
1638                         if (subopt_len != 1) {
1639                                 proto_tree_add_text(v_tree, tvb, optoff, subopt_len+2,
1640                                         "Suboption %d: suboption length isn't 1", subopt);
1641                                 break;
1642                         }
1643                         proto_tree_add_text(v_tree, tvb, optoff, 3, "Suboption %d: %s = %u",
1644                             subopt, o43pxeclient_opt[subopt].text,
1645                             tvb_get_guint8(tvb, suboptoff));
1646                         break;
1647
1648                 case val_u_le_short:
1649                         if (subopt_len != 2) {
1650                                 proto_tree_add_text(v_tree, tvb, optoff, subopt_len+2,
1651                                         "Suboption %d: suboption length isn't 2", subopt);
1652                                 break;
1653                         }
1654                         proto_tree_add_text(v_tree, tvb, optoff, 4, "Suboption %d: %s = %u",
1655                             subopt, o43pxeclient_opt[subopt].text,
1656                             tvb_get_letohs(tvb, suboptoff));
1657                         break;
1658
1659                 default:
1660                         proto_tree_add_text(v_tree, tvb, optoff, subopt_len+2,"ERROR, please report: Unknown subopt type handler %d", subopt);
1661                         break;
1662                 }
1663         }
1664         optoff += (subopt_len + 2);
1665         return optoff;
1666 }
1667
1668
1669 static int
1670 dissect_vendor_cablelabs_suboption(proto_tree *v_tree, tvbuff_t *tvb,
1671     int optoff, int optend)
1672 {
1673         int suboptoff = optoff;
1674         guint8 subopt, byte_val;
1675         guint8 subopt_len;
1676
1677         static struct opt_info o43cablelabs_opt[]= {
1678                 /* 0 */ {"nop", special, NULL}, /* dummy */
1679                 /* 1 */ {"Suboption Request List", string, NULL},
1680                 /* 2 */ {"Device Type", string, NULL},
1681                 /* 3 */ {"eSAFE Types", string, NULL},
1682                 /* 4 */ {"Serial Number", string, NULL},
1683                 /* 5 */ {"Hardware Version", string, NULL},
1684                 /* 6 */ {"Software Version", string, NULL},
1685                 /* 7 */ {"Boot ROM version", string, NULL},
1686                 /* 8 */ {"Organizationally Unique Identifier", special, NULL},
1687                 /* 9 */ {"Model Number", string, NULL},
1688                 /* 10 */ {"Vendor Name", string, NULL},
1689                 /* *** 11-30: CableHome *** */
1690                 /* 11 */ {"Address Realm", special, NULL},
1691                 /* 12 */ {"CM/PS System Description", string, NULL},
1692                 /* 13 */ {"CM/PS Firmware Revision", string, NULL},
1693                 /* 14 */ {"Firewall Policy File Version", string, NULL},
1694                 /* 15 */ {"Unassigned (CableHome)", special, NULL},
1695                 /* 16 */ {"Unassigned (CableHome)", special, NULL},
1696                 /* 17 */ {"Unassigned (CableHome)", special, NULL},
1697                 /* 18 */ {"Unassigned (CableHome)", special, NULL},
1698                 /* 19 */ {"Unassigned (CableHome)", special, NULL},
1699                 /* 20 */ {"Unassigned (CableHome)", special, NULL},
1700                 /* 21 */ {"Unassigned (CableHome)", special, NULL},
1701                 /* 22 */ {"Unassigned (CableHome)", special, NULL},
1702                 /* 23 */ {"Unassigned (CableHome)", special, NULL},
1703                 /* 24 */ {"Unassigned (CableHome)", special, NULL},
1704                 /* 25 */ {"Unassigned (CableHome)", special, NULL},
1705                 /* 26 */ {"Unassigned (CableHome)", special, NULL},
1706                 /* 27 */ {"Unassigned (CableHome)", special, NULL},
1707                 /* 28 */ {"Unassigned (CableHome)", special, NULL},
1708                 /* 29 */ {"Unassigned (CableHome)", special, NULL},
1709                 /* 30 */ {"Unassigned (CableHome)", special, NULL},
1710                 /* *** 31-50: PacketCable *** */
1711                 /* 31 */ {"MTA MAC Address", special, NULL},
1712                 /* 32 */ {"Correlation ID", val_u_long, NULL},
1713                 /* 33-50 {"Unassigned (PacketCable)", special, NULL}, */
1714                 /* *** 51-127: CableLabs *** */
1715                 /* 51-127 {"Unassigned (CableLabs)", special, NULL}, */
1716                 /* *** 128-254: Vendors *** */
1717                 /* 128-254 {"Unassigned (Vendors)", special, NULL}, */
1718                 /* 255 {"end options", special, NULL} */
1719         };
1720
1721         static const value_string cablehome_subopt11_vals[] = {
1722                 { 1, "PS WAN-Man" },
1723                 { 2, "PS WAN-Data" },
1724                 { 0, NULL }
1725         };
1726
1727         subopt = tvb_get_guint8(tvb, suboptoff);
1728         suboptoff++;
1729
1730         if (subopt == 0) {
1731                 proto_tree_add_text(v_tree, tvb, optoff, 1, "Padding");
1732                 return (suboptoff);
1733         } else if (subopt == 255) {     /* End Option */
1734                 proto_tree_add_text(v_tree, tvb, optoff, 1, "End CableLabs option");
1735                 /* Make sure we skip any junk left this option */
1736                 return (optend);
1737         }
1738
1739         if (suboptoff >= optend) {
1740                 proto_tree_add_text(v_tree, tvb, optoff, 1,
1741                         "Suboption %d: no room left in option for suboption length",
1742                         subopt);
1743                 return (optend);
1744         }
1745         subopt_len = tvb_get_guint8(tvb, suboptoff);
1746         suboptoff++;
1747
1748         if (suboptoff+subopt_len > optend) {
1749                 proto_tree_add_text(v_tree, tvb, optoff, optend-optoff,
1750                         "Suboption %d: no room left in option for suboption value",
1751                         subopt);
1752                 return (optend);
1753         }
1754         if ( (subopt < 1 ) || (subopt >= array_length(o43cablelabs_opt)) ) {
1755                 proto_tree_add_text(v_tree, tvb, optoff, subopt_len+2,
1756                         "Suboption %d: Unassigned (%d byte%s)", subopt, subopt_len,
1757                         plurality(subopt_len, "", "s"));
1758         } else {
1759                 switch (o43cablelabs_opt[subopt].ftype) {
1760
1761                 case special:
1762                         if ( subopt == 8 ) {    /* OUI */
1763                                 /* CableLabs specs treat 43.8 inconsistently
1764                                  * as either binary (3b) or string (6b) */
1765                                 if (subopt_len == 3) {
1766                                         proto_tree_add_text(v_tree, tvb, optoff, subopt_len+2,
1767                                                 "Suboption %d: OUI = %s", subopt,
1768                                                 bytes_to_str_punct(tvb_get_ptr(tvb, suboptoff, 3), 3, ':'));
1769                                 } else if (subopt_len == 6) {
1770                                         proto_tree_add_text(v_tree, tvb, optoff, subopt_len+2,
1771                                                 "Suboption %d: OUI = \"%s\"", subopt,
1772                                                 tvb_format_stringzpad(tvb, suboptoff, subopt_len));
1773                                 } else {
1774                                         proto_tree_add_text(v_tree, tvb, optoff, subopt_len+2,
1775                                                 "Suboption %d: suboption length isn't 3 or 6", subopt);
1776                                 }
1777                                 break;
1778                         } else if ( subopt == 11 ) { /* Address Realm */
1779                                 if (subopt_len != 1) {
1780                                         proto_tree_add_text(v_tree, tvb, optoff, subopt_len+2,
1781                                                 "Suboption %d: suboption length isn't 1", subopt);
1782                                         break;
1783                                 }
1784                                 byte_val = tvb_get_guint8(tvb, suboptoff);
1785                                 proto_tree_add_text(v_tree, tvb, optoff, subopt_len+2,
1786                                         "Suboption %d: %s = %s (0x%02x)",
1787                                         subopt, o43cablelabs_opt[subopt].text,
1788                                         val_to_str(byte_val, cablehome_subopt11_vals, "Unknown"), byte_val);
1789                         } else if ( subopt == 31 ) { /* MTA MAC address */
1790                                 if (subopt_len != 6) {
1791                                         proto_tree_add_text(v_tree, tvb, optoff, subopt_len+2,
1792                                                 "Suboption %d: suboption length isn't 6", subopt);
1793                                         break;
1794                                 }
1795                                 proto_tree_add_text(v_tree, tvb, optoff, subopt_len+2,
1796                                         "Suboption %d: %s = %s",
1797                                         subopt,  o43cablelabs_opt[subopt].text,
1798                                         bytes_to_str_punct(tvb_get_ptr(tvb, suboptoff, 6), 6, ':'));
1799                         } else {
1800                                 proto_tree_add_text(v_tree, tvb, optoff, subopt_len+2,
1801                                         "Suboption %d: %s (%d byte%s)" ,
1802                                         subopt, o43cablelabs_opt[subopt].text,
1803                                         subopt_len, plurality(subopt_len, "", "s"));
1804                         }
1805                         break;
1806
1807                 case string:
1808                         proto_tree_add_text(v_tree, tvb, optoff, subopt_len+2,
1809                                 "Suboption %d: %s = \"%s\"", subopt,
1810                                 o43cablelabs_opt[subopt].text,
1811                                 tvb_format_stringzpad(tvb, suboptoff, subopt_len));
1812                         break;
1813
1814                 case bytes:
1815                         proto_tree_add_text(v_tree, tvb, optoff, subopt_len+2,
1816                                 "Suboption %d: %s = 0x%s", subopt,
1817                                 o43cablelabs_opt[subopt].text,
1818                                 tvb_bytes_to_str(tvb, suboptoff, subopt_len));
1819                         break;
1820
1821                 case val_u_long:
1822                         if (subopt_len != 4) {
1823                                 proto_tree_add_text(v_tree, tvb, optoff, subopt_len+2,
1824                                         "Suboption %d: suboption length isn't 4", subopt);
1825                                 break;
1826                         }
1827                         proto_tree_add_text(v_tree, tvb, optoff, subopt_len+2,
1828                                 "Suboption %d: %s = %u", subopt,
1829                                 o43cablelabs_opt[subopt].text,
1830                                 tvb_get_ntohl(tvb, suboptoff));
1831                         break;
1832
1833                 default:
1834                         proto_tree_add_text(v_tree, tvb, optoff, subopt_len+2,"ERROR, please report: Unknown subopt type handler %d", subopt);
1835                         break;
1836                 }
1837         }
1838         optoff += (subopt_len + 2);
1839         return optoff;
1840 }
1841
1842
1843
1844 static int
1845 dissect_netware_ip_suboption(proto_tree *v_tree, tvbuff_t *tvb,
1846     int optoff, int optend)
1847 {
1848         int suboptoff = optoff;
1849         guint8 subopt;
1850         guint8 subopt_len;
1851         int suboptleft;
1852         const struct true_false_string *tfs;
1853         int i;
1854         proto_tree *o63_v_tree;
1855         proto_item *vti;
1856
1857         static struct opt_info o63_opt[]= {
1858                 /* 0 */ {"",none,NULL},
1859                 /* 1 */ {"NWIP does not exist on subnet",presence,NULL},
1860                 /* 2 */ {"NWIP exists in options area",presence,NULL},
1861                 /* 3 */ {"NWIP exists in sname/file",presence,NULL},
1862                 /* 4 */ {"NWIP exists, but too big",presence,NULL},
1863                 /* 5 */ {"Broadcast for nearest Netware server",val_boolean,TFS(&yes_no_tfs)},
1864                 /* 6 */ {"Preferred DSS server",ipv4_list,NULL},
1865                 /* 7 */ {"Nearest NWIP server",ipv4_list,NULL},
1866                 /* 8 */ {"Autoretries",val_u_byte,NULL},
1867                 /* 9 */ {"Autoretry delay, secs",val_u_byte,NULL},
1868                 /* 10*/ {"Support NetWare/IP v1.1",val_boolean,TFS(&yes_no_tfs)},
1869                 /* 11*/ {"Primary DSS",ipv4,NULL}
1870         };
1871
1872         subopt = tvb_get_guint8(tvb, optoff);
1873         suboptoff++;
1874
1875         if (suboptoff >= optend) {
1876                 proto_tree_add_text(v_tree, tvb, optoff, 1,
1877                         "Suboption %d: no room left in option for suboption length",
1878                         subopt);
1879                 return (optend);
1880         }
1881         subopt_len = tvb_get_guint8(tvb, suboptoff);
1882         suboptoff++;
1883
1884         if (subopt >= array_length(o63_opt)) {
1885                 proto_tree_add_text(v_tree, tvb, optoff, subopt_len + 2, "Unknown suboption %d", subopt);
1886         } else {
1887                 switch (o63_opt[subopt].ftype) {
1888
1889                 case presence:
1890                         if (subopt_len != 0) {
1891                                 proto_tree_add_text(v_tree, tvb, optoff, subopt_len + 2,
1892                                         "Suboption %d: length isn't 0", subopt);
1893                                 break;
1894                         }
1895                         proto_tree_add_text(v_tree, tvb, optoff, 2, "Suboption %d: %s", subopt, o63_opt[subopt].text);
1896                         break;
1897
1898                 case ipv4:
1899                         if (subopt_len != 4) {
1900                                 proto_tree_add_text(v_tree, tvb, optoff, subopt_len + 2,
1901                                         "Suboption %d: length isn't 4", subopt);
1902                                 break;
1903                         }
1904                         if (suboptoff+4 > optend) {
1905                                 proto_tree_add_text(v_tree, tvb, optoff, optend-optoff,
1906                                     "Suboption %d: no room left in option for suboption value",
1907                                     subopt);
1908                                 return (optend);
1909                         }
1910                         proto_tree_add_text(v_tree, tvb, optoff, 6,
1911                             "Suboption %d: %s = %s" ,
1912                             subopt, o63_opt[subopt].text,
1913                             ip_to_str(tvb_get_ptr(tvb, suboptoff, 4)));
1914                         break;
1915
1916                 case ipv4_list:
1917                         if (subopt_len == 4) {
1918                                 /* one IP address */
1919                                 proto_tree_add_text(v_tree, tvb, optoff, 6,
1920                                     "Suboption %d : %s = %s",
1921                                     subopt, o63_opt[subopt].text,
1922                                     ip_to_str(tvb_get_ptr(tvb, suboptoff, 4)));
1923                         } else {
1924                                 /* > 1 IP addresses. Let's make a sub-tree */
1925                                 vti = proto_tree_add_text(v_tree, tvb, optoff,
1926                                     subopt_len+2, "Suboption %d: %s",
1927                                     subopt, o63_opt[subopt].text);
1928                                 o63_v_tree = proto_item_add_subtree(vti, ett_bootp_option);
1929                                 for (suboptleft = subopt_len; suboptleft > 0;
1930                                     suboptoff += 4, suboptleft -= 4) {
1931                                         if (suboptleft < 4) {
1932                                                 proto_tree_add_text(o63_v_tree,
1933                                                     tvb, suboptoff, suboptleft,
1934                                                     "Suboption length isn't a multiple of 4");
1935                                                 break;
1936                                         }
1937                                         proto_tree_add_text(o63_v_tree, tvb, suboptoff, 4, "IP Address: %s",
1938                                             ip_to_str(tvb_get_ptr(tvb, suboptoff, 4)));
1939                                 }
1940                         }
1941                         break;
1942
1943                 case val_boolean:
1944                         if (subopt_len != 1) {
1945                                 proto_tree_add_text(v_tree, tvb, optoff, subopt_len + 2,
1946                                         "Suboption %d: suboption length isn't 1", subopt);
1947                                 break;
1948                         }
1949                         if (suboptoff+1 > optend) {
1950                                 proto_tree_add_text(v_tree, tvb, optoff, optend-optoff,
1951                                     "Suboption %d: no room left in option for suboption value",
1952                                     subopt);
1953                                 return (optend);
1954                         }
1955                         tfs = (const struct true_false_string *) o63_opt[subopt].data;
1956                         i = tvb_get_guint8(tvb, suboptoff);
1957                         if (i != 0 && i != 1) {
1958                                 proto_tree_add_text(v_tree, tvb, optoff, 3,
1959                                     "Suboption %d: %s = Invalid Value %d",
1960                                     subopt, o63_opt[subopt].text, i);
1961                         } else {
1962                                 proto_tree_add_text(v_tree, tvb, optoff, 3,
1963                                     "Suboption %d: %s = %s", subopt,
1964                                     o63_opt[subopt].text,
1965                                     i == 0 ? tfs->false_string : tfs->true_string);
1966                         }
1967                         break;
1968
1969                 case val_u_byte:
1970                         if (subopt_len != 1) {
1971                                 proto_tree_add_text(v_tree, tvb, optoff, subopt_len + 2,
1972                                         "Suboption %d: length isn't 1", subopt);
1973                                 break;
1974                         }
1975                         if (suboptoff+1 > optend) {
1976                                 proto_tree_add_text(v_tree, tvb, optoff, optend-optoff,
1977                                     "Suboption %d: no room left in option for suboption value",
1978                                     subopt);
1979                                 return (optend);
1980                         }
1981                         proto_tree_add_text(v_tree, tvb, optoff, 3, "Suboption %d: %s = %u",
1982                             subopt, o63_opt[subopt].text,
1983                             tvb_get_guint8(tvb, suboptoff));
1984                         break;
1985
1986                 default:
1987                         proto_tree_add_text(v_tree, tvb, optoff, subopt_len + 2,"Unknown suboption %d", subopt);
1988                         break;
1989                 }
1990         }
1991         optoff += (subopt_len + 2);
1992         return optoff;
1993 }
1994
1995
1996
1997 static int
1998 dissect_vendor_tr111_suboption(proto_tree *v_tree, tvbuff_t *tvb,
1999     int optoff, int optend)
2000 {
2001         int suboptoff = optoff;
2002         guint8 subopt;
2003         guint8 subopt_len;
2004
2005         /* Reference: TR-111 DHCP Option 125 Sub-Option Data Fields
2006            Page 10.
2007          */
2008
2009         static struct opt_info o125_tr111_opt[]= {
2010                 /* 0 */ {"nop", special, NULL}, /* dummy */
2011                 /* 1 */ {"DeviceManufacturerOUI", string, NULL},
2012                 /* 2 */ {"DeviceSerialNumber", string, NULL},
2013                 /* 3 */ {"DeviceProductClass", string, NULL},
2014                 /* 4 */ {"GatewayManufacturerOUI", string, NULL},
2015                 /* 5 */ {"GatewaySerialNumber", string, NULL},
2016                 /* 6 */ {"GatewayProductClass", string, NULL},
2017         };
2018
2019         subopt = tvb_get_guint8(tvb, suboptoff);
2020         suboptoff++;
2021
2022         if (suboptoff >= optend) {
2023                 proto_tree_add_text(v_tree, tvb, optoff, 1,
2024                         "Suboption %d: no room left in option for suboption length",
2025                         subopt);
2026                 return (optend);
2027         }
2028         subopt_len = tvb_get_guint8(tvb, suboptoff);
2029         suboptoff++;
2030
2031         if (suboptoff+subopt_len > optend) {
2032                 proto_tree_add_text(v_tree, tvb, optoff, optend-optoff,
2033                         "Suboption %d: no room left in option for suboption value",
2034                         subopt);
2035                 return (optend);
2036         }
2037
2038
2039         if ((subopt < 1) || (subopt >= array_length(o125_tr111_opt))) {
2040                 proto_tree_add_text(v_tree, tvb, optoff, subopt_len+2,
2041                         "Unknown suboption %d (%d byte%s)", subopt, subopt_len,
2042                         plurality(subopt_len, "", "s"));
2043         } else {
2044                 switch (o125_tr111_opt[subopt].ftype) {
2045
2046                 case special:
2047                         /* I may need to decode that properly one day */
2048                         proto_tree_add_text(v_tree, tvb, optoff, subopt_len+2,
2049                                 "Suboption %d: %s (%d byte%s)",
2050                                 subopt, o125_tr111_opt[subopt].text,
2051                                 subopt_len, plurality(subopt_len, "", "s"));
2052                         break;
2053
2054                 case string:
2055                         proto_tree_add_text(v_tree, tvb, optoff, subopt_len+2,
2056                                 "Suboption %d: %s = \"%s\"", subopt,
2057                                 o125_tr111_opt[subopt].text,
2058                                 tvb_format_stringzpad(tvb, suboptoff, subopt_len));
2059                         break;
2060
2061                 default:
2062                         proto_tree_add_text(v_tree, tvb, optoff, subopt_len+2,"ERROR, please report: Unknown subopt type handler %d", subopt);
2063                         break;
2064                 }
2065         }
2066         optoff += (subopt_len + 2);
2067         return optoff;
2068 }
2069
2070
2071 /* PacketCable Multimedia Terminal Adapter device capabilities (option 60).
2072    Ref: PKT-SP-I05-021127 sections 8.2 and 10 */
2073
2074 #define PKT_MDC_TLV_OFF 10
2075
2076
2077 /* These are ASCII-encoded hexadecimal digits.  We use the raw hex equivalent for
2078    convenience. */
2079 #define PKT_MDC_VERSION                 0x3031  /* "01" */
2080 #define PKT_MDC_TEL_END                 0x3032  /* "02" */
2081 #define PKT_MDC_TGT                     0x3033  /* "03" */
2082 #define PKT_MDC_HTTP_ACC                0x3034  /* "04" */
2083 #define PKT_MDC_SYSLOG                  0x3035  /* "05" */
2084 #define PKT_MDC_NCS                     0x3036  /* "06" */
2085 #define PKT_MDC_PRI_LINE                0x3037  /* "07" */
2086 #define PKT_MDC_VENDOR_TLV              0x3038  /* "08" */
2087 #define PKT_MDC_NVRAM_STOR              0x3039  /* "09" */
2088 #define PKT_MDC_PROV_REP                0x3041  /* "0A" */
2089 #define PKT_MDC_PROV_REP_LC             0x3061  /* "0A" */
2090 #define PKT_MDC_SUPP_CODECS             0x3042  /* "0B" */
2091 #define PKT_MDC_SUPP_CODECS_LC          0x3062  /* "0b" */
2092 #define PKT_MDC_SILENCE                 0x3043  /* "0C" */
2093 #define PKT_MDC_SILENCE_LC              0x3063  /* "0c" */
2094 #define PKT_MDC_ECHO_CANCEL             0x3044  /* "0D" */
2095 #define PKT_MDC_ECHO_CANCEL_LC          0x3064  /* "0d" */
2096 #define PKT_MDC_RSVP                    0x3045  /* "0E" */
2097 #define PKT_MDC_RSVP_LC                 0x3065  /* "0e" */
2098 #define PKT_MDC_UGS_AD                  0x3046  /* "0F" */
2099 #define PKT_MDC_UGS_AD_LC               0x3066  /* "0f" */
2100 #define PKT_MDC_IF_INDEX                0x3130  /* "10" */
2101 #define PKT_MDC_FLOW_LOG                0x3131  /* "11" */
2102 #define PKT_MDC_PROV_FLOWS              0x3132  /* "12" */
2103 /* PacketCable 1.5: */
2104 #define PKT_MDC_T38_VERSION             0x3133  /* "13" */
2105 #define PKT_MDC_T38_EC                  0x3134  /* "14" */
2106 #define PKT_MDC_RFC2833_DTMF            0x3135  /* "15" */
2107 #define PKT_MDC_VOICE_METRICS           0x3136  /* "16" */
2108 #define PKT_MDC_MIBS                    0x3137  /* "17" */
2109 #define PKT_MDC_MGPI                    0x3138  /* "18" */
2110
2111 static const value_string pkt_mdc_type_vals[] = {
2112         { PKT_MDC_VERSION,              "PacketCable Version" },
2113         { PKT_MDC_TEL_END,              "Number Of Telephony Endpoints" },
2114         { PKT_MDC_TGT,                  "TGT Support" },
2115         { PKT_MDC_HTTP_ACC,             "HTTP Download File Access Method Support" },
2116         { PKT_MDC_SYSLOG,               "MTA-24 Event SYSLOG Notification Support" },
2117         { PKT_MDC_NCS,                  "NCS Service Flow Support" },
2118         { PKT_MDC_PRI_LINE,             "Primary Line Support" },
2119         { PKT_MDC_VENDOR_TLV,           "Vendor Specific TLV Type(s)" },
2120         { PKT_MDC_NVRAM_STOR,           "NVRAM Ticket/Session Keys Storage Support" },
2121         { PKT_MDC_PROV_REP,             "Provisioning Event Reporting Support" },
2122         { PKT_MDC_PROV_REP_LC,          "Provisioning Event Reporting Support" },
2123         { PKT_MDC_SUPP_CODECS,          "Supported CODEC(s)" },
2124         { PKT_MDC_SUPP_CODECS_LC,       "Supported CODEC(s)" },
2125         { PKT_MDC_SILENCE,              "Silence Suppression Support" },
2126         { PKT_MDC_SILENCE_LC,           "Silence Suppression Support" },
2127         { PKT_MDC_ECHO_CANCEL,          "Echo Cancellation Support" },
2128         { PKT_MDC_ECHO_CANCEL_LC,       "Echo Cancellation Support" },
2129         { PKT_MDC_RSVP,                 "RSVP Support/ Reserved" },
2130         { PKT_MDC_RSVP_LC,              "RSVP Support/ Reserved" },
2131         { PKT_MDC_UGS_AD,               "UGS-AD Support" },
2132         { PKT_MDC_UGS_AD_LC,            "UGS-AD Support" },
2133         { PKT_MDC_IF_INDEX,             "MTA's \"ifIndex\" starting number in \"ifTable\"" },
2134         { PKT_MDC_FLOW_LOG,             "Provisioning Flow Logging Support" },
2135         { PKT_MDC_PROV_FLOWS,           "Supported Provisioning Flows" },
2136         /* PacketCable 1.5: */
2137         { PKT_MDC_T38_VERSION,          "T38 Version Support" },
2138         { PKT_MDC_T38_EC,               "T38 Error Correction Support" },
2139         { PKT_MDC_RFC2833_DTMF,         "RFC 2833 DTMF Support" },
2140         { PKT_MDC_VOICE_METRICS,        "Voice Metrics Support" },
2141         { PKT_MDC_MIBS,                 "MIB Support" },
2142         { PKT_MDC_MGPI,                 "Multiple Grants Per Interval Support" },
2143         { 0,                                    NULL }
2144 };
2145
2146 static const value_string pkt_mdc_version_vals[] = {
2147         { 0x3030,       "PacketCable 1.0" },
2148         { 0x3031,       "PacketCable 1.1/1.5" }, /* 1.5 replaces 1.1-1.3 */
2149         { 0x3032,       "PacketCable 1.2" },
2150         { 0x3033,       "PacketCable 1.3" },
2151         { 0,            NULL }
2152 };
2153
2154 static const value_string pkt_mdc_boolean_vals[] = {
2155         { 0x3030,       "No" },
2156         { 0x3031,       "Yes" },
2157         { 0,            NULL }
2158 };
2159
2160 static const value_string pkt_mdc_codec_vals[] = {
2161         { 0x3031,       "other" },           /* "01" */
2162         { 0x3032,       "unknown" },
2163         { 0x3033,       "G.729" },
2164         { 0x3034,       "reserved" },
2165         { 0x3035,       "G.729E" },
2166         { 0x3036,       "PCMU" },
2167         { 0x3037,       "G.726-32" },
2168         { 0x3038,       "G.728" },
2169         { 0x3039,       "PCMA" },            /* "09" */
2170         { 0x3041,       "G.726-16" },        /* "0A" */
2171         { 0x3042,       "G.726-24" },
2172         { 0x3043,       "G.726-40" },
2173         { 0x3044,       "iLBC" },
2174         { 0x3045,       "BV16" },
2175         { 0x3046,       "telephone-event" }, /* "0F" */
2176         { 0,            NULL }
2177 };
2178
2179 static const value_string pkt_mdc_t38_version_vals[] = {
2180         { 0x3030,       "Unsupported" },
2181         { 0x3031,       "T.38 Version Zero" }, /* default */
2182         { 0x3032,       "T.38 Version One" },
2183         { 0x3033,       "T.38 Version Two" },
2184         { 0x3035,       "T.38 Version Three" },
2185         { 0,            NULL }
2186 };
2187
2188 static const value_string pkt_mdc_t38_ec_vals[] = {
2189         { 0x3030,       "None" },
2190         { 0x3031,       "Redundancy" }, /* default */
2191         { 0x3032,       "FEC" },
2192         { 0,            NULL }
2193 };
2194
2195 static const value_string pkt_mdc_mib_orgs[] = {
2196         { 0x3030,       "CableLabs" },
2197         { 0x3031,       "IETF" },
2198         { 0x3032,       "Reserved" },
2199         { 0x3033,       "Reserved" },
2200         { 0x3034,       "Reserved" },
2201         { 0x3035,       "Reserved" },
2202         { 0x3036,       "Reserved" },
2203         { 0x3037,       "Reserved" },
2204         { 0x3038,       "Reserved" },
2205         { 0x3039,       "Reserved" },
2206         { 0,            NULL }
2207 };
2208
2209 /* DOCSIS Cable Modem device capabilities (option 60). */
2210 #define DOCS_CM_TLV_OFF 12
2211
2212 #define DOCS_CM_CONCAT_SUP      0x3031  /* "01" */
2213 #define DOCS_CM_DOCSIS_VER      0x3032  /* "02" */
2214 #define DOCS_CM_FRAG_SUP        0x3033  /* "03" */
2215 #define DOCS_CM_PHS_SUP         0x3034  /* "04" */
2216 #define DOCS_CM_IGMP_SUP        0x3035  /* "05" */
2217 #define DOCS_CM_PRIV_SUP        0x3036  /* "06" */
2218 #define DOCS_CM_DSAID_SUP       0x3037  /* "07" */
2219 #define DOCS_CM_USID_SUP        0x3038  /* "08" */
2220 #define DOCS_CM_FILT_SUP        0x3039  /* "09" */
2221 #define DOCS_CM_TET_MI          0x3041  /* "0A" */
2222 #define DOCS_CM_TET_MI_LC       0x3061  /* "0a" */
2223 #define DOCS_CM_TET             0x3042  /* "0B" */
2224 #define DOCS_CM_TET_LC          0x3062  /* "0b" */
2225 #define DOCS_CM_DCC_SUP         0x3043  /* "0C" */
2226 #define DOCS_CM_DCC_SUP_LC      0x3063  /* "0c" */
2227 #define DOCS_CM_IPFILT_SUP      0x3044  /* "0D" */
2228 #define DOCS_CM_IPFILT_SUP_LC   0x3064  /* "0d" */
2229 #define DOCS_CM_LLCFILT_SUP     0x3045  /* "0E" */
2230 #define DOCS_CM_LLCFILT_SUP_LC  0x3065  /* "0e" */
2231
2232 static const value_string docs_cm_type_vals[] = {
2233         { DOCS_CM_CONCAT_SUP,   "Concatenation Support" },
2234         { DOCS_CM_DOCSIS_VER,   "DOCSIS Version" },
2235         { DOCS_CM_FRAG_SUP,     "Fragmentation Support" },
2236         { DOCS_CM_PHS_SUP,      "PHS Support" },
2237         { DOCS_CM_IGMP_SUP,     "IGMP Support" },
2238         { DOCS_CM_PRIV_SUP,     "Privacy Support" },
2239         { DOCS_CM_DSAID_SUP,    "Downstream SAID Support" },
2240         { DOCS_CM_USID_SUP,     "Upstream SID Support" },
2241         { DOCS_CM_FILT_SUP,     "Optional Filtering Support" },
2242         { DOCS_CM_TET_MI,       "Transmit Equalizer Taps per Modulation Interval" },
2243         { DOCS_CM_TET_MI_LC,    "Transmit Equalizer Taps per Modulation Interval" },
2244         { DOCS_CM_TET,          "Number of Transmit Equalizer Taps" },
2245         { DOCS_CM_TET_LC,       "Number of Transmit Equalizer Taps" },
2246         { DOCS_CM_DCC_SUP,      "DCC Support" },
2247         { DOCS_CM_DCC_SUP_LC,   "DCC Support" },
2248         { DOCS_CM_IPFILT_SUP,   "IP Filters Support" },
2249         { DOCS_CM_IPFILT_SUP_LC,        "IP Filters Support" },
2250         { DOCS_CM_LLCFILT_SUP,  "LLC Filters Support" },
2251         { DOCS_CM_LLCFILT_SUP_LC,       "LLC Filters Support" },
2252         { 0, NULL }
2253 };
2254
2255 static const value_string docs_cm_version_vals[] = {
2256         { 0x3030,       "DOCSIS 1.0" },
2257         { 0x3031,       "DOCSIS 1.1" },
2258         { 0x3032,       "DOCSIS 2.0" },
2259         { 0,            NULL }
2260 };
2261
2262 static const value_string docs_cm_privacy_vals[] = {
2263         { 0x3030,       "BPI Support" },
2264         { 0x3031,       "BPI Plus Support" },
2265         { 0,            NULL }
2266 };
2267
2268
2269 static const value_string pkt_mdc_supp_flow_vals[] = {
2270         { 1 << 0, "Secure Flow (Full Secure Provisioning Flow)" },
2271         { 1 << 1, "Hybrid Flow" },
2272         { 1 << 2, "Basic Flow" },
2273         { 0, NULL }
2274 };
2275
2276 #define PKT_MDC_MIB_CL 0x3030
2277 static const value_string pkt_mdc_cl_mib_vals[] = {
2278         { 1 << 0, "PacketCable 1.5 MTA MIB" },
2279         { 1 << 1, "PacketCable 1.5 Signaling MIB" },
2280         { 1 << 2, "PacketCable 1.5 Management Event MIB" },
2281         { 1 << 3, "PacketCable 1.5 MTA Extension MIB" },
2282         { 1 << 4, "PacketCable 1.5 Signaling Extension MIB" },
2283         { 1 << 5, "PacketCable 1.5 MEM Extension MIB" },
2284         { 1 << 6, "Reserved" },
2285         { 1 << 7, "Reserved" },
2286         { 0, NULL }
2287 };
2288
2289 #define PKT_MDC_MIB_IETF 0x3031
2290 static const value_string pkt_mdc_ietf_mib_vals[] = {
2291         { 1 << 0, "IETF MTA MIB" },
2292         { 1 << 1, "IETF Signaling MIB" },
2293         { 1 << 2, "IETF Management Event MIB" },
2294         { 1 << 3, "Reserved" },
2295         { 1 << 4, "Reserved" },
2296         { 1 << 5, "Reserved" },
2297         { 1 << 6, "Reserved" },
2298         { 1 << 7, "Reserved" },
2299         { 0, NULL }
2300 };
2301
2302
2303 static void
2304 dissect_packetcable_mta_cap(proto_tree *v_tree, tvbuff_t *tvb, int voff, int len)
2305 {
2306         guint16 raw_val;
2307         unsigned long flow_val = 0;
2308         int off = PKT_MDC_TLV_OFF + voff;
2309         int tlv_len, i, subopt_off, max_len, mib_val;
2310         guint8 asc_val[3] = "  ", flow_val_str[5];
2311         char bit_fld[64];
2312         proto_item *ti, *mib_ti;
2313         proto_tree *subtree, *subtree2;
2314
2315         tvb_memcpy (tvb, asc_val, off, 2);
2316         if (sscanf((gchar*)asc_val, "%x", &tlv_len) != 1 || tlv_len < 1) {
2317                 proto_tree_add_text(v_tree, tvb, off, len - off,
2318                         "Bogus length: %s", asc_val);
2319                 return;
2320         } else {
2321                 proto_tree_add_uint_format_value(v_tree, hf_bootp_pkt_mtacap_len, tvb, off, 2,
2322                                 tlv_len, "%d", tlv_len);
2323                 off += 2;
2324
2325                 while (off - voff < len) {
2326                         /* Type */
2327                         raw_val = tvb_get_ntohs (tvb, off);
2328
2329                         /* Length */
2330                         tvb_memcpy(tvb, asc_val, off + 2, 2);
2331                         if (sscanf((gchar*)asc_val, "%x", &tlv_len) != 1 || tlv_len < 1) {
2332                                 proto_tree_add_text(v_tree, tvb, off, len - off,
2333                                                         "[Bogus length: %s]", asc_val);
2334                                 return;
2335                         } else {
2336                                 /* Value(s) */
2337
2338                                 ti = proto_tree_add_text(v_tree,
2339                                     tvb, off, (tlv_len * 2) + 4,
2340                                     "0x%s: %s = ",
2341                                     tvb_format_text(tvb, off, 2),
2342                                     val_to_str(raw_val, pkt_mdc_type_vals, "unknown"));
2343                                 switch (raw_val) {
2344                                         case PKT_MDC_VERSION:
2345                                                 raw_val = tvb_get_ntohs(tvb, off + 4);
2346                                                 proto_item_append_text(ti,
2347                                                     "%s (%s)",
2348                                                     val_to_str(raw_val, pkt_mdc_version_vals, "Reserved"),
2349                                                     tvb_format_stringzpad(tvb, off + 4, 2) );
2350                                                 break;
2351                                         case PKT_MDC_TEL_END:
2352                                         case PKT_MDC_IF_INDEX:
2353                                                 proto_item_append_text(ti,
2354                                                     "%s",
2355                                                     tvb_format_stringzpad(tvb, off + 4, 2) );
2356                                                 break;
2357                                         case PKT_MDC_TGT:
2358                                         case PKT_MDC_HTTP_ACC:
2359                                         case PKT_MDC_SYSLOG:
2360                                         case PKT_MDC_NCS:
2361                                         case PKT_MDC_PRI_LINE:
2362                                         case PKT_MDC_NVRAM_STOR:
2363                                         case PKT_MDC_PROV_REP:
2364                                         case PKT_MDC_PROV_REP_LC:
2365                                         case PKT_MDC_SILENCE:
2366                                         case PKT_MDC_SILENCE_LC:
2367                                         case PKT_MDC_ECHO_CANCEL:
2368                                         case PKT_MDC_ECHO_CANCEL_LC:
2369                                         case PKT_MDC_RSVP:
2370                                         case PKT_MDC_RSVP_LC:
2371                                         case PKT_MDC_UGS_AD:
2372                                         case PKT_MDC_UGS_AD_LC:
2373                                         case PKT_MDC_FLOW_LOG:
2374                                         case PKT_MDC_RFC2833_DTMF:
2375                                         case PKT_MDC_VOICE_METRICS:
2376                                                 raw_val = tvb_get_ntohs(tvb, off + 4);
2377                                                 proto_item_append_text(ti,
2378                                                     "%s (%s)",
2379                                                     val_to_str(raw_val, pkt_mdc_boolean_vals, "unknown"),
2380                                                     tvb_format_stringzpad(tvb, off + 4, 2) );
2381                                                 break;
2382                                         case PKT_MDC_SUPP_CODECS:
2383                                         case PKT_MDC_SUPP_CODECS_LC:
2384                                                 for (i = 0; i < tlv_len; i++) {
2385                                                         raw_val = tvb_get_ntohs(tvb, off + 4 + (i * 2) );
2386                                                         proto_item_append_text(ti,
2387                                                             "%s%s (%s)",
2388                                                             plurality(i + 1, "", ", "),
2389                                                             val_to_str(raw_val, pkt_mdc_codec_vals, "unknown"),
2390                                                             tvb_format_stringzpad(tvb, off + 4 + (i * 2), 2) );
2391                                                 }
2392                                                 break;
2393                                         case PKT_MDC_PROV_FLOWS:
2394                                                 tvb_memcpy(tvb, flow_val_str, off + 4, 4);
2395                                                 flow_val_str[4] = '\0';
2396                                                 flow_val = strtoul((gchar*)flow_val_str, NULL, 16);
2397                                                 proto_item_append_text(ti,
2398                                                     "0x%04lx", flow_val);
2399                                                 break;
2400                                         case PKT_MDC_T38_VERSION:
2401                                                 raw_val = tvb_get_ntohs(tvb, off + 4);
2402                                                 proto_item_append_text(ti,
2403                                                     "%s (%s)",
2404                                                     val_to_str(raw_val, pkt_mdc_t38_version_vals, "unknown"),
2405                                                     tvb_format_stringzpad(tvb, off + 4, 2) );
2406                                                 break;
2407                                         case PKT_MDC_T38_EC:
2408                                                 raw_val = tvb_get_ntohs(tvb, off + 4);
2409                                                 proto_item_append_text(ti,
2410                                                     "%s (%s)",
2411                                                     val_to_str(raw_val, pkt_mdc_t38_ec_vals, "unknown"),
2412                                                     tvb_format_stringzpad(tvb, off + 4, 2) );
2413                                                 break;
2414                                         case PKT_MDC_MIBS:
2415                                                 break;
2416                                         case PKT_MDC_VENDOR_TLV:
2417                                         default:
2418                                                 proto_item_append_text(ti,
2419                                                     "%s",
2420                                                     tvb_format_stringzpad(tvb, off + 4, tlv_len * 2) );
2421                                                 break;
2422                                 }
2423                         }
2424                         subtree = proto_item_add_subtree(ti, ett_bootp_option);
2425                         if (raw_val == PKT_MDC_PROV_FLOWS) {
2426                                 for (i = 0 ; i < 3; i++) {
2427                                         if (flow_val & pkt_mdc_supp_flow_vals[i].value) {
2428                                                 decode_bitfield_value(bit_fld, flow_val, pkt_mdc_supp_flow_vals[i].value, 16);
2429                                                 proto_tree_add_text(subtree, tvb, off + 4, 4, "%s%s",
2430                                                         bit_fld, pkt_mdc_supp_flow_vals[i].strptr);
2431                                         }
2432                                 }
2433                         } else if (raw_val == PKT_MDC_MIBS) {
2434                         /* 17 06 02 00 38 02 01 07 */
2435                                 subopt_off = off + 4;
2436                                 max_len = subopt_off + (tlv_len * 2);
2437                                 while (subopt_off < max_len) {
2438                                         raw_val = tvb_get_ntohs(tvb, subopt_off);
2439                                         if (raw_val != 0x3032) { /* We only know how to handle a length of 2 */
2440                                                 tvb_memcpy(tvb, asc_val, subopt_off, 2);
2441                                                 proto_tree_add_text(subtree, tvb, subopt_off, 2,
2442                                                                         "[Bogus length: %s]", asc_val);
2443                                                 return;
2444                                         }
2445
2446                                         subopt_off += 2;
2447                                         raw_val = tvb_get_ntohs(tvb, subopt_off);
2448                                         tvb_memcpy(tvb, asc_val, subopt_off, 2);
2449
2450                                         mib_ti = proto_tree_add_text(subtree, tvb, subopt_off, 2, "%s (%s)",
2451                                                 val_to_str(raw_val, pkt_mdc_mib_orgs, "Unknown"), asc_val);
2452                                         if (subopt_off > off + 4 + 2) {
2453                                                 proto_item_append_text(ti, ", ");
2454                                         }
2455                                         proto_item_append_text(ti, "%s", val_to_str(raw_val, pkt_mdc_mib_orgs, "Unknown"));
2456
2457                                         subopt_off += 2;
2458                                         tvb_memcpy(tvb, asc_val, subopt_off, 2);
2459                                         if (sscanf((gchar*)asc_val, "%x", &mib_val) != 1) {
2460                                                 proto_tree_add_text(v_tree, tvb, subopt_off, 2,
2461                                                                         "[Bogus bitfield: %s]", asc_val);
2462                                                 return;
2463                                         }
2464                                         switch (raw_val) {
2465                                                 case PKT_MDC_MIB_CL:
2466                                                         subtree2 = proto_item_add_subtree(mib_ti, ett_bootp_option);
2467
2468                                                         for (i = 0; i < 8; i++) {
2469                                                                 if (mib_val & pkt_mdc_cl_mib_vals[i].value) {
2470                                                                         decode_bitfield_value(bit_fld, mib_val, pkt_mdc_cl_mib_vals[i].value, 8);
2471                                                                         proto_tree_add_text(subtree2, tvb, subopt_off, 2,
2472                                                                                 "%s%s", bit_fld, pkt_mdc_cl_mib_vals[i].strptr);
2473                                                                 }
2474                                                         }
2475                                                         break;
2476                                                 case PKT_MDC_MIB_IETF:
2477                                                         subtree2 = proto_item_add_subtree(mib_ti, ett_bootp_option);
2478
2479                                                         for (i = 0; i < 8; i++) {
2480                                                                 if (mib_val & pkt_mdc_ietf_mib_vals[i].value) {
2481                                                                         decode_bitfield_value(bit_fld, mib_val, pkt_mdc_ietf_mib_vals[i].value, 8);
2482                                                                         proto_tree_add_text(subtree2, tvb, subopt_off, 2,
2483                                                                                 "%s%s", bit_fld, pkt_mdc_ietf_mib_vals[i].strptr);
2484                                                                 }
2485                                                         }
2486                                                         break;
2487                                                 default:
2488                                                         break;
2489                                         }
2490                                         subopt_off += 2;
2491                                 }
2492
2493                         }
2494                         off += (tlv_len * 2) + 4;
2495                 }
2496         }
2497 }
2498
2499 static void
2500 dissect_docsis_cm_cap(proto_tree *v_tree, tvbuff_t *tvb, int voff, int len)
2501 {
2502         unsigned long raw_val;
2503         int off = DOCS_CM_TLV_OFF + voff;
2504         int tlv_len, i;
2505         guint8 asc_val[4] = "  ";
2506         proto_item *ti;
2507
2508         tvb_memcpy (tvb, asc_val, off, 2);
2509         if (sscanf((gchar*)asc_val, "%x", &tlv_len) != 1 || tlv_len < 1) {
2510                 proto_tree_add_text(v_tree, tvb, off, len - off,
2511                                     "Bogus length: %s", asc_val);
2512                 return;
2513         } else {
2514                 proto_tree_add_uint_format_value(v_tree, hf_bootp_docsis_cmcap_len, tvb, off, 2,
2515                                 tlv_len, "%d", tlv_len);
2516                 off += 2;
2517
2518                 while (off - voff < len) {
2519                         /* Type */
2520                         raw_val = tvb_get_ntohs (tvb, off);
2521
2522                         /* Length */
2523                         tvb_memcpy(tvb, asc_val, off + 2, 2);
2524                         if (sscanf((gchar*)asc_val, "%x", &tlv_len) != 1 || tlv_len < 1) {
2525                                 proto_tree_add_text(v_tree, tvb, off, len - off,
2526                                                         "[Bogus length: %s]", asc_val);
2527                                 return;
2528                         } else {
2529                                 /* Value(s) */
2530                                 ti = proto_tree_add_text(v_tree, tvb, off,
2531                                     (tlv_len * 2) + 4,
2532                                     "0x%s: %s = ",
2533                                     tvb_format_text(tvb, off, 2),
2534                                     val_to_str(raw_val, docs_cm_type_vals, "unknown"));
2535                                 switch (raw_val) {
2536                                         case DOCS_CM_CONCAT_SUP:
2537                                         case DOCS_CM_FRAG_SUP:
2538                                         case DOCS_CM_PHS_SUP:
2539                                         case DOCS_CM_IGMP_SUP:
2540                                         case DOCS_CM_DCC_SUP:
2541                                         case DOCS_CM_DCC_SUP_LC:
2542                                                 for (i = 0; i < tlv_len; i++) {
2543                                                         raw_val = tvb_get_ntohs(tvb, off + 4 + (i * 2) );
2544                                                         proto_item_append_text(ti,
2545                                                             "%s%s (%s)",
2546                                                             plurality(i + 1, "", ", "),
2547                                                             val_to_str(raw_val, pkt_mdc_boolean_vals, "unknown"),
2548                                                             tvb_format_text(tvb, off + 4 + (i * 2), 2) );
2549                                                 }
2550                                                 break;
2551                                         case DOCS_CM_DOCSIS_VER:
2552                                                 raw_val = tvb_get_ntohs(tvb, off + 4);
2553                                                 proto_item_append_text(ti,
2554                                                     "%s (%s)",
2555                                                     val_to_str(raw_val, docs_cm_version_vals, "Reserved"),
2556                                                     tvb_format_text(tvb, off + 4, 2) );
2557                                                 break;
2558                                         case DOCS_CM_PRIV_SUP:
2559                                                 raw_val = tvb_get_ntohs(tvb, off + 4);
2560                                                 proto_item_append_text(ti,
2561                                                     "%s (%s)",
2562                                                     val_to_str(raw_val, docs_cm_privacy_vals, "Reserved"),
2563                                                     tvb_format_text(tvb, off + 4, 2) );
2564                                                 break;
2565                                         case DOCS_CM_DSAID_SUP:
2566                                         case DOCS_CM_USID_SUP:
2567                                         case DOCS_CM_TET_MI:
2568                                         case DOCS_CM_TET_MI_LC:
2569                                         case DOCS_CM_TET:
2570                                         case DOCS_CM_TET_LC:
2571                                                 tvb_memcpy (tvb, asc_val, off + 4, 2);
2572                                                 raw_val = strtoul((gchar*)asc_val, NULL, 16);
2573                                                 proto_item_append_text(ti,
2574                                                     "%lu", raw_val);
2575                                                 break;
2576                                         case DOCS_CM_IPFILT_SUP:
2577                                         case DOCS_CM_IPFILT_SUP_LC:
2578                                         case DOCS_CM_LLCFILT_SUP:
2579                                         case DOCS_CM_LLCFILT_SUP_LC:
2580                                                 tvb_memcpy (tvb, asc_val, off + 4, 4);
2581                                                 raw_val = strtoul((gchar*)asc_val, NULL, 16);
2582                                                 proto_item_append_text(ti,
2583                                                     "%lu", raw_val);
2584                                                 break;
2585                                         case DOCS_CM_FILT_SUP:
2586                                                 tvb_memcpy (tvb, asc_val, off + 4, 2);
2587                                                 raw_val = strtoul((gchar*)asc_val, NULL, 16);
2588                                                 if (raw_val & 0x01)
2589                                                         proto_item_append_text(ti,
2590                                                             "802.1p filtering");
2591                                                 if (raw_val & 0x02) {
2592                                                         if (raw_val & 0x01)
2593                                                                 proto_item_append_text(ti, ", ");
2594                                                         proto_item_append_text(ti,
2595                                                             "802.1Q filtering");
2596                                                 }
2597                                                 if (! raw_val & 0x03)
2598                                                         proto_item_append_text(ti,
2599                                                             "None");
2600                                                 proto_item_append_text(ti,
2601                                                     " (0x%02lx)", raw_val);
2602                                                 break;
2603                                 }
2604                         }
2605                         off += (tlv_len * 2) + 4;
2606                 }
2607         }
2608 }
2609
2610
2611 /* Definitions specific to PKT-SP-PROV-I05-021127 begin with "PKT_CCC_I05".
2612    Definitions specific to IETF draft 5 and RFC 3495 begin with "PKT_CCC_IETF".
2613    Shared definitions begin with "PKT_CCC".
2614  */
2615 #define PKT_CCC_PRI_DHCP       1
2616 #define PKT_CCC_SEC_DHCP       2
2617 #define PKT_CCC_I05_SNMP       3
2618 #define PKT_CCC_IETF_PROV_SRV  3
2619 #define PKT_CCC_I05_PRI_DNS    4
2620 #define PKT_CCC_IETF_AS_KRB    4
2621 #define PKT_CCC_I05_SEC_DNS    5
2622 #define PKT_CCC_IETF_AP_KRB    5
2623 #define PKT_CCC_KRB_REALM      6
2624 #define PKT_CCC_TGT_FLAG       7
2625 #define PKT_CCC_PROV_TIMER     8
2626 #define PKT_CCC_CMS_FQDN       9
2627 #define PKT_CCC_IETF_SEC_TKT   9
2628 #define PKT_CCC_AS_KRB        10
2629 #define PKT_CCC_AP_KRB        11
2630 #define PKT_CCC_MTA_KRB_CLEAR 12
2631
2632 static const value_string pkt_i05_ccc_opt_vals[] = {
2633         { PKT_CCC_PRI_DHCP,             "Primary DHCP Server" },
2634         { PKT_CCC_SEC_DHCP,             "Secondary DHCP Server" },
2635         { PKT_CCC_I05_SNMP,             "SNMP Entity" },
2636         { PKT_CCC_I05_PRI_DNS,          "Primary DNS Server" },
2637         { PKT_CCC_I05_SEC_DNS,          "Secondary DNS Server" },
2638         { PKT_CCC_KRB_REALM,            "Kerberos Realm" },
2639         { PKT_CCC_TGT_FLAG,             "MTA should fetch TGT?" },
2640         { PKT_CCC_PROV_TIMER,           "Provisioning Timer" },
2641         { PKT_CCC_CMS_FQDN,             "CMS FQDN" },
2642         { PKT_CCC_AS_KRB,               "AS-REQ/AS-REP Backoff and Retry" },
2643         { PKT_CCC_AP_KRB,               "AP-REQ/AP-REP Backoff and Retry" },
2644         { PKT_CCC_MTA_KRB_CLEAR,        "MTA should clear Kerberos tickets?" },
2645         { 0, NULL },
2646 };
2647
2648 static const value_string pkt_draft5_ccc_opt_vals[] = {
2649         { PKT_CCC_PRI_DHCP,             "TSP's Primary DHCP Server" },
2650         { PKT_CCC_SEC_DHCP,             "TSP's Secondary DHCP Server" },
2651         { PKT_CCC_IETF_PROV_SRV,        "TSP's Provisioning Server" },
2652         { PKT_CCC_IETF_AS_KRB,          "TSP's AS-REQ/AS-REP Backoff and Retry" },
2653         { PKT_CCC_IETF_AP_KRB,          "TSP's AP-REQ/AP-REP Backoff and Retry" },
2654         { PKT_CCC_KRB_REALM,            "TSP's Kerberos Realm Name" },
2655         { PKT_CCC_TGT_FLAG,             "TSP's Ticket Granting Server Utilization" },
2656         { PKT_CCC_PROV_TIMER,           "TSP's Provisioning Timer Value" },
2657         { PKT_CCC_IETF_SEC_TKT,         "PacketCable Security Ticket Control" },
2658         { 0, NULL },
2659 };
2660
2661 static const value_string pkt_i05_ccc_ticket_ctl_vals[] = {
2662         { 1, "Invalidate Provisioning Application Server's ticket" },
2663         { 2, "Invalidate all CMS Application Server tickets" },
2664         { 3, "Invalidate all Application Server tickets" },
2665         { 0, NULL },
2666 };
2667
2668 static int
2669 dissect_packetcable_i05_ccc(proto_tree *v_tree, tvbuff_t *tvb, int optoff,
2670     int optend)
2671 {
2672         int suboptoff = optoff;
2673         guint8 subopt, subopt_len, fetch_tgt, timer_val, ticket_ctl;
2674         proto_tree *pkt_s_tree;
2675         proto_item *vti;
2676
2677         subopt = tvb_get_guint8(tvb, optoff);
2678         suboptoff++;
2679
2680         if (suboptoff >= optend) {
2681                 proto_tree_add_text(v_tree, tvb, optoff, 1,
2682                         "Suboption %d: no room left in option for suboption length",
2683                         subopt);
2684                 return (optend);
2685         }
2686         subopt_len = tvb_get_guint8(tvb, optoff);
2687         suboptoff++;
2688
2689         vti = proto_tree_add_text(v_tree, tvb, optoff, subopt_len + 2,
2690             "Suboption %u: %s: ", subopt,
2691             val_to_str(subopt, pkt_i05_ccc_opt_vals, "unknown/reserved") );
2692
2693         switch (subopt) {
2694                 case PKT_CCC_PRI_DHCP:  /* String values */
2695                 case PKT_CCC_SEC_DHCP:
2696                 case PKT_CCC_I05_SNMP:
2697                 case PKT_CCC_I05_PRI_DNS:
2698                 case PKT_CCC_I05_SEC_DNS:
2699                 case PKT_CCC_KRB_REALM:
2700                 case PKT_CCC_CMS_FQDN:
2701                         proto_item_append_text(vti, "%s (%u byte%s)",
2702                                         tvb_format_stringzpad(tvb, suboptoff, subopt_len),
2703                                         subopt_len,
2704                                         plurality(subopt_len, "", "s") );
2705                         suboptoff += subopt_len;
2706                         break;
2707
2708                 case PKT_CCC_TGT_FLAG:
2709                         if (suboptoff+1 > optend) {
2710                                 proto_item_append_text(vti,
2711                                     "no room left in option for suboption value");
2712                                 return (optend);
2713                         }
2714                         fetch_tgt = tvb_get_guint8(tvb, suboptoff);
2715                         proto_item_append_text(vti, "%s (%u byte%s%s)",
2716                                         fetch_tgt ? "Yes" : "No",
2717                                         subopt_len,
2718                                         plurality(subopt_len, "", "s"),
2719                                         subopt_len != 1 ? " [Invalid]" : "");
2720                         suboptoff += subopt_len;
2721                         break;
2722
2723                 case PKT_CCC_PROV_TIMER:
2724                         if (suboptoff+1 > optend) {
2725                                 proto_item_append_text(vti,
2726                                     "no room left in option for suboption value");
2727                                 return (optend);
2728                         }
2729                         timer_val = tvb_get_guint8(tvb, suboptoff);
2730                         proto_item_append_text(vti, "%u%s (%u byte%s%s)", timer_val,
2731                                         timer_val > 30 ? " [Invalid]" : "",
2732                                         subopt_len,
2733                                         plurality(subopt_len, "", "s"),
2734                                         subopt_len != 1 ? " [Invalid]" : "");
2735                         suboptoff += subopt_len;
2736                         break;
2737
2738                 case PKT_CCC_AS_KRB:
2739                         if (suboptoff+12 > optend) {
2740                                 proto_item_append_text(vti,
2741                                     "no room left in option for suboption value");
2742                                 return (optend);
2743                         }
2744                         proto_item_append_text(vti, "(%u byte%s%s)", subopt_len,
2745                                         plurality(subopt_len, "", "s"),
2746                                         subopt_len != 12 ? " [Invalid]" : "");
2747                         if (subopt_len == 12) {
2748                                 pkt_s_tree = proto_item_add_subtree(vti, ett_bootp_option);
2749                                 proto_tree_add_text(pkt_s_tree, tvb, suboptoff, 4,
2750                                                 "pktcMtaDevRealmUnsolicitedKeyNomTimeout: %u",
2751                                                 tvb_get_ntohl(tvb, suboptoff));
2752                                 proto_tree_add_text(pkt_s_tree, tvb, suboptoff + 4, 4,
2753                                                 "pktcMtaDevRealmUnsolicitedKeyMaxTimeout: %u",
2754                                                 tvb_get_ntohl(tvb, suboptoff + 4));
2755                                 proto_tree_add_text(pkt_s_tree, tvb, suboptoff + 8, 4,
2756                                                 "pktcMtaDevRealmUnsolicitedKeyMaxRetries: %u",
2757                                                 tvb_get_ntohl(tvb, suboptoff + 8));
2758                         }
2759                         suboptoff += subopt_len;
2760                         break;
2761
2762                 case PKT_CCC_AP_KRB:
2763                         if (suboptoff+12 > optend) {
2764                                 proto_item_append_text(vti,
2765                                     "no room left in option for suboption value");
2766                                 return (optend);
2767                         }
2768                         proto_item_append_text(vti, "(%u byte%s%s)", subopt_len,
2769                                         plurality(subopt_len, "", "s"),
2770                                         subopt_len != 12 ? " [Invalid]" : "");
2771                         if (subopt_len == 12) {
2772                                 pkt_s_tree = proto_item_add_subtree(vti, ett_bootp_option);
2773                                 proto_tree_add_text(pkt_s_tree, tvb, suboptoff, 4,
2774                                                 "pktcMtaDevProvUnsolicitedKeyNomTimeout: %u",
2775                                                 tvb_get_ntohl(tvb, suboptoff));
2776                                 proto_tree_add_text(pkt_s_tree, tvb, suboptoff + 4, 4,
2777                                                 "pktcMtaDevProvUnsolicitedKeyMaxTimeout: %u",
2778                                                 tvb_get_ntohl(tvb, suboptoff + 4));
2779                                 proto_tree_add_text(pkt_s_tree, tvb, suboptoff + 8, 4,
2780                                                 "pktcMtaDevProvUnsolicitedKeyMaxRetries: %u",
2781                                                 tvb_get_ntohl(tvb, suboptoff + 8));
2782                         }
2783                         suboptoff += subopt_len;
2784                         break;
2785
2786                 case PKT_CCC_MTA_KRB_CLEAR:
2787                         if (suboptoff+1 > optend) {
2788                                 proto_item_append_text(vti,
2789                                     "no room left in option for suboption value");
2790                                 return (optend);
2791                         }
2792                         ticket_ctl = tvb_get_guint8(tvb, suboptoff);
2793                         proto_item_append_text(vti, "%s (%u) (%u byte%s%s)",
2794                                         val_to_str (ticket_ctl, pkt_i05_ccc_ticket_ctl_vals, "unknown/invalid"),
2795                                         ticket_ctl,
2796                                         subopt_len,
2797                                         plurality(subopt_len, "", "s"),
2798                                         subopt_len != 1 ? " [Invalid]" : "");
2799                         suboptoff += subopt_len;
2800                         break;
2801
2802                 default:
2803                         suboptoff += subopt_len;
2804                         break;
2805
2806         }
2807         return suboptoff;
2808 }
2809
2810
2811 static const value_string sec_tcm_vals[] = {
2812         { 1 << 0, "PacketCable Provisioning Server" },
2813         { 1 << 1, "All PacketCable Call Management Servers" },
2814         { 0, NULL }
2815 };
2816
2817 static int
2818 dissect_packetcable_ietf_ccc(proto_tree *v_tree, tvbuff_t *tvb, int optoff,
2819     int optend, int revision)
2820 {
2821         int suboptoff = optoff;
2822         guint8 subopt, subopt_len;
2823         guint32 ipv4_addr;
2824         guint8 prov_type, fetch_tgt, timer_val;
2825         guint16 sec_tcm;
2826         proto_tree *pkt_s_tree;
2827         proto_item *vti;
2828         int max_timer_val = 255, i;
2829         const char *dns_name;
2830         char bit_fld[24];
2831
2832         subopt = tvb_get_guint8(tvb, suboptoff);
2833         suboptoff++;
2834
2835         if (suboptoff >= optend) {
2836                 proto_tree_add_text(v_tree, tvb, optoff, 1,
2837                         "Suboption %d: no room left in option for suboption length",
2838                         subopt);
2839                 return (optend);
2840         }
2841         subopt_len = tvb_get_guint8(tvb, suboptoff);
2842         suboptoff++;
2843
2844         vti = proto_tree_add_text(v_tree, tvb, optoff, subopt_len + 2,
2845             "Suboption %u: %s: ", subopt,
2846             val_to_str(subopt, pkt_draft5_ccc_opt_vals, "unknown/reserved") );
2847
2848         switch (subopt) {
2849                 case PKT_CCC_PRI_DHCP:  /* IPv4 values */
2850                 case PKT_CCC_SEC_DHCP:
2851                         if (suboptoff+4 > optend) {
2852                                 proto_item_append_text(vti,
2853                                     "no room left in option for suboption value");
2854                                 return (optend);
2855                         }
2856                         ipv4_addr = tvb_get_ipv4(tvb, suboptoff);
2857                         proto_item_append_text(vti, "%s (%u byte%s%s)",
2858                                         ip_to_str((guint8 *)&ipv4_addr),
2859                                         subopt_len,
2860                                         plurality(subopt_len, "", "s"),
2861                                         subopt_len != 4 ? " [Invalid]" : "");
2862                         suboptoff += subopt_len;
2863                         break;
2864
2865                 case PKT_CCC_IETF_PROV_SRV:
2866                         if (suboptoff+1 > optend) {
2867                                 proto_item_append_text(vti,
2868                                     "no room left in option for suboption value");
2869                                 return (optend);
2870                         }
2871                         prov_type = tvb_get_guint8(tvb, suboptoff);
2872                         suboptoff += 1;
2873                         switch (prov_type) {
2874                                 case 0:
2875                                         /* XXX - check suboption length */
2876                                         get_dns_name(tvb, suboptoff, suboptoff, &dns_name);
2877                                         proto_item_append_text(vti, "%s (%u byte%s)", dns_name,
2878                                                         subopt_len - 1, plurality(subopt_len, "", "s") );
2879                                         break;
2880                                 case 1:
2881                                         if (suboptoff+4 > optend) {
2882                                                 proto_item_append_text(vti,
2883                                                     "no room left in option for suboption value");
2884                                                 return (optend);
2885                                         }
2886                                         ipv4_addr = tvb_get_ipv4(tvb, suboptoff);
2887                                         proto_item_append_text(vti, "%s (%u byte%s%s)",
2888                                                         ip_to_str((guint8 *)&ipv4_addr),
2889                                                         subopt_len,
2890                                                         plurality(subopt_len, "", "s"),
2891                                                         subopt_len != 5 ? " [Invalid]" : "");
2892                                         break;
2893                                 default:
2894                                         proto_item_append_text(vti, "Invalid type: %u (%u byte%s)",
2895                                                         prov_type,
2896                                                         subopt_len,
2897                                                         plurality(subopt_len, "", "s") );
2898                                         break;
2899                         }
2900                         suboptoff += subopt_len - 1;
2901                         break;
2902
2903                 case PKT_CCC_IETF_AS_KRB:
2904                         if (suboptoff+12 > optend) {
2905                                 proto_item_append_text(vti,
2906                                     "no room left in option for suboption value");
2907                                 return (optend);
2908                         }
2909                         proto_item_append_text(vti, "(%u byte%s%s)", subopt_len,
2910                                         plurality(subopt_len, "", "s"),
2911                                         subopt_len != 12 ? " [Invalid]" : "");
2912                         if (subopt_len == 12) {
2913                                 pkt_s_tree = proto_item_add_subtree(vti, ett_bootp_option);
2914                                 proto_tree_add_text(pkt_s_tree, tvb, suboptoff, 4,
2915                                                 "pktcMtaDevRealmUnsolicitedKeyNomTimeout: %u",
2916                                                 tvb_get_ntohl(tvb, suboptoff));
2917                                 proto_tree_add_text(pkt_s_tree, tvb, suboptoff + 4, 4,
2918                                                 "pktcMtaDevRealmUnsolicitedKeyMaxTimeout: %u",
2919                                                 tvb_get_ntohl(tvb, suboptoff + 4));
2920                                 proto_tree_add_text(pkt_s_tree, tvb, suboptoff + 8, 4,
2921                                                 "pktcMtaDevRealmUnsolicitedKeyMaxRetries: %u",
2922                                                 tvb_get_ntohl(tvb, suboptoff + 8));
2923                         }
2924                         suboptoff += subopt_len;
2925                         break;
2926
2927                 case PKT_CCC_IETF_AP_KRB:
2928                         proto_item_append_text(vti, "(%u byte%s%s)", subopt_len,
2929                                         plurality(subopt_len, "", "s"),
2930                                         subopt_len != 12 ? " [Invalid]" : "");
2931                         if (subopt_len == 12) {
2932                                 pkt_s_tree = proto_item_add_subtree(vti, ett_bootp_option);
2933                                 proto_tree_add_text(pkt_s_tree, tvb, suboptoff, 4,
2934                                         "pktcMtaDevProvUnsolicitedKeyNomTimeout: %u",
2935                                         tvb_get_ntohl(tvb, suboptoff));
2936                                 proto_tree_add_text(pkt_s_tree, tvb, suboptoff + 4, 4,
2937                                                 "pktcMtaDevProvUnsolicitedKeyMaxTimeout: %u",
2938                                                 tvb_get_ntohl(tvb, suboptoff + 4));
2939                                 proto_tree_add_text(pkt_s_tree, tvb, suboptoff + 8, 4,
2940                                         "pktcMtaDevProvUnsolicitedKeyMaxRetries: %u",
2941                                         tvb_get_ntohl(tvb, suboptoff + 8));
2942                         }
2943                         suboptoff += subopt_len;
2944                         break;
2945
2946                 case PKT_CCC_KRB_REALM: /* String values */
2947                         /* XXX - check suboption length */
2948                         get_dns_name(tvb, suboptoff, suboptoff, &dns_name);
2949                         proto_item_append_text(vti, "%s (%u byte%s)", dns_name,
2950                                         subopt_len, plurality(subopt_len, "", "s") );
2951                         suboptoff += subopt_len;
2952                         break;
2953
2954                 case PKT_CCC_TGT_FLAG:
2955                         if (suboptoff+1 > optend) {
2956                                 proto_item_append_text(vti,
2957                                     "no room left in option for suboption value");
2958                                 return (optend);
2959                         }
2960                         fetch_tgt = tvb_get_guint8(tvb, suboptoff);
2961                         proto_item_append_text(vti, "%s (%u byte%s%s)",
2962                                         fetch_tgt ? "Yes" : "No",
2963                                         subopt_len,
2964                                         plurality(subopt_len, "", "s"),
2965                                         subopt_len != 1 ? " [Invalid]" : "");
2966                         suboptoff += 1;
2967                         break;
2968
2969                 case PKT_CCC_PROV_TIMER:
2970                         if (suboptoff+1 > optend) {
2971                                 proto_item_append_text(vti,
2972                                     "no room left in option for suboption value");
2973                                 return (optend);
2974                         }
2975                         if (revision == PACKETCABLE_CCC_DRAFT5)
2976                                 max_timer_val = 30;
2977                         timer_val = tvb_get_guint8(tvb, suboptoff);
2978                         proto_item_append_text(vti, "%u%s (%u byte%s%s)", timer_val,
2979                                         timer_val > max_timer_val ? " [Invalid]" : "",
2980                                         subopt_len,
2981                                         plurality(subopt_len, "", "s"),
2982                                         subopt_len != 1 ? " [Invalid]" : "");
2983                         suboptoff += 1;
2984                         break;
2985
2986                 case PKT_CCC_IETF_SEC_TKT:
2987                         if (suboptoff+2 > optend) {
2988                                 proto_item_append_text(vti,
2989                                     "no room left in option for suboption value");
2990                                 return (optend);
2991                         }
2992                         sec_tcm = tvb_get_ntohs(tvb, suboptoff);
2993                         proto_item_append_text(vti, "0x%04x (%u byte%s%s)", sec_tcm, subopt_len,
2994                                         plurality(subopt_len, "", "s"),
2995                                         subopt_len != 2 ? " [Invalid]" : "");
2996                         if (subopt_len == 2) {
2997                                 pkt_s_tree = proto_item_add_subtree(vti, ett_bootp_option);
2998                                 for (i = 0; i < 2; i++) {
2999                                         if (sec_tcm & sec_tcm_vals[i].value) {
3000                                                 decode_bitfield_value(bit_fld, sec_tcm, sec_tcm_vals[i].value, 16);
3001                                                 proto_tree_add_text(pkt_s_tree, tvb, suboptoff, 2, "%sInvalidate %s",
3002                                                         bit_fld, sec_tcm_vals[i].strptr);
3003                                         }
3004                                 }
3005                         }
3006                         suboptoff += subopt_len;
3007                         break;
3008
3009                 default:
3010                         suboptoff += subopt_len;
3011                         break;
3012         }
3013         return suboptoff;
3014 }
3015
3016 #define BOOTREQUEST     1
3017 #define BOOTREPLY       2
3018
3019 static const value_string op_vals[] = {
3020         { BOOTREQUEST,  "Boot Request" },
3021         { BOOTREPLY,    "Boot Reply" },
3022         { 0,            NULL }
3023 };
3024
3025 static void
3026 dissect_bootp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
3027 {
3028         proto_tree      *bp_tree = NULL;
3029         proto_item      *ti;
3030         proto_tree      *flag_tree = NULL;
3031         proto_item      *fi;
3032         guint8          op;
3033         guint8          htype, hlen;
3034         const guint8    *haddr;
3035         int             voff, eoff, tmpvoff; /* vendor offset, end offset */
3036         guint32         ip_addr;
3037         gboolean        at_end;
3038         const char      *dhcp_type = NULL;
3039         const guint8    *vendor_class_id = NULL;
3040         guint16         flags;
3041         int             offset_delta;
3042
3043         if (check_col(pinfo->cinfo, COL_PROTOCOL))
3044                 col_set_str(pinfo->cinfo, COL_PROTOCOL, "BOOTP");
3045         if (check_col(pinfo->cinfo, COL_INFO)) {
3046                 /*
3047                  * In case we throw an exception fetching the opcode, etc.
3048                  */
3049                 col_clear(pinfo->cinfo, COL_INFO);
3050         }
3051
3052         op = tvb_get_guint8(tvb, 0);
3053         htype = tvb_get_guint8(tvb, 1);
3054         hlen = tvb_get_guint8(tvb, 2);
3055         if (check_col(pinfo->cinfo, COL_INFO)) {
3056                 switch (op) {
3057
3058                 case BOOTREQUEST:
3059                         if ((htype == ARPHRD_ETHER || htype == ARPHRD_IEEE802)
3060                             && hlen == 6)
3061                                 col_add_fstr(pinfo->cinfo, COL_INFO, "Boot Request from %s (%s)",
3062                                     arphrdaddr_to_str(tvb_get_ptr(tvb, 28, hlen),
3063                                         hlen, htype),
3064                                     get_ether_name(tvb_get_ptr(tvb, 28, hlen)));
3065                         else
3066                                 col_add_fstr(pinfo->cinfo, COL_INFO, "Boot Request from %s",
3067                                     arphrdaddr_to_str(tvb_get_ptr(tvb, 28, hlen),
3068                                         hlen, htype));
3069                         break;
3070
3071                 case BOOTREPLY:
3072                         col_set_str(pinfo->cinfo, COL_INFO, "Boot Reply");
3073                         break;
3074
3075                 default:
3076                         col_add_fstr(pinfo->cinfo, COL_INFO, "Unknown BOOTP message type (%u)",
3077                             op);
3078                         break;
3079                 }
3080         }
3081
3082         if (tree) {
3083                 ti = proto_tree_add_item(tree, proto_bootp, tvb, 0, -1, FALSE);
3084                 bp_tree = proto_item_add_subtree(ti, ett_bootp);
3085
3086                 proto_tree_add_uint(bp_tree, hf_bootp_type, tvb,
3087                                            0, 1,
3088                                            op);
3089                 proto_tree_add_uint_format_value(bp_tree, hf_bootp_hw_type, tvb,
3090                                                  1, 1,
3091                                                  htype,
3092                                                  "%s",
3093                                                  arphrdtype_to_str(htype,
3094                                                              "Unknown (0x%02x)"));
3095                 proto_tree_add_uint(bp_tree, hf_bootp_hw_len, tvb,
3096                                     2, 1, hlen);
3097                 proto_tree_add_item(bp_tree, hf_bootp_hops, tvb,
3098                                     3, 1, FALSE);
3099                 proto_tree_add_item(bp_tree, hf_bootp_id, tvb,
3100                                     4, 4, FALSE);
3101                 proto_tree_add_item(bp_tree, hf_bootp_secs, tvb,
3102                                     8, 2, FALSE);
3103                 flags = tvb_get_ntohs(tvb, 10);
3104                 fi = proto_tree_add_uint(bp_tree, hf_bootp_flags, tvb,
3105                                     10, 2, flags);
3106                 proto_item_append_text(fi, " (%s)",
3107                     (flags & BOOTP_BC) ? "Broadcast" : "Unicast");
3108                 flag_tree = proto_item_add_subtree(fi, ett_bootp_flags);
3109                 proto_tree_add_boolean(flag_tree, hf_bootp_flags_broadcast, tvb,
3110                                     10, 2, flags);
3111                 proto_tree_add_uint(flag_tree, hf_bootp_flags_reserved, tvb,
3112                                     10, 2, flags);
3113                 proto_tree_add_item(bp_tree, hf_bootp_ip_client, tvb,
3114                                     12, 4, FALSE);
3115                 proto_tree_add_item(bp_tree, hf_bootp_ip_your, tvb,
3116                                     16, 4, FALSE);
3117                 proto_tree_add_item(bp_tree, hf_bootp_ip_server, tvb,
3118                                     20, 4, FALSE);
3119                 proto_tree_add_item(bp_tree, hf_bootp_ip_relay, tvb,
3120                                     24, 4, FALSE);
3121
3122                 if (hlen > 0 && hlen <= 16) {
3123                         haddr = tvb_get_ptr(tvb, 28, hlen);
3124                         if ((htype == ARPHRD_ETHER || htype == ARPHRD_IEEE802)
3125                             && hlen == 6)
3126                                 proto_tree_add_ether(bp_tree, hf_bootp_hw_ether_addr, tvb, 28, 6, haddr);
3127                         else
3128                                 /* The chaddr element is 16 bytes in length,
3129                                    although only the first hlen bytes are used */
3130                                 proto_tree_add_bytes_format_value(bp_tree, hf_bootp_hw_addr, tvb,
3131                                                    28, 16,
3132                                                    haddr,
3133                                                    "%s",
3134                                                    arphrdaddr_to_str(haddr,
3135                                                                      hlen,
3136                                                                      htype));
3137                 }
3138                 else {
3139                         proto_tree_add_text(bp_tree,  tvb,
3140                                                    28, 16, "Client address not given");
3141                 }
3142
3143                 /* The server host name is optional */
3144                 if (tvb_get_guint8(tvb, SERVER_NAME_OFFSET) != '\0') {
3145                         proto_tree_add_item(bp_tree, hf_bootp_server, tvb,
3146                                                    SERVER_NAME_OFFSET,
3147                                                    SERVER_NAME_LEN, FALSE);
3148                 }
3149                 else {
3150                         proto_tree_add_string_format(bp_tree, hf_bootp_server, tvb,
3151                                                    SERVER_NAME_OFFSET,
3152                                                    SERVER_NAME_LEN,
3153                                                    (const gchar*)tvb_get_ptr(tvb, SERVER_NAME_OFFSET, 1),
3154                                                    "Server host name not given");
3155                 }
3156
3157                 /* Boot file */
3158                 if (tvb_get_guint8(tvb, FILE_NAME_OFFSET) != '\0') {
3159                         proto_tree_add_item(bp_tree, hf_bootp_file, tvb,
3160                                                    FILE_NAME_OFFSET,
3161                                                    FILE_NAME_LEN, FALSE);
3162                 }
3163                 else {
3164                         proto_tree_add_string_format(bp_tree, hf_bootp_file, tvb,
3165                                                    FILE_NAME_OFFSET,
3166                                                    FILE_NAME_LEN,
3167                                                    (const gchar*)tvb_get_ptr(tvb, FILE_NAME_OFFSET, 1),
3168                                                    "Boot file name not given");
3169                 }
3170         }
3171
3172         voff = VENDOR_INFO_OFFSET;
3173
3174         /* rfc2132 says it SHOULD exist, not that it MUST exist */
3175         if (tvb_bytes_exist(tvb, voff, 4)) {
3176                 if (tvb_get_ntohl(tvb, voff) == 0x63825363) {
3177                         if (tree) {
3178                                 ip_addr = tvb_get_ipv4(tvb, voff);
3179                                 proto_tree_add_ipv4_format_value(bp_tree, hf_bootp_cookie, tvb,
3180                                     voff, 4, ip_addr,
3181                                     "(OK)");
3182                         }
3183                         voff += 4;
3184                 }
3185                 else {
3186                         if (tree) {
3187                                 proto_tree_add_text(bp_tree,  tvb,
3188                                         voff, 64, "Bootp vendor specific options");
3189                         }
3190                         voff += 64;
3191                 }
3192         }
3193
3194         eoff = tvb_reported_length(tvb);
3195
3196         /*
3197          * In the first pass, we just look for the DHCP message type
3198          * and Vendor class identifier options.
3199          */
3200         tmpvoff = voff;
3201         at_end = FALSE;
3202         while (tmpvoff < eoff && !at_end) {
3203                 offset_delta = bootp_option(tvb, 0, tmpvoff, eoff, TRUE, &at_end,
3204                     &dhcp_type, &vendor_class_id);
3205                 if (offset_delta <= 0) {
3206                         THROW(ReportedBoundsError);
3207                 }
3208                 tmpvoff += offset_delta;
3209         }
3210
3211         /*
3212          * If there was a DHCP message type option, flag this packet
3213          * as DHCP.
3214          */
3215         if (dhcp_type != NULL) {
3216                 /*
3217                  * Yes, this is a DHCP packet, and "dhcp_type" is the
3218                  * packet type.
3219                  */
3220                 if (check_col(pinfo->cinfo, COL_PROTOCOL))
3221                         col_set_str(pinfo->cinfo, COL_PROTOCOL, "DHCP");
3222                 if (check_col(pinfo->cinfo, COL_INFO))
3223                         col_add_fstr(pinfo->cinfo, COL_INFO, "DHCP %-8s - Transaction ID 0x%x",
3224                             dhcp_type, tvb_get_ntohl(tvb, 4));
3225                 if (tree)
3226                         proto_tree_add_boolean_hidden(bp_tree, hf_bootp_dhcp,
3227                             tvb, 0, 0, 1);
3228                 tap_queue_packet( bootp_dhcp_tap, pinfo, dhcp_type);
3229         }
3230
3231         /*
3232          * If we're not building the protocol tree, we don't need to
3233          * make a second pass.
3234          */
3235         if (tree == NULL)
3236                 return;
3237
3238         /*
3239          * OK, now build the protocol tree.
3240          */
3241         at_end = FALSE;
3242         while (voff < eoff && !at_end) {
3243                 offset_delta = bootp_option(tvb, bp_tree, voff, eoff, FALSE, &at_end,
3244                     &dhcp_type, &vendor_class_id);
3245                 if (offset_delta <= 0) {
3246                         THROW(ReportedBoundsError);
3247                 }
3248                 voff += offset_delta;
3249         }
3250         if (voff < eoff) {
3251                 /*
3252                  * Padding after the end option.
3253                  */
3254                 proto_tree_add_text(bp_tree, tvb, voff, eoff - voff, "Padding");
3255         }
3256 }
3257
3258 void
3259 proto_register_bootp(void)
3260 {
3261   static hf_register_info hf[] = {
3262     { &hf_bootp_dhcp,
3263       { "Frame is DHCP",                "bootp.dhcp",    FT_BOOLEAN,
3264         BASE_NONE,                      NULL,            0x0,
3265         "", HFILL }},
3266
3267     { &hf_bootp_type,
3268       { "Message type",                 "bootp.type",    FT_UINT8,
3269          BASE_DEC,                      VALS(op_vals),   0x0,
3270         "", HFILL }},
3271
3272     { &hf_bootp_hw_type,
3273       { "Hardware type",                "bootp.hw.type", FT_UINT8,
3274         BASE_HEX,                       NULL,            0x0,
3275         "", HFILL }},
3276
3277     { &hf_bootp_hw_len,
3278       { "Hardware address length",      "bootp.hw.len",  FT_UINT8,
3279         BASE_DEC,                       NULL,            0x0,
3280         "", HFILL }},
3281
3282     { &hf_bootp_hops,
3283       { "Hops",                         "bootp.hops",    FT_UINT8,
3284         BASE_DEC,                       NULL,            0x0,
3285         "", HFILL }},
3286
3287     { &hf_bootp_id,
3288       { "Transaction ID",               "bootp.id",      FT_UINT32,
3289         BASE_HEX,                        NULL,           0x0,
3290         "", HFILL }},
3291
3292     { &hf_bootp_secs,
3293       { "Seconds elapsed",              "bootp.secs",    FT_UINT16,
3294         BASE_DEC,                        NULL,           0x0,
3295         "", HFILL }},
3296
3297     { &hf_bootp_flags,
3298       { "Bootp flags",                  "bootp.flags",   FT_UINT16,
3299         BASE_HEX,                       NULL,            0x0,
3300         "", HFILL }},
3301
3302     { &hf_bootp_flags_broadcast,
3303       { "Broadcast flag",               "bootp.flags.bc", FT_BOOLEAN,
3304         16,                     TFS(&flag_set_broadcast), BOOTP_BC,
3305         "", HFILL }},
3306
3307     { &hf_bootp_flags_reserved,
3308       { "Reserved flags",               "bootp.flags.reserved", FT_UINT16,
3309         BASE_HEX,                       NULL,           BOOTP_MBZ,
3310         "", HFILL }},
3311
3312     { &hf_bootp_ip_client,
3313       { "Client IP address",            "bootp.ip.client",FT_IPv4,
3314         BASE_NONE,                      NULL,             0x0,
3315         "", HFILL }},
3316
3317     { &hf_bootp_ip_your,
3318       { "Your (client) IP address",     "bootp.ip.your",  FT_IPv4,
3319         BASE_NONE,                      NULL,             0x0,
3320         "", HFILL }},
3321
3322     { &hf_bootp_ip_server,
3323       { "Next server IP address",       "bootp.ip.server",FT_IPv4,
3324         BASE_NONE,                      NULL,             0x0,
3325         "", HFILL }},
3326
3327     { &hf_bootp_ip_relay,
3328       { "Relay agent IP address",       "bootp.ip.relay", FT_IPv4,
3329         BASE_NONE,                      NULL,             0x0,
3330         "", HFILL }},
3331
3332     { &hf_bootp_hw_addr,
3333       { "Client hardware address",      "bootp.hw.addr", FT_BYTES,
3334         BASE_NONE,                      NULL,            0x0,
3335         "", HFILL }},
3336
3337     { &hf_bootp_hw_ether_addr,
3338       { "Client MAC address",           "bootp.hw.mac_addr", FT_ETHER,
3339         BASE_NONE,                      NULL,            0x0,
3340         "", HFILL }},
3341
3342     { &hf_bootp_server,
3343       { "Server host name",             "bootp.server",  FT_STRING,
3344         BASE_NONE,                      NULL,            0x0,
3345         "", HFILL }},
3346
3347     { &hf_bootp_file,
3348       { "Boot file name",               "bootp.file",    FT_STRING,
3349         BASE_NONE,                      NULL,            0x0,
3350         "", HFILL }},
3351
3352     { &hf_bootp_cookie,
3353       { "Magic cookie",                 "bootp.cookie",  FT_IPv4,
3354          BASE_NONE,                     NULL,            0x0,
3355         "", HFILL }},
3356
3357     { &hf_bootp_vendor,
3358       { "Bootp Vendor Options",         "bootp.vendor", FT_BYTES,
3359         BASE_NONE,                      NULL,            0x0,
3360         "", HFILL }},
3361
3362     { &hf_bootp_fqdn_s,
3363       { "Server",               "bootp.fqdn.s",         FT_BOOLEAN,
3364         8,                      TFS(&tfs_fqdn_s),       F_FQDN_S,
3365         "If true, server should do DDNS update", HFILL }},
3366
3367     { &hf_bootp_fqdn_o,
3368       { "Server overrides",     "bootp.fqdn.o",         FT_BOOLEAN,
3369         8,                      TFS(&tfs_fqdn_o),       F_FQDN_O,
3370         "If true, server insists on doing DDNS update", HFILL }},
3371
3372     { &hf_bootp_fqdn_e,
3373       { "Encoding",     "bootp.fqdn.e",         FT_BOOLEAN,
3374         8,                      TFS(&tfs_fqdn_e),       F_FQDN_E,
3375         "If true, name is binary encoded", HFILL }},
3376
3377     { &hf_bootp_fqdn_n,
3378       { "Server DDNS",  "bootp.fqdn.n",         FT_BOOLEAN,
3379         8,                      TFS(&tfs_fqdn_n),       F_FQDN_N,
3380         "If true, server should not do any DDNS updates", HFILL }},
3381
3382     { &hf_bootp_fqdn_mbz,
3383       { "Reserved flags",       "bootp.fqdn.mbz",       FT_UINT8,
3384         BASE_HEX,               NULL,                   F_FQDN_MBZ,
3385         "", HFILL }},
3386
3387     { &hf_bootp_fqdn_rcode1,
3388       { "A-RR result",          "bootp.fqdn.rcode1",     FT_UINT8,
3389         BASE_DEC,               NULL,                    0x0,
3390         "Result code of A-RR update", HFILL }},
3391
3392     { &hf_bootp_fqdn_rcode2,
3393       { "PTR-RR result",        "bootp.fqdn.rcode2",     FT_UINT8,
3394         BASE_DEC,               NULL,                    0x0,
3395         "Result code of PTR-RR update", HFILL }},
3396
3397     { &hf_bootp_fqdn_name,
3398       { "Client name",          "bootp.fqdn.name",      FT_BYTES,
3399         BASE_NONE,              NULL,                   0x0,
3400         "Name to register via DDNS", HFILL }},
3401
3402     { &hf_bootp_fqdn_asciiname,
3403       { "Client name",          "bootp.fqdn.name",      FT_STRING,
3404         BASE_NONE,              NULL,                   0x0,
3405         "Name to register via DDNS", HFILL }},
3406
3407     { &hf_bootp_pkt_mtacap_len,
3408       { "MTA DC Length",        "bootp.vendor.pktc.mtacap_len",
3409         FT_UINT8, BASE_DEC, NULL, 0x0,
3410         "PacketCable MTA Device Capabilities Length", HFILL }},
3411
3412     { &hf_bootp_docsis_cmcap_len,
3413       { "CM DC Length",         "bootp.vendor.docsis.cmcap_len",
3414         FT_UINT8, BASE_DEC, NULL, 0x0,
3415         "DOCSIS Cable Modem Device Capabilities Length", HFILL }},
3416
3417     { &hf_bootp_alcatel_vid,
3418       { "Voice VLAN ID",        "bootp.vendor.alcatel.vid",
3419         FT_UINT16, BASE_DEC, NULL, 0x0,
3420         "Alcatel VLAN ID to define Voice VLAN", HFILL }},
3421
3422     { &hf_bootp_client_identifier_uuid,
3423       { "Client Identifier (UUID)",    "bootp.client_id_uuid",
3424         FT_GUID, BASE_NONE, NULL, 0x0,
3425         "Client Machine Identifier (UUID)", HFILL }},
3426
3427     { &hf_bootp_client_network_id_major_ver,
3428       { "Client Network ID Major Version",    "bootp.client_network_id_major",
3429         FT_UINT8, BASE_DEC, NULL, 0x0,
3430         "Client Machine Identifier, Major Version", HFILL }},
3431
3432     { &hf_bootp_client_network_id_minor_ver,
3433       { "Client Network ID Minor Version",    "bootp.client_network_id_minor",
3434         FT_UINT8, BASE_DEC, NULL, 0x0,
3435         "Client Machine Identifier, Major Version", HFILL }},
3436
3437     { &hf_bootp_option_type,
3438       { "Option",       "bootp.option.type",
3439         FT_UINT8, BASE_DEC, NULL, 0x0,
3440         "Bootp/Dhcp option type", HFILL }},
3441
3442     { &hf_bootp_option_length,
3443       { "Length",       "bootp.option.length",
3444         FT_UINT8, BASE_DEC, NULL, 0x0,
3445         "Bootp/Dhcp option length", HFILL }},
3446
3447     { &hf_bootp_option_value,
3448       { "Value",        "bootp.option.value",
3449         FT_BYTES, BASE_NONE, NULL, 0x0,
3450         "Bootp/Dhcp option value", HFILL }},
3451
3452   };
3453
3454   static gint *ett[] = {
3455     &ett_bootp,
3456     &ett_bootp_flags,
3457     &ett_bootp_option,
3458     &ett_bootp_fqdn,
3459   };
3460
3461   module_t *bootp_module;
3462
3463   proto_bootp = proto_register_protocol("Bootstrap Protocol", "BOOTP/DHCP",
3464                                         "bootp");
3465   proto_register_field_array(proto_bootp, hf, array_length(hf));
3466   proto_register_subtree_array(ett, array_length(ett));
3467   bootp_dhcp_tap = register_tap("bootp");
3468
3469   /* Allow dissector to find be found by name. */
3470   register_dissector("bootp", dissect_bootp, proto_bootp);
3471
3472   bootp_module = prefs_register_protocol(proto_bootp, NULL);
3473
3474   prefs_register_bool_preference(bootp_module, "novellserverstring",
3475     "Decode Option 85 as String",
3476     "Novell Servers option 85 can be configured as a string instead of address",
3477     &novell_string);
3478
3479   prefs_register_enum_preference(bootp_module, "pkt.ccc.protocol_version",
3480     "PacketCable CCC protocol version",
3481     "The PacketCable CCC protocol version",
3482     &pkt_ccc_protocol_version,
3483     pkt_ccc_protocol_versions,
3484     FALSE);
3485
3486   prefs_register_uint_preference(bootp_module, "pkt.ccc.option",
3487     "PacketCable CCC option",
3488     "Option Number for PacketCable CableLabs Client Configuration",
3489     10,
3490     &pkt_ccc_option);
3491
3492
3493 }
3494
3495 void
3496 proto_reg_handoff_bootp(void)
3497 {
3498   dissector_handle_t bootp_handle;
3499
3500   bootp_handle = create_dissector_handle(dissect_bootp, proto_bootp);
3501   dissector_add("udp.port", UDP_PORT_BOOTPS, bootp_handle);
3502   dissector_add("udp.port", UDP_PORT_BOOTPC, bootp_handle);
3503 }