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