From Didier Gautheron:
[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  * RFC 3442: Classless Static Route Option for DHCP version 4
24  * RFC 3825: Dynamic Host Configuration Protocol Option for Coordinate-based Location Configuration Information
25  * RFC 3942: Reclassifying DHCPv4 Options
26  * RFC 4243: Vendor-Specific Information Suboption for the Dynamic Host Configuration Protocol (DHCP) Relay Agent Option
27  * RFC 4776: Dynamic Host Configuration Protocol (DHCPv4 and DHCPv6) Option for Civic Addresses Configuration Information
28  * RFC 5223: Discovering Location-to-Service Translation (LoST) Servers Using the Dynamic Host Configuration Protocol (DHCP)
29  * RFC 5417: CAPWAP Access Controller DHCP Option
30  * draft-ietf-dhc-fqdn-option-07.txt
31  * BOOTP and DHCP Parameters
32  *     http://www.iana.org/assignments/bootp-dhcp-parameters
33  * DOCSIS(TM) 2.0 Radio Frequency Interface Specification
34  *     http://www.cablemodem.com/downloads/specs/CM-SP-RFI2.0-I10-051209.pdf
35  * PacketCable(TM) 1.0 MTA Device Provisioning Specification
36  *     http://www.packetcable.com/downloads/specs/PKT-SP-PROV-I11-050812.pdf
37  *     http://www.cablelabs.com/specifications/archives/PKT-SP-PROV-I05-021127.pdf (superseded by above)
38  * PacketCable(TM) 1.5 MTA Device Provisioning Specification
39  *     http://www.packetcable.com/downloads/specs/PKT-SP-PROV1.5-I02-050812.pdf
40  * CableHome(TM) 1.1 Specification
41  *     http://www.cablelabs.com/projects/cablehome/downloads/specs/CH-SP-CH1.1-I11-060407.pdf
42  * DSL Forum TR-111
43  *     http://www.dslforum.org/techwork/tr/TR-111.pdf
44  *
45  * Wireshark - Network traffic analyzer
46  * By Gerald Combs <gerald@wireshark.org>
47  * Copyright 1998 Gerald Combs
48  *
49  * This program is free software; you can redistribute it and/or
50  * modify it under the terms of the GNU General Public License
51  * as published by the Free Software Foundation; either version 2
52  * of the License, or (at your option) any later version.
53  *
54  * This program is distributed in the hope that it will be useful,
55  * but WITHOUT ANY WARRANTY; without even the implied warranty of
56  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
57  * GNU General Public License for more details.
58  *
59  * You should have received a copy of the GNU General Public License
60  * along with this program; if not, write to the Free Software
61  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
62  */
63
64 /*
65  * Some of the development of the BOOTP/DHCP protocol decoder was sponsored by
66  * Cable Television Laboratories, Inc. ("CableLabs") based upon proprietary
67  * CableLabs' specifications. Your license and use of this protocol decoder
68  * does not mean that you are licensed to use the CableLabs'
69  * specifications.  If you have questions about this protocol, contact
70  * jf.mule [AT] cablelabs.com or c.stuart [AT] cablelabs.com for additional
71  * information.
72  */
73
74
75 #ifdef HAVE_CONFIG_H
76 # include "config.h"
77 #endif
78
79 #include <stdio.h>
80 #include <string.h>
81 #include <glib.h>
82 #include <epan/packet.h>
83 #include "packet-arp.h"
84 #include "packet-dns.h"                         /* for get_dns_name() */
85 #include <epan/addr_resolv.h>
86 #include <epan/prefs.h>
87 #include <epan/tap.h>
88 #include <epan/strutil.h>
89 #include <epan/arptypes.h>
90 #include <epan/sminmpec.h>
91 #include <epan/expert.h>
92
93
94 static int bootp_dhcp_tap = -1;
95 static int proto_bootp = -1;
96 static int hf_bootp_type = -1;
97 static int hf_bootp_hw_type = -1;
98 static int hf_bootp_hw_len = -1;
99 static int hf_bootp_hops = -1;
100 static int hf_bootp_id = -1;
101 static int hf_bootp_secs = -1;
102 static int hf_bootp_flags = -1;
103 static int hf_bootp_flags_broadcast = -1;
104 static int hf_bootp_flags_reserved = -1;
105 static int hf_bootp_ip_client = -1;
106 static int hf_bootp_ip_your = -1;
107 static int hf_bootp_ip_server = -1;
108 static int hf_bootp_ip_relay = -1;
109 static int hf_bootp_hw_addr = -1;
110 static int hf_bootp_hw_addr_padding = -1;
111 static int hf_bootp_hw_ether_addr = -1;
112 static int hf_bootp_server = -1;
113 static int hf_bootp_file = -1;
114 static int hf_bootp_cookie = -1;
115 static int hf_bootp_vendor = -1;
116 static int hf_bootp_dhcp = -1;
117 static int hf_bootp_fqdn_s = -1;
118 static int hf_bootp_fqdn_o = -1;
119 static int hf_bootp_fqdn_e = -1;
120 static int hf_bootp_fqdn_n = -1;
121 static int hf_bootp_fqdn_mbz = -1;
122 static int hf_bootp_fqdn_rcode1 = -1;
123 static int hf_bootp_fqdn_rcode2 = -1;
124 static int hf_bootp_fqdn_name = -1;
125 static int hf_bootp_fqdn_asciiname = -1;
126 static int hf_bootp_pkt_mtacap_len = -1;
127 static int hf_bootp_docsis_cmcap_len = -1;
128 static int hf_bootp_alu_vid = -1;
129 static int hf_bootp_alu_tftp1 = -1;
130 static int hf_bootp_alu_tftp2 = -1;
131 static int hf_bootp_client_identifier_uuid = -1;
132 static int hf_bootp_client_network_id_major_ver = -1;
133 static int hf_bootp_client_network_id_minor_ver = -1;
134 static int hf_bootp_option_type = -1;
135 static int hf_bootp_option_length = -1;
136 static int hf_bootp_option_value = -1;
137
138 static gint ett_bootp = -1;
139 static gint ett_bootp_flags = -1;
140 static gint ett_bootp_option = -1;
141 static gint ett_bootp_fqdn = -1;
142
143 static const char *pref_optionstring = "";
144
145 /* RFC3825decoder error codes of the conversion function */
146 #define RFC3825_NOERROR                           0
147 #define RFC3825_LATITUDE_OUTOFRANGE               1
148 #define RFC3825_LATITUDE_UNCERTAINTY_OUTOFRANGE   2
149 #define RFC3825_LONGITUDE_OUTOFRANGE              3
150 #define RFC3825_LONGITUDE_UNCERTAINTY_OUTOFRANGE  4
151 #define RFC3825_ALTITUDE_OUTOFRANGE               5
152 #define RFC3825_ALTITUDE_UNCERTAINTY_OUTOFRANGE   6
153 #define RFC3825_ALTITUDE_TYPE_OUTOFRANGE          7
154 #define RFC3825_DATUM_TYPE_OUTOFRANGE             8
155
156 struct rfc3825_location_fixpoint_t {
157
158         gint64 latitude;                /* latitude in degrees, allowed range from -90deg to 90deg.
159                                                            Fixpoint A(8,25) with 34 bits */
160         guint8 latitude_res;    /* the resolution of the latitude in bits, allowed range is from 0 to 34.
161                                                            6 bits. */
162         gint64 longitude;               /* longitude in degrees, range from -180deg to 180deg.
163                                                            Fixpoint A(8,25) with 34 bits */
164         guint8 longitude_res;   /* the resolution of the longitude in bits, allowed range is from 0 to 34.
165                                                            6 bits. */
166         gint32 altitude;                /* the altitude, 30 bits.
167                                                            Depending on alt_type this are meters or floors, no range limit.
168                                                            altitude_type==1: A(13,8) with 22 bits
169                                                            altitude_type==2: A(13,8) with 22 bits */
170         guint8 altitude_res;    /* the resolution of the altitude in bits, allowed range is from 0 to 30.
171                                                            6 bits.
172                                                            altitude_type==1: any value between 0 and 30
173                                                            altitude_type==2: either 0 (floor unknown) or 30 */
174         guint8 altitude_type;   /* the type of the altitude, 4 bits. allowed values are:
175                                                            0: unknown
176                                                            1: altitude in meters
177                                                            2: altitude in floors */
178         guint8 datum_type;              /* the map datum used for the coordinates. 8 bits.
179                                                            All values are allowed although currently only the 
180                                                            following ones are defined: 
181                                                            1: WGS84
182                                                            2: NAD83/NAVD88
183                                                            3: NAD83/MLLW */
184 };
185
186 /* The rfc3825_location_decimal_t structure holds the location parameters
187  * in decimal (floating point) format.
188  */
189 struct rfc3825_location_decimal_t {
190
191         double latitude;                /* latitude in degrees, allowed range from -90deg to 90deg */
192         double latitude_res;    /* the uncertainty of the latitude in grad, "0.01" means +-0.01deg
193                                                            from the altitude. During conversion this will be rounded to
194                                                            next smaller value which can be respresented in fixpoint arithmetic */
195         double longitude;               /* longitude in degrees, range from -180deg to 180deg */
196         double longitude_res;   /* the uncertainty of the longitude in grad, "0.01" means +-0.01deg
197                                                            from the longitude. During conversion this will be rounded to
198                                                            next smaller value which can be respresented in fixpoint arithmetic */
199         double altitude;                /* the altitude, depending on alt_type this are meters or floors, no range limit */
200         double altitude_res;    /* the uncertainty of the altitude in either:
201                                                            - altitude-type=meters: "10" means 10 meters which means +-10 meters from the altitude
202                                                            - altitude-type=floors: either 0 (unknown) or 30 (exact) */
203         int altitude_type;              /* the type of the altitude, allowed values are 
204                                                            0: unknown
205                                                            1: altitude in meters
206                                                            2: altitude in floors */
207         int datum_type;          /* the map datum used for the coordinates.
208                                                             All values are allowed although currently only the 
209                                                                 following ones are defined:
210                                                                 1: WGS84
211                                                                 2: NAD83/NAVD88
212                                                                 3: NAD83/MLLW */
213 };
214
215 /* converts fixpoint presentation into decimal presentation
216    also converts values which are out of range to allow decoding of received data */
217 static int rfc3825_fixpoint_to_decimal(struct rfc3825_location_fixpoint_t *fixpoint, struct rfc3825_location_decimal_t *decimal);
218
219 /* decodes the LCI string received from DHCP into the fixpoint values */
220 static void rfc3825_lci_to_fixpoint(const unsigned char lci[16], struct rfc3825_location_fixpoint_t *fixpoint);
221
222
223 /* Map Datum Types used for the coordinates (RFC 3825) */
224 static const value_string map_datum_type_values[] = {
225         { 1,    "WGS 84" },
226         { 2,    "NAD83 (NAVD88)" },
227         { 3,    "NAD83 (MLLW)" },
228         { 0,    NULL }
229 };
230
231
232 /* Altitude Types used for the coordinates (RFC 3825) */
233 static const value_string altitude_type_values[] = {
234         { 1,    "Meters" },
235         { 2,    "Floors" },
236         { 0,    NULL }
237 };
238
239 /* AutoConfigure (RFC 2563) */
240 static const value_string dhcp_autoconfig[] = {
241         {0,     "DoNotAutoConfigure"},
242         {1,     "AutoConfigure"},
243         {0,     NULL }
244 };
245
246 /* Error Types for RFC 3825 coordinate location decoding */
247 static const value_string rfc3825_error_types[] = {
248         {1,     "Latitude is out of range [-90,90]"},
249         {2,     "Latitude Uncertainty is out of range [0,90]"},
250         {3,     "Longitude is out of range [-180,180]"},
251         {4,     "Longitude Uncertainty is out of range [0,180]"},
252         {5,     "Altitude is out of range [-(2^21),(2^21)-1]"},
253         {6,     "Altitude Uncertainty is out of range [0,2^20]"},
254         {7,     "Altitude Type is out of range [0,2]"},
255         {8,     "Datum is out of range [1,3]"},
256         {0,     NULL }
257 };
258
259
260
261 /* Civic Address What field (RFC 4776) */
262 static const value_string civic_address_what_values[] = {
263         { 0,    "Location of the DHCP server" },
264         { 1,    "Location of the network element believed to be closest to the client" },
265         { 2,    "Location of the client"},
266         { 0, NULL}
267 };
268
269 /* Civic Address Type field (RFC 4119, RFC 4776, RFC 5139) */
270 static const value_string civic_address_type_values[] = {
271         { 0,    "Language" },
272         { 1,    "A1" },
273         { 2,    "A2" },
274         { 3,    "A3" },
275         { 4,    "A4" },
276         { 5,    "A5" },
277         { 6,    "A6" },
278         { 16,   "PRD (Leading street direction)" },
279         { 17,   "POD (Trailing street suffix)" },
280         { 18,   "STS (Street suffix)" },
281         { 19,   "HNO (House number)" },
282         { 20,   "HNS (House number suffix)" },
283         { 21,   "LMK (Landmark or vanity address)" },
284         { 22,   "LOC (Additional location information)" },
285         { 23,   "NAM" },
286         { 24,   "PC (Postal/ZIP code)" },
287         { 25,   "BLD (Building)" },
288         { 26,   "UNIT" },
289         { 27,   "FLR (Floor)" },
290         { 28,   "ROOM" },
291         { 29,   "PLC (Place-type)" },
292         { 30,   "PCN (Postal community name)" },
293         { 31,   "POBOX" },
294         { 32,   "ADDCODE (Additional Code)" },
295         { 33,   "SEAT" },
296         { 34,   "RD (Primary road or street)" },
297         { 35,   "RDSEC (Road section)" },
298         { 36,   "RDBR (Road branch)" },
299         { 37,   "RDSUBBR (Road sub-branch)" },
300         { 38,   "PRM (Road pre-modifier)" },
301         { 39,   "POM (Road post-modifier" },
302         { 128,  "Script" },
303         { 0, NULL }
304 };
305
306
307 static gboolean novell_string = FALSE;
308
309 #define UDP_PORT_BOOTPS  67
310 #define UDP_PORT_BOOTPC  68
311
312 #define BOOTP_BC        0x8000
313 #define BOOTP_MBZ       0x7FFF
314
315 /* FQDN stuff */
316 #define F_FQDN_S        0x01
317 #define F_FQDN_O        0x02
318 #define F_FQDN_E        0x04
319 #define F_FQDN_N        0x08
320 #define F_FQDN_MBZ      0xf0
321
322 static const true_false_string tfs_fqdn_s = {
323         "Server",
324         "Client"
325 };
326
327 static const true_false_string tfs_fqdn_o = {
328         "Override",
329         "No override"
330 };
331
332 static const true_false_string tfs_fqdn_e = {
333         "Binary encoding",
334         "ASCII encoding"
335 };
336
337 static const true_false_string tfs_fqdn_n = {
338         "No server updates",
339         "Some server updates"
340 };
341
342 enum field_type {
343         special,
344         none,
345         presence,
346         ipv4,                   /* single IPv4 address */
347         ipv4_list,              /* list of IPv4 addresses */
348         string,
349         bytes,
350         opaque,
351         val_boolean,
352         val_u_byte,
353         val_u_short,
354         val_u_short_list,
355         val_u_le_short,
356         val_u_long,
357         time_in_secs,
358         fqdn,
359         ipv4_or_fqdn
360 };
361
362 struct opt_info {
363         const char      *text;
364         enum field_type ftype;
365         const void      *data;
366 };
367
368 static const true_false_string flag_set_broadcast = {
369         "Broadcast",
370         "Unicast"
371 };
372
373
374 /* PacketCable/DOCSIS definitions */
375 #define PACKETCABLE_MTA_CAP10 "pktc1.0:"
376 #define PACKETCABLE_MTA_CAP15 "pktc1.5:"
377 #define PACKETCABLE_CM_CAP11  "docsis1.1:"
378 #define PACKETCABLE_CM_CAP20  "docsis2.0:"
379
380 #define PACKETCABLE_CCC_I05      1
381 #define PACKETCABLE_CCC_DRAFT5   2
382 #define PACKETCABLE_CCC_RFC_3495 3
383
384 static enum_val_t pkt_ccc_protocol_versions[] = {
385         { "ccc_i05",     "PKT-SP-PROV-I05-021127", PACKETCABLE_CCC_I05 },
386         { "ccc_draft_5", "IETF Draft 5",           PACKETCABLE_CCC_DRAFT5 },
387         { "rfc_3495",    "RFC 3495",               PACKETCABLE_CCC_RFC_3495 },
388         { NULL, NULL, 0 }
389 };
390
391 static gint pkt_ccc_protocol_version = PACKETCABLE_CCC_RFC_3495;
392 static guint pkt_ccc_option = 122;
393
394
395 static int dissect_vendor_pxeclient_suboption(proto_tree *v_tree, tvbuff_t *tvb,
396     int optoff, int optend);
397 static int dissect_vendor_cablelabs_suboption(proto_tree *v_tree, tvbuff_t *tvb,
398     int optoff, int optend);
399 static int dissect_netware_ip_suboption(proto_tree *v_tree, tvbuff_t *tvb,
400     int optoff, int optend);
401 static int dissect_vendor_tr111_suboption(proto_tree *v_tree, tvbuff_t *tvb,
402     int optoff, int optend);
403 static int bootp_dhcp_decode_agent_info(proto_tree *v_tree, tvbuff_t *tvb,
404     int optoff, int optend);
405 static void dissect_packetcable_mta_cap(proto_tree *v_tree, tvbuff_t *tvb,
406        int voff, int len);
407 static void dissect_docsis_cm_cap(proto_tree *v_tree, tvbuff_t *tvb,
408        int voff, int len);
409 static int dissect_packetcable_i05_ccc(proto_tree *v_tree, tvbuff_t *tvb,
410     int optoff, int optend);
411 static int dissect_packetcable_ietf_ccc(proto_tree *v_tree, tvbuff_t *tvb,
412     int optoff, int optend, int revision);
413 static int dissect_vendor_cl_suboption(proto_tree *v_tree, tvbuff_t *tvb,
414     int optoff, int optend);
415
416 #define OPT53_DISCOVER "Discover"
417 /* http://www.iana.org/assignments/bootp-dhcp-parameters */
418 static const value_string opt53_text[] = {
419         { 1,    OPT53_DISCOVER },
420         { 2,    "Offer" },
421         { 3,    "Request" },
422         { 4,    "Decline" },
423         { 5,    "ACK" },
424         { 6,    "NAK" },
425         { 7,    "Release" },
426         { 8,    "Inform" },
427         { 9,    "Force Renew" },
428         { 10,   "Lease query" },                /* RFC4388 */
429         { 11,   "Lease Unassigned" },   /* RFC4388 */
430         { 12,   "Lease Unknown" },              /* RFC4388 */
431         { 13,   "Lease Active" },               /* RFC4388 */
432         /* draft-ietf-dhc-leasequery-09.txt
433         { 13,   "Lease query" },                        */
434         { 14,   "Lease known" },
435         { 15,   "Lease unknown" },
436         { 16,   "Lease active" },
437         { 17,   "Unimplemented" },
438
439         { 0,    NULL }
440 };
441
442 /* DHCP Authentication protocols */
443 #define AUTHEN_PROTO_CONFIG_TOKEN       0
444 #define AUTHEN_PROTO_DELAYED_AUTHEN     1
445
446 /* DHCP Authentication algorithms for delayed authentication */
447 #define AUTHEN_DELAYED_ALGO_HMAC_MD5    1
448
449 /* DHCP Authentication Replay Detection Methods */
450 #define AUTHEN_RDM_MONOTONIC_COUNTER    0x00
451
452 /* DHCP Option Overload (option code 52) */
453 #define OPT_OVERLOAD_FILE               1
454 #define OPT_OVERLOAD_SNAME              2
455 #define OPT_OVERLOAD_BOTH               3
456
457 /* Server name and boot file offsets and lengths */
458 #define SERVER_NAME_OFFSET              44
459 #define SERVER_NAME_LEN                 64
460 #define FILE_NAME_OFFSET                108
461 #define FILE_NAME_LEN                   128
462 #define VENDOR_INFO_OFFSET              236
463
464 static const value_string bootp_nbnt_vals[] = {
465         {0x1,   "B-node" },
466         {0x2,   "P-node" },
467         {0x4,   "M-node" },
468         {0x8,   "H-node" },
469         {0,     NULL     }
470 };
471
472 static const value_string bootp_client_arch[] = {
473         { 0x0000, "IA x86 PC" },
474         { 0x0001, "NEC/PC98" },
475         { 0x0002, "IA64 PC" },
476         { 0x0003, "DEC Alpha" },
477         { 0x0004, "ArcX86" },
478         { 0x0005, "Intel Lean Client" },
479         { 0,      NULL }
480 };
481
482 /* bootp options administration */
483 #define BOOTP_OPT_NUM   256
484
485 /* Re-define structure.  Values to be upated by bootp_init_protocol */
486 static struct opt_info bootp_opt[BOOTP_OPT_NUM];
487
488 static struct opt_info default_bootp_opt[BOOTP_OPT_NUM] = {
489 /*   0 */ { "Padding",                                  none, NULL },
490 /*   1 */ { "Subnet Mask",                              ipv4, NULL },
491 /*   2 */ { "Time Offset",                              time_in_secs, NULL },
492 /*   3 */ { "Router",                                   ipv4_list, NULL },
493 /*   4 */ { "Time Server",                              ipv4_list, NULL },
494 /*   5 */ { "Name Server",                              ipv4_list, NULL },
495 /*   6 */ { "Domain Name Server",                       ipv4_list, NULL },
496 /*   7 */ { "Log Server",                               ipv4_list, NULL },
497 /*   8 */ { "Quotes Server",                            ipv4_list, NULL },
498 /*   9 */ { "LPR Server",                               ipv4_list, NULL },
499 /*  10 */ { "Impress Server",                           ipv4_list, NULL },
500 /*  11 */ { "Resource Location Server",                 ipv4_list, NULL },
501 /*  12 */ { "Host Name",                                string, NULL },
502 /*  13 */ { "Boot File Size",                           val_u_short, NULL },
503 /*  14 */ { "Merit Dump File",                          string, NULL },
504 /*  15 */ { "Domain Name",                              string, NULL },
505 /*  16 */ { "Swap Server",                              ipv4, NULL },
506 /*  17 */ { "Root Path",                                string, NULL },
507 /*  18 */ { "Extensions Path",                          string, NULL },
508 /*  19 */ { "IP Forwarding",                            val_boolean, TFS(&tfs_enabled_disabled) },
509 /*  20 */ { "Non-Local Source Routing",                 val_boolean, TFS(&tfs_enabled_disabled) },
510 /*  21 */ { "Policy Filter",                            special, NULL },
511 /*  22 */ { "Maximum Datagram Reassembly Size",         val_u_short, NULL },
512 /*  23 */ { "Default IP Time-to-Live",                  val_u_byte, NULL },
513 /*  24 */ { "Path MTU Aging Timeout",                   time_in_secs, NULL },
514 /*  25 */ { "Path MTU Plateau Table",                   val_u_short_list, NULL },
515 /*  26 */ { "Interface MTU",                            val_u_short, NULL },
516 /*  27 */ { "All Subnets are Local",                    val_boolean, TFS(&tfs_yes_no) },
517 /*  28 */ { "Broadcast Address",                        ipv4, NULL },
518 /*  29 */ { "Perform Mask Discovery",                   val_boolean, TFS(&tfs_enabled_disabled) },
519 /*  30 */ { "Mask Supplier",                            val_boolean, TFS(&tfs_yes_no) },
520 /*  31 */ { "Perform Router Discover",                  val_boolean, TFS(&tfs_enabled_disabled) },
521 /*  32 */ { "Router Solicitation Address",              ipv4, NULL },
522 /*  33 */ { "Static Route",                             special, NULL },
523 /*  34 */ { "Trailer Encapsulation",                    val_boolean, TFS(&tfs_enabled_disabled) },
524 /*  35 */ { "ARP Cache Timeout",                        time_in_secs, NULL },
525 /*  36 */ { "Ethernet Encapsulation",                   val_boolean, TFS(&tfs_enabled_disabled) },
526 /*  37 */ { "TCP Default TTL",                          val_u_byte, NULL },
527 /*  38 */ { "TCP Keepalive Interval",                   time_in_secs, NULL },
528 /*  39 */ { "TCP Keepalive Garbage",                    val_boolean, TFS(&tfs_enabled_disabled) },
529 /*  40 */ { "Network Information Service Domain",       string, NULL },
530 /*  41 */ { "Network Information Service Servers",      ipv4_list, NULL },
531 /*  42 */ { "Network Time Protocol Servers",            ipv4_list, NULL },
532 /*  43 */ { "Vendor-Specific Information",              special, NULL },
533 /*  44 */ { "NetBIOS over TCP/IP Name Server",          ipv4_list, NULL },
534 /*  45 */ { "NetBIOS over TCP/IP Datagram Distribution Name Server", ipv4_list, NULL },
535 /*  46 */ { "NetBIOS over TCP/IP Node Type",            val_u_byte, VALS(bootp_nbnt_vals) },
536 /*  47 */ { "NetBIOS over TCP/IP Scope",                string, NULL },
537 /*  48 */ { "X Window System Font Server",              ipv4_list, NULL },
538 /*  49 */ { "X Window System Display Manager",          ipv4_list, NULL },
539 /*  50 */ { "Requested IP Address",                     ipv4, NULL },
540 /*  51 */ { "IP Address Lease Time",                    time_in_secs, NULL },
541 /*  52 */ { "Option Overload",                          special, NULL },
542 /*  53 */ { "DHCP Message Type",                        special, NULL },
543 /*  54 */ { "DHCP Server Identifier",                   ipv4, NULL },
544 /*  55 */ { "Parameter Request List",                   special, NULL },
545 /*  56 */ { "Message",                                  string, NULL },
546 /*  57 */ { "Maximum DHCP Message Size",                val_u_short, NULL },
547 /*  58 */ { "Renewal Time Value",                       time_in_secs, NULL },
548 /*  59 */ { "Rebinding Time Value",                     time_in_secs, NULL },
549 /*  60 */ { "Vendor class identifier",                  special, NULL },
550 /*  61 */ { "Client identifier",                        special, NULL },
551 /*  62 */ { "Novell/Netware IP domain",                 string, NULL },
552 /*  63 */ { "Novell Options",                           special, NULL },
553 /*  64 */ { "Network Information Service+ Domain",      string, NULL },
554 /*  65 */ { "Network Information Service+ Servers",     ipv4_list, NULL },
555 /*  66 */ { "TFTP Server Name",                         string, NULL },
556 /*  67 */ { "Bootfile name",                            string, NULL },
557 /*  68 */ { "Mobile IP Home Agent",                     ipv4_list, NULL },
558 /*  69 */ { "SMTP Server",                              ipv4_list, NULL },
559 /*  70 */ { "POP3 Server",                              ipv4_list, NULL },
560 /*  71 */ { "NNTP Server",                              ipv4_list, NULL },
561 /*  72 */ { "Default WWW Server",                       ipv4_list, NULL },
562 /*  73 */ { "Default Finger Server",                    ipv4_list, NULL },
563 /*  74 */ { "Default IRC Server",                       ipv4_list, NULL },
564 /*  75 */ { "StreetTalk Server",                        ipv4_list, NULL },
565 /*  76 */ { "StreetTalk Directory Assistance Server",   ipv4_list, NULL },
566 /*  77 */ { "User Class Information",                   opaque, NULL },
567 /*  78 */ { "Directory Agent Information",              special, NULL },
568 /*  79 */ { "Service Location Agent Scope",             special, NULL },
569 /*  80 */ { "Rapid commit",                             opaque, NULL },
570 /*  81 */ { "Client Fully Qualified Domain Name",       special, NULL },
571 /*  82 */ { "Agent Information Option",                 special, NULL },
572 /*  83 */ { "iSNS [TODO:RFC4174]",                      opaque, NULL },
573 /*  84 */ { "Removed/Unassigned",                       opaque, NULL },
574 /*  85 */ { "Novell Directory Services Servers",        special, NULL },
575 /*  86 */ { "Novell Directory Services Tree Name",      string, NULL },
576 /*  87 */ { "Novell Directory Services Context",        string, NULL },
577 /*  88 */ { "BCMCS Controller Domain Name [TODO:RFC4280]",      opaque, NULL },
578 /*  89 */ { "BCMCS Controller IPv4 address [TODO:RFC4280]",     opaque, NULL },
579 /*  90 */ { "Authentication",                           special, NULL },
580 /*  91 */ { "Client last transaction time [TODO:RFC4388]",      opaque, NULL },
581 /*  92 */ { "associated ip option [TODO:RFC4388]",      opaque, NULL },
582 /*  93 */ { "Client System Architecture",               val_u_short, VALS(bootp_client_arch) },
583 /*  94 */ { "Client Network Device Interface",          special, NULL },
584 /*  95 */ { "LDAP [TODO:RFC3679]",                      opaque, NULL },
585 /*  96 */ { "Removed/Unassigend",                       opaque, NULL },
586 /*  97 */ { "UUID/GUID-based Client Identifier",        special, NULL },
587 /*  98 */ { "Open Group's User Authentication [TODO:RFC2485]",  opaque, NULL },
588 /*  99 */ { "Civic Addresses Configuration",            special, NULL },
589 /* 100 */ { "PCode [TODO:RFC4833]",                     opaque, NULL },
590 /* 101 */ { "TCode [TODO:RFC4833]",                     opaque, NULL },
591 /* 102 */ { "Removed/unassigned",                       opaque, NULL },
592 /* 103 */ { "Removed/unassigned",                       opaque, NULL },
593 /* 104 */ { "Removed/unassigned",                       opaque, NULL },
594 /* 105 */ { "Removed/unassigned",                       opaque, NULL },
595 /* 106 */ { "Removed/unassigned",                       opaque, NULL },
596 /* 107 */ { "Removed/unassigned",                       opaque, NULL },
597 /* 108 */ { "Removed/Unassigend",                       opaque, NULL },
598 /* 109 */ { "Unassigned",                               opaque, NULL },
599 /* 110 */ { "Removed/Uassigend",                        opaque, NULL },
600 /* 111 */ { "Unassigned",                               opaque, NULL },
601 /* 112 */ { "NetInfo Parent Server Address",            ipv4_list, NULL },
602 /* 113 */ { "NetInfo Parent Server Tag",                string, NULL },
603 /* 114 */ { "URL [TODO:RFC3679]",                       opaque, NULL },
604 /* 115 */ { "Removed/Unassigend",                       opaque, NULL },
605 /* 116 */ { "DHCP Auto-Configuration",                  val_u_byte, VALS(dhcp_autoconfig) },
606 /* 117 */ { "Name Service Search [TODO:RFC2937]",       opaque, NULL },
607 /* 118 */ { "Subnet Selection Option",                  ipv4_list, NULL },
608 /* 119 */ { "Domain Search [TODO:RFC3397]",             opaque, NULL },
609 /* 120 */ { "SIP Servers [TODO:RFC3361]",               opaque, NULL },
610 /* 121 */ { "Classless Static Route",                   special, NULL },
611 /* 122 */ { "CableLabs Client Configuration [TODO:RFC3495]",    opaque, NULL },
612 /* 123 */ { "Coordinate-based Location Configuration",  special, NULL },
613 /* 124 */ { "V-I Vendor Class [TODO:RFC3925]",          opaque, NULL },
614 /* 125 */ { "V-I Vendor-specific Information",          special, NULL },
615 /* 126 */ { "Removed/Unassigned",                       opaque, NULL },
616 /* 127 */ { "Removed/Unassigend",                       opaque, NULL },
617 /* 128 */ { "DOCSIS full security server IP [TODO]",    opaque, NULL },
618 /* 129 */ { "PXE - undefined (vendor specific)",        opaque, NULL },
619 /* 130 */ { "PXE - undefined (vendor specific)",        opaque, NULL },
620 /* 131 */ { "PXE - undefined (vendor specific)",        opaque, NULL },
621 /* 132 */ { "PXE - undefined (vendor specific)",        opaque, NULL },
622 /* 133 */ { "PXE - undefined (vendor specific)",        opaque, NULL },
623 /* 134 */ { "PXE - undefined (vendor specific)",        opaque, NULL },
624 /* 135 */ { "PXE - undefined (vendor specific)",        opaque, NULL },
625 /* 136 */ { "OPTION_PANA_AGENT [TODO:RFC5192]",         opaque, NULL },
626 /* 137 */ { "LoST Server Domain Name",                  string, NULL },
627 /* 138 */ { "CAPWAP Access Controllers",                ipv4_list, NULL },
628 /* 139 */ { "Unassigned",                               opaque, NULL },
629 /* 140 */ { "Unassigned",                               opaque, NULL },
630 /* 141 */ { "Unassigned",                               opaque, NULL },
631 /* 142 */ { "Unassigned",                               opaque, NULL },
632 /* 143 */ { "Unassigned",                               opaque, NULL },
633 /* 144 */ { "Unassigned",                               opaque, NULL },
634 /* 145 */ { "Unassigned",                               opaque, NULL },
635 /* 146 */ { "Unassigned",                               opaque, NULL },
636 /* 147 */ { "Unassigned",                               opaque, NULL },
637 /* 148 */ { "Unassigned",                               opaque, NULL },
638 /* 149 */ { "Unassigned",                               opaque, NULL },
639 /* 150 */ { "TFTP server address",                      opaque, NULL },
640 /* 151 */ { "Unassigned",                               opaque, NULL },
641 /* 152 */ { "Unassigned",                               opaque, NULL },
642 /* 153 */ { "Unassigned",                               opaque, NULL },
643 /* 154 */ { "Unassigned",                               opaque, NULL },
644 /* 155 */ { "Unassigned",                               opaque, NULL },
645 /* 156 */ { "Unassigned",                               opaque, NULL },
646 /* 157 */ { "Unassigned",                               opaque, NULL },
647 /* 158 */ { "Unassigned",                               opaque, NULL },
648 /* 159 */ { "Unassigned",                               opaque, NULL },
649 /* 160 */ { "Unassigned",                               opaque, NULL },
650 /* 161 */ { "Unassigned",                               opaque, NULL },
651 /* 162 */ { "Unassigned",                               opaque, NULL },
652 /* 163 */ { "Unassigned",                               opaque, NULL },
653 /* 164 */ { "Unassigned",                               opaque, NULL },
654 /* 165 */ { "Unassigned",                               opaque, NULL },
655 /* 166 */ { "Unassigned",                               opaque, NULL },
656 /* 167 */ { "Unassigned",                               opaque, NULL },
657 /* 168 */ { "Unassigned",                               opaque, NULL },
658 /* 169 */ { "Unassigned",                               opaque, NULL },
659 /* 170 */ { "Unassigned",                               opaque, NULL },
660 /* 171 */ { "Unassigned",                               opaque, NULL },
661 /* 172 */ { "Unassigned",                               opaque, NULL },
662 /* 173 */ { "Unassigned",                               opaque, NULL },
663 /* 174 */ { "Unassigned",                               opaque, NULL },
664 /* 175 */ { "Etherboot",                                opaque, NULL },
665 /* 176 */ { "IP Telephone",                             opaque, NULL },
666 /* 177 */ { "Etherboot",                                opaque, NULL },
667 /* 178 */ { "Unassigned",                               opaque, NULL },
668 /* 179 */ { "Unassigned",                               opaque, NULL },
669 /* 180 */ { "Unassigned",                               opaque, NULL },
670 /* 181 */ { "Unassigned",                               opaque, NULL },
671 /* 182 */ { "Unassigned",                               opaque, NULL },
672 /* 183 */ { "Unassigned",                               opaque, NULL },
673 /* 184 */ { "Unassigned",                               opaque, NULL },
674 /* 185 */ { "Unassigned",                               opaque, NULL },
675 /* 186 */ { "Unassigned",                               opaque, NULL },
676 /* 187 */ { "Unassigned",                               opaque, NULL },
677 /* 188 */ { "Unassigned",                               opaque, NULL },
678 /* 189 */ { "Unassigned",                               opaque, NULL },
679 /* 190 */ { "Unassigned",                               opaque, NULL },
680 /* 191 */ { "Unassigned",                               opaque, NULL },
681 /* 192 */ { "Unassigned",                               opaque, NULL },
682 /* 193 */ { "Unassigned",                               opaque, NULL },
683 /* 194 */ { "Unassigned",                               opaque, NULL },
684 /* 195 */ { "Unassigned",                               opaque, NULL },
685 /* 196 */ { "Unassigned",                               opaque, NULL },
686 /* 197 */ { "Unassigned",                               opaque, NULL },
687 /* 198 */ { "Unassigned",                               opaque, NULL },
688 /* 199 */ { "Unassigned",                               opaque, NULL },
689 /* 200 */ { "Unassigned",                               opaque, NULL },
690 /* 201 */ { "Unassigned",                               opaque, NULL },
691 /* 202 */ { "Unassigned",                               opaque, NULL },
692 /* 203 */ { "Unassigned",                               opaque, NULL },
693 /* 204 */ { "Unassigned",                               opaque, NULL },
694 /* 205 */ { "Unassigned",                               opaque, NULL },
695 /* 206 */ { "Unassigned",                               opaque, NULL },
696 /* 207 */ { "Unassigned",                               opaque, NULL },
697 /* 208 */ { "PXELINUX Magic",                           opaque, NULL },
698 /* 209 */ { "Configuration file",                       opaque, NULL },
699 /* 210 */ { "Authentication",                           special, NULL }, /* Path Prefix rfc5071 */
700 /* 211 */ { "Reboot Time",                              opaque, NULL },
701 /* 212 */ { "Unassigned",                               opaque, NULL },
702 /* 213 */ { "Unassigned",                               opaque, NULL },
703 /* 214 */ { "Unassigned",                               opaque, NULL },
704 /* 215 */ { "Unassigned",                               opaque, NULL },
705 /* 216 */ { "Unassigned",                               opaque, NULL },
706 /* 217 */ { "Unassigned",                               opaque, NULL },
707 /* 218 */ { "Unassigned",                               opaque, NULL },
708 /* 219 */ { "Unassigned",                               opaque, NULL },
709 /* 220 */ { "Subnet Allocation",                        opaque, NULL },
710 /* 221 */ { "Virtual Subnet Selection",                 opaque, NULL },
711 /* 222 */ { "Unassigned",                               opaque, NULL },
712 /* 223 */ { "Unassigned",                               opaque, NULL },
713 /* 224 */ { "Private",                                  opaque, NULL },
714 /* 225 */ { "Private",                                  opaque, NULL },
715 /* 226 */ { "Private",                                  opaque, NULL },
716 /* 227 */ { "Private",                                  opaque, NULL },
717 /* 228 */ { "Private",                                  opaque, NULL },
718 /* 229 */ { "Private",                                  opaque, NULL },
719 /* 230 */ { "Private",                                  opaque, NULL },
720 /* 231 */ { "Private",                                  opaque, NULL },
721 /* 232 */ { "Private",                                  opaque, NULL },
722 /* 233 */ { "Private",                                  opaque, NULL },
723 /* 234 */ { "Private",                                  opaque, NULL },
724 /* 235 */ { "Private",                                  opaque, NULL },
725 /* 236 */ { "Private",                                  opaque, NULL },
726 /* 237 */ { "Private",                                  opaque, NULL },
727 /* 238 */ { "Private",                                  opaque, NULL },
728 /* 239 */ { "Private",                                  opaque, NULL },
729 /* 240 */ { "Private",                                  opaque, NULL },
730 /* 241 */ { "Private",                                  opaque, NULL },
731 /* 242 */ { "Private",                                  opaque, NULL },
732 /* 243 */ { "Private",                                  opaque, NULL },
733 /* 244 */ { "Private",                                  opaque, NULL },
734 /* 245 */ { "Private",                                  opaque, NULL },
735 /* 246 */ { "Private",                                  opaque, NULL },
736 /* 247 */ { "Private",                                  opaque, NULL },
737 /* 248 */ { "Private",                                  opaque, NULL },
738 /* 249 */ { "Private/Classless Static Route (Microsoft)",       special, NULL },
739 /* 250 */ { "Private",                                  opaque, NULL },
740 /* 251 */ { "Private",                                  opaque, NULL },
741 /* 252 */ { "Private/Proxy autodiscovery",                      string, NULL },
742 /* 253 */ { "Private",                                  opaque, NULL },
743 /* 254 */ { "Private",                                  opaque, NULL },
744 /* 255 */ { "End",                                      opaque, NULL }
745 };
746
747 static const char *
748 bootp_get_opt_text(unsigned int idx)
749 {
750         if(idx>=BOOTP_OPT_NUM)
751                 return "unknown";
752         return bootp_opt[idx].text;
753 }
754
755 static const void *
756 bootp_get_opt_data(unsigned int idx)
757 {
758         if(idx>=BOOTP_OPT_NUM)
759                 return NULL;
760         return bootp_opt[idx].data;
761 }
762
763 static enum field_type
764 bootp_get_opt_ftype(unsigned int idx)
765 {
766         if(idx>=BOOTP_OPT_NUM)
767                 return none;
768         return bootp_opt[idx].ftype;
769 }
770
771
772 /* Returns the number of bytes consumed by this option. */
773 static int
774 bootp_option(tvbuff_t *tvb, proto_tree *bp_tree, int voff, int eoff,
775              gboolean first_pass, gboolean *at_end, const char **dhcp_type_p,
776              const guint8 **vendor_class_id_p, guint8 *overload_p)
777 {
778         const char              *text;
779         enum field_type         ftype;
780         guchar                  code = tvb_get_guint8(tvb, voff);
781         int                     optlen;
782         const struct true_false_string *tfs;
783         const value_string      *vs;
784         guchar                  byte;
785         int                     i, consumed;
786         int                     optoff, optleft, optend;
787         gulong                  time_secs;
788         proto_tree              *v_tree, *ft;
789         proto_item              *vti;
790         guint8                  protocol;
791         guint8                  algorithm;
792         guint8                  rdm;
793         guint8                  fqdn_flags;
794         int                     o52voff, o52eoff;
795         gboolean                o52at_end;
796         guint8                  s_option;
797         int                     ava_vid;
798         const guchar            *dns_name;
799
800
801         static const value_string slpda_vals[] = {
802                 {0x00,   "Dynamic Discovery" },
803                 {0x01,   "Static Discovery" },
804                 {0x80,   "Backwards compatibility" },
805                 {0,     NULL     } };
806
807         static const value_string slp_scope_vals[] = {
808                 {0x00,   "Preferred Scope" },
809                 {0x01,   "Mandatory Scope" },
810                 {0,     NULL     } };
811
812         static const value_string authen_protocol_vals[] = {
813                 {AUTHEN_PROTO_CONFIG_TOKEN,   "configuration token" },
814                 {AUTHEN_PROTO_DELAYED_AUTHEN, "delayed authentication" },
815                 {0,                           NULL     } };
816
817         static const value_string authen_da_algo_vals[] = {
818                 {AUTHEN_DELAYED_ALGO_HMAC_MD5, "HMAC_MD5" },
819                 {0,                            NULL     } };
820
821         static const value_string authen_rdm_vals[] = {
822                 {AUTHEN_RDM_MONOTONIC_COUNTER, "Monotonically-increasing counter" },
823                 {0,                            NULL     } };
824
825         static const value_string opt_overload_vals[] = {
826                 { OPT_OVERLOAD_FILE,  "Boot file name holds options",                },
827                 { OPT_OVERLOAD_SNAME, "Server host name holds options",              },
828                 { OPT_OVERLOAD_BOTH,  "Boot file and server host names hold options" },
829                 { 0,                  NULL                                           } };
830
831         /* Options whose length isn't "optlen + 2". */
832         switch (code) {
833
834         case 0:         /* Padding */
835                 /* check how much padding we have */
836                 for (i = voff + 1; i < eoff; i++ ) {
837                         if (tvb_get_guint8(tvb, i) != 0) {
838                                 break;
839                         }
840                 }
841                 i = i - voff;
842                 if (!first_pass) {
843                         if (bp_tree != NULL) {
844                                 proto_tree_add_text(bp_tree, tvb, voff, i,
845                                     "Padding (%d byte%s)", i, (i>1)?"s":"");
846                         }
847                 }
848                 consumed = i;
849                 return consumed;
850
851         case 255:       /* End Option */
852                 if (!first_pass) {
853                         if (bp_tree != NULL) {
854                                 proto_tree_add_text(bp_tree, tvb, voff, 1,
855                                     "End Option%s", *overload_p?" (overload)":"");
856                         }
857                 }
858                 *at_end = TRUE;
859                 consumed = 1;
860                 return consumed;
861         }
862
863         /*
864          * Get the length of the option, and the number of bytes it
865          * consumes (the length doesn't include the option code or
866          * length bytes).
867          *
868          * On the first pass, check first whether we have the length
869          * byte, so that we don't throw an exception; if we throw an
870          * exception in the first pass, which is only checking for options
871          * whose values we need in order to properly dissect the packet
872          * on the second pass, we won't actually dissect the options, so
873          * you won't be able to see which option had the problem.
874          */
875         if (first_pass) {
876                 if (!tvb_bytes_exist(tvb, voff+1, 1)) {
877                         /*
878                          * We don't have the length byte; just return 1
879                          * as the number of bytes we consumed, to count
880                          * the code byte.
881                          */
882                         return 1;
883                 }
884         }
885         optlen = tvb_get_guint8(tvb, voff+1);
886         consumed = optlen + 2;
887
888         /*
889          * In the first pass, we don't put anything into the protocol
890          * tree; we just check for some options we have to look at
891          * in order to properly process the packet:
892          *
893          *      52 (Overload) - we need this to properly dissect the
894          *         file and sname fields
895          *
896          *      53 (DHCP message type) - if this is present, this is DHCP
897          *
898          *      60 (Vendor class identifier) - we need this in order to
899          *         interpret the vendor-specific info
900          *
901          * We also check, before fetching anything, to make sure we
902          * have the entire item we're fetching, so that we don't throw
903          * an exception.
904          */
905         if (first_pass) {
906                 if (tvb_bytes_exist(tvb, voff+2, consumed-2)) {
907                         switch (code) {
908
909                         case 52:
910                                 *overload_p = tvb_get_guint8(tvb, voff+2);
911                                 break;
912
913                         case 53:
914                                 *dhcp_type_p =
915                                     val_to_str(tvb_get_guint8(tvb, voff+2),
916                                         opt53_text,
917                                         "Unknown Message Type (0x%02x)");
918                                 break;
919
920                         case 60:
921                                 *vendor_class_id_p =
922                                     tvb_get_ptr(tvb, voff+2, consumed-2);
923                                 break;
924                         }
925                 }
926
927                 /*
928                  * We don't do anything else here.
929                  */
930                 return consumed;
931         }
932
933         /*
934          * This is the second pass - if there's a protocol tree to be
935          * built, we put stuff into it, otherwise we just return.
936          */
937         if (bp_tree == NULL) {
938                 /* Don't put anything in the protocol tree. */
939                 return consumed;
940         }
941
942         /* Normal cases */
943         text = bootp_get_opt_text(code);
944         ftype = bootp_get_opt_ftype(code);
945
946         optoff = voff+2;
947
948         vti = proto_tree_add_text(bp_tree, tvb, voff, consumed,
949             "Option: (t=%d,l=%d) %s", code, optlen, text);
950         v_tree = proto_item_add_subtree(vti, ett_bootp_option);
951         proto_tree_add_uint_format_value(v_tree, hf_bootp_option_type,
952                 tvb, voff, 1, code, "(%d) %s", code, text);
953         proto_tree_add_item(v_tree, hf_bootp_option_length, tvb, voff+1, 1, FALSE);
954         if (optlen > 0) {
955                 proto_tree_add_item(v_tree, hf_bootp_option_value, tvb, voff+2, optlen, FALSE);
956         }
957
958         /* Special cases */
959         switch (code) {
960
961         case 21:        /* Policy Filter */
962                 if (optlen == 8) {
963                         /* one IP address pair */
964                         proto_item_append_text(vti, " = %s/%s",
965                                 ip_to_str(tvb_get_ptr(tvb, optoff, 4)),
966                                 ip_to_str(tvb_get_ptr(tvb, optoff+4, 4)));
967                 } else {
968                         /* > 1 IP address pair. Let's make a sub-tree */
969                         for (i = optoff, optleft = optlen;
970                             optleft > 0; i += 8, optleft -= 8) {
971                                 if (optleft < 8) {
972                                         proto_tree_add_text(v_tree, tvb, i, optleft,
973                                             "Option length isn't a multiple of 8");
974                                         break;
975                                 }
976                                 proto_tree_add_text(v_tree, tvb, i, 8, "IP Address/Mask: %s/%s",
977                                         ip_to_str(tvb_get_ptr(tvb, i, 4)),
978                                         ip_to_str(tvb_get_ptr(tvb, i+4, 4)));
979                         }
980                 }
981                 break;
982
983         case 33:        /* Static Route */
984                 if (optlen == 8) {
985                         /* one IP address pair */
986                         proto_item_append_text(vti, " = %s/%s",
987                                 ip_to_str(tvb_get_ptr(tvb, optoff, 4)),
988                                 ip_to_str(tvb_get_ptr(tvb, optoff+4, 4)));
989                 } else {
990                         /* > 1 IP address pair. Let's make a sub-tree */
991                         for (i = optoff, optleft = optlen; optleft > 0;
992                             i += 8, optleft -= 8) {
993                                 if (optleft < 8) {
994                                         proto_tree_add_text(v_tree, tvb, i, optleft,
995                                             "Option length isn't a multiple of 8");
996                                         break;
997                                 }
998                                 proto_tree_add_text(v_tree, tvb, i, 8,
999                                         "Destination IP Address/Router: %s/%s",
1000                                         ip_to_str(tvb_get_ptr(tvb, i, 4)),
1001                                         ip_to_str(tvb_get_ptr(tvb, i+4, 4)));
1002                         }
1003                 }
1004                 break;
1005
1006         case 43:        /* Vendor-Specific Info */
1007                 s_option = tvb_get_guint8(tvb, optoff);
1008
1009                 /* Alcatel-Lucent AVA */
1010                 if (optlen == 5 && s_option == 58)
1011                 {
1012                                 proto_item_append_text(vti, " (Alcatel-Lucent AVA)");
1013                                 ava_vid =  tvb_get_ntohs(tvb, optoff + 2);
1014                                 proto_tree_add_text (v_tree, tvb, optoff + 2,
1015                                         2, "Opcode: 58");
1016
1017                                 proto_tree_add_uint (v_tree, hf_bootp_alu_vid, tvb, optoff + 2,
1018                                         2, ava_vid);
1019
1020                                 if (ava_vid == 65535)
1021                                 {
1022                                         proto_tree_add_text (v_tree, tvb, optoff + 2,
1023                                                 2, "Type: Request from ALU IP Phone");
1024                                 } else {
1025                                         proto_tree_add_text (v_tree, tvb, optoff + 2,
1026                                                 2, "Type: Response from DHCP Server");
1027                                 }
1028
1029                                 break;
1030                 }
1031
1032                 /* Alcatel-Lucent DHCP Extensions for Spatial Redundancy */
1033
1034                 if ((optlen == 12 && s_option == 64) ||
1035                         (optlen == 6  && s_option == 64) ||
1036                         (optlen == 6  && s_option == 65))
1037                 {
1038                         if (optlen == 6 && s_option == 64)
1039                         {
1040                                 proto_item_append_text(vti, " (Alcatel-Lucent TFTP Options)");
1041                                 proto_tree_add_text (v_tree, tvb, optoff + 2,
1042                                         2, "Opcode: 64");
1043                                 proto_tree_add_ipv4(v_tree,hf_bootp_alu_tftp1 ,tvb,optoff+2, 4,
1044                                         tvb_get_ipv4(tvb,optoff+2));
1045                         }
1046                         if (optlen == 6 && s_option == 65)
1047                         {
1048                                 proto_item_append_text(vti, " (Alcatel-Lucent TFTP Options)");
1049                                         proto_tree_add_text (v_tree, tvb, optoff + 2,
1050                                         2, "Opcode: 65");
1051                                 proto_tree_add_ipv4(v_tree,hf_bootp_alu_tftp2 ,tvb,optoff+2 ,4,
1052                                         tvb_get_ipv4(tvb,optoff+2));
1053                         }
1054                         if (optlen == 12 && s_option == 64)
1055                         {
1056                                 proto_item_append_text(vti, " (Alcatel-Lucent TFTP Options)");
1057                                 proto_tree_add_text (v_tree, tvb, optoff + 2,
1058                                         2, "Opcode: 64 and 65");
1059                                 proto_tree_add_ipv4(v_tree,hf_bootp_alu_tftp1 ,tvb,optoff+2 ,4,
1060                                         tvb_get_ipv4(tvb,optoff+2));
1061                                 proto_tree_add_ipv4(v_tree,hf_bootp_alu_tftp2 ,tvb,optoff+8 ,4,
1062                                         tvb_get_ipv4(tvb,optoff+8));
1063                         }
1064                         break;
1065                 }
1066
1067
1068
1069                 /* PXE protocol 2.1 as described in the intel specs */
1070                 if (*vendor_class_id_p != NULL &&
1071                     strncmp((const gchar*)*vendor_class_id_p, "PXEClient", strlen("PXEClient")) == 0) {
1072                         proto_item_append_text(vti, " (PXEClient)");
1073                         v_tree = proto_item_add_subtree(vti, ett_bootp_option);
1074
1075                         optend = optoff + optlen;
1076                         while (optoff < optend) {
1077                                 optoff = dissect_vendor_pxeclient_suboption(v_tree,
1078                                         tvb, optoff, optend);
1079                         }
1080                 } else if (*vendor_class_id_p != NULL &&
1081                            ((strncmp((const gchar*)*vendor_class_id_p, "pktc", strlen("pktc")) == 0) ||
1082                             (strncmp((const gchar*)*vendor_class_id_p, "docsis", strlen("docsis")) == 0) ||
1083                             (strncmp((const gchar*)*vendor_class_id_p, "OpenCable2.0", strlen("OpenCable2.0")) == 0) ||
1084                             (strncmp((const gchar*)*vendor_class_id_p, "CableHome", strlen("CableHome")) == 0))) {
1085                         /* CableLabs standard - see www.cablelabs.com/projects */
1086                         proto_item_append_text(vti, " (CableLabs)");
1087
1088                         optend = optoff + optlen;
1089                         while (optoff < optend) {
1090                                 optoff = dissect_vendor_cablelabs_suboption(v_tree,
1091                                         tvb, optoff, optend);
1092                         }
1093                 }
1094                 break;
1095
1096         case 52:        /* Option Overload */
1097                 if (optlen < 1) {
1098                         proto_item_append_text(vti, " length isn't >= 1");
1099                         break;
1100                 }
1101                 byte = tvb_get_guint8(tvb, optoff);
1102                 proto_item_append_text(vti, " = %s",
1103                         val_to_str(byte, opt_overload_vals,
1104                             "Unknown (0x%02x)"));
1105
1106                 /* Just in case we find an option 52 in sname or file */
1107                 if (voff > VENDOR_INFO_OFFSET && byte >= 1 && byte <= 3) {
1108                         if (byte & OPT_OVERLOAD_FILE) {
1109                                 proto_tree_add_text (bp_tree, tvb,
1110                                         FILE_NAME_OFFSET, FILE_NAME_LEN,
1111                                         "Boot file name option overload");
1112                                 o52voff = FILE_NAME_OFFSET;
1113                                 o52eoff = FILE_NAME_OFFSET + FILE_NAME_LEN;
1114                                 o52at_end = FALSE;
1115                                 while (o52voff < o52eoff && !o52at_end) {
1116                                         o52voff += bootp_option(tvb, bp_tree, o52voff,
1117                                                 o52eoff, FALSE, &o52at_end,
1118                                                 dhcp_type_p, vendor_class_id_p,
1119                                                 overload_p);
1120                                 }
1121                         }
1122                         if (byte & OPT_OVERLOAD_SNAME) {
1123                                 proto_tree_add_text (bp_tree, tvb,
1124                                         SERVER_NAME_OFFSET, SERVER_NAME_LEN,
1125                                         "Server host name option overload");
1126                                 o52voff = SERVER_NAME_OFFSET;
1127                                 o52eoff = SERVER_NAME_OFFSET + SERVER_NAME_LEN;
1128                                 o52at_end = FALSE;
1129                                 while (o52voff < o52eoff && !o52at_end) {
1130                                         o52voff += bootp_option(tvb, bp_tree, o52voff,
1131                                                 o52eoff, FALSE, &o52at_end,
1132                                                 dhcp_type_p, vendor_class_id_p,
1133                                                 overload_p);
1134                                 }
1135                         }
1136                         /* The final end option is not in overload */
1137                         *overload_p = 0;
1138                 }
1139                 break;
1140
1141         case 53:        /* DHCP Message Type */
1142                 if (optlen != 1) {
1143                         proto_item_append_text(vti, " length isn't 1");
1144                         break;
1145                 }
1146                 proto_item_append_text(vti, " = DHCP %s",
1147                         val_to_str(tvb_get_guint8(tvb, optoff),
1148                                 opt53_text,
1149                                 "Unknown Message Type (0x%02x)"));
1150                 break;
1151
1152         case 55:        /* Parameter Request List */
1153                 for (i = 0; i < optlen; i++) {
1154                         byte = tvb_get_guint8(tvb, optoff+i);
1155                         proto_tree_add_text(v_tree, tvb, optoff+i, 1, "%d = %s",
1156                                         byte, bootp_get_opt_text(byte));
1157                 }
1158                 break;
1159
1160         case 60:        /* Vendor class identifier */
1161                 /*
1162                  * XXX - RFC 2132 says this is a string of octets;
1163                  * should we check for non-printables?
1164                  */
1165                 proto_item_append_text(vti, " = \"%s\"",
1166                         tvb_format_stringzpad(tvb, optoff, consumed-2));
1167                 if ((tvb_memeql(tvb, optoff, (const guint8*)PACKETCABLE_MTA_CAP10,
1168                                       (int)strlen(PACKETCABLE_MTA_CAP10)) == 0)
1169                     ||
1170                     (tvb_memeql(tvb, optoff, (const guint8*)PACKETCABLE_MTA_CAP15,
1171                                       (int)strlen(PACKETCABLE_MTA_CAP10)) == 0))
1172                 {
1173                         dissect_packetcable_mta_cap(v_tree, tvb, optoff, optlen);
1174                 }
1175                 else {
1176                   if (tvb_memeql(tvb, optoff, (const guint8*)PACKETCABLE_CM_CAP11,
1177                                       (int)strlen(PACKETCABLE_CM_CAP11)) == 0
1178                       ||
1179                       tvb_memeql(tvb, optoff, (const guint8*)PACKETCABLE_CM_CAP20,
1180                                       (int)strlen(PACKETCABLE_CM_CAP20)) == 0 )
1181                   {
1182                         dissect_docsis_cm_cap(v_tree, tvb, optoff, optlen);
1183                   }
1184                 }
1185                 break;
1186
1187         case 61:        /* Client Identifier */
1188         case 97:        /* Client Identifier (UUID) */
1189                 if (optlen > 0)
1190                         byte = tvb_get_guint8(tvb, optoff);
1191                 else
1192                         byte = 0;
1193
1194                 /* We *MAY* use hwtype/hwaddr. If we have 7 bytes, I'll
1195                    guess that the first is the hwtype, and the last 6
1196                    are the hw addr */
1197                 /* See http://www.iana.org/assignments/arp-parameters */
1198                 /* RFC2132 9.14 Client-identifier has the following to say:
1199                    A hardware type of 0 (zero) should be used when the value
1200                    field contains an identifier other than a hardware address
1201                    (e.g. a fully qualified domain name). */
1202
1203                 if (optlen == 7 && byte > 0 && byte < 48) {
1204                         proto_tree_add_text(v_tree, tvb, optoff, 1,
1205                                 "Hardware type: %s",
1206                                 arphrdtype_to_str(byte,
1207                                         "Unknown (0x%02x)"));
1208                         if (byte == ARPHRD_ETHER || byte == ARPHRD_IEEE802)
1209                                 proto_tree_add_item(v_tree,
1210                                     hf_bootp_hw_ether_addr, tvb, optoff+1, 6,
1211                                     FALSE);
1212                         else
1213                                 proto_tree_add_text(v_tree, tvb, optoff+1, 6,
1214                                         "Client hardware address: %s",
1215                                         arphrdaddr_to_str(tvb_get_ptr(tvb, optoff+1, 6),
1216                                         6, byte));
1217                 } else if (optlen == 17 && byte == 0) {
1218                         /* Identifier is a UUID */
1219                         proto_tree_add_item(v_tree, hf_bootp_client_identifier_uuid,
1220                                             tvb, optoff + 1, 16, TRUE);
1221                 } else {
1222                         /* otherwise, it's opaque data */
1223                 }
1224                 break;
1225
1226         case 63:        /* NetWare/IP options (RFC 2242) */
1227
1228                 optend = optoff + optlen;
1229                 while (optoff < optend)
1230                         optoff = dissect_netware_ip_suboption(v_tree, tvb, optoff, optend);
1231                 break;
1232
1233         case 78:        /* SLP Directory Agent Option RFC2610 Added by Greg Morris (gmorris@novell.com)*/
1234                 if (optlen < 1) {
1235                         proto_item_append_text(vti, " length isn't >= 1");
1236                         break;
1237                 }
1238                 optleft = optlen;
1239                 byte = tvb_get_guint8(tvb, optoff);
1240                 proto_item_append_text(vti, " = %s",
1241                                 val_to_str(byte, slpda_vals,
1242                                         "Unknown (0x%02x)"));
1243                 optoff++;
1244                 optleft--;
1245                 if (byte == 0x80) {
1246                         if (optleft == 0)
1247                                 break;
1248                         optoff++;
1249                         optleft--;
1250                 }
1251                 for (i = optoff; optleft > 0; i += 4, optleft -= 4) {
1252                         if (optleft < 4) {
1253                                 proto_tree_add_text(v_tree, tvb, i, optleft,
1254                                     "Option length isn't a multiple of 4");
1255                                 break;
1256                         }
1257                         proto_tree_add_text(v_tree, tvb, i, 4, "SLPDA Address: %s",
1258                             ip_to_str(tvb_get_ptr(tvb, i, 4)));
1259                 }
1260                 break;
1261
1262         case 79:        /* SLP Service Scope Option RFC2610 Added by Greg Morris (gmorris@novell.com)*/
1263                 byte = tvb_get_guint8(tvb, optoff);
1264                 proto_item_append_text(vti, " = %s",
1265                                 val_to_str(byte, slp_scope_vals,
1266                                     "Unknown (0x%02x)"));
1267                 optoff++;
1268                 optleft = optlen - 1;
1269                 proto_tree_add_text(v_tree, tvb, optoff, optleft,
1270                     "%s = \"%s\"", text,
1271                     tvb_format_stringzpad(tvb, optoff, optleft));
1272                 break;
1273
1274         case 81:        /* Client Fully Qualified Domain Name */
1275                 if (optlen < 3) {
1276                         proto_item_append_text(vti, " length isn't >= 3");
1277                         break;
1278                 }
1279                 fqdn_flags = tvb_get_guint8(tvb, optoff);
1280                 ft = proto_tree_add_text(v_tree, tvb, optoff, 1, "Flags: 0x%02x", fqdn_flags);
1281                 proto_tree_add_item(v_tree, hf_bootp_fqdn_mbz, tvb, optoff, 1, FALSE);
1282                 proto_tree_add_item(v_tree, hf_bootp_fqdn_n, tvb, optoff, 1, FALSE);
1283                 proto_tree_add_item(v_tree, hf_bootp_fqdn_e, tvb, optoff, 1, FALSE);
1284                 proto_tree_add_item(v_tree, hf_bootp_fqdn_o, tvb, optoff, 1, FALSE);
1285                 proto_tree_add_item(v_tree, hf_bootp_fqdn_s, tvb, optoff, 1, FALSE);
1286                 /* XXX: use code from packet-dns for return code decoding */
1287                 proto_tree_add_item(v_tree, hf_bootp_fqdn_rcode1, tvb, optoff+1, 1, FALSE);
1288                 /* XXX: use code from packet-dns for return code decoding */
1289                 proto_tree_add_item(v_tree, hf_bootp_fqdn_rcode2, tvb, optoff+2, 1, FALSE);
1290                 if (optlen > 3) {
1291                         if (fqdn_flags & F_FQDN_E) {
1292                                 get_dns_name(tvb, optoff+3, optlen-3, optoff+3, &dns_name);
1293                                 proto_tree_add_string(v_tree, hf_bootp_fqdn_name, 
1294                                     tvb, optoff+3, optlen-3, dns_name);
1295                         } else {
1296                                 proto_tree_add_item(v_tree, hf_bootp_fqdn_asciiname,
1297                                     tvb, optoff+3, optlen-3, FALSE);
1298                         }
1299                 }
1300                 break;
1301
1302         case 82:        /* Relay Agent Information Option */
1303                 optend = optoff + optlen;
1304                 while (optoff < optend)
1305                         optoff = bootp_dhcp_decode_agent_info(v_tree, tvb, optoff, optend);
1306                 break;
1307
1308         case 85:        /* Novell Servers (RFC 2241) */
1309                 /* Option 85 can be sent as a string */
1310                 /* Added by Greg Morris (gmorris[AT]novell.com) */
1311                 if (novell_string) {
1312                         proto_item_append_text(vti, " = \"%s\"",
1313                             tvb_format_stringzpad(tvb, optoff, optlen));
1314                 } else {
1315                         if (optlen == 4) {
1316                                 /* one IP address */
1317                                 proto_item_append_text(vti, " = %s",
1318                                         ip_to_str(tvb_get_ptr(tvb, optoff, 4)));
1319                         } else {
1320                                 /* > 1 IP addresses. Let's make a sub-tree */
1321                                 for (i = optoff, optleft = optlen; optleft > 0;
1322                                     i += 4, optleft -= 4) {
1323                                         if (optleft < 4) {
1324                                                 proto_tree_add_text(v_tree, tvb, i, optleft,
1325                                                     "Option length isn't a multiple of 4");
1326                                                 break;
1327                                         }
1328                                         proto_tree_add_text(v_tree, tvb, i, 4, "IP Address: %s",
1329                                                 ip_to_str(tvb_get_ptr(tvb, i, 4)));
1330                                 }
1331                         }
1332                 }
1333                 break;
1334
1335         case 94: {      /* Client network interface identifier */
1336                 guint8 id_type;
1337
1338                 id_type = tvb_get_guint8(tvb, optoff);
1339
1340                 if (id_type == 0x01) {
1341                         proto_tree_add_item(v_tree, hf_bootp_client_network_id_major_ver,
1342                                             tvb, optoff + 1, 1, TRUE);
1343                         proto_tree_add_item(v_tree, hf_bootp_client_network_id_minor_ver,
1344                                             tvb, optoff + 2, 1, TRUE);
1345                 }
1346
1347                 break;
1348         }
1349
1350         case 90:        /* DHCP Authentication */
1351         case 210:       /* Was this used for authentication at one time? */
1352                 if (optlen < 11) {
1353                         proto_item_append_text(vti, " length isn't >= 11");
1354                         break;
1355                 }
1356                 optleft = optlen;
1357                 protocol = tvb_get_guint8(tvb, optoff);
1358                 proto_tree_add_text(v_tree, tvb, optoff, 1, "Protocol: %s (%u)",
1359                                     val_to_str(protocol, authen_protocol_vals, "Unknown"),
1360                                     protocol);
1361                 optoff++;
1362                 optleft--;
1363
1364                 algorithm = tvb_get_guint8(tvb, optoff);
1365                 switch (protocol) {
1366
1367                 case AUTHEN_PROTO_DELAYED_AUTHEN:
1368                         proto_tree_add_text(v_tree, tvb, optoff, 1,
1369                                     "Algorithm: %s (%u)",
1370                                     val_to_str(algorithm, authen_da_algo_vals, "Unknown"),
1371                                     algorithm);
1372                         break;
1373
1374                 default:
1375                         proto_tree_add_text(v_tree, tvb, optoff, 1,
1376                                     "Algorithm: %u", algorithm);
1377                         break;
1378                 }
1379                 optoff++;
1380                 optleft--;
1381
1382                 rdm = tvb_get_guint8(tvb, optoff);
1383                 proto_tree_add_text(v_tree, tvb, optoff, 1,
1384                                     "Replay Detection Method: %s (%u)",
1385                                     val_to_str(rdm, authen_rdm_vals, "Unknown"),
1386                                     rdm);
1387                 optoff++;
1388                 optleft--;
1389
1390                 switch (rdm) {
1391
1392                 case AUTHEN_RDM_MONOTONIC_COUNTER:
1393                         proto_tree_add_text(v_tree, tvb, optoff, 8,
1394                                     "RDM Replay Detection Value: %" G_GINT64_MODIFIER "x",
1395                                     tvb_get_ntoh64(tvb, optoff));
1396                         break;
1397
1398                 default:
1399                         proto_tree_add_text(v_tree, tvb, optoff, 8,
1400                                     "Replay Detection Value: %s",
1401                                     tvb_bytes_to_str(tvb, optoff, 8));
1402                         break;
1403                 }
1404                 optoff += 8;
1405                 optleft -= 8;
1406
1407                 switch (protocol) {
1408
1409                 case AUTHEN_PROTO_DELAYED_AUTHEN:
1410                         switch (algorithm) {
1411
1412                         case AUTHEN_DELAYED_ALGO_HMAC_MD5:
1413                                 if (*dhcp_type_p && !strcmp(*dhcp_type_p, OPT53_DISCOVER)) {
1414                                         /* Discover has no Secret ID nor HMAC MD5 Hash */
1415                                         break;
1416                                 } else {
1417                                         if (optlen < 31) {
1418                                                 proto_item_append_text(vti,
1419                                                         " length isn't >= 31");
1420                                                 break;
1421                                         }
1422                                         proto_tree_add_text(v_tree, tvb, optoff, 4,
1423                                                 "Secret ID: 0x%08x",
1424                                                 tvb_get_ntohl(tvb, optoff));
1425                                         optoff += 4;
1426                                         optleft -= 4;
1427                                         proto_tree_add_text(v_tree, tvb, optoff, 16,
1428                                                 "HMAC MD5 Hash: %s",
1429                                                 tvb_bytes_to_str(tvb, optoff, 16));
1430                                         break;
1431                                 }
1432
1433                         default:
1434                                 if (optleft == 0)
1435                                         break;
1436                                 proto_tree_add_text(v_tree, tvb, optoff, optleft,
1437                                         "Authentication Information: %s",
1438                                         tvb_bytes_to_str(tvb, optoff, optleft));
1439                                 break;
1440                         }
1441                         break;
1442
1443                 default:
1444                         if (optleft == 0)
1445                                 break;
1446                         proto_tree_add_text(v_tree, tvb, optoff, optleft,
1447                                 "Authentication Information: %s",
1448                                 tvb_bytes_to_str(tvb, optoff, optleft));
1449                         break;
1450                 }
1451                 break;
1452
1453         case 99: /* civic location (RFC 4776) */
1454
1455                 optleft = optlen;
1456                 if (optleft >= 3)
1457                 {
1458                         proto_tree_add_text(v_tree, tvb, optoff, 1, "What: %d (%s)",
1459                                 tvb_get_guint8(tvb, optoff), val_to_str(tvb_get_guint8(tvb, optoff),
1460                                 civic_address_what_values, "Unknown") );
1461                         proto_tree_add_text(v_tree, tvb, optoff + 1, 2, "Country: \"%s\"",
1462                                 tvb_format_text(tvb, optoff + 1, 2) );
1463                         optleft = optleft - 3;
1464                         optoff = optoff + 3;
1465
1466                         while (optleft >= 2)
1467                         {
1468                                 int catype = tvb_get_guint8(tvb, optoff);
1469                                 optoff++;
1470                                 optleft--;
1471                                 s_option = tvb_get_guint8(tvb, optoff);
1472                                 optoff++;
1473                                 optleft--;
1474
1475                                 if (s_option == 0)
1476                                 {
1477                                         proto_tree_add_text(v_tree, tvb, optoff, s_option,
1478                                                 "CAType %d [%s] (l=%d): EMTPY", catype,
1479                                                 val_to_str(catype, civic_address_type_values,
1480                                                 "Unknown"), s_option);
1481                                         continue;
1482                                 }
1483
1484                                 if (optleft >= s_option)
1485                                 {
1486                                         proto_tree_add_text(v_tree, tvb, optoff, s_option,
1487                                                 "CAType %d [%s] (l=%d): \"%s\"", catype,
1488                                                 val_to_str(catype, civic_address_type_values,
1489                                                 "Unknown"), s_option,
1490                                                 tvb_format_text(tvb, optoff, s_option));
1491                                         optoff = optoff + s_option;
1492                                         optleft = optleft - s_option;
1493                                 }
1494                                 else
1495                                 {
1496                                         optleft = 0;
1497                                         proto_tree_add_text(v_tree, tvb, optoff, s_option,
1498                                                 "Error with CAType");
1499                                 }
1500                         }
1501                 }
1502
1503                 break;
1504
1505         case 121:       /* Classless Static Route */
1506         case 249: {     /* Classless Static Route (Microsoft) */
1507                 int mask_width, significant_octets;
1508                 optend = optoff + optlen;
1509                 /* minimum length is 5 bytes */
1510                 if (optlen < 5) {
1511                         proto_item_append_text(vti, " [ERROR: Option length < 5 bytes]");
1512                         break;
1513                 }
1514                 while (optoff < optend) {
1515                         mask_width = tvb_get_guint8(tvb, optoff);
1516                         /* mask_width <= 32 */
1517                         if (mask_width > 32) {
1518                                 proto_tree_add_text(v_tree, tvb, optoff,
1519                                         optend - optoff,
1520                                         "Subnet/MaskWidth-Router: [ERROR: Mask width (%d) > 32]",
1521                                         mask_width);
1522                                 break;
1523                         }
1524                         significant_octets = (mask_width + 7) / 8;
1525                         vti = proto_tree_add_text(v_tree, tvb, optoff,
1526                                 1 + significant_octets + 4,
1527                                 "Subnet/MaskWidth-Router: ");
1528                         optoff++;
1529                         /* significant octets + router(4) */
1530                         if (optend < optoff + significant_octets + 4) {
1531                                 proto_item_append_text(vti, "[ERROR: Remaining length (%d) < %d bytes]",
1532                                         optend - optoff, significant_octets + 4);
1533                                 break;
1534                         }
1535                         if(mask_width == 0)
1536                                 proto_item_append_text(vti, "default");
1537                         else {
1538                                 for(i = 0 ; i < significant_octets ; i++) {
1539                                         if (i > 0)
1540                                                 proto_item_append_text(vti, ".");
1541                                         byte = tvb_get_guint8(tvb, optoff++);
1542                                         proto_item_append_text(vti, "%d", byte);
1543                                 }
1544                                 for(i = significant_octets ; i < 4 ; i++)
1545                                         proto_item_append_text(vti, ".0");
1546                                 proto_item_append_text(vti, "/%d", mask_width);
1547                         }
1548                         proto_item_append_text(vti, "-%s",
1549                             ip_to_str(tvb_get_ptr(tvb, optoff, 4)));
1550                         optoff += 4;
1551                 }
1552                 break;
1553         }
1554
1555         case 123: /* coordinate based location RFC 3825 */
1556                 if (optlen == 16) {
1557                         int c;
1558                         unsigned char lci[16];
1559                         struct rfc3825_location_fixpoint_t location_fp;
1560                         struct rfc3825_location_decimal_t location;
1561
1562                         for (c=0; c < 16;c++)
1563                                 lci[c] = (unsigned char) tvb_get_guint8(tvb, optoff + c);
1564
1565                         /* convert lci encoding into fixpoint location */
1566                         rfc3825_lci_to_fixpoint(lci, &location_fp);
1567
1568                         /* convert location from decimal to fixpoint */
1569                         i = rfc3825_fixpoint_to_decimal(&location_fp, &location);
1570
1571                         if (i != RFC3825_NOERROR) {
1572                                 proto_tree_add_text(v_tree, tvb, optoff, optlen, "Error: %s", val_to_str(i, rfc3825_error_types, "Unknown"));
1573                         } else {
1574                                 proto_tree_add_text(v_tree, tvb, optoff, 5, "Latitude: %15.10f", location.latitude);
1575                                 proto_tree_add_text(v_tree, tvb, optoff+5, 5, "Longitude: %15.10f", location.longitude);
1576                                 proto_tree_add_text(v_tree, tvb, optoff, 1, "Latitude resolution: %15.10f", location.latitude_res);
1577                                 proto_tree_add_text(v_tree, tvb, optoff+5, 1, "Longitude resolution: %15.10f", location.longitude_res);
1578                                 proto_tree_add_text(v_tree, tvb, optoff+12, 4, "Altitude: %15.10f", location.altitude);
1579                                 proto_tree_add_text(v_tree, tvb, optoff+10, 2, "Altitude resolution: %15.10f", location.altitude_res);
1580                                 proto_tree_add_text(v_tree, tvb, optoff+10, 1, "Altitude type: %s (%d)", val_to_str(location.altitude_type, altitude_type_values, "Unknown"), location.altitude_type);
1581                                 proto_tree_add_text(v_tree, tvb, optoff+15, 1, "Map Datum: %s (%d)", val_to_str(location.datum_type, map_datum_type_values, "Unknown"), location.datum_type);
1582                         }
1583                 } else {
1584                         proto_tree_add_text(v_tree, tvb, optoff, optlen, "Error: Invalid length of DHCP option!");
1585                 }
1586                 break;
1587
1588         case 125: {     /* V-I Vendor-specific Information */
1589                 int enterprise = 0;
1590                 int s_end = 0;
1591                 int s_option_len = 0;
1592                 proto_tree *e_tree = 0;
1593
1594                 optend = optoff + optlen;
1595
1596                 optleft = optlen;
1597
1598                 while (optleft > 0) {
1599
1600                   if (optleft < 5) {
1601                     proto_tree_add_text(v_tree, tvb, optoff,
1602                                         optleft, "Vendor-specific Information: malformed option");
1603                     break;
1604                   }
1605
1606                   enterprise = tvb_get_ntohl(tvb, optoff);
1607
1608                   vti = proto_tree_add_text(v_tree, tvb, optoff, 4,
1609                                             "Enterprise-number: %s-%u",
1610                                             val_to_str( enterprise, sminmpec_values, "Unknown"),
1611                                             enterprise);
1612
1613                   s_option_len = tvb_get_guint8(tvb, optoff + 4);
1614
1615                   optoff += 5;
1616                   optleft -= 5;
1617
1618                   /* Handle DSL Forum TR-111 Option 125 */
1619                   if ( enterprise == 3561 ) {
1620
1621                     s_end = optoff + s_option_len;
1622                     if ( s_end > optend ) {
1623                       proto_tree_add_text(v_tree, tvb, optoff, 1,
1624                                           "no room left in option for enterprise %u data", enterprise);
1625                       break;
1626                     }
1627
1628
1629                     e_tree = proto_item_add_subtree(vti, ett_bootp_option);
1630                     while (optoff < s_end) {
1631
1632                       optoff = dissect_vendor_tr111_suboption(e_tree,
1633                                                                  tvb, optoff, s_end);
1634                     }
1635                   } else if ( enterprise == 4491 ) {
1636
1637                     s_end = optoff + s_option_len;
1638                     if ( s_end > optend ) {
1639                       proto_tree_add_text(v_tree, tvb, optoff, 1,
1640                                           "no room left in option for enterprise %u data", enterprise);
1641                       break;
1642                     }
1643
1644
1645                     e_tree = proto_item_add_subtree(vti, ett_bootp_option);
1646                     while (optoff < s_end) {
1647
1648                       optoff = dissect_vendor_cl_suboption(e_tree,
1649                                                                  tvb, optoff, s_end);
1650                     }
1651                   } else {
1652
1653                     /* skip over the data and look for next enterprise number */
1654                     optoff += s_option_len;
1655                   }
1656
1657                   optleft -= s_option_len;
1658
1659                 }
1660                 break;
1661         }
1662
1663         default:        /* not special */
1664                 /* The PacketCable CCC option number can vary.  If this is a CCC option,
1665                    handle it as a special.
1666                  */
1667                 if (code == pkt_ccc_option) {
1668                         ftype = special;
1669                         proto_item_append_text(vti,
1670                                 "CableLabs Client Configuration (%d bytes)",
1671                                 optlen);
1672                         optend = optoff + optlen;
1673                         while (optoff < optend) {
1674                                 switch (pkt_ccc_protocol_version) {
1675
1676                                 case PACKETCABLE_CCC_I05:
1677                                         optoff = dissect_packetcable_i05_ccc(v_tree, tvb, optoff, optend);
1678                                         break;
1679                                 case PACKETCABLE_CCC_DRAFT5:
1680                                 case PACKETCABLE_CCC_RFC_3495:
1681                                         optoff = dissect_packetcable_ietf_ccc(v_tree, tvb, optoff, optend, pkt_ccc_protocol_version);
1682                                         break;
1683                                 default: /* XXX Should we do something here? */
1684                                         break;
1685                                 }
1686                         }
1687                 }
1688
1689                 break;
1690         }
1691
1692         switch (ftype) {
1693
1694         case ipv4:
1695                 if (optlen != 4) {
1696                         proto_item_append_text(vti,
1697                             " - length isn't 4");
1698                         break;
1699                 }
1700                 proto_item_append_text(vti, " = %s",
1701                         ip_to_str(tvb_get_ptr(tvb, optoff, 4)));
1702                 break;
1703
1704         case ipv4_list:
1705                 if (optlen == 4) {
1706                         /* one IP address */
1707                         proto_item_append_text(vti, " = %s",
1708                                 ip_to_str(tvb_get_ptr(tvb, optoff, 4)));
1709                 } else {
1710                         /* > 1 IP addresses. Let's make a sub-tree */
1711                         for (i = optoff, optleft = optlen; optleft > 0;
1712                             i += 4, optleft -= 4) {
1713                                 if (optleft < 4) {
1714                                         proto_tree_add_text(v_tree, tvb, i, voff + consumed - i,
1715                                             "Option length isn't a multiple of 4");
1716                                         break;
1717                                 }
1718                                 proto_tree_add_text(v_tree, tvb, i, 4, "IP Address: %s",
1719                                         ip_to_str(tvb_get_ptr(tvb, i, 4)));
1720                         }
1721                 }
1722                 break;
1723
1724         case string:
1725                 /* Fix for non null-terminated string supplied by
1726                  * John Lines <John.Lines[AT]aeat.co.uk>
1727                  */
1728                 proto_item_append_text(vti, " = \"%s\"",
1729                                 tvb_format_stringzpad(tvb, optoff, consumed-2));
1730                 break;
1731
1732         case val_boolean:
1733                 if (optlen != 1) {
1734                         proto_item_append_text(vti,
1735                             " - length isn't 1");
1736                         break;
1737                 }
1738                 tfs = (const struct true_false_string *) bootp_get_opt_data(code);
1739                 if(tfs){
1740                         i = tvb_get_guint8(tvb, optoff);
1741                         if (i != 0 && i != 1) {
1742                                 proto_item_append_text(vti,
1743                                     " = Invalid Value %d", i);
1744                         } else {
1745                                 proto_item_append_text(vti, " = %s",
1746                                         i == 0 ? tfs->false_string : tfs->true_string);
1747                         }
1748                 }
1749                 break;
1750
1751         case val_u_byte:
1752                 if (optlen != 1) {
1753                         proto_item_append_text(vti,
1754                             " - length isn't 1");
1755                         break;
1756                 }
1757                 vs = (const value_string *) bootp_get_opt_data(code);
1758                 byte = tvb_get_guint8(tvb, optoff);
1759                 if (vs != NULL) {
1760                         proto_item_append_text(vti, " = %s",
1761                             val_to_str(byte, vs, "Unknown (%u)"));
1762                 } else
1763                         proto_item_append_text(vti, " = %u", byte);
1764                 break;
1765
1766         case val_u_short: {
1767                 gushort vd;
1768
1769                 if (optlen != 2) {
1770                         proto_item_append_text(vti,
1771                             " - length isn't 2");
1772                         break;
1773                 }
1774
1775                 vs = (const value_string *) bootp_get_opt_data(code);
1776                 vd = tvb_get_ntohs(tvb, optoff);
1777
1778                 if (vs != NULL) {
1779                         proto_item_append_text(vti, " = %s",
1780                             val_to_str(vd, vs, "Unknown (%u)"));
1781                 } else
1782                         proto_item_append_text(vti, " = %u", vd);
1783
1784                 break;
1785         }
1786
1787         case val_u_short_list:
1788                 if (optlen == 2) {
1789                         /* one gushort */
1790                         proto_item_append_text(vti, " = %u",
1791                             tvb_get_ntohs(tvb, optoff));
1792                 } else {
1793                         /* > 1 gushort */
1794                         for (i = optoff, optleft = optlen; optleft > 0;
1795                             i += 2, optleft -= 2) {
1796                                 if (optleft < 2) {
1797                                         proto_tree_add_text(v_tree, tvb, i, voff + consumed - i,
1798                                             "Option length isn't a multiple of 2");
1799                                         break;
1800                                 }
1801                                 proto_tree_add_text(v_tree, tvb, i, 4, "Value: %u",
1802                                         tvb_get_ntohs(tvb, i));
1803                         }
1804                 }
1805                 break;
1806
1807         case val_u_long:
1808                 if (optlen != 4) {
1809                         proto_item_append_text(vti,
1810                             " - length isn't 4");
1811                         break;
1812                 }
1813                 proto_item_append_text(vti, " = %u",
1814                     tvb_get_ntohl(tvb, optoff));
1815                 break;
1816
1817         case time_in_secs:
1818                 if (optlen != 4) {
1819                         proto_item_append_text(vti,
1820                             " - length isn't 4");
1821                         break;
1822                 }
1823                 time_secs = tvb_get_ntohl(tvb, optoff);
1824                 proto_item_append_text(vti, " = %s",
1825                     ((time_secs == 0xffffffff) ?
1826                       "infinity" :
1827                       time_secs_to_str_unsigned(time_secs)));
1828                 break;
1829
1830         default:
1831                 break;
1832         }
1833
1834         return consumed;
1835 }
1836
1837 static int
1838 bootp_dhcp_decode_agent_info(proto_tree *v_tree, tvbuff_t *tvb, int optoff,
1839     int optend)
1840 {
1841         int suboptoff = optoff;
1842         guint8 subopt, vs_opt, vs_len;
1843         int subopt_len, datalen;
1844         guint32 enterprise;
1845         proto_item *vti;
1846         proto_tree *subtree = 0;
1847         guint8 tag, tag_len;
1848         
1849         subopt = tvb_get_guint8(tvb, optoff);
1850         suboptoff++;
1851
1852         if (suboptoff >= optend) {
1853                 proto_tree_add_text(v_tree, tvb, optoff, 1,
1854                         "Suboption %d: no room left in option for suboption length",
1855                         subopt);
1856                 return (optend);
1857         }
1858         subopt_len = tvb_get_guint8(tvb, suboptoff);
1859         suboptoff++;
1860
1861         if (suboptoff+subopt_len > optend) {
1862                 proto_tree_add_text(v_tree, tvb, optoff, optend-optoff,
1863                         "Suboption %d: no room left in option for suboption value",
1864                         subopt);
1865                 return (optend);
1866         }
1867         switch (subopt) {
1868
1869         case 1: /* 1   Agent Circuit ID Sub-option            [RFC3046] */
1870                 proto_tree_add_text(v_tree, tvb, optoff, subopt_len + 2,
1871                                     "Agent Circuit ID: %s",
1872                                     tvb_bytes_to_str(tvb, suboptoff, subopt_len));
1873                 break;
1874
1875         case 2: /* 2   Agent Remote ID Sub-option             [RFC3046] */
1876                 proto_tree_add_text(v_tree, tvb, optoff, subopt_len + 2,
1877                                     "Agent Remote ID: %s",
1878                                     tvb_bytes_to_str(tvb, suboptoff, subopt_len));
1879                 break;
1880
1881         case 3:
1882                 proto_tree_add_text(v_tree, tvb, optoff, subopt_len + 2,
1883                                     "Reserved: %s",
1884                                     tvb_bytes_to_str(tvb, suboptoff, subopt_len));
1885                 break;
1886
1887         case 4: /* 4   DOCSIS Device Class Suboption          [RFC3256] */
1888                 proto_tree_add_text(v_tree, tvb, optoff, subopt_len + 2,
1889                                     "DOCSIS Device Class: %s",
1890                                     tvb_bytes_to_str(tvb, suboptoff, subopt_len));
1891                 break;
1892
1893         case 5: /* 5   Link selection Sub-option              [RFC3527] */
1894                 proto_tree_add_text(v_tree, tvb, optoff, subopt_len + 2,
1895                                     "Link selection: %s",
1896                                         ip_to_str(tvb_get_ptr(tvb, suboptoff, subopt_len)));
1897                 break;
1898
1899         case 6: /*Subscriber-ID Suboption                [RFC3993] */
1900                 proto_tree_add_text(v_tree, tvb, optoff, subopt_len + 2,
1901                                         "Subscriber ID: %s",
1902                                         tvb_bytes_to_str(tvb, suboptoff, subopt_len));
1903                 break;
1904
1905         case 7: /* 7   RADIUS Attributes Sub-option           [RFC4014] */
1906                 proto_tree_add_text(v_tree, tvb, optoff, subopt_len + 2,
1907                                         "RADIUS Attributes: %s",
1908                                         tvb_bytes_to_str(tvb, suboptoff, subopt_len));
1909                 break;
1910
1911         case 8: /* 8   Authentication Suboption               [RFC4030]  */
1912                 proto_tree_add_text(v_tree, tvb, optoff, subopt_len + 2,
1913                                         "Authentication: %s",
1914                                         tvb_bytes_to_str(tvb, suboptoff, subopt_len));
1915                 break;
1916
1917         case 9: /* Vendor-Specific Information Suboption    [RFC 4243] */
1918                 while (suboptoff < optend) {
1919                         enterprise = tvb_get_ntohl(tvb, suboptoff);
1920                         vti = proto_tree_add_text(v_tree, tvb, suboptoff, 4,
1921                                             "Enterprise-number: %s-%u",
1922                                             val_to_str( enterprise, sminmpec_values, "Unknown"),
1923                                             enterprise);
1924                         suboptoff += 4;
1925
1926                         if ( enterprise == 4491 ) {
1927                                 subtree = proto_item_add_subtree(vti, ett_bootp_option);
1928                                 vs_opt = tvb_get_guint8(tvb, suboptoff);
1929                                 suboptoff++;
1930                                 vs_len = tvb_get_guint8(tvb, suboptoff);
1931                                 suboptoff++;
1932
1933                                 switch (vs_opt) {
1934
1935                                 case 1:
1936                                         if (vs_len == 4) {
1937                                                 tag = tvb_get_guint8(tvb, suboptoff);
1938                                                 tag_len = tvb_get_guint8(tvb, suboptoff+1);
1939                                                 suboptoff+=2;
1940                                                 if (tag == 1) {
1941                                                         proto_tree_add_text(subtree, tvb, suboptoff, vs_len,
1942                                                             "DOCSIS Version Number %d.%d",
1943                                                             tvb_get_guint8(tvb, suboptoff),
1944                                                             tvb_get_guint8(tvb, suboptoff+1));
1945                                                         suboptoff+=2;
1946                                                 } else {
1947                                                         proto_tree_add_text(subtree, tvb, suboptoff, vs_len,
1948                                                             "Unknown tag=%u %s (%d byte%s)", tag, 
1949                                                             tvb_bytes_to_str(tvb, suboptoff, tag_len),
1950                                                             tag_len, plurality(tag_len, "", "s"));
1951                                                         suboptoff += tag_len;
1952                                                 }
1953                                         }
1954                                         break;
1955
1956                                 default:
1957                                         proto_tree_add_text(subtree, tvb, suboptoff, vs_len,
1958                                             "Invalid suboption %d (%d byte%s)",
1959                                             vs_opt, vs_len, plurality(vs_len, "", "s"));
1960                                         break;
1961                                 }
1962                         } else {
1963                                 datalen = tvb_get_guint8(tvb, suboptoff);
1964                                 proto_tree_add_text(v_tree, tvb, suboptoff, 1,
1965                                     "Data Length: %u", datalen);
1966                                 suboptoff++;
1967
1968                                 proto_tree_add_text(v_tree, tvb, suboptoff, datalen,
1969                                     "Suboption Data: %s", tvb_bytes_to_str(tvb, suboptoff, datalen));
1970                                 suboptoff += datalen;
1971                         }
1972                 }
1973                 break;
1974
1975         case 10: /* 10   Relay Agent Flags                      [RFC5010] */
1976                 proto_tree_add_text(v_tree, tvb, optoff, subopt_len + 2,
1977                                         "Flags: %s",
1978                                         tvb_bytes_to_str(tvb, suboptoff, subopt_len));
1979                 break;
1980
1981         case 11: /* Server Identifier Override Suboption     [RFC 5107] */
1982                 if (subopt_len == 4) {
1983                         proto_tree_add_text(v_tree, tvb, optoff, subopt_len + 2,
1984                                 "Server ID Override: %s",
1985                                 ip_to_str(tvb_get_ptr(tvb, suboptoff, 4)));
1986                 } else {
1987                         proto_tree_add_text(v_tree, tvb, optoff, subopt_len + 2,
1988                                 "Server ID Override: Invalid length (%d instead of 4)",
1989                                 subopt_len);
1990                 }
1991                 break;
1992
1993         default:
1994                 proto_tree_add_text(v_tree, tvb, optoff, subopt_len + 2,
1995                                     "Unknown agent suboption %d (%d bytes)",
1996                                     subopt, subopt_len);
1997                 break;
1998         }
1999         optoff += (subopt_len + 2);
2000         return optoff;
2001 }
2002
2003 static int
2004 dissect_vendor_pxeclient_suboption(proto_tree *v_tree, tvbuff_t *tvb,
2005     int optoff, int optend)
2006 {
2007         int suboptoff = optoff;
2008         guint8 subopt;
2009         guint8 subopt_len;
2010         int suboptleft;
2011         proto_tree *o43pxeclient_v_tree;
2012         proto_item *vti;
2013
2014         static struct opt_info o43pxeclient_opt[]= {
2015                 /* 0 */ {"nop", special, NULL}, /* dummy */
2016                 /* 1 */ {"PXE mtftp IP", ipv4_list, NULL},
2017                 /* 2 */ {"PXE mtftp client port", val_u_le_short, NULL},
2018                 /* 3 */ {"PXE mtftp server port",val_u_le_short, NULL},
2019                 /* 4 */ {"PXE mtftp timeout", val_u_byte, NULL},
2020                 /* 5 */ {"PXE mtftp delay", val_u_byte, NULL},
2021                 /* 6 */ {"PXE discovery control", val_u_byte, NULL},
2022                         /*
2023                          * Correct: b0 (lsb): disable broadcast discovery
2024                          *      b1: disable multicast discovery
2025                          *      b2: only use/accept servers in boot servers
2026                          *      b3: download bootfile without prompt/menu/disc
2027                          */
2028                 /* 7 */ {"PXE multicast address", ipv4_list, NULL},
2029                 /* 8 */ {"PXE boot servers", special, NULL},
2030                 /* 9 */ {"PXE boot menu", special, NULL},
2031                 /* 10 */ {"PXE menu prompt", special, NULL},
2032                 /* 11 */ {"PXE multicast address alloc", special, NULL},
2033                 /* 12 */ {"PXE credential types", special, NULL},
2034                 /* 71 {"PXE boot item", special, NULL}, */
2035                 /* 255 {"PXE end options", special, NULL} */
2036         };
2037
2038         subopt = tvb_get_guint8(tvb, suboptoff);
2039         suboptoff++;
2040
2041         if (subopt == 0) {
2042                 proto_tree_add_text(v_tree, tvb, optoff, 1, "Padding");
2043                 return (suboptoff);
2044         } else if (subopt == 255) {     /* End Option */
2045                 proto_tree_add_text(v_tree, tvb, optoff, 1, "End PXEClient option");
2046                 /* Make sure we skip any junk left this option */
2047                 return (optend);
2048         }
2049
2050         if (suboptoff >= optend) {
2051                 proto_tree_add_text(v_tree, tvb, optoff, 1,
2052                         "Suboption %d: no room left in option for suboption length",
2053                         subopt);
2054                 return (optend);
2055         }
2056         subopt_len = tvb_get_guint8(tvb, suboptoff);
2057         suboptoff++;
2058
2059         if (suboptoff+subopt_len > optend) {
2060                 proto_tree_add_text(v_tree, tvb, optoff, optend-optoff,
2061                         "Suboption %d: no room left in option for suboption value",
2062                         subopt);
2063                 return (optend);
2064         }
2065         if ( subopt == 71 ) {   /* 71 {"PXE boot item", special} */
2066                 /* case special */
2067                 /* I may need to decode that properly one day */
2068                 proto_tree_add_text(v_tree, tvb, optoff, subopt_len+2,
2069                         "Suboption %d: %s (%d byte%s)" ,
2070                         subopt, "PXE boot item",
2071                         subopt_len, plurality(subopt_len, "", "s"));
2072         } else if ((subopt < 1) || (subopt >= array_length(o43pxeclient_opt))) {
2073                 proto_tree_add_text(v_tree, tvb, optoff, subopt_len+2,
2074                         "Unknown suboption %d (%d byte%s)", subopt, subopt_len,
2075                         plurality(subopt_len, "", "s"));
2076         } else {
2077                 switch (o43pxeclient_opt[subopt].ftype) {
2078
2079                 case special:
2080                         /* I may need to decode that properly one day */
2081                         proto_tree_add_text(v_tree, tvb, optoff, subopt_len+2,
2082                                 "Suboption %d: %s (%d byte%s)",
2083                                 subopt, o43pxeclient_opt[subopt].text,
2084                                 subopt_len, plurality(subopt_len, "", "s"));
2085                         break;
2086
2087                 case ipv4_list:
2088                         if (subopt_len == 4) {
2089                                 /* one IP address */
2090                                 proto_tree_add_text(v_tree, tvb, optoff, 6,
2091                                     "Suboption %d : %s = %s",
2092                                     subopt, o43pxeclient_opt[subopt].text,
2093                                     ip_to_str(tvb_get_ptr(tvb, suboptoff, 4)));
2094                         } else {
2095                                 /* > 1 IP addresses. Let's make a sub-tree */
2096                                 vti = proto_tree_add_text(v_tree, tvb, optoff,
2097                                     subopt_len+2, "Suboption %d: %s",
2098                                     subopt, o43pxeclient_opt[subopt].text);
2099                                 o43pxeclient_v_tree = proto_item_add_subtree(vti, ett_bootp_option);
2100                                 for (suboptleft = subopt_len; suboptleft > 0;
2101                                     suboptoff += 4, suboptleft -= 4) {
2102                                         if (suboptleft < 4) {
2103                                                 proto_tree_add_text(o43pxeclient_v_tree,
2104                                                     tvb, suboptoff, suboptleft,
2105                                                     "Suboption length isn't a multiple of 4");
2106                                                 break;
2107                                         }
2108                                         proto_tree_add_text(o43pxeclient_v_tree,
2109                                             tvb, suboptoff, 4, "IP Address: %s",
2110                                             ip_to_str(tvb_get_ptr(tvb, suboptoff, 4)));
2111                                 }
2112                         }
2113                         break;
2114
2115 #if 0 /* XXX */
2116                 case string:
2117                         proto_tree_add_text(v_tree, tvb, optoff, subopt_len+2,
2118                                 "Suboption %d: %s", subopt, o43pxeclient_opt[subopt].text);
2119                         break;
2120 #endif /*  XXX */
2121
2122                 case val_u_byte:
2123                         if (subopt_len != 1) {
2124                                 proto_tree_add_text(v_tree, tvb, optoff, subopt_len+2,
2125                                         "Suboption %d: suboption length isn't 1", subopt);
2126                                 break;
2127                         }
2128                         proto_tree_add_text(v_tree, tvb, optoff, 3, "Suboption %d: %s = %u",
2129                             subopt, o43pxeclient_opt[subopt].text,
2130                             tvb_get_guint8(tvb, suboptoff));
2131                         break;
2132
2133                 case val_u_le_short:
2134                         if (subopt_len != 2) {
2135                                 proto_tree_add_text(v_tree, tvb, optoff, subopt_len+2,
2136                                         "Suboption %d: suboption length isn't 2", subopt);
2137                                 break;
2138                         }
2139                         proto_tree_add_text(v_tree, tvb, optoff, 4, "Suboption %d: %s = %u",
2140                             subopt, o43pxeclient_opt[subopt].text,
2141                             tvb_get_letohs(tvb, suboptoff));
2142                         break;
2143
2144                 default:
2145                         proto_tree_add_text(v_tree, tvb, optoff, subopt_len+2,"ERROR, please report: Unknown subopt type handler %d", subopt);
2146                         break;
2147                 }
2148         }
2149         optoff += (subopt_len + 2);
2150         return optoff;
2151 }
2152
2153 /* RFC3825Decoder: http://www.enum.at/rfc3825encoder.529.0.html */
2154 static void
2155 rfc3825_lci_to_fixpoint(const unsigned char lci[16], struct rfc3825_location_fixpoint_t *fixpoint)
2156 {
2157         fixpoint->latitude_res = (lci[0]>>2) & 0x3F; /* make sure that right-shift does not copy sign bit */
2158         if (lci[0] & 2) { /* LSB<<1 contains the sign of the latitude */
2159                 /* Latitude is negative, expand two's complement */
2160                 fixpoint->latitude = (((gint64)lci[0] & 3)<<32) | ((gint64)lci[1]<<24) | 
2161                                            ((gint64)lci[2]<<16) | ((gint64)lci[3]<<8)  | 
2162                                             (gint64)lci[4]      | ((gint64)0x3FFFFFFF<<34);
2163                 
2164         } else {
2165                 /* Latitude is positive */
2166                 fixpoint->latitude = (((gint64)lci[0] & 3)<<32) | ((gint64)lci[1]<<24) | 
2167                                            ((gint64)lci[2]<<16) | ((gint64)lci[3]<<8)  | 
2168                                             (gint64)lci[4];
2169         }
2170         fixpoint->longitude_res = (lci[5]>>2) & 0x3F;  /* make sure that right-shift does not copy sign bit */
2171         if (lci[5] & 2) { /* LSB<<1 contains the sign of the latitude */
2172                 /* Longitude is negative, expand two's complement */
2173                 fixpoint->longitude = (((gint64)lci[5] & 3)<<32) | ((gint64)lci[6]<<24) | 
2174                                             ((gint64)lci[7]<<16) | ((gint64)lci[8]<<8)  | 
2175                                              (gint64)lci[9]      | ((gint64)0x3FFFFFFF<<34);
2176                 
2177         } else {
2178                 /* Longitude is positive */
2179                 fixpoint->longitude = (((gint64)lci[5] & 3)<<32) | ((gint64)lci[6]<<24) | 
2180                                             ((gint64)lci[7]<<16) | ((gint64)lci[8]<<8)  | 
2181                                              (gint64)lci[9];
2182         }
2183         fixpoint->altitude_type = (lci[10]>>4) & 0x0F;  /* make sure that right-shift does not copy sign bit */
2184         fixpoint->altitude_res  = ((lci[10] & 0x0F) << 2) | ((lci[11]>>6) & 0x03);
2185         if (lci[11] & 0x20) { /* LSB<<1 contains the sign of the latitude */
2186                 /* Altitude is negative, expand two's complement */
2187                 fixpoint->altitude = (((gint32)lci[11] & 0x3F)<<24) | ((gint32)lci[12]<<16) | 
2188                                      ((gint32)lci[13]<<8) | ((gint32)lci[14]) | 
2189                                       ((gint32)0x03<<30);
2190                 
2191         } else {
2192                 /* Altitudee is positive */
2193                 fixpoint->altitude = (((gint32)lci[11] & 0x3F)<<24) | ((gint32)lci[12]<<16) | 
2194                                      ((gint32)lci[13]<<8) | ((gint32)lci[14]);
2195         }
2196
2197         fixpoint->datum_type = lci[15];
2198
2199 }
2200
2201 /* RFC3825Decoder: http://www.enum.at/rfc3825encoder.529.0.html */
2202 static int
2203 rfc3825_fixpoint_to_decimal(struct rfc3825_location_fixpoint_t *fixpoint, struct rfc3825_location_decimal_t *decimal)
2204 {
2205         /* Latitude */
2206         decimal->latitude = (double) fixpoint->latitude / (1 << 25);
2207         if ((decimal->latitude > 90) || (decimal->latitude < -90)) {
2208                 return RFC3825_LATITUDE_OUTOFRANGE;
2209         }
2210
2211         /* Latitude Uncertainty */
2212         if (fixpoint->latitude_res > 34) {
2213                 return RFC3825_LATITUDE_UNCERTAINTY_OUTOFRANGE;
2214         }
2215         if (fixpoint->latitude_res > 8 ) {
2216                 decimal->latitude_res = (double) 1  / (1 << (fixpoint->latitude_res - 8));
2217         } else {
2218                 decimal->latitude_res = 1 << (8 - fixpoint->latitude_res);
2219         }
2220
2221         /* Longitude */
2222         decimal->longitude = (double) fixpoint->longitude / (1 << 25);
2223         if ((decimal->longitude > 180) || (decimal->longitude < -180)) {
2224                 return RFC3825_LONGITUDE_OUTOFRANGE;
2225         }
2226
2227         /* Longitude Uncertainty */
2228         if (fixpoint->longitude_res > 34) {
2229                 return RFC3825_LONGITUDE_UNCERTAINTY_OUTOFRANGE;
2230         }
2231         if (fixpoint->longitude_res > 8 ) {
2232                 decimal->longitude_res = (double) 1 / (1 << (fixpoint->longitude_res - 8));
2233         } else {
2234                 decimal->longitude_res = 1 << (8 - fixpoint->longitude_res);
2235         }
2236
2237         /* Altitude Type */
2238         decimal->altitude_type = fixpoint->altitude_type;
2239         decimal->altitude = 0;
2240         decimal->altitude_res = 0;
2241
2242         if (decimal->altitude_type == 0) { /* Unknown */
2243         } else if (decimal->altitude_type == 1) { /* Meters */
2244                 /* Altitude */
2245                 decimal->altitude = (double) fixpoint->altitude / (1 << 8);
2246                 if ((decimal->altitude > ((gint32) 1<<21)-1) || (decimal->altitude < ((gint32) -(1<<21)))) 
2247                         return RFC3825_ALTITUDE_OUTOFRANGE;
2248
2249                 /* Altitude Uncertainty */
2250                 if (fixpoint->altitude_res > 30) {
2251                         return RFC3825_ALTITUDE_UNCERTAINTY_OUTOFRANGE;
2252                 }
2253                 if (fixpoint->altitude_res > 21 ) {
2254                         decimal->altitude_res = (double) 1 / (1 << (fixpoint->altitude_res - 21));
2255                 } else {
2256                         decimal->altitude_res = 1 << (21 - fixpoint->altitude_res);
2257                 }
2258         } else if (decimal->altitude_type == 2) { /* Floors */
2259                 /* Altitude */
2260                 if ((fixpoint->altitude_res != 30) && (fixpoint->altitude_res != 0)) { 
2261                         return RFC3825_ALTITUDE_UNCERTAINTY_OUTOFRANGE;
2262                 }
2263                 decimal->altitude = (double) fixpoint->altitude / (1 << 8);
2264         } else { /* invalid type */
2265                 return RFC3825_ALTITUDE_TYPE_OUTOFRANGE;
2266         }
2267
2268         /* Datum Type */
2269         decimal->datum_type = 0;
2270         if ((fixpoint->datum_type > 3) || (fixpoint->datum_type < 1)) {
2271                 return RFC3825_DATUM_TYPE_OUTOFRANGE;
2272         }
2273         decimal->datum_type = fixpoint->datum_type;
2274
2275         return RFC3825_NOERROR;
2276 }
2277
2278
2279 static int
2280 dissect_vendor_cablelabs_suboption(proto_tree *v_tree, tvbuff_t *tvb,
2281     int optoff, int optend)
2282 {
2283         int suboptoff = optoff;
2284         guint8 subopt, byte_val;
2285         guint8 subopt_len;
2286
2287         static struct opt_info o43cablelabs_opt[]= {
2288                 /* 0 */ {"nop", special, NULL}, /* dummy */
2289                 /* 1 */ {"Suboption Request List", string, NULL},
2290                 /* 2 */ {"Device Type", string, NULL},
2291                 /* 3 */ {"eSAFE Types", string, NULL},
2292                 /* 4 */ {"Serial Number", string, NULL},
2293                 /* 5 */ {"Hardware Version", string, NULL},
2294                 /* 6 */ {"Software Version", string, NULL},
2295                 /* 7 */ {"Boot ROM version", string, NULL},
2296                 /* 8 */ {"Organizationally Unique Identifier", special, NULL},
2297                 /* 9 */ {"Model Number", string, NULL},
2298                 /* 10 */ {"Vendor Name", string, NULL},
2299                 /* *** 11-30: CableHome *** */
2300                 /* 11 */ {"Address Realm", special, NULL},
2301                 /* 12 */ {"CM/PS System Description", string, NULL},
2302                 /* 13 */ {"CM/PS Firmware Revision", string, NULL},
2303                 /* 14 */ {"Firewall Policy File Version", string, NULL},
2304                 /* 15 */ {"eSafe Config File Devices", string, NULL},
2305                 /* 16 */ {"Unassigned (CableHome)", special, NULL},
2306                 /* 17 */ {"Unassigned (CableHome)", special, NULL},
2307                 /* 18 */ {"Video Security Type", string, NULL},
2308                 /* 19 */ {"Unassigned (CableHome)", special, NULL},
2309                 /* 20 */ {"Unassigned (CableHome)", special, NULL},
2310                 /* 21 */ {"Unassigned (CableHome)", special, NULL},
2311                 /* 22 */ {"Unassigned (CableHome)", special, NULL},
2312                 /* 23 */ {"Unassigned (CableHome)", special, NULL},
2313                 /* 24 */ {"Unassigned (CableHome)", special, NULL},
2314                 /* 25 */ {"Unassigned (CableHome)", special, NULL},
2315                 /* 26 */ {"Unassigned (CableHome)", special, NULL},
2316                 /* 27 */ {"Unassigned (CableHome)", special, NULL},
2317                 /* 28 */ {"Unassigned (CableHome)", special, NULL},
2318                 /* 29 */ {"Unassigned (CableHome)", special, NULL},
2319                 /* 30 */ {"Unassigned (CableHome)", special, NULL},
2320                 /* *** 31-50: PacketCable *** */
2321                 /* 31 */ {"MTA MAC Address", special, NULL},
2322                 /* 32 */ {"Correlation ID", val_u_long, NULL},
2323                 /* 33 */ {"Unassigned (PacketCable)", special, NULL},
2324                 /* 34 */ {"Unassigned (PacketCable)", special, NULL},
2325                 /* 35 */ {"Unassigned (PacketCable)", special, NULL},
2326                 /* 36 */ {"Unassigned (PacketCable)", special, NULL},
2327                 /* 37 */ {"Unassigned (PacketCable)", special, NULL},
2328                 /* 38 */ {"Unassigned (PacketCable)", special, NULL},
2329                 /* 39 */ {"Unassigned (PacketCable)", special, NULL},
2330                 /* 40 */ {"Unassigned (PacketCable)", special, NULL},
2331                 /* 41 */ {"Unassigned (PacketCable)", special, NULL},
2332                 /* 42 */ {"Unassigned (PacketCable)", special, NULL},
2333                 /* 43 */ {"Unassigned (PacketCable)", special, NULL},
2334                 /* 44 */ {"Unassigned (PacketCable)", special, NULL},
2335                 /* 45 */ {"Unassigned (PacketCable)", special, NULL},
2336                 /* 46 */ {"Unassigned (PacketCable)", special, NULL},
2337                 /* 47 */ {"Unassigned (PacketCable)", special, NULL},
2338                 /* 48 */ {"Unassigned (PacketCable)", special, NULL},
2339                 /* 49 */ {"Unassigned (PacketCable)", special, NULL},
2340                 /* 50 */ {"Unassigned (PacketCable)", special, NULL},
2341                 /* *** 51-127: CableLabs *** */
2342                 /* 51 */ {"Vendor Name", string, NULL},
2343                 /* 52 */ {"CableCARD Capability", special, NULL},
2344                 /* 53 */ {"Device Identification (CA)", special, NULL},
2345                 /* 54 */ {"Device Identification (X.509)", string, NULL},
2346                 /* 55 */ {"Unassigned (CableLabs)", special, NULL},
2347                 /* *** 128-254: Vendors *** */
2348                 /* 128-254 {"Unassigned (Vendors)", special, NULL}, */
2349                 /* 255 {"end options", special, NULL} */
2350         };
2351
2352         static const value_string cablehome_subopt11_vals[] = {
2353                 { 1, "PS WAN-Man" },
2354                 { 2, "PS WAN-Data" },
2355                 { 0, NULL }
2356         };
2357
2358         subopt = tvb_get_guint8(tvb, suboptoff);
2359         suboptoff++;
2360
2361         if (subopt == 0) {
2362                 proto_tree_add_text(v_tree, tvb, optoff, 1, "Padding");
2363                 return (suboptoff);
2364         } else if (subopt == 255) {     /* End Option */
2365                 proto_tree_add_text(v_tree, tvb, optoff, 1, "End CableLabs option");
2366                 /* Make sure we skip any junk left this option */
2367                 return (optend);
2368         }
2369
2370         if (suboptoff >= optend) {
2371                 proto_tree_add_text(v_tree, tvb, optoff, 1,
2372                         "Suboption %d: no room left in option for suboption length",
2373                         subopt);
2374                 return (optend);
2375         }
2376         subopt_len = tvb_get_guint8(tvb, suboptoff);
2377         suboptoff++;
2378
2379         if (suboptoff+subopt_len > optend) {
2380                 proto_tree_add_text(v_tree, tvb, optoff, optend-optoff,
2381                         "Suboption %d: no room left in option for suboption value",
2382                         subopt);
2383                 return (optend);
2384         }
2385         if ( (subopt < 1 ) || (subopt >= array_length(o43cablelabs_opt)) ) {
2386                 proto_tree_add_text(v_tree, tvb, optoff, subopt_len+2,
2387                         "Suboption %d: Unassigned (%d byte%s)", subopt, subopt_len,
2388                         plurality(subopt_len, "", "s"));
2389         } else {
2390                 switch (o43cablelabs_opt[subopt].ftype) {
2391
2392                 case special:
2393                         if ( subopt == 8 ) {    /* OUI */
2394                                 /* CableLabs specs treat 43.8 inconsistently
2395                                  * as either binary (3b) or string (6b) */
2396                                 if (subopt_len == 3) {
2397                                         proto_tree_add_text(v_tree, tvb, optoff, subopt_len+2,
2398                                                 "Suboption %d: OUI = %s", subopt,
2399                                                 bytes_to_str_punct(tvb_get_ptr(tvb, suboptoff, 3), 3, ':'));
2400                                 } else if (subopt_len == 6) {
2401                                         proto_tree_add_text(v_tree, tvb, optoff, subopt_len+2,
2402                                                 "Suboption %d: OUI = \"%s\"", subopt,
2403                                                 tvb_format_stringzpad(tvb, suboptoff, subopt_len));
2404                                 } else {
2405                                         proto_tree_add_text(v_tree, tvb, optoff, subopt_len+2,
2406                                                 "Suboption %d: suboption length isn't 3 or 6", subopt);
2407                                 }
2408                                 break;
2409                         } else if ( subopt == 11 ) { /* Address Realm */
2410                                 if (subopt_len != 1) {
2411                                         proto_tree_add_text(v_tree, tvb, optoff, subopt_len+2,
2412                                                 "Suboption %d: suboption length isn't 1", subopt);
2413                                         break;
2414                                 }
2415                                 byte_val = tvb_get_guint8(tvb, suboptoff);
2416                                 proto_tree_add_text(v_tree, tvb, optoff, subopt_len+2,
2417                                         "Suboption %d: %s = %s (0x%02x)",
2418                                         subopt, o43cablelabs_opt[subopt].text,
2419                                         val_to_str(byte_val, cablehome_subopt11_vals, "Unknown"), byte_val);
2420                         } else if ( subopt == 31 ) { /* MTA MAC address */
2421                                 if (subopt_len != 6) {
2422                                         proto_tree_add_text(v_tree, tvb, optoff, subopt_len+2,
2423                                                 "Suboption %d: suboption length isn't 6", subopt);
2424                                         break;
2425                                 }
2426                                 proto_tree_add_text(v_tree, tvb, optoff, subopt_len+2,
2427                                         "Suboption %d: %s = %s",
2428                                         subopt,  o43cablelabs_opt[subopt].text,
2429                                         bytes_to_str_punct(tvb_get_ptr(tvb, suboptoff, 6), 6, ':'));
2430                         } else {
2431                                 proto_tree_add_text(v_tree, tvb, optoff, subopt_len+2,
2432                                         "Suboption %d: %s (%d byte%s)" ,
2433                                         subopt, o43cablelabs_opt[subopt].text,
2434                                         subopt_len, plurality(subopt_len, "", "s"));
2435                         }
2436                         break;
2437
2438                 case string:
2439                         proto_tree_add_text(v_tree, tvb, optoff, subopt_len+2,
2440                                 "Suboption %d: %s = \"%s\"", subopt,
2441                                 o43cablelabs_opt[subopt].text,
2442                                 tvb_format_stringzpad(tvb, suboptoff, subopt_len));
2443                         break;
2444
2445                 case bytes:
2446                         proto_tree_add_text(v_tree, tvb, optoff, subopt_len+2,
2447                                 "Suboption %d: %s = 0x%s", subopt,
2448                                 o43cablelabs_opt[subopt].text,
2449                                 tvb_bytes_to_str(tvb, suboptoff, subopt_len));
2450                         break;
2451
2452                 case val_u_long:
2453                         if (subopt_len != 4) {
2454                                 proto_tree_add_text(v_tree, tvb, optoff, subopt_len+2,
2455                                         "Suboption %d: suboption length isn't 4", subopt);
2456                                 break;
2457                         }
2458                         proto_tree_add_text(v_tree, tvb, optoff, subopt_len+2,
2459                                 "Suboption %d: %s = %u", subopt,
2460                                 o43cablelabs_opt[subopt].text,
2461                                 tvb_get_ntohl(tvb, suboptoff));
2462                         break;
2463
2464                 default:
2465                         proto_tree_add_text(v_tree, tvb, optoff, subopt_len+2,"ERROR, please report: Unknown subopt type handler %d", subopt);
2466                         break;
2467                 }
2468         }
2469         optoff += (subopt_len + 2);
2470         return optoff;
2471 }
2472
2473
2474
2475 static int
2476 dissect_netware_ip_suboption(proto_tree *v_tree, tvbuff_t *tvb,
2477     int optoff, int optend)
2478 {
2479         int suboptoff = optoff;
2480         guint8 subopt;
2481         guint8 subopt_len;
2482         int suboptleft;
2483         const struct true_false_string *tfs;
2484         int i;
2485         proto_tree *o63_v_tree;
2486         proto_item *vti;
2487
2488         static struct opt_info o63_opt[]= {
2489                 /* 0 */ {"",none,NULL},
2490                 /* 1 */ {"NWIP does not exist on subnet",presence,NULL},
2491                 /* 2 */ {"NWIP exists in options area",presence,NULL},
2492                 /* 3 */ {"NWIP exists in sname/file",presence,NULL},
2493                 /* 4 */ {"NWIP exists, but too big",presence,NULL},
2494                 /* 5 */ {"Broadcast for nearest Netware server",val_boolean,TFS(&tfs_yes_no)},
2495                 /* 6 */ {"Preferred DSS server",ipv4_list,NULL},
2496                 /* 7 */ {"Nearest NWIP server",ipv4_list,NULL},
2497                 /* 8 */ {"Autoretries",val_u_byte,NULL},
2498                 /* 9 */ {"Autoretry delay, secs",val_u_byte,NULL},
2499                 /* 10*/ {"Support NetWare/IP v1.1",val_boolean,TFS(&tfs_yes_no)},
2500                 /* 11*/ {"Primary DSS",ipv4,NULL}
2501         };
2502
2503         subopt = tvb_get_guint8(tvb, optoff);
2504         suboptoff++;
2505
2506         if (suboptoff >= optend) {
2507                 proto_tree_add_text(v_tree, tvb, optoff, 1,
2508                         "Suboption %d: no room left in option for suboption length",
2509                         subopt);
2510                 return (optend);
2511         }
2512         subopt_len = tvb_get_guint8(tvb, suboptoff);
2513         suboptoff++;
2514
2515         if (subopt >= array_length(o63_opt)) {
2516                 proto_tree_add_text(v_tree, tvb, optoff, subopt_len + 2, "Unknown suboption %d", subopt);
2517         } else {
2518                 switch (o63_opt[subopt].ftype) {
2519
2520                 case presence:
2521                         if (subopt_len != 0) {
2522                                 proto_tree_add_text(v_tree, tvb, optoff, subopt_len + 2,
2523                                         "Suboption %d: length isn't 0", subopt);
2524                                 break;
2525                         }
2526                         proto_tree_add_text(v_tree, tvb, optoff, 2, "Suboption %d: %s", subopt, o63_opt[subopt].text);
2527                         break;
2528
2529                 case ipv4:
2530                         if (subopt_len != 4) {
2531                                 proto_tree_add_text(v_tree, tvb, optoff, subopt_len + 2,
2532                                         "Suboption %d: length isn't 4", subopt);
2533                                 break;
2534                         }
2535                         if (suboptoff+4 > optend) {
2536                                 proto_tree_add_text(v_tree, tvb, optoff, optend-optoff,
2537                                     "Suboption %d: no room left in option for suboption value",
2538                                     subopt);
2539                                 return (optend);
2540                         }
2541                         proto_tree_add_text(v_tree, tvb, optoff, 6,
2542                             "Suboption %d: %s = %s" ,
2543                             subopt, o63_opt[subopt].text,
2544                             ip_to_str(tvb_get_ptr(tvb, suboptoff, 4)));
2545                         break;
2546
2547                 case ipv4_list:
2548                         if (subopt_len == 4) {
2549                                 /* one IP address */
2550                                 proto_tree_add_text(v_tree, tvb, optoff, 6,
2551                                     "Suboption %d : %s = %s",
2552                                     subopt, o63_opt[subopt].text,
2553                                     ip_to_str(tvb_get_ptr(tvb, suboptoff, 4)));
2554                         } else {
2555                                 /* > 1 IP addresses. Let's make a sub-tree */
2556                                 vti = proto_tree_add_text(v_tree, tvb, optoff,
2557                                     subopt_len+2, "Suboption %d: %s",
2558                                     subopt, o63_opt[subopt].text);
2559                                 o63_v_tree = proto_item_add_subtree(vti, ett_bootp_option);
2560                                 for (suboptleft = subopt_len; suboptleft > 0;
2561                                     suboptoff += 4, suboptleft -= 4) {
2562                                         if (suboptleft < 4) {
2563                                                 proto_tree_add_text(o63_v_tree,
2564                                                     tvb, suboptoff, suboptleft,
2565                                                     "Suboption length isn't a multiple of 4");
2566                                                 break;
2567                                         }
2568                                         proto_tree_add_text(o63_v_tree, tvb, suboptoff, 4, "IP Address: %s",
2569                                             ip_to_str(tvb_get_ptr(tvb, suboptoff, 4)));
2570                                 }
2571                         }
2572                         break;
2573
2574                 case val_boolean:
2575                         if (subopt_len != 1) {
2576                                 proto_tree_add_text(v_tree, tvb, optoff, subopt_len + 2,
2577                                         "Suboption %d: suboption length isn't 1", subopt);
2578                                 break;
2579                         }
2580                         if (suboptoff+1 > optend) {
2581                                 proto_tree_add_text(v_tree, tvb, optoff, optend-optoff,
2582                                     "Suboption %d: no room left in option for suboption value",
2583                                     subopt);
2584                                 return (optend);
2585                         }
2586                         tfs = (const struct true_false_string *) o63_opt[subopt].data;
2587                         i = tvb_get_guint8(tvb, suboptoff);
2588                         if (i != 0 && i != 1) {
2589                                 proto_tree_add_text(v_tree, tvb, optoff, 3,
2590                                     "Suboption %d: %s = Invalid Value %d",
2591                                     subopt, o63_opt[subopt].text, i);
2592                         } else {
2593                                 proto_tree_add_text(v_tree, tvb, optoff, 3,
2594                                     "Suboption %d: %s = %s", subopt,
2595                                     o63_opt[subopt].text,
2596                                     i == 0 ? tfs->false_string : tfs->true_string);
2597                         }
2598                         break;
2599
2600                 case val_u_byte:
2601                         if (subopt_len != 1) {
2602                                 proto_tree_add_text(v_tree, tvb, optoff, subopt_len + 2,
2603                                         "Suboption %d: length isn't 1", subopt);
2604                                 break;
2605                         }
2606                         if (suboptoff+1 > optend) {
2607                                 proto_tree_add_text(v_tree, tvb, optoff, optend-optoff,
2608                                     "Suboption %d: no room left in option for suboption value",
2609                                     subopt);
2610                                 return (optend);
2611                         }
2612                         proto_tree_add_text(v_tree, tvb, optoff, 3, "Suboption %d: %s = %u",
2613                             subopt, o63_opt[subopt].text,
2614                             tvb_get_guint8(tvb, suboptoff));
2615                         break;
2616
2617                 default:
2618                         proto_tree_add_text(v_tree, tvb, optoff, subopt_len + 2,"Unknown suboption %d", subopt);
2619                         break;
2620                 }
2621         }
2622         optoff += (subopt_len + 2);
2623         return optoff;
2624 }
2625
2626
2627
2628 static int
2629 dissect_vendor_tr111_suboption(proto_tree *v_tree, tvbuff_t *tvb,
2630     int optoff, int optend)
2631 {
2632         int suboptoff = optoff;
2633         guint8 subopt;
2634         guint8 subopt_len;
2635
2636         /* Reference: TR-111 DHCP Option 125 Sub-Option Data Fields
2637            Page 10.
2638          */
2639
2640         static struct opt_info o125_tr111_opt[]= {
2641                 /* 0 */ {"nop", special, NULL}, /* dummy */
2642                 /* 1 */ {"DeviceManufacturerOUI", string, NULL},
2643                 /* 2 */ {"DeviceSerialNumber", string, NULL},
2644                 /* 3 */ {"DeviceProductClass", string, NULL},
2645                 /* 4 */ {"GatewayManufacturerOUI", string, NULL},
2646                 /* 5 */ {"GatewaySerialNumber", string, NULL},
2647                 /* 6 */ {"GatewayProductClass", string, NULL},
2648         };
2649
2650         subopt = tvb_get_guint8(tvb, suboptoff);
2651         suboptoff++;
2652
2653         if (suboptoff >= optend) {
2654                 proto_tree_add_text(v_tree, tvb, optoff, 1,
2655                         "Suboption %d: no room left in option for suboption length",
2656                         subopt);
2657                 return (optend);
2658         }
2659         subopt_len = tvb_get_guint8(tvb, suboptoff);
2660         suboptoff++;
2661
2662         if (suboptoff+subopt_len > optend) {
2663                 proto_tree_add_text(v_tree, tvb, optoff, optend-optoff,
2664                         "Suboption %d: no room left in option for suboption value",
2665                         subopt);
2666                 return (optend);
2667         }
2668
2669
2670         if ((subopt < 1) || (subopt >= array_length(o125_tr111_opt))) {
2671                 proto_tree_add_text(v_tree, tvb, optoff, subopt_len+2,
2672                         "Unknown suboption %d (%d byte%s)", subopt, subopt_len,
2673                         plurality(subopt_len, "", "s"));
2674         } else {
2675                 switch (o125_tr111_opt[subopt].ftype) {
2676
2677                 case special:
2678                         /* I may need to decode that properly one day */
2679                         proto_tree_add_text(v_tree, tvb, optoff, subopt_len+2,
2680                                 "Suboption %d: %s (%d byte%s)",
2681                                 subopt, o125_tr111_opt[subopt].text,
2682                                 subopt_len, plurality(subopt_len, "", "s"));
2683                         break;
2684
2685                 case string:
2686                         proto_tree_add_text(v_tree, tvb, optoff, subopt_len+2,
2687                                 "Suboption %d: %s = \"%s\"", subopt,
2688                                 o125_tr111_opt[subopt].text,
2689                                 tvb_format_stringzpad(tvb, suboptoff, subopt_len));
2690                         break;
2691
2692                 default:
2693                         proto_tree_add_text(v_tree, tvb, optoff, subopt_len+2,"ERROR, please report: Unknown subopt type handler %d", subopt);
2694                         break;
2695                 }
2696         }
2697         optoff += (subopt_len + 2);
2698         return optoff;
2699 }
2700
2701 static int
2702 dissect_vendor_cl_suboption(proto_tree *v_tree, tvbuff_t *tvb,
2703     int optoff, int optend)
2704 {
2705         int suboptoff = optoff;
2706         guint8 subopt, val;
2707         guint8 subopt_len;
2708         proto_item *ti;
2709         proto_tree *subtree;
2710         int i;
2711
2712         static struct opt_info o125_cl_opt[]= {
2713                 /* 0 */ {"nop", special, NULL}, /* dummy */
2714                 /* 1 */ {"Option Request = ", val_u_byte, NULL},
2715                 /* 2 */ {"TFTP Server Addresses : ", ipv4_list, NULL},
2716                 /* 3 */ {"eRouter Container Option : ", bytes, NULL},
2717                 /* 4 */ {"MIB Environment Indicator Option = ", special, NULL},
2718                 /* 5 */ {"Modem Capabilities : ", special, NULL},
2719         };
2720
2721         static const value_string pkt_mib_env_ind_opt_vals[] = {
2722                 { 0x00, "Reserved" },
2723                 { 0x01, "CableLabs" },
2724                 { 0x02, "IETF" },
2725                 { 0x03, "EuroCableLabs" },
2726                 { 0, NULL } 
2727         };
2728
2729         subopt = tvb_get_guint8(tvb, suboptoff);
2730         suboptoff++;
2731
2732         if (suboptoff >= optend) {
2733                 proto_tree_add_text(v_tree, tvb, optoff, 1,
2734                         "Suboption %d: no room left in option for suboption length",
2735                         subopt);
2736                 return (optend);
2737         }
2738         subopt_len = tvb_get_guint8(tvb, suboptoff);
2739         suboptoff++;
2740
2741         if (suboptoff+subopt_len > optend) {
2742                 proto_tree_add_text(v_tree, tvb, optoff, optend-optoff,
2743                         "Suboption %d: no room left in option for suboption value",
2744                         subopt);
2745                 return (optend);
2746         }
2747
2748         if ((subopt < 1) || (subopt >= array_length(o125_cl_opt))) {
2749                 proto_tree_add_text(v_tree, tvb, optoff, subopt_len+2,
2750                         "Unknown suboption %d (%d byte%s)", subopt, subopt_len,
2751                         plurality(subopt_len, "", "s"));
2752         } else {
2753                 switch (o125_cl_opt[subopt].ftype) {
2754
2755                 case bytes:
2756                         proto_tree_add_text(v_tree, tvb, optoff, subopt_len+2,
2757                                 "Suboption %d: %s%s (%d byte%s)", subopt,
2758                                 o125_cl_opt[subopt].text,
2759                                 tvb_bytes_to_str(tvb, suboptoff, subopt_len),
2760                                 subopt_len, plurality(subopt_len, "", "s"));
2761                         break;
2762                 
2763                 case ipv4_list: 
2764                         ti = proto_tree_add_text(v_tree, tvb, optoff, 2,
2765                                         "Suboption %d %s", subopt, o125_cl_opt[subopt].text);
2766
2767                         if ((subopt_len % 4) != 0) {
2768                                 proto_item_append_text(ti, 
2769                                         "Invalid length for suboption %d (%d byte%s)", subopt, subopt_len,
2770                                         plurality(subopt_len, "", "s"));
2771                         } else {
2772                                 subtree = proto_item_add_subtree(ti, ett_bootp_option);
2773                                 for (i = 0; i < subopt_len; i+=4) {
2774                                                 proto_tree_add_text(subtree, tvb, suboptoff+i, 4, "IP Address: %s",
2775                                                         ip_to_str(tvb_get_ptr(tvb, (suboptoff+i), 4)));
2776                                 }
2777                         }
2778                         break;
2779
2780                 case special:
2781                         if (subopt == 4) {
2782                                 val = tvb_get_guint8(tvb, suboptoff);
2783                                 proto_tree_add_text(v_tree, tvb, optoff, subopt_len+2,
2784                                         "Suboption %d: %s%s", subopt,
2785                                         o125_cl_opt[subopt].text,
2786                                         val_to_str(tvb_get_guint8(tvb, suboptoff),
2787                                         pkt_mib_env_ind_opt_vals, "unknown"));
2788                         }
2789                         else {
2790                                 proto_tree_add_text(v_tree, tvb, optoff, subopt_len+2,
2791                                         "Suboption %d: %s%s (%d byte%s)",
2792                                         subopt, o125_cl_opt[subopt].text,
2793                                         tvb_bytes_to_str(tvb, suboptoff, subopt_len), 
2794                                         subopt_len, plurality(subopt_len, "", "s"));
2795                         }
2796                         break;
2797
2798                 case string:
2799                         proto_tree_add_text(v_tree, tvb, optoff, subopt_len+2,
2800                                 "Suboption %d: %s\"%s\"", subopt,
2801                                 o125_cl_opt[subopt].text,
2802                                 tvb_format_stringzpad(tvb, suboptoff, subopt_len));
2803                         break;
2804
2805                 case val_u_byte:
2806                         val = tvb_get_guint8(tvb, suboptoff);
2807                         proto_tree_add_text(v_tree, tvb, optoff, subopt_len+2,
2808                                 "Suboption %d: %s%d", subopt,
2809                                 o125_cl_opt[subopt].text, val);
2810                         break;
2811
2812                 case val_u_short:
2813                         proto_tree_add_text(v_tree, tvb, optoff, subopt_len+2,
2814                                 "Suboption %d: %s%d", subopt,
2815                                 o125_cl_opt[subopt].text,
2816                                 tvb_get_ntohs(tvb, suboptoff));
2817                         break;
2818
2819                 default:
2820                         proto_tree_add_text(v_tree, tvb, optoff, subopt_len+2,"ERROR, please report: Unknown subopt type handler %d", subopt);
2821                         break;
2822                 }
2823         }
2824         optoff += (subopt_len + 2);
2825         return optoff;
2826 }
2827
2828 /* PacketCable Multimedia Terminal Adapter device capabilities (option 60).
2829    Ref: PKT-SP-I05-021127 sections 8.2 and 10 */
2830
2831 #define PKT_MDC_TLV_OFF 10
2832
2833
2834 /* These are ASCII-encoded hexadecimal digits.  We use the raw hex equivalent for
2835    convenience. */
2836 #define PKT_MDC_VERSION                 0x3031  /* "01" */
2837 #define PKT_MDC_TEL_END                 0x3032  /* "02" */
2838 #define PKT_MDC_TGT                     0x3033  /* "03" */
2839 #define PKT_MDC_HTTP_ACC                0x3034  /* "04" */
2840 #define PKT_MDC_SYSLOG                  0x3035  /* "05" */
2841 #define PKT_MDC_NCS                     0x3036  /* "06" */
2842 #define PKT_MDC_PRI_LINE                0x3037  /* "07" */
2843 #define PKT_MDC_VENDOR_TLV              0x3038  /* "08" */
2844 #define PKT_MDC_NVRAM_STOR              0x3039  /* "09" */
2845 #define PKT_MDC_PROV_REP                0x3041  /* "0A" */
2846 #define PKT_MDC_PROV_REP_LC             0x3061  /* "0A" */
2847 #define PKT_MDC_SUPP_CODECS             0x3042  /* "0B" */
2848 #define PKT_MDC_SUPP_CODECS_LC          0x3062  /* "0b" */
2849 #define PKT_MDC_SILENCE                 0x3043  /* "0C" */
2850 #define PKT_MDC_SILENCE_LC              0x3063  /* "0c" */
2851 #define PKT_MDC_ECHO_CANCEL             0x3044  /* "0D" */
2852 #define PKT_MDC_ECHO_CANCEL_LC          0x3064  /* "0d" */
2853 #define PKT_MDC_RSVP                    0x3045  /* "0E" */
2854 #define PKT_MDC_RSVP_LC                 0x3065  /* "0e" */
2855 #define PKT_MDC_UGS_AD                  0x3046  /* "0F" */
2856 #define PKT_MDC_UGS_AD_LC               0x3066  /* "0f" */
2857 #define PKT_MDC_IF_INDEX                0x3130  /* "10" */
2858 #define PKT_MDC_FLOW_LOG                0x3131  /* "11" */
2859 #define PKT_MDC_PROV_FLOWS              0x3132  /* "12" */
2860 /* PacketCable 1.5: */
2861 #define PKT_MDC_T38_VERSION             0x3133  /* "13" */
2862 #define PKT_MDC_T38_EC                  0x3134  /* "14" */
2863 #define PKT_MDC_RFC2833_DTMF            0x3135  /* "15" */
2864 #define PKT_MDC_VOICE_METRICS           0x3136  /* "16" */
2865 #define PKT_MDC_MIBS                    0x3137  /* "17" */
2866 #define PKT_MDC_MGPI                    0x3138  /* "18" */
2867 #define PKT_MDC_V152                    0x3139  /* "19" */
2868
2869 static const value_string pkt_mdc_type_vals[] = {
2870         { PKT_MDC_VERSION,              "PacketCable Version" },
2871         { PKT_MDC_TEL_END,              "Number Of Telephony Endpoints" },
2872         { PKT_MDC_TGT,                  "TGT Support" },
2873         { PKT_MDC_HTTP_ACC,             "HTTP Download File Access Method Support" },
2874         { PKT_MDC_SYSLOG,               "MTA-24 Event SYSLOG Notification Support" },
2875         { PKT_MDC_NCS,                  "NCS Service Flow Support" },
2876         { PKT_MDC_PRI_LINE,             "Primary Line Support" },
2877         { PKT_MDC_VENDOR_TLV,           "Vendor Specific TLV Type(s)" },
2878         { PKT_MDC_NVRAM_STOR,           "NVRAM Ticket/Session Keys Storage Support" },
2879         { PKT_MDC_PROV_REP,             "Provisioning Event Reporting Support" },
2880         { PKT_MDC_PROV_REP_LC,          "Provisioning Event Reporting Support" },
2881         { PKT_MDC_SUPP_CODECS,          "Supported CODEC(s)" },
2882         { PKT_MDC_SUPP_CODECS_LC,       "Supported CODEC(s)" },
2883         { PKT_MDC_SILENCE,              "Silence Suppression Support" },
2884         { PKT_MDC_SILENCE_LC,           "Silence Suppression Support" },
2885         { PKT_MDC_ECHO_CANCEL,          "Echo Cancellation Support" },
2886         { PKT_MDC_ECHO_CANCEL_LC,       "Echo Cancellation Support" },
2887         { PKT_MDC_RSVP,                 "RSVP Support/ Reserved" },
2888         { PKT_MDC_RSVP_LC,              "RSVP Support/ Reserved" },
2889         { PKT_MDC_UGS_AD,               "UGS-AD Support" },
2890         { PKT_MDC_UGS_AD_LC,            "UGS-AD Support" },
2891         { PKT_MDC_IF_INDEX,             "MTA's \"ifIndex\" starting number in \"ifTable\"" },
2892         { PKT_MDC_FLOW_LOG,             "Provisioning Flow Logging Support" },
2893         { PKT_MDC_PROV_FLOWS,           "Supported Provisioning Flows" },
2894         /* PacketCable 1.5: */
2895         { PKT_MDC_T38_VERSION,          "T38 Version Support" },
2896         { PKT_MDC_T38_EC,               "T38 Error Correction Support" },
2897         { PKT_MDC_RFC2833_DTMF,         "RFC 2833 DTMF Support" },
2898         { PKT_MDC_VOICE_METRICS,        "Voice Metrics Support" },
2899         { PKT_MDC_MIBS,                 "MIB Support" },
2900         { PKT_MDC_MGPI,                 "Multiple Grants Per Interval Support" },
2901         { PKT_MDC_V152,                 "V.152 Support" },
2902         { 0,                            NULL }
2903 };
2904
2905 static const value_string pkt_mdc_version_vals[] = {
2906         { 0x3030,       "PacketCable 1.0" },
2907         { 0x3031,       "PacketCable 1.1/1.5" }, /* 1.5 replaces 1.1-1.3 */
2908         { 0x3032,       "PacketCable 1.2" },
2909         { 0x3033,       "PacketCable 1.3" },
2910         { 0,            NULL }
2911 };
2912
2913 static const value_string pkt_mdc_boolean_vals[] = {
2914         { 0x3030,       "No" },
2915         { 0x3031,       "Yes" },
2916         { 0,            NULL }
2917 };
2918
2919 static const value_string pkt_mdc_codec_vals[] = {
2920         { 0x3031,       "other" },           /* "01" */
2921         { 0x3032,       "unknown" },
2922         { 0x3033,       "G.729" },
2923         { 0x3034,       "reserved" },
2924         { 0x3035,       "G.729E" },
2925         { 0x3036,       "PCMU" },
2926         { 0x3037,       "G.726-32" },
2927         { 0x3038,       "G.728" },
2928         { 0x3039,       "PCMA" },            /* "09" */
2929         { 0x3041,       "G.726-16" },        /* "0A" */
2930         { 0x3042,       "G.726-24" },
2931         { 0x3043,       "G.726-40" },
2932         { 0x3044,       "iLBC" },
2933         { 0x3045,       "BV16" },
2934         { 0x3046,       "telephone-event" }, /* "0F" */
2935         { 0,            NULL }
2936 };
2937
2938 static const value_string pkt_mdc_t38_version_vals[] = {
2939         { 0x3030,       "Unsupported" },
2940         { 0x3031,       "T.38 Version Zero" }, /* default */
2941         { 0x3032,       "T.38 Version One" },
2942         { 0x3033,       "T.38 Version Two" },
2943         { 0x3035,       "T.38 Version Three" },
2944         { 0,            NULL }
2945 };
2946
2947 static const value_string pkt_mdc_t38_ec_vals[] = {
2948         { 0x3030,       "None" },
2949         { 0x3031,       "Redundancy" }, /* default */
2950         { 0x3032,       "FEC" },
2951         { 0,            NULL }
2952 };
2953
2954 static const value_string pkt_mdc_mib_orgs[] = {
2955         { 0x3030,       "CableLabs" },
2956         { 0x3031,       "IETF" },
2957         { 0x3032,       "Reserved" },
2958         { 0x3033,       "Reserved" },
2959         { 0x3034,       "Reserved" },
2960         { 0x3035,       "Reserved" },
2961         { 0x3036,       "Reserved" },
2962         { 0x3037,       "Reserved" },
2963         { 0x3038,       "Reserved" },
2964         { 0x3039,       "Reserved" },
2965         { 0,            NULL }
2966 };
2967
2968 /* DOCSIS Cable Modem device capabilities (option 60). */
2969 #define DOCS_CM_TLV_OFF 12
2970
2971 #define DOCS_CM_CONCAT_SUP      0x3031  /* "01" */
2972 #define DOCS_CM_DOCSIS_VER      0x3032  /* "02" */
2973 #define DOCS_CM_FRAG_SUP        0x3033  /* "03" */
2974 #define DOCS_CM_PHS_SUP         0x3034  /* "04" */
2975 #define DOCS_CM_IGMP_SUP        0x3035  /* "05" */
2976 #define DOCS_CM_PRIV_SUP        0x3036  /* "06" */
2977 #define DOCS_CM_DSAID_SUP       0x3037  /* "07" */
2978 #define DOCS_CM_USID_SUP        0x3038  /* "08" */
2979 #define DOCS_CM_FILT_SUP        0x3039  /* "09" */
2980 #define DOCS_CM_TET_MI          0x3041  /* "0A" */
2981 #define DOCS_CM_TET_MI_LC       0x3061  /* "0a" */
2982 #define DOCS_CM_TET             0x3042  /* "0B" */
2983 #define DOCS_CM_TET_LC          0x3062  /* "0b" */
2984 #define DOCS_CM_DCC_SUP         0x3043  /* "0C" */
2985 #define DOCS_CM_DCC_SUP_LC      0x3063  /* "0c" */
2986 #define DOCS_CM_IPFILT_SUP      0x3044  /* "0D" */
2987 #define DOCS_CM_IPFILT_SUP_LC   0x3064  /* "0d" */
2988 #define DOCS_CM_LLCFILT_SUP     0x3045  /* "0E" */
2989 #define DOCS_CM_LLCFILT_SUP_LC  0x3065  /* "0e" */
2990
2991 static const value_string docs_cm_type_vals[] = {
2992         { DOCS_CM_CONCAT_SUP,   "Concatenation Support" },
2993         { DOCS_CM_DOCSIS_VER,   "DOCSIS Version" },
2994         { DOCS_CM_FRAG_SUP,     "Fragmentation Support" },
2995         { DOCS_CM_PHS_SUP,      "PHS Support" },
2996         { DOCS_CM_IGMP_SUP,     "IGMP Support" },
2997         { DOCS_CM_PRIV_SUP,     "Privacy Support" },
2998         { DOCS_CM_DSAID_SUP,    "Downstream SAID Support" },
2999         { DOCS_CM_USID_SUP,     "Upstream SID Support" },
3000         { DOCS_CM_FILT_SUP,     "Optional Filtering Support" },
3001         { DOCS_CM_TET_MI,       "Transmit Equalizer Taps per Modulation Interval" },
3002         { DOCS_CM_TET_MI_LC,    "Transmit Equalizer Taps per Modulation Interval" },
3003         { DOCS_CM_TET,          "Number of Transmit Equalizer Taps" },
3004         { DOCS_CM_TET_LC,       "Number of Transmit Equalizer Taps" },
3005         { DOCS_CM_DCC_SUP,      "DCC Support" },
3006         { DOCS_CM_DCC_SUP_LC,   "DCC Support" },
3007         { DOCS_CM_IPFILT_SUP,   "IP Filters Support" },
3008         { DOCS_CM_IPFILT_SUP_LC,        "IP Filters Support" },
3009         { DOCS_CM_LLCFILT_SUP,  "LLC Filters Support" },
3010         { DOCS_CM_LLCFILT_SUP_LC,       "LLC Filters Support" },
3011         { 0, NULL }
3012 };
3013
3014 static const value_string docs_cm_version_vals[] = {
3015         { 0x3030,       "DOCSIS 1.0" },
3016         { 0x3031,       "DOCSIS 1.1" },
3017         { 0x3032,       "DOCSIS 2.0" },
3018         { 0x3033,       "DOCSIS 3.0" },
3019         { 0,            NULL }
3020 };
3021
3022 static const value_string docs_cm_privacy_vals[] = {
3023         { 0x3030,       "BPI Support" },
3024         { 0x3031,       "BPI Plus Support" },
3025         { 0,            NULL }
3026 };
3027
3028
3029 static const value_string pkt_mdc_supp_flow_vals[] = {
3030         { 1 << 0, "Secure Flow (Full Secure Provisioning Flow)" },
3031         { 1 << 1, "Hybrid Flow" },
3032         { 1 << 2, "Basic Flow" },
3033         { 0, NULL }
3034 };
3035
3036 #define PKT_MDC_MIB_CL 0x3030
3037 static const value_string pkt_mdc_cl_mib_vals[] = {
3038         { 1 << 0, "PacketCable 1.5 MTA MIB" },
3039         { 1 << 1, "PacketCable 1.5 Signaling MIB" },
3040         { 1 << 2, "PacketCable 1.5 Management Event MIB" },
3041         { 1 << 3, "PacketCable 1.5 MTA Extension MIB" },
3042         { 1 << 4, "PacketCable 1.5 Signaling Extension MIB" },
3043         { 1 << 5, "PacketCable 1.5 MEM Extension MIB" },
3044         { 1 << 6, "Reserved" },
3045         { 1 << 7, "Reserved" },
3046         { 0, NULL }
3047 };
3048
3049 #define PKT_MDC_MIB_IETF 0x3031
3050 static const value_string pkt_mdc_ietf_mib_vals[] = {
3051         { 1 << 0, "IETF MTA MIB" },
3052         { 1 << 1, "IETF Signaling MIB" },
3053         { 1 << 2, "IETF Management Event MIB" },
3054         { 1 << 3, "Reserved" },
3055         { 1 << 4, "Reserved" },
3056         { 1 << 5, "Reserved" },
3057         { 1 << 6, "Reserved" },
3058         { 1 << 7, "Reserved" },
3059         { 0, NULL }
3060 };
3061
3062
3063 static void
3064 dissect_packetcable_mta_cap(proto_tree *v_tree, tvbuff_t *tvb, int voff, int len)
3065 {
3066         guint16 raw_val;
3067         unsigned long flow_val = 0;
3068         int off = PKT_MDC_TLV_OFF + voff;
3069         int subopt_off, max_len;
3070         guint tlv_len, i, mib_val;
3071         guint8 asc_val[3] = "  ", flow_val_str[5];
3072         char bit_fld[64];
3073         proto_item *ti, *mib_ti;
3074         proto_tree *subtree, *subtree2;
3075
3076         tvb_memcpy (tvb, asc_val, off, 2);
3077         if (sscanf((gchar*)asc_val, "%x", &tlv_len) != 1 || tlv_len > 0xff) {
3078                 proto_tree_add_text(v_tree, tvb, off, len - off,
3079                         "Bogus length: %s", asc_val);
3080                 return;
3081         } else {
3082                 proto_tree_add_uint_format_value(v_tree, hf_bootp_pkt_mtacap_len, tvb, off, 2,
3083                                 tlv_len, "%d", tlv_len);
3084                 off += 2;
3085
3086                 while (off - voff < len) {
3087                         /* Type */
3088                         raw_val = tvb_get_ntohs (tvb, off);
3089
3090                         /* Length */
3091                         tvb_memcpy(tvb, asc_val, off + 2, 2);
3092                         if (sscanf((gchar*)asc_val, "%x", &tlv_len) != 1 || tlv_len < 1) {
3093                                 proto_tree_add_text(v_tree, tvb, off, len - off,
3094                                                         "[Bogus length: %s]", asc_val);
3095                                 return;
3096                         } else {
3097                                 /* Value(s) */
3098
3099                                 ti = proto_tree_add_text(v_tree,
3100                                     tvb, off, (tlv_len * 2) + 4,
3101                                     "0x%s: %s = ",
3102                                     tvb_format_text(tvb, off, 2),
3103                                     val_to_str(raw_val, pkt_mdc_type_vals, "unknown"));
3104                                 switch (raw_val) {
3105
3106                                 case PKT_MDC_VERSION:
3107                                         raw_val = tvb_get_ntohs(tvb, off + 4);
3108                                         proto_item_append_text(ti,
3109                                                                "%s (%s)",
3110                                                                val_to_str(raw_val, pkt_mdc_version_vals, "Reserved"),
3111                                                                tvb_format_stringzpad(tvb, off + 4, 2) );
3112                                         break;
3113
3114                                 case PKT_MDC_TEL_END:
3115                                 case PKT_MDC_IF_INDEX:
3116                                         proto_item_append_text(ti,
3117                                                                "%s",
3118                                                                tvb_format_stringzpad(tvb, off + 4, 2) );
3119                                         break;
3120
3121                                 case PKT_MDC_TGT:
3122                                 case PKT_MDC_HTTP_ACC:
3123                                 case PKT_MDC_SYSLOG:
3124                                 case PKT_MDC_NCS:
3125                                 case PKT_MDC_PRI_LINE:
3126                                 case PKT_MDC_NVRAM_STOR:
3127                                 case PKT_MDC_PROV_REP:
3128                                 case PKT_MDC_PROV_REP_LC:
3129                                 case PKT_MDC_SILENCE:
3130                                 case PKT_MDC_SILENCE_LC:
3131                                 case PKT_MDC_ECHO_CANCEL:
3132                                 case PKT_MDC_ECHO_CANCEL_LC:
3133                                 case PKT_MDC_RSVP:
3134                                 case PKT_MDC_RSVP_LC:
3135                                 case PKT_MDC_UGS_AD:
3136                                 case PKT_MDC_UGS_AD_LC:
3137                                 case PKT_MDC_FLOW_LOG:
3138                                 case PKT_MDC_RFC2833_DTMF:
3139                                 case PKT_MDC_VOICE_METRICS:
3140                                 case PKT_MDC_MGPI:
3141                                 case PKT_MDC_V152:
3142                                         raw_val = tvb_get_ntohs(tvb, off + 4);
3143                                         proto_item_append_text(ti,
3144                                                                "%s (%s)",
3145                                                                val_to_str(raw_val, pkt_mdc_boolean_vals, "unknown"),
3146                                                                tvb_format_stringzpad(tvb, off + 4, 2) );
3147                                         break;
3148
3149                                 case PKT_MDC_SUPP_CODECS:
3150                                 case PKT_MDC_SUPP_CODECS_LC:
3151                                         for (i = 0; i < tlv_len; i++) {
3152                                                 raw_val = tvb_get_ntohs(tvb, off + 4 + (i * 2) );
3153                                                 proto_item_append_text(ti,
3154                                                                        "%s%s (%s)",
3155                                                                        plurality(i + 1, "", ", "),
3156                                                                        val_to_str(raw_val, pkt_mdc_codec_vals, "unknown"),
3157                                                                        tvb_format_stringzpad(tvb, off + 4 + (i * 2), 2) );
3158                                         }
3159                                         break;
3160
3161                                 case PKT_MDC_PROV_FLOWS:
3162                                         tvb_memcpy(tvb, flow_val_str, off + 4, 4);
3163                                         flow_val_str[4] = '\0';
3164                                         flow_val = strtoul((gchar*)flow_val_str, NULL, 16);
3165                                         proto_item_append_text(ti,
3166                                                                "0x%04lx", flow_val);
3167                                         break;
3168
3169                                 case PKT_MDC_T38_VERSION:
3170                                         raw_val = tvb_get_ntohs(tvb, off + 4);
3171                                         proto_item_append_text(ti,
3172                                                                "%s (%s)",
3173                                                                val_to_str(raw_val, pkt_mdc_t38_version_vals, "unknown"),
3174                                                                tvb_format_stringzpad(tvb, off + 4, 2) );
3175                                         break;
3176
3177                                 case PKT_MDC_T38_EC:
3178                                         raw_val = tvb_get_ntohs(tvb, off + 4);
3179                                         proto_item_append_text(ti,
3180                                                                "%s (%s)",
3181                                                                val_to_str(raw_val, pkt_mdc_t38_ec_vals, "unknown"),
3182                                                                tvb_format_stringzpad(tvb, off + 4, 2) );
3183                                         break;
3184
3185                                 case PKT_MDC_MIBS:
3186                                         break;
3187
3188                                 case PKT_MDC_VENDOR_TLV:
3189                                 default:
3190                                         proto_item_append_text(ti,
3191                                                                "%s",
3192                                                                tvb_format_stringzpad(tvb, off + 4, tlv_len * 2) );
3193                                         break;
3194                                 }
3195                         }
3196                         subtree = proto_item_add_subtree(ti, ett_bootp_option);
3197                         if (raw_val == PKT_MDC_PROV_FLOWS) {
3198                                 for (i = 0 ; i < 3; i++) {
3199                                         if (flow_val & pkt_mdc_supp_flow_vals[i].value) {
3200                                                 decode_bitfield_value(bit_fld, flow_val, pkt_mdc_supp_flow_vals[i].value, 16);
3201                                                 proto_tree_add_text(subtree, tvb, off + 4, 4, "%s%s",
3202                                                         bit_fld, pkt_mdc_supp_flow_vals[i].strptr);
3203                                         }
3204                                 }
3205                         } else if (raw_val == PKT_MDC_MIBS) {
3206                         /* 17 06 02 00 38 02 01 07 */
3207                                 subopt_off = off + 4;
3208                                 max_len = subopt_off + (tlv_len * 2);
3209                                 while (subopt_off < max_len) {
3210                                         raw_val = tvb_get_ntohs(tvb, subopt_off);
3211                                         if (raw_val != 0x3032) { /* We only know how to handle a length of 2 */
3212                                                 tvb_memcpy(tvb, asc_val, subopt_off, 2);
3213                                                 proto_tree_add_text(subtree, tvb, subopt_off, 2,
3214                                                                         "[Bogus length: %s]", asc_val);
3215                                                 return;
3216                                         }
3217
3218                                         subopt_off += 2;
3219                                         raw_val = tvb_get_ntohs(tvb, subopt_off);
3220                                         tvb_memcpy(tvb, asc_val, subopt_off, 2);
3221
3222                                         mib_ti = proto_tree_add_text(subtree, tvb, subopt_off, 2, "%s (%s)",
3223                                                 val_to_str(raw_val, pkt_mdc_mib_orgs, "Unknown"), asc_val);
3224                                         if (subopt_off > off + 4 + 2) {
3225                                                 proto_item_append_text(ti, ", ");
3226                                         }
3227                                         proto_item_append_text(ti, "%s", val_to_str(raw_val, pkt_mdc_mib_orgs, "Unknown"));
3228
3229                                         subopt_off += 2;
3230                                         tvb_memcpy(tvb, asc_val, subopt_off, 2);
3231                                         if (sscanf((gchar*)asc_val, "%x", &mib_val) != 1) {
3232                                                 proto_tree_add_text(v_tree, tvb, subopt_off, 2,
3233                                                                         "[Bogus bitfield: %s]", asc_val);
3234                                                 return;
3235                                         }
3236                                         switch (raw_val) {
3237
3238                                         case PKT_MDC_MIB_CL:
3239                                                 subtree2 = proto_item_add_subtree(mib_ti, ett_bootp_option);
3240
3241                                                 for (i = 0; i < 8; i++) {
3242                                                         if (mib_val & pkt_mdc_cl_mib_vals[i].value) {
3243                                                                 decode_bitfield_value(bit_fld, mib_val, pkt_mdc_cl_mib_vals[i].value, 8);
3244                                                                 proto_tree_add_text(subtree2, tvb, subopt_off, 2,
3245                                                                                     "%s%s", bit_fld, pkt_mdc_cl_mib_vals[i].strptr);
3246                                                         }
3247                                                 }
3248                                                 break;
3249
3250                                         case PKT_MDC_MIB_IETF:
3251                                                 subtree2 = proto_item_add_subtree(mib_ti, ett_bootp_option);
3252
3253                                                 for (i = 0; i < 8; i++) {
3254                                                         if (mib_val & pkt_mdc_ietf_mib_vals[i].value) {
3255                                                                 decode_bitfield_value(bit_fld, mib_val, pkt_mdc_ietf_mib_vals[i].value, 8);
3256                                                                 proto_tree_add_text(subtree2, tvb, subopt_off, 2,
3257                                                                                     "%s%s", bit_fld, pkt_mdc_ietf_mib_vals[i].strptr);
3258                                                         }
3259                                                 }
3260                                                 break;
3261
3262                                         default:
3263                                                 break;
3264                                         }
3265                                         subopt_off += 2;
3266                                 }
3267
3268                         }
3269                         off += (tlv_len * 2) + 4;
3270                 }
3271         }
3272 }
3273
3274 static void
3275 dissect_docsis_cm_cap(proto_tree *v_tree, tvbuff_t *tvb, int voff, int len)
3276 {
3277         unsigned long raw_val;
3278         int off = DOCS_CM_TLV_OFF + voff;
3279         guint tlv_len, i;
3280         guint8 asc_val[4] = "  ";
3281         proto_item *ti;
3282
3283         tvb_memcpy (tvb, asc_val, off, 2);
3284         if (sscanf((gchar*)asc_val, "%x", &tlv_len) != 1 || tlv_len < 1) {
3285                 proto_tree_add_text(v_tree, tvb, off, len - off,
3286                                     "Bogus length: %s", asc_val);
3287                 return;
3288         } else {
3289                 proto_tree_add_uint_format_value(v_tree, hf_bootp_docsis_cmcap_len, tvb, off, 2,
3290                                 tlv_len, "%d", tlv_len);
3291                 off += 2;
3292
3293                 while (off - voff < len) {
3294                         /* Type */
3295                         raw_val = tvb_get_ntohs (tvb, off);
3296
3297                         /* Length */
3298                         tvb_memcpy(tvb, asc_val, off + 2, 2);
3299                         if (sscanf((gchar*)asc_val, "%x", &tlv_len) != 1 || tlv_len > 0xff) {
3300                                 proto_tree_add_text(v_tree, tvb, off, len - off,
3301                                                         "[Bogus length: %s]", asc_val);
3302                                 return;
3303                         } else {
3304                                 /* Value(s) */
3305                                 ti = proto_tree_add_text(v_tree, tvb, off,
3306                                     (tlv_len * 2) + 4,
3307                                     "0x%s: %s = ",
3308                                     tvb_format_text(tvb, off, 2),
3309                                     val_to_str(raw_val, docs_cm_type_vals, "unknown"));
3310                                 switch (raw_val) {
3311
3312                                 case DOCS_CM_CONCAT_SUP:
3313                                 case DOCS_CM_FRAG_SUP:
3314                                 case DOCS_CM_PHS_SUP:
3315                                 case DOCS_CM_IGMP_SUP:
3316                                 case DOCS_CM_DCC_SUP:
3317                                 case DOCS_CM_DCC_SUP_LC:
3318                                         for (i = 0; i < tlv_len; i++) {
3319                                                 raw_val = tvb_get_ntohs(tvb, off + 4 + (i * 2) );
3320                                                 proto_item_append_text(ti,
3321                                                                        "%s%s (%s)",
3322                                                                        plurality(i + 1, "", ", "),
3323                                                                        val_to_str(raw_val, pkt_mdc_boolean_vals, "unknown"),
3324                                                                        tvb_format_text(tvb, off + 4 + (i * 2), 2) );
3325                                         }
3326                                         break;
3327
3328                                 case DOCS_CM_DOCSIS_VER:
3329                                         raw_val = tvb_get_ntohs(tvb, off + 4);
3330                                         proto_item_append_text(ti,
3331                                                                "%s (%s)",
3332                                                                val_to_str(raw_val, docs_cm_version_vals, "Reserved"),
3333                                                                tvb_format_text(tvb, off + 4, 2) );
3334                                         break;
3335
3336                                 case DOCS_CM_PRIV_SUP:
3337                                         raw_val = tvb_get_ntohs(tvb, off + 4);
3338                                         proto_item_append_text(ti,
3339                                                                "%s (%s)",
3340                                                                val_to_str(raw_val, docs_cm_privacy_vals, "Reserved"),
3341                                                                tvb_format_text(tvb, off + 4, 2) );
3342                                         break;
3343
3344                                 case DOCS_CM_DSAID_SUP:
3345                                 case DOCS_CM_USID_SUP:
3346                                 case DOCS_CM_TET_MI:
3347                                 case DOCS_CM_TET_MI_LC:
3348                                 case DOCS_CM_TET:
3349                                 case DOCS_CM_TET_LC:
3350                                         tvb_memcpy (tvb, asc_val, off + 4, 2);
3351                                         raw_val = strtoul((gchar*)asc_val, NULL, 16);
3352                                         proto_item_append_text(ti,
3353                                                                "%lu", raw_val);
3354                                         break;
3355
3356                                 case DOCS_CM_IPFILT_SUP:
3357                                 case DOCS_CM_IPFILT_SUP_LC:
3358                                 case DOCS_CM_LLCFILT_SUP:
3359                                 case DOCS_CM_LLCFILT_SUP_LC:
3360                                         tvb_memcpy (tvb, asc_val, off + 4, 4);
3361                                         raw_val = strtoul((gchar*)asc_val, NULL, 16);
3362                                         proto_item_append_text(ti,
3363                                                                "%lu", raw_val);
3364                                         break;
3365
3366                                 case DOCS_CM_FILT_SUP:
3367                                         tvb_memcpy (tvb, asc_val, off + 4, 2);
3368                                         raw_val = strtoul((gchar*)asc_val, NULL, 16);
3369                                         if (raw_val & 0x01)
3370                                                 proto_item_append_text(ti,
3371                                                                        "802.1p filtering");
3372                                         if (raw_val & 0x02) {
3373                                                 if (raw_val & 0x01)
3374                                                         proto_item_append_text(ti, ", ");
3375                                                 proto_item_append_text(ti,
3376                                                                        "802.1Q filtering");
3377                                         }
3378                                         if (!(raw_val & 0x03))
3379                                                 proto_item_append_text(ti,
3380                                                                        "None");
3381                                         proto_item_append_text(ti,
3382                                                                " (0x%02lx)", raw_val);
3383                                         break;
3384                                 }
3385                         }
3386                         off += (tlv_len * 2) + 4;
3387                 }
3388         }
3389 }
3390
3391
3392 /* Definitions specific to PKT-SP-PROV-I05-021127 begin with "PKT_CCC_I05".
3393    Definitions specific to IETF draft 5 and RFC 3495 begin with "PKT_CCC_IETF".
3394    Shared definitions begin with "PKT_CCC".
3395  */
3396 #define PKT_CCC_PRI_DHCP       1
3397 #define PKT_CCC_SEC_DHCP       2
3398 #define PKT_CCC_I05_SNMP       3
3399 #define PKT_CCC_IETF_PROV_SRV  3
3400 #define PKT_CCC_I05_PRI_DNS    4
3401 #define PKT_CCC_IETF_AS_KRB    4
3402 #define PKT_CCC_I05_SEC_DNS    5
3403 #define PKT_CCC_IETF_AP_KRB    5
3404 #define PKT_CCC_KRB_REALM      6
3405 #define PKT_CCC_TGT_FLAG       7
3406 #define PKT_CCC_PROV_TIMER     8
3407 #define PKT_CCC_CMS_FQDN       9
3408 #define PKT_CCC_IETF_SEC_TKT   9
3409 #define PKT_CCC_AS_KRB        10
3410 #define PKT_CCC_AP_KRB        11
3411 #define PKT_CCC_MTA_KRB_CLEAR 12
3412
3413 static const value_string pkt_i05_ccc_opt_vals[] = {
3414         { PKT_CCC_PRI_DHCP,                     "Primary DHCP Server" },
3415         { PKT_CCC_SEC_DHCP,                     "Secondary DHCP Server" },
3416         { PKT_CCC_I05_SNMP,                     "SNMP Entity" },
3417         { PKT_CCC_I05_PRI_DNS,          "Primary DNS Server" },
3418         { PKT_CCC_I05_SEC_DNS,          "Secondary DNS Server" },
3419         { PKT_CCC_KRB_REALM,            "Kerberos Realm" },
3420         { PKT_CCC_TGT_FLAG,                     "MTA should fetch TGT?" },
3421         { PKT_CCC_PROV_TIMER,           "Provisioning Timer" },
3422         { PKT_CCC_CMS_FQDN,                     "CMS FQDN" },
3423         { PKT_CCC_AS_KRB,                       "AS-REQ/AS-REP Backoff and Retry" },
3424         { PKT_CCC_AP_KRB,                       "AP-REQ/AP-REP Backoff and Retry" },
3425         { PKT_CCC_MTA_KRB_CLEAR,        "MTA should clear Kerberos tickets?" },
3426         { 0, NULL },
3427 };
3428
3429 static const value_string pkt_draft5_ccc_opt_vals[] = {
3430         { PKT_CCC_PRI_DHCP,             "TSP's Primary DHCP Server" },
3431         { PKT_CCC_SEC_DHCP,             "TSP's Secondary DHCP Server" },
3432         { PKT_CCC_IETF_PROV_SRV,        "TSP's Provisioning Server" },
3433         { PKT_CCC_IETF_AS_KRB,          "TSP's AS-REQ/AS-REP Backoff and Retry" },
3434         { PKT_CCC_IETF_AP_KRB,          "TSP's AP-REQ/AP-REP Backoff and Retry" },
3435         { PKT_CCC_KRB_REALM,            "TSP's Kerberos Realm Name" },
3436         { PKT_CCC_TGT_FLAG,             "TSP's Ticket Granting Server Utilization" },
3437         { PKT_CCC_PROV_TIMER,           "TSP's Provisioning Timer Value" },
3438         { PKT_CCC_IETF_SEC_TKT,         "PacketCable Security Ticket Control" },
3439         { 0, NULL },
3440 };
3441
3442 static const value_string pkt_i05_ccc_ticket_ctl_vals[] = {
3443         { 1, "Invalidate Provisioning Application Server's ticket" },
3444         { 2, "Invalidate all CMS Application Server tickets" },
3445         { 3, "Invalidate all Application Server tickets" },
3446         { 0, NULL },
3447 };
3448
3449 static int
3450 dissect_packetcable_i05_ccc(proto_tree *v_tree, tvbuff_t *tvb, int optoff,
3451     int optend)
3452 {
3453         int suboptoff = optoff;
3454         guint8 subopt, subopt_len, fetch_tgt, timer_val, ticket_ctl;
3455         proto_tree *pkt_s_tree;
3456         proto_item *vti;
3457
3458         subopt = tvb_get_guint8(tvb, optoff);
3459         suboptoff++;
3460
3461         if (suboptoff >= optend) {
3462                 proto_tree_add_text(v_tree, tvb, optoff, 1,
3463                         "Suboption %d: no room left in option for suboption length",
3464                         subopt);
3465                 return (optend);
3466         }
3467         subopt_len = tvb_get_guint8(tvb, optoff);
3468         suboptoff++;
3469
3470         vti = proto_tree_add_text(v_tree, tvb, optoff, subopt_len + 2,
3471             "Suboption %u: %s: ", subopt,
3472             val_to_str(subopt, pkt_i05_ccc_opt_vals, "unknown/reserved") );
3473
3474         switch (subopt) {
3475
3476         case PKT_CCC_PRI_DHCP:  /* String values */
3477         case PKT_CCC_SEC_DHCP:
3478         case PKT_CCC_I05_SNMP:
3479         case PKT_CCC_I05_PRI_DNS:
3480         case PKT_CCC_I05_SEC_DNS:
3481         case PKT_CCC_KRB_REALM:
3482         case PKT_CCC_CMS_FQDN:
3483                 proto_item_append_text(vti, "%s (%u byte%s)",
3484                                        tvb_format_stringzpad(tvb, suboptoff, subopt_len),
3485                                        subopt_len,
3486                                        plurality(subopt_len, "", "s") );
3487                 suboptoff += subopt_len;
3488                 break;
3489
3490         case PKT_CCC_TGT_FLAG:
3491                 if (suboptoff+1 > optend) {
3492                         proto_item_append_text(vti,
3493                                                "no room left in option for suboption value");
3494                         return (optend);
3495                 }
3496                 fetch_tgt = tvb_get_guint8(tvb, suboptoff);
3497                 proto_item_append_text(vti, "%s (%u byte%s%s)",
3498                                        fetch_tgt ? "Yes" : "No",
3499                                        subopt_len,
3500                                        plurality(subopt_len, "", "s"),
3501                                        subopt_len != 1 ? " [Invalid]" : "");
3502                 suboptoff += subopt_len;
3503                 break;
3504
3505         case PKT_CCC_PROV_TIMER:
3506                 if (suboptoff+1 > optend) {
3507                         proto_item_append_text(vti,
3508                                                "no room left in option for suboption value");
3509                         return (optend);
3510                 }
3511                 timer_val = tvb_get_guint8(tvb, suboptoff);
3512                 proto_item_append_text(vti, "%u%s (%u byte%s%s)", timer_val,
3513                                        timer_val > 30 ? " [Invalid]" : "",
3514                                        subopt_len,
3515                                        plurality(subopt_len, "", "s"),
3516                                        subopt_len != 1 ? " [Invalid]" : "");
3517                 suboptoff += subopt_len;
3518                 break;
3519
3520         case PKT_CCC_AS_KRB:
3521                 if (suboptoff+12 > optend) {
3522                         proto_item_append_text(vti,
3523                                                "no room left in option for suboption value");
3524                         return (optend);
3525                 }
3526                 proto_item_append_text(vti, "(%u byte%s%s)", subopt_len,
3527                                        plurality(subopt_len, "", "s"),
3528                                        subopt_len != 12 ? " [Invalid]" : "");
3529                 if (subopt_len == 12) {
3530                         pkt_s_tree = proto_item_add_subtree(vti, ett_bootp_option);
3531                         proto_tree_add_text(pkt_s_tree, tvb, suboptoff, 4,
3532                                             "pktcMtaDevRealmUnsolicitedKeyNomTimeout: %u",
3533                                             tvb_get_ntohl(tvb, suboptoff));
3534                         proto_tree_add_text(pkt_s_tree, tvb, suboptoff + 4, 4,
3535                                             "pktcMtaDevRealmUnsolicitedKeyMaxTimeout: %u",
3536                                             tvb_get_ntohl(tvb, suboptoff + 4));
3537                         proto_tree_add_text(pkt_s_tree, tvb, suboptoff + 8, 4,
3538                                             "pktcMtaDevRealmUnsolicitedKeyMaxRetries: %u",
3539                                             tvb_get_ntohl(tvb, suboptoff + 8));
3540                 }
3541                 suboptoff += subopt_len;
3542                 break;
3543
3544         case PKT_CCC_AP_KRB:
3545                 if (suboptoff+12 > optend) {
3546                         proto_item_append_text(vti,
3547                                                "no room left in option for suboption value");
3548                         return (optend);
3549                 }
3550                 proto_item_append_text(vti, "(%u byte%s%s)", subopt_len,
3551                                        plurality(subopt_len, "", "s"),
3552                                        subopt_len != 12 ? " [Invalid]" : "");
3553                 if (subopt_len == 12) {
3554                         pkt_s_tree = proto_item_add_subtree(vti, ett_bootp_option);
3555                         proto_tree_add_text(pkt_s_tree, tvb, suboptoff, 4,
3556                                             "pktcMtaDevProvUnsolicitedKeyNomTimeout: %u",
3557                                             tvb_get_ntohl(tvb, suboptoff));
3558                         proto_tree_add_text(pkt_s_tree, tvb, suboptoff + 4, 4,
3559                                             "pktcMtaDevProvUnsolicitedKeyMaxTimeout: %u",
3560                                             tvb_get_ntohl(tvb, suboptoff + 4));
3561                         proto_tree_add_text(pkt_s_tree, tvb, suboptoff + 8, 4,
3562                                             "pktcMtaDevProvUnsolicitedKeyMaxRetries: %u",
3563                                             tvb_get_ntohl(tvb, suboptoff + 8));
3564                 }
3565                 suboptoff += subopt_len;
3566                 break;
3567
3568         case PKT_CCC_MTA_KRB_CLEAR:
3569                 if (suboptoff+1 > optend) {
3570                         proto_item_append_text(vti,
3571                                                "no room left in option for suboption value");
3572                         return (optend);
3573                 }
3574                 ticket_ctl = tvb_get_guint8(tvb, suboptoff);
3575                 proto_item_append_text(vti, "%s (%u) (%u byte%s%s)",
3576                                        val_to_str (ticket_ctl, pkt_i05_ccc_ticket_ctl_vals, "unknown/invalid"),
3577                                        ticket_ctl,
3578                                        subopt_len,
3579                                        plurality(subopt_len, "", "s"),
3580                                        subopt_len != 1 ? " [Invalid]" : "");
3581                 suboptoff += subopt_len;
3582                 break;
3583
3584         default:
3585                 suboptoff += subopt_len;
3586                 break;
3587
3588         }
3589         return suboptoff;
3590 }
3591
3592
3593 static const value_string sec_tcm_vals[] = {
3594         { 1 << 0, "PacketCable Provisioning Server" },
3595         { 1 << 1, "All PacketCable Call Management Servers" },
3596         { 0, NULL }
3597 };
3598
3599 static int
3600 dissect_packetcable_ietf_ccc(proto_tree *v_tree, tvbuff_t *tvb, int optoff,
3601     int optend, int revision)
3602 {
3603         int suboptoff = optoff;
3604         guint8 subopt, subopt_len;
3605         guint32 ipv4addr;
3606         guint8 prov_type, fetch_tgt, timer_val;
3607         guint16 sec_tcm;
3608         proto_tree *pkt_s_tree;
3609         proto_item *vti;
3610         int max_timer_val = 255, i;
3611         const guchar *dns_name;
3612         char bit_fld[24];
3613
3614         subopt = tvb_get_guint8(tvb, suboptoff);
3615         suboptoff++;
3616
3617         if (suboptoff >= optend) {
3618                 proto_tree_add_text(v_tree, tvb, optoff, 1,
3619                         "Suboption %d: no room left in option for suboption length",
3620                         subopt);
3621                 return (optend);
3622         }
3623         subopt_len = tvb_get_guint8(tvb, suboptoff);
3624         suboptoff++;
3625
3626         vti = proto_tree_add_text(v_tree, tvb, optoff, subopt_len + 2,
3627             "Suboption %u: %s: ", subopt,
3628             val_to_str(subopt, pkt_draft5_ccc_opt_vals, "unknown/reserved") );
3629
3630         switch (subopt) {
3631
3632         case PKT_CCC_PRI_DHCP:  /* IPv4 values */
3633         case PKT_CCC_SEC_DHCP:
3634                 if (suboptoff+4 > optend) {
3635                         proto_item_append_text(vti,
3636                                                "no room left in option for suboption value");
3637                         return (optend);
3638                 }
3639                 ipv4addr = tvb_get_ipv4(tvb, suboptoff);
3640                 proto_item_append_text(vti, "%s (%u byte%s%s)",
3641                                        ip_to_str((guint8 *)&ipv4addr),
3642                                        subopt_len,
3643                                        plurality(subopt_len, "", "s"),
3644                                        subopt_len != 4 ? " [Invalid]" : "");
3645                 suboptoff += subopt_len;
3646                 break;
3647
3648         case PKT_CCC_IETF_PROV_SRV:
3649                 if (suboptoff+1 > optend) {
3650                         proto_item_append_text(vti,
3651                                                "no room left in option for suboption value");
3652                         return (optend);
3653                 }
3654                 prov_type = tvb_get_guint8(tvb, suboptoff);
3655                 suboptoff += 1;
3656                 switch (prov_type) {
3657
3658                 case 0:
3659                         get_dns_name(tvb, suboptoff, subopt_len, suboptoff, &dns_name);
3660                         proto_item_append_text(vti, "%s (%u byte%s)", dns_name,
3661                                                subopt_len - 1, plurality(subopt_len, "", "s") );
3662                         break;
3663
3664                 case 1:
3665                         if (suboptoff+4 > optend) {
3666                                 proto_item_append_text(vti,
3667                                                        "no room left in option for suboption value");
3668                                 return (optend);
3669                         }
3670                         ipv4addr = tvb_get_ipv4(tvb, suboptoff);
3671                         proto_item_append_text(vti, "%s (%u byte%s%s)",
3672                                                ip_to_str((guint8 *)&ipv4addr),
3673                                                subopt_len,
3674                                                plurality(subopt_len, "", "s"),
3675                                                subopt_len != 5 ? " [Invalid]" : "");
3676                         break;
3677
3678                 default:
3679                         proto_item_append_text(vti, "Invalid type: %u (%u byte%s)",
3680                                                prov_type,
3681                                                subopt_len,
3682                                                plurality(subopt_len, "", "s") );
3683                         break;
3684                 }
3685                 suboptoff += subopt_len - 1;
3686                 break;
3687
3688         case PKT_CCC_IETF_AS_KRB:
3689                 if (suboptoff+12 > optend) {
3690                         proto_item_append_text(vti,
3691                                                "no room left in option for suboption value");
3692                         return (optend);
3693                 }
3694                 proto_item_append_text(vti, "(%u byte%s%s)", subopt_len,
3695                                        plurality(subopt_len, "", "s"),
3696                                        subopt_len != 12 ? " [Invalid]" : "");
3697                 if (subopt_len == 12) {
3698                         pkt_s_tree = proto_item_add_subtree(vti, ett_bootp_option);
3699                         proto_tree_add_text(pkt_s_tree, tvb, suboptoff, 4,
3700                                             "pktcMtaDevRealmUnsolicitedKeyNomTimeout: %u",
3701                                             tvb_get_ntohl(tvb, suboptoff));
3702                         proto_tree_add_text(pkt_s_tree, tvb, suboptoff + 4, 4,
3703                                             "pktcMtaDevRealmUnsolicitedKeyMaxTimeout: %u",
3704                                             tvb_get_ntohl(tvb, suboptoff + 4));
3705                         proto_tree_add_text(pkt_s_tree, tvb, suboptoff + 8, 4,
3706                                             "pktcMtaDevRealmUnsolicitedKeyMaxRetries: %u",
3707                                             tvb_get_ntohl(tvb, suboptoff + 8));
3708                 }
3709                 suboptoff += subopt_len;
3710                 break;
3711
3712         case PKT_CCC_IETF_AP_KRB:
3713                 proto_item_append_text(vti, "(%u byte%s%s)", subopt_len,
3714                                        plurality(subopt_len, "", "s"),
3715                                        subopt_len != 12 ? " [Invalid]" : "");
3716                 if (subopt_len == 12) {
3717                         pkt_s_tree = proto_item_add_subtree(vti, ett_bootp_option);
3718                         proto_tree_add_text(pkt_s_tree, tvb, suboptoff, 4,
3719                                             "pktcMtaDevProvUnsolicitedKeyNomTimeout: %u",
3720                                             tvb_get_ntohl(tvb, suboptoff));
3721                         proto_tree_add_text(pkt_s_tree, tvb, suboptoff + 4, 4,
3722                                             "pktcMtaDevProvUnsolicitedKeyMaxTimeout: %u",
3723                                             tvb_get_ntohl(tvb, suboptoff + 4));
3724                         proto_tree_add_text(pkt_s_tree, tvb, suboptoff + 8, 4,
3725                                             "pktcMtaDevProvUnsolicitedKeyMaxRetries: %u",
3726                                             tvb_get_ntohl(tvb, suboptoff + 8));
3727                 }
3728                 suboptoff += subopt_len;
3729                 break;
3730
3731         case PKT_CCC_KRB_REALM: /* String values */
3732                 get_dns_name(tvb, suboptoff, subopt_len, suboptoff, &dns_name);
3733                 proto_item_append_text(vti, "%s (%u byte%s)", dns_name,
3734                                        subopt_len, plurality(subopt_len, "", "s") );
3735                 suboptoff += subopt_len;
3736                 break;
3737
3738         case PKT_CCC_TGT_FLAG:
3739                 if (suboptoff+1 > optend) {
3740                         proto_item_append_text(vti,
3741                                                "no room left in option for suboption value");
3742                         return (optend);
3743                 }
3744                 fetch_tgt = tvb_get_guint8(tvb, suboptoff);
3745                 proto_item_append_text(vti, "%s (%u byte%s%s)",
3746                                        fetch_tgt ? "Yes" : "No",
3747                                        subopt_len,
3748                                        plurality(subopt_len, "", "s"),
3749                                        subopt_len != 1 ? " [Invalid]" : "");
3750                 suboptoff += 1;
3751                 break;
3752
3753         case PKT_CCC_PROV_TIMER:
3754                 if (suboptoff+1 > optend) {
3755                         proto_item_append_text(vti,
3756                                                "no room left in option for suboption value");
3757                         return (optend);
3758                 }
3759                 if (revision == PACKETCABLE_CCC_DRAFT5)
3760                         max_timer_val = 30;
3761                 timer_val = tvb_get_guint8(tvb, suboptoff);
3762                 proto_item_append_text(vti, "%u%s (%u byte%s%s)", timer_val,
3763                                        timer_val > max_timer_val ? " [Invalid]" : "",
3764                                        subopt_len,
3765                                        plurality(subopt_len, "", "s"),
3766                                        subopt_len != 1 ? " [Invalid]" : "");
3767                 suboptoff += 1;
3768                 break;
3769
3770         case PKT_CCC_IETF_SEC_TKT:
3771                 if (suboptoff+2 > optend) {
3772                         proto_item_append_text(vti,
3773                                                "no room left in option for suboption value");
3774                         return (optend);
3775                 }
3776                 sec_tcm = tvb_get_ntohs(tvb, suboptoff);
3777                 proto_item_append_text(vti, "0x%04x (%u byte%s%s)", sec_tcm, subopt_len,
3778                                        plurality(subopt_len, "", "s"),
3779                                        subopt_len != 2 ? " [Invalid]" : "");
3780                 if (subopt_len == 2) {
3781                         pkt_s_tree = proto_item_add_subtree(vti, ett_bootp_option);
3782                         for (i = 0; i < 2; i++) {
3783                                 if (sec_tcm & sec_tcm_vals[i].value) {
3784                                         decode_bitfield_value(bit_fld, sec_tcm, sec_tcm_vals[i].value, 16);
3785                                         proto_tree_add_text(pkt_s_tree, tvb, suboptoff, 2, "%sInvalidate %s",
3786                                                             bit_fld, sec_tcm_vals[i].strptr);
3787                                 }
3788                         }
3789                 }
3790                 suboptoff += subopt_len;
3791                 break;
3792
3793         default:
3794                 suboptoff += subopt_len;
3795                 break;
3796         }
3797         return suboptoff;
3798 }
3799
3800 #define BOOTREQUEST     1
3801 #define BOOTREPLY       2
3802
3803 static const value_string op_vals[] = {
3804         { BOOTREQUEST,  "Boot Request" },
3805         { BOOTREPLY,    "Boot Reply" },
3806         { 0,            NULL }
3807 };
3808
3809 static void
3810 dissect_bootp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
3811 {
3812         proto_tree      *bp_tree;
3813         proto_item      *ti;
3814         proto_tree      *flag_tree;
3815         proto_item      *fi, *hidden_item;
3816         guint8          op;
3817         guint8          htype, hlen;
3818         const guint8    *haddr;
3819         int             voff, eoff, tmpvoff; /* vendor offset, end offset */
3820         guint32         ip_addr;
3821         gboolean        at_end;
3822         const char      *dhcp_type = NULL;
3823         const guint8    *vendor_class_id = NULL;
3824         guint16         flags, secs;
3825         int             offset_delta;
3826         guint8          overload = 0; /* DHCP option overload */
3827
3828         col_set_str(pinfo->cinfo, COL_PROTOCOL, "BOOTP");
3829         /*
3830          * In case we throw an exception fetching the opcode, etc.
3831          */
3832         col_clear(pinfo->cinfo, COL_INFO);
3833
3834         op = tvb_get_guint8(tvb, 0);
3835         htype = tvb_get_guint8(tvb, 1);
3836         hlen = tvb_get_guint8(tvb, 2);
3837         switch (op) {
3838
3839         case BOOTREQUEST:
3840                 if ((htype == ARPHRD_ETHER || htype == ARPHRD_IEEE802)
3841                     && hlen == 6) {
3842                         if (check_col(pinfo->cinfo, COL_INFO)) { 
3843                                 col_add_fstr(pinfo->cinfo, COL_INFO, "Boot Request from %s (%s)",
3844                                              arphrdaddr_to_str(tvb_get_ptr(tvb, 28, hlen),
3845                                                                hlen, htype),
3846                                              get_ether_name(tvb_get_ptr(tvb, 28, hlen)));
3847                         }
3848                 }
3849                 else {
3850                         if (check_col(pinfo->cinfo, COL_INFO)) {
3851                                 col_add_fstr(pinfo->cinfo, COL_INFO, "Boot Request from %s",
3852                                              arphrdaddr_to_str(tvb_get_ptr(tvb, 28, hlen),
3853                                                                hlen, htype));
3854                         }
3855                 }
3856                 break;
3857
3858         case BOOTREPLY:
3859                 col_set_str(pinfo->cinfo, COL_INFO, "Boot Reply");
3860                 break;
3861
3862         default:
3863                 if (check_col(pinfo->cinfo, COL_INFO))  
3864                         col_add_fstr(pinfo->cinfo, COL_INFO, "Unknown BOOTP message type (%u)", op);
3865                 break;
3866         }
3867
3868         voff = VENDOR_INFO_OFFSET;
3869
3870         /* rfc2132 says it SHOULD exist, not that it MUST exist */
3871         if (tvb_bytes_exist(tvb, voff, 4) &&
3872             (tvb_get_ntohl(tvb, voff) == 0x63825363)) {
3873                 voff += 4;
3874         } else {
3875                 voff += 64;
3876         }
3877         eoff = tvb_reported_length(tvb);
3878
3879         /*
3880          * In the first pass, we just look for the DHCP message type
3881          * and Vendor class identifier options.
3882          */
3883         tmpvoff = voff;
3884         at_end = FALSE;
3885         while (tmpvoff < eoff && !at_end) {
3886                 offset_delta = bootp_option(tvb, 0, tmpvoff, eoff, TRUE, &at_end,
3887                     &dhcp_type, &vendor_class_id, &overload);
3888                 if (offset_delta <= 0) {
3889                         THROW(ReportedBoundsError);
3890                 }
3891                 tmpvoff += offset_delta;
3892         }
3893
3894         /*
3895          * If there was a DHCP message type option, flag this packet
3896          * as DHCP.
3897          */
3898         if (dhcp_type != NULL) {
3899                 /*
3900                  * Yes, this is a DHCP packet, and "dhcp_type" is the
3901                  * packet type.
3902                  */
3903                 col_set_str(pinfo->cinfo, COL_PROTOCOL, "DHCP");
3904                 if (check_col(pinfo->cinfo, COL_INFO))  
3905                         col_add_fstr(pinfo->cinfo, COL_INFO, "DHCP %-8s - Transaction ID 0x%x",
3906                                      dhcp_type, tvb_get_ntohl(tvb, 4));
3907                 tap_queue_packet( bootp_dhcp_tap, pinfo, dhcp_type);
3908         }
3909
3910         /*
3911          * OK, now build the protocol tree.
3912          */
3913
3914         ti = proto_tree_add_item(tree, proto_bootp, tvb, 0, -1, FALSE);
3915         bp_tree = proto_item_add_subtree(ti, ett_bootp);
3916
3917         proto_tree_add_uint(bp_tree, hf_bootp_type, tvb,
3918                                    0, 1,
3919                                    op);
3920         proto_tree_add_uint_format_value(bp_tree, hf_bootp_hw_type, tvb,
3921                                          1, 1,
3922                                          htype,
3923                                          "%s",
3924                                          arphrdtype_to_str(htype,
3925                                                      "Unknown (0x%02x)"));
3926         proto_tree_add_uint(bp_tree, hf_bootp_hw_len, tvb,
3927                             2, 1, hlen);
3928         proto_tree_add_item(bp_tree, hf_bootp_hops, tvb,
3929                             3, 1, FALSE);
3930         proto_tree_add_item(bp_tree, hf_bootp_id, tvb,
3931                             4, 4, FALSE);
3932         /*
3933          * Windows (98, XP and Vista tested) sends the "secs" value on
3934          * the wire formatted as little-endian. See if the LE value
3935          * makes sense.
3936          */
3937         secs = tvb_get_letohs(tvb, 8);
3938         if (secs > 0 && secs <= 0xff) {
3939                 ti = proto_tree_add_uint_format_value(bp_tree, hf_bootp_secs, tvb,
3940                             8, 2, secs, "%u", secs);
3941                 expert_add_info_format(pinfo, ti, PI_MALFORMED, PI_NOTE,
3942                             "Seconds elapsed (%u) appears to be encoded as little-endian", secs);
3943         } else {
3944                 proto_tree_add_item(bp_tree, hf_bootp_secs, tvb,
3945                             8, 2, FALSE);
3946         }
3947
3948         /*
3949          * If we're not building the protocol tree, we don't need to
3950          * make a second pass.
3951          */
3952         if (tree == NULL)
3953                 return;
3954
3955         flags = tvb_get_ntohs(tvb, 10);
3956         fi = proto_tree_add_uint(bp_tree, hf_bootp_flags, tvb,
3957                             10, 2, flags);
3958         proto_item_append_text(fi, " (%s)",
3959             (flags & BOOTP_BC) ? "Broadcast" : "Unicast");
3960         flag_tree = proto_item_add_subtree(fi, ett_bootp_flags);
3961         proto_tree_add_boolean(flag_tree, hf_bootp_flags_broadcast, tvb,
3962                             10, 2, flags);
3963         proto_tree_add_uint(flag_tree, hf_bootp_flags_reserved, tvb,
3964                             10, 2, flags);
3965         proto_tree_add_item(bp_tree, hf_bootp_ip_client, tvb,
3966                             12, 4, FALSE);
3967         proto_tree_add_item(bp_tree, hf_bootp_ip_your, tvb,
3968                             16, 4, FALSE);
3969         proto_tree_add_item(bp_tree, hf_bootp_ip_server, tvb,
3970                             20, 4, FALSE);
3971         proto_tree_add_item(bp_tree, hf_bootp_ip_relay, tvb,
3972                             24, 4, FALSE);
3973
3974         if (hlen > 0 && hlen <= 16) {
3975                 haddr = tvb_get_ptr(tvb, 28, hlen);
3976                 if ((htype == ARPHRD_ETHER || htype == ARPHRD_IEEE802)
3977                     && hlen == 6)
3978                         proto_tree_add_item(bp_tree, hf_bootp_hw_ether_addr, tvb, 28, 6, FALSE);
3979                 else
3980                         /* The chaddr element is 16 bytes in length,
3981                            although only the first hlen bytes are used */
3982                         proto_tree_add_bytes_format_value(bp_tree, hf_bootp_hw_addr, tvb, 28, 16,
3983                                            haddr,
3984                                            "%s", arphrdaddr_to_str(haddr, hlen, htype));
3985                 if ((16 - hlen) > 0)
3986                         proto_tree_add_item(bp_tree, hf_bootp_hw_addr_padding, tvb, 28+hlen, 16-hlen, FALSE);
3987         } else {
3988                 proto_tree_add_text(bp_tree,  tvb,
3989                                            28, 16, "Client address not given");
3990         }
3991
3992         /* The server host name is optional */
3993         if (tvb_get_guint8(tvb, SERVER_NAME_OFFSET) != '\0') {
3994                 if (overload & OPT_OVERLOAD_SNAME) {
3995                         proto_tree_add_text (bp_tree, tvb,
3996                                 SERVER_NAME_OFFSET, SERVER_NAME_LEN,
3997                                 "Server name option overloaded by DHCP");
3998                 } else {
3999                         proto_tree_add_item(bp_tree, hf_bootp_server, tvb,
4000                                            SERVER_NAME_OFFSET,
4001                                            SERVER_NAME_LEN, FALSE);
4002                 }
4003         } else {
4004                 proto_tree_add_string_format(bp_tree, hf_bootp_server, tvb,
4005                                            SERVER_NAME_OFFSET,
4006                                            SERVER_NAME_LEN,
4007                                            (const gchar*)tvb_get_ptr(tvb, SERVER_NAME_OFFSET, 1),
4008                                            "Server host name not given");
4009         }
4010
4011         /* Boot file */
4012         if (tvb_get_guint8(tvb, FILE_NAME_OFFSET) != '\0') {
4013                 if (overload & OPT_OVERLOAD_FILE) {
4014                         proto_tree_add_text (bp_tree, tvb,
4015                                 FILE_NAME_OFFSET, FILE_NAME_LEN,
4016                                 "Boot file name option overloaded by DHCP");
4017                 } else {
4018                         proto_tree_add_item(bp_tree, hf_bootp_file, tvb,
4019                                            FILE_NAME_OFFSET,
4020                                            FILE_NAME_LEN, FALSE);
4021                 }
4022         } else {
4023                 proto_tree_add_string_format(bp_tree, hf_bootp_file, tvb,
4024                                            FILE_NAME_OFFSET,
4025                                            FILE_NAME_LEN,
4026                                            (const gchar*)tvb_get_ptr(tvb, FILE_NAME_OFFSET, 1),
4027                                            "Boot file name not given");
4028         }
4029
4030         voff = VENDOR_INFO_OFFSET;
4031         if (dhcp_type != NULL) {
4032                 hidden_item = proto_tree_add_boolean(bp_tree, hf_bootp_dhcp, tvb, 0, 0, 1);
4033                 PROTO_ITEM_SET_HIDDEN(hidden_item);
4034         }
4035         if (tvb_bytes_exist(tvb, voff, 4) &&
4036             (tvb_get_ntohl(tvb, voff) == 0x63825363)) {
4037                 ip_addr = tvb_get_ipv4(tvb, voff);
4038                 proto_tree_add_ipv4_format_value(bp_tree, hf_bootp_cookie, tvb,
4039                         voff, 4, ip_addr, "(OK)");
4040                 voff += 4;
4041         } else {
4042                 proto_tree_add_text(bp_tree,  tvb,
4043                         voff, 64, "Bootp vendor specific options");
4044                 voff += 64;
4045         }
4046
4047         at_end = FALSE;
4048         while (voff < eoff && !at_end) {
4049                 offset_delta = bootp_option(tvb, bp_tree, voff, eoff, FALSE, &at_end,
4050                     &dhcp_type, &vendor_class_id, &overload);
4051                 if (offset_delta <= 0) {
4052                         THROW(ReportedBoundsError);
4053                 }
4054                 voff += offset_delta;
4055         }
4056         if (voff < eoff) {
4057                 /*
4058                  * Padding after the end option.
4059                  */
4060                 proto_tree_add_text(bp_tree, tvb, voff, eoff - voff, "Padding");
4061         }
4062 }
4063
4064 static void 
4065 bootp_init_protocol(void)
4066 {
4067         gchar **optionstrings = NULL;
4068         gchar **optiondetail = NULL;
4069         gchar *type = NULL;
4070         guint i, ii;
4071
4072         /* first copy default_bootp_opt[] to bootp_opt[].  This resets all values to default */
4073         for(i=0; i<BOOTP_OPT_NUM; i++)
4074         {
4075                 bootp_opt[i].text = default_bootp_opt[i].text;
4076                 bootp_opt[i].ftype = default_bootp_opt[i].ftype;
4077                 bootp_opt[i].data = default_bootp_opt[i].data;
4078         }
4079
4080         /* now split semicolon seperated fields groups */
4081         optionstrings = ep_strsplit(pref_optionstring, ";", -1);
4082         for (i=0;optionstrings[i]!=NULL;i++)
4083         {
4084                 /* input string should have 3 fields:
4085                    1 - bootp option - uint8 1-254, not being a special
4086                    2 - option name - string
4087                    3 - option type - defined in enum represented as a string
4088                 */
4089
4090                 /* now split field groups to usable data */
4091                 optiondetail = ep_strsplit(optionstrings[i], ",",-1);
4092                 /* verify array has 3 or more entries, any entries beyond 3 are ingnored */
4093                 for(ii=0;(optiondetail[ii]!=NULL);ii++)
4094                 {
4095                         /* do nothing */
4096                 }
4097                 if (ii < 3) continue;                            /* not enough values.  Go again              */
4098                 ii = atoi(optiondetail[0]);                      /* get the bootp option number               */
4099                 if (ii==0 || ii>=BOOTP_OPT_NUM-1) continue;      /* not a number or out of range.  Go again   */
4100                 if (bootp_opt[ii].ftype == special) continue;    /* don't mess with specials.  Go again       */
4101                 bootp_opt[ii].text = se_strdup(optiondetail[1]); /* store a permanent ("seasonal") copy       */
4102                 type = optiondetail[2];                          /* A string to be converted to an ftype enum */
4103                 /* XXX This if statement could be extended to allow for additinonal types */
4104                 if (g_ascii_strcasecmp(type,"string") == 0)
4105                 {
4106                         bootp_opt[ii].ftype = string;
4107                 } else if (g_ascii_strcasecmp(type,"ipv4") == 0)
4108                 {
4109                         bootp_opt[ii].ftype = ipv4;
4110                 } else if (g_ascii_strcasecmp(type,"bytes") == 0)
4111                 {
4112                         bootp_opt[ii].ftype = bytes;
4113                 } else
4114                 {
4115                         bootp_opt[ii].ftype = opaque;
4116                 }
4117         }
4118 }
4119
4120 void
4121 proto_register_bootp(void)
4122 {
4123     static hf_register_info hf[] = {
4124         { &hf_bootp_dhcp,
4125           { "Frame is DHCP",            "bootp.dhcp",    FT_BOOLEAN,
4126             BASE_NONE,                  NULL,            0x0,
4127             NULL, HFILL }},
4128
4129         { &hf_bootp_type,
4130           { "Message type",             "bootp.type",    FT_UINT8,
4131             BASE_DEC,                   VALS(op_vals),   0x0,
4132             NULL, HFILL }},
4133
4134         { &hf_bootp_hw_type,
4135           { "Hardware type",            "bootp.hw.type", FT_UINT8,
4136             BASE_HEX,                   NULL,            0x0,
4137             NULL, HFILL }},
4138
4139         { &hf_bootp_hw_len,
4140           { "Hardware address length",  "bootp.hw.len",  FT_UINT8,
4141             BASE_DEC,                   NULL,            0x0,
4142             NULL, HFILL }},
4143
4144         { &hf_bootp_hops,
4145           { "Hops",                     "bootp.hops",    FT_UINT8,
4146             BASE_DEC,                   NULL,            0x0,
4147             NULL, HFILL }},
4148
4149         { &hf_bootp_id,
4150           { "Transaction ID",           "bootp.id",      FT_UINT32,
4151             BASE_HEX,                    NULL,           0x0,
4152             NULL, HFILL }},
4153
4154         { &hf_bootp_secs,
4155           { "Seconds elapsed",          "bootp.secs",    FT_UINT16,
4156             BASE_DEC,                    NULL,           0x0,
4157             NULL, HFILL }},
4158
4159         { &hf_bootp_flags,
4160           { "Bootp flags",              "bootp.flags",   FT_UINT16,
4161             BASE_HEX,                   NULL,            0x0,
4162             NULL, HFILL }},
4163
4164         { &hf_bootp_flags_broadcast,
4165           { "Broadcast flag",           "bootp.flags.bc", FT_BOOLEAN,
4166             16,                 TFS(&flag_set_broadcast), BOOTP_BC,
4167             NULL, HFILL }},
4168
4169         { &hf_bootp_flags_reserved,
4170           { "Reserved flags",           "bootp.flags.reserved", FT_UINT16,
4171             BASE_HEX,                   NULL,           BOOTP_MBZ,
4172             NULL, HFILL }},
4173
4174         { &hf_bootp_ip_client,
4175           { "Client IP address",        "bootp.ip.client",FT_IPv4,
4176             BASE_NONE,                  NULL,             0x0,
4177             NULL, HFILL }},
4178
4179         { &hf_bootp_ip_your,
4180           { "Your (client) IP address", "bootp.ip.your",  FT_IPv4,
4181             BASE_NONE,                  NULL,             0x0,
4182             NULL, HFILL }},
4183
4184         { &hf_bootp_ip_server,
4185           { "Next server IP address",   "bootp.ip.server",FT_IPv4,
4186             BASE_NONE,                  NULL,             0x0,
4187             NULL, HFILL }},
4188
4189         { &hf_bootp_ip_relay,
4190           { "Relay agent IP address",   "bootp.ip.relay", FT_IPv4,
4191             BASE_NONE,                  NULL,             0x0,
4192             NULL, HFILL }},
4193
4194         { &hf_bootp_hw_addr,
4195           { "Client hardware address",  "bootp.hw.addr", FT_BYTES,
4196             BASE_NONE,                  NULL,            0x0,
4197             NULL, HFILL }},
4198
4199         { &hf_bootp_hw_addr_padding,
4200           { "Client hardware address padding",  "bootp.hw.addr_padding", FT_BYTES,
4201             BASE_NONE,                  NULL,            0x0,
4202             NULL, HFILL }},
4203
4204         { &hf_bootp_hw_ether_addr,
4205           { "Client MAC address",       "bootp.hw.mac_addr", FT_ETHER,
4206             BASE_NONE,                  NULL,            0x0,
4207             NULL, HFILL }},
4208
4209         { &hf_bootp_server,
4210           { "Server host name",         "bootp.server",  FT_STRING,
4211             BASE_NONE,                  NULL,            0x0,
4212             NULL, HFILL }},
4213
4214         { &hf_bootp_file,
4215           { "Boot file name",           "bootp.file",    FT_STRING,
4216             BASE_NONE,                  NULL,            0x0,
4217             NULL, HFILL }},
4218
4219         { &hf_bootp_cookie,
4220           { "Magic cookie",             "bootp.cookie",  FT_IPv4,
4221             BASE_NONE,                  NULL,            0x0,
4222             NULL, HFILL }},
4223
4224         { &hf_bootp_vendor,
4225           { "Bootp Vendor Options",     "bootp.vendor",  FT_BYTES,
4226             BASE_NONE,                  NULL,            0x0,
4227             NULL, HFILL }},
4228
4229         { &hf_bootp_fqdn_s,
4230           { "Server",                   "bootp.fqdn.s",  FT_BOOLEAN,
4231             8,                  TFS(&tfs_fqdn_s),       F_FQDN_S,
4232             "If true, server should do DDNS update", HFILL }},
4233
4234         { &hf_bootp_fqdn_o,
4235           { "Server overrides",         "bootp.fqdn.o",  FT_BOOLEAN,
4236             8,                        TFS(&tfs_fqdn_o),  F_FQDN_O,
4237             "If true, server insists on doing DDNS update", HFILL }},
4238
4239         { &hf_bootp_fqdn_e,
4240           { "Encoding",                 "bootp.fqdn.e",  FT_BOOLEAN,
4241             8,                        TFS(&tfs_fqdn_e),  F_FQDN_E,
4242             "If true, name is binary encoded", HFILL }},
4243
4244         { &hf_bootp_fqdn_n,
4245           { "Server DDNS",              "bootp.fqdn.n",  FT_BOOLEAN,
4246             8,                        TFS(&tfs_fqdn_n),  F_FQDN_N,
4247             "If true, server should not do any DDNS updates", HFILL }},
4248
4249         { &hf_bootp_fqdn_mbz,
4250           { "Reserved flags",           "bootp.fqdn.mbz",FT_UINT8,
4251             BASE_HEX,                   NULL,            F_FQDN_MBZ,
4252             NULL, HFILL }},
4253
4254         { &hf_bootp_fqdn_rcode1,
4255           { "A-RR result",              "bootp.fqdn.rcode1", FT_UINT8,
4256             BASE_DEC,                   NULL,            0x0,
4257             "Result code of A-RR update", HFILL }},
4258
4259         { &hf_bootp_fqdn_rcode2,
4260           { "PTR-RR result",            "bootp.fqdn.rcode2", FT_UINT8,
4261             BASE_DEC,                   NULL,            0x0,
4262             "Result code of PTR-RR update", HFILL }},
4263
4264         { &hf_bootp_fqdn_name,
4265           { "Client name",              "bootp.fqdn.name", FT_STRING,
4266             BASE_NONE,                  NULL,            0x0,
4267             "Name to register via DDNS", HFILL }},
4268
4269         { &hf_bootp_fqdn_asciiname,
4270           { "Client name",              "bootp.fqdn.name", FT_STRING,
4271             BASE_NONE,                  NULL,            0x0,
4272             "Name to register via DDNS", HFILL }},
4273
4274         { &hf_bootp_pkt_mtacap_len,
4275           { "MTA DC Length",            "bootp.vendor.pktc.mtacap_len", FT_UINT8,
4276             BASE_DEC,                    NULL,           0x0,
4277             "PacketCable MTA Device Capabilities Length", HFILL }},
4278
4279         { &hf_bootp_docsis_cmcap_len,
4280           { "CM DC Length",             "bootp.vendor.docsis.cmcap_len", FT_UINT8,
4281             BASE_DEC,                   NULL,            0x0,
4282             "DOCSIS Cable Modem Device Capabilities Length", HFILL }},
4283
4284         { &hf_bootp_alu_vid,
4285           { "Voice VLAN ID",            "bootp.vendor.alu.vid", FT_UINT16,
4286             BASE_DEC,                   NULL,            0x0,
4287             "Alcatel-Lucent VLAN ID to define Voice VLAN", HFILL }},
4288
4289         { &hf_bootp_alu_tftp1,
4290           { "Spatial Redundancy TFTP1", "bootp.vendor.alu.tftp1" , FT_IPv4,
4291             BASE_NONE,                  NULL,            0x0,
4292             NULL, HFILL }},
4293
4294         { &hf_bootp_alu_tftp2,
4295           { "Spatial Redundancy TFTP2", "bootp.vendor.alu.tftp2" ,FT_IPv4,
4296             BASE_NONE,                  NULL,            0x0,
4297             NULL, HFILL }},
4298
4299         { &hf_bootp_client_identifier_uuid,
4300           { "Client Identifier (UUID)", "bootp.client_id_uuid", FT_GUID,
4301             BASE_NONE,                  NULL,            0x0,
4302             "Client Machine Identifier (UUID)", HFILL }},
4303
4304         { &hf_bootp_client_network_id_major_ver,
4305           { "Client Network ID Major Version", "bootp.client_network_id_major", FT_UINT8,
4306             BASE_DEC,                   NULL,            0x0,
4307             "Client Machine Identifier, Major Version", HFILL }},
4308
4309         { &hf_bootp_client_network_id_minor_ver,
4310           { "Client Network ID Minor Version", "bootp.client_network_id_minor", FT_UINT8,
4311             BASE_DEC,                   NULL,            0x0,
4312             "Client Machine Identifier, Major Version", HFILL }},
4313
4314         { &hf_bootp_option_type,
4315           { "Option",   "bootp.option.type", FT_UINT8,
4316             BASE_DEC,                    NULL,           0x0,
4317             "Bootp/Dhcp option type", HFILL }},
4318
4319         { &hf_bootp_option_length,
4320           { "Length",   "bootp.option.length", FT_UINT8,
4321             BASE_DEC,                   NULL,            0x0,
4322             "Bootp/Dhcp option length", HFILL }},
4323
4324         { &hf_bootp_option_value,
4325           { "Value",    "bootp.option.value", FT_BYTES,
4326             BASE_NONE,                  NULL,            0x0,
4327             "Bootp/Dhcp option value", HFILL }},
4328
4329     };
4330
4331         static gint *ett[] = {
4332                 &ett_bootp,
4333                 &ett_bootp_flags,
4334                 &ett_bootp_option,
4335                 &ett_bootp_fqdn,
4336         };
4337
4338         module_t *bootp_module;
4339
4340         proto_bootp = proto_register_protocol("Bootstrap Protocol", "BOOTP/DHCP",
4341                                               "bootp");
4342         proto_register_field_array(proto_bootp, hf, array_length(hf));
4343         proto_register_subtree_array(ett, array_length(ett));
4344         bootp_dhcp_tap = register_tap("bootp");
4345
4346         /* register init routine to setup the custom bootp options */
4347         register_init_routine(&bootp_init_protocol);
4348   
4349         /* Allow dissector to find be found by name. */
4350         register_dissector("bootp", dissect_bootp, proto_bootp);
4351
4352         bootp_module = prefs_register_protocol(proto_bootp, NULL);
4353
4354         prefs_register_bool_preference(bootp_module, "novellserverstring",
4355                                        "Decode Option 85 as String",
4356                                        "Novell Servers option 85 can be configured as a string instead of address",
4357                                        &novell_string);
4358
4359         prefs_register_enum_preference(bootp_module, "pkt.ccc.protocol_version",
4360                                        "PacketCable CCC protocol version",
4361                                        "The PacketCable CCC protocol version",
4362                                        &pkt_ccc_protocol_version,
4363                                        pkt_ccc_protocol_versions,
4364                                        FALSE);
4365
4366         prefs_register_uint_preference(bootp_module, "pkt.ccc.option",
4367                                        "PacketCable CCC option",
4368                                        "Option Number for PacketCable CableLabs Client Configuration",
4369                                        10,
4370                                        &pkt_ccc_option);
4371
4372         prefs_register_string_preference(bootp_module, "displayasstring",
4373                                          "Custom BootP/DHCP Options (Excl. suboptions)",
4374                                          "Format: OptionNumber,OptionName,OptionType[;Format].\n"
4375                                          "Example: 176,MyOption,string;242,NewOption,ipv4.\n"
4376                                          "OptionNumbers: 1-254, but no special options. "
4377                                          "OptionType: string, ipv4 and bytes",
4378                                          &pref_optionstring );
4379 }
4380
4381 void
4382 proto_reg_handoff_bootp(void)
4383 {
4384         dissector_handle_t bootp_handle;
4385
4386         bootp_handle = create_dissector_handle(dissect_bootp, proto_bootp);
4387         dissector_add("udp.port", UDP_PORT_BOOTPS, bootp_handle);
4388         dissector_add("udp.port", UDP_PORT_BOOTPC, bootp_handle);
4389 }