Rename "ipv4" to "ipv4_list", as it's used for lists of IPv4 addresses,
[obnox/wireshark/wip.git] / epan / dissectors / packet-bootp.c
1 /* packet-bootp.c
2  * Routines for BOOTP/DHCP packet disassembly
3  * Copyright 1998, Gilbert Ramirez <gram@alumni.rice.edu>
4  * Copyright 2004, Thomas Anders <thomas.anders [AT] blue-cable.de>
5  *
6  * $Id$
7  *
8  * The information used comes from:
9  * RFC  951: Bootstrap Protocol
10  * RFC 1497: BOOTP extensions
11  * RFC 1542: Clarifications and Extensions for the Bootstrap Protocol
12  * RFC 2131: Dynamic Host Configuration Protocol
13  * RFC 2132: DHCP Options and BOOTP Vendor Extensions
14  * RFC 2489: Procedure for Defining New DHCP Options
15  * RFC 2610: DHCP Options for Service Location Protocol
16  * RFC 3046: DHCP Relay Agent Information Option
17  * RFC 3118: Authentication for DHCP Messages
18  * RFC 3203: DHCP reconfigure extension
19  * RFC 3495: DHCP Option (122) for CableLabs Client Configuration
20  * RFC 3594: PacketCable Security Ticket Control Sub-Option (122.9)
21  * draft-ietf-dhc-fqdn-option-07.txt
22  * BOOTP and DHCP Parameters
23  *     http://www.iana.org/assignments/bootp-dhcp-parameters
24  * DOCSIS(TM) 2.0 Radio Frequency Interface Specification
25  *     http://www.cablemodem.com/downloads/specs/CM-SP-RFIv2.0-I06-040804.pdf
26  * PacketCable(TM) MTA Device Provisioning Specification
27  *     http://www.packetcable.com/downloads/specs/PKT-SP-PROV-I10-040730.pdf
28  *     http://www.cablelabs.com/specifications/archives/PKT-SP-PROV-I05-021127.pdf (superseded by above)
29  * CableHome(TM) 1.1 Specification
30  *     http://www.cablelabs.com/projects/cablehome/downloads/specs/CH-SP-CH1.1-I05-040806.pdf
31  *
32  * Ethereal - Network traffic analyzer
33  * By Gerald Combs <gerald@ethereal.com>
34  * Copyright 1998 Gerald Combs
35  *
36  * This program is free software; you can redistribute it and/or
37  * modify it under the terms of the GNU General Public License
38  * as published by the Free Software Foundation; either version 2
39  * of the License, or (at your option) any later version.
40  *
41  * This program is distributed in the hope that it will be useful,
42  * but WITHOUT ANY WARRANTY; without even the implied warranty of
43  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
44  * GNU General Public License for more details.
45  *
46  * You should have received a copy of the GNU General Public License
47  * along with this program; if not, write to the Free Software
48  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
49  */
50
51 /*
52  * Some of the development of the BOOTP/DHCP protocol decoder was sponsored by
53  * Cable Television Laboratories, Inc. ("CableLabs") based upon proprietary
54  * CableLabs' specifications. Your license and use of this protocol decoder
55  * does not mean that you are licensed to use the CableLabs'
56  * specifications.  If you have questions about this protocol, contact
57  * jf.mule [AT] cablelabs.com or c.stuart [AT] cablelabs.com for additional
58  * information.
59  */
60
61
62 #ifdef HAVE_CONFIG_H
63 # include "config.h"
64 #endif
65
66 #include <string.h>
67 #include <glib.h>
68 #include <epan/packet.h>
69 #include "packet-arp.h"
70 #include "packet-dns.h"                         /* for get_dns_name() */
71
72 #include <epan/prefs.h>
73 #include <epan/tap.h>
74 #include <epan/strutil.h>
75
76 static int bootp_dhcp_tap = -1;
77 static int proto_bootp = -1;
78 static int hf_bootp_type = -1;
79 static int hf_bootp_hw_type = -1;
80 static int hf_bootp_hw_len = -1;
81 static int hf_bootp_hops = -1;
82 static int hf_bootp_id = -1;
83 static int hf_bootp_secs = -1;
84 static int hf_bootp_flags = -1;
85 static int hf_bootp_flags_broadcast = -1;
86 static int hf_bootp_flags_reserved = -1;
87 static int hf_bootp_ip_client = -1;
88 static int hf_bootp_ip_your = -1;
89 static int hf_bootp_ip_server = -1;
90 static int hf_bootp_ip_relay = -1;
91 static int hf_bootp_hw_addr = -1;
92 static int hf_bootp_server = -1;
93 static int hf_bootp_file = -1;
94 static int hf_bootp_cookie = -1;
95 static int hf_bootp_vendor = -1;
96 static int hf_bootp_dhcp = -1;
97 static int hf_bootp_fqdn_s = -1;
98 static int hf_bootp_fqdn_o = -1;
99 static int hf_bootp_fqdn_e = -1;
100 static int hf_bootp_fqdn_n = -1;
101 static int hf_bootp_fqdn_mbz = -1;
102 static int hf_bootp_fqdn_rcode1 = -1;
103 static int hf_bootp_fqdn_rcode2 = -1;
104 static int hf_bootp_fqdn_name = -1;
105 static int hf_bootp_fqdn_asciiname = -1;
106 static int hf_bootp_pkt_mtacap_len = -1;
107 static int hf_bootp_docsis_cmcap_len = -1;
108
109 static gint ett_bootp = -1;
110 static gint ett_bootp_flags = -1;
111 static gint ett_bootp_option = -1;
112 static gint ett_bootp_fqdn = -1;
113
114 gboolean novell_string = FALSE;
115
116 #define UDP_PORT_BOOTPS  67
117 #define UDP_PORT_BOOTPC  68
118
119 #define BOOTP_BC        0x8000
120 #define BOOTP_MBZ       0x7FFF
121
122 /* FQDN stuff */
123 #define F_FQDN_S        0x01
124 #define F_FQDN_O        0x02
125 #define F_FQDN_E        0x04
126 #define F_FQDN_N        0x08
127 #define F_FQDN_MBZ      0xf0
128
129 static const true_false_string tfs_fqdn_s = {
130   "Server",
131   "Client"
132 };
133
134 static const true_false_string tfs_fqdn_o = {
135   "Override",
136   "No override"
137 };
138
139 static const true_false_string tfs_fqdn_e = {
140   "Binary encoding",
141   "ASCII encoding"
142 };
143
144 static const true_false_string tfs_fqdn_n = {
145   "No server updates",
146   "Some server updates"
147 };
148
149 #define PLURALIZE(n)    (((n) > 1) ? "s" : "")
150
151 enum field_type {
152         none,
153         presence,
154         ipv4,                   /* single IPv4 address */
155         ipv4_list,              /* list of IPv4 addresses */
156         string,
157         toggle,
158         yes_no,
159         special,
160         opaque,
161         time_in_secs,
162         val_u_byte, val_u_short, val_u_le_short, val_u_long,
163         val_s_long, fqdn, ipv4_or_fqdn, bytes
164 };
165
166 struct opt_info {
167         char    *text;
168         enum field_type ftype;
169 };
170
171 static const true_false_string flag_set_broadcast = {
172   "Broadcast",
173   "Unicast"
174 };
175
176
177 /* PacketCable definitions */
178 #define PACKETCABLE_MTA_CAP10 "pktc1.0:"
179 #define PACKETCABLE_MTA_CAP15 "pktc1.5:"
180 #define PACKETCABLE_CM_CAP11  "docsis1.1:"
181 #define PACKETCABLE_CM_CAP20  "docsis2.0:"
182
183 #define PACKETCABLE_CCC_I05      1
184 #define PACKETCABLE_CCC_DRAFT5   2
185 #define PACKETCABLE_CCC_RFC_3495 3
186
187 static enum_val_t pkt_ccc_protocol_versions[] = {
188         { "ccc_i05",     "PKT-SP-PROV-I05-021127", PACKETCABLE_CCC_I05 },
189         { "ccc_draft_5", "IETF Draft 5",           PACKETCABLE_CCC_DRAFT5 },
190         { "rfc_3495",    "RFC 3495",               PACKETCABLE_CCC_RFC_3495 },
191         { NULL, NULL, 0 }
192 };
193
194 static gint pkt_ccc_protocol_version = PACKETCABLE_CCC_RFC_3495;
195 static gint pkt_ccc_option = 122;
196
197
198 static int dissect_vendor_pxeclient_suboption(proto_tree *v_tree, tvbuff_t *tvb,
199     int optoff, int optend);
200 static int dissect_vendor_cablelabs_suboption(proto_tree *v_tree, tvbuff_t *tvb,
201     int optoff, int optend);
202 static int dissect_netware_ip_suboption(proto_tree *v_tree, tvbuff_t *tvb,
203     int optoff, int optend);
204 static int bootp_dhcp_decode_agent_info(proto_tree *v_tree, tvbuff_t *tvb,
205     int optoff, int optend);
206 static void dissect_packetcable_mta_cap(proto_tree *v_tree, tvbuff_t *tvb,
207        int voff, int len);
208 static void dissect_docsis_cm_cap(proto_tree *v_tree, tvbuff_t *tvb,
209        int voff, int len);
210 static int dissect_packetcable_i05_ccc(proto_tree *v_tree, tvbuff_t *tvb,
211     int optoff, int optend);
212 static int dissect_packetcable_ietf_ccc(proto_tree *v_tree, tvbuff_t *tvb,
213     int optoff, int optend, int revision);
214
215
216 static const char *
217 get_dhcp_type(guint8 byte)
218 {
219         static const char       *opt53_text[] = {
220                 "Unknown Message Type",
221                 "Discover",
222                 "Offer",
223                 "Request",
224                 "Decline",
225                 "ACK",
226                 "NAK",
227                 "Release",
228                 "Inform",
229                 "Force Renew"
230         };
231         int i;
232
233         if (byte > 0 && byte < (sizeof opt53_text / sizeof opt53_text[0]))
234                 i = byte;
235         else
236                 i = 0;
237         return opt53_text[i];
238 }
239
240 /* DHCP Authentication protocols */
241 #define AUTHEN_PROTO_CONFIG_TOKEN       0
242 #define AUTHEN_PROTO_DELAYED_AUTHEN     1
243
244 /* DHCP Authentication algorithms for delayed authentication */
245 #define AUTHEN_DELAYED_ALGO_HMAC_MD5    1
246
247 /* DHCP Authentication Replay Detection Methods */
248 #define AUTHEN_RDM_MONOTONIC_COUNTER    0x00
249
250 /* DHCP Option Overload (option code 52) */
251 #define OPT_OVERLOAD_FILE               1
252 #define OPT_OVERLOAD_SNAME              2
253 #define OPT_OVERLOAD_BOTH               3
254
255 /* Server name and boot file offsets and lengths */
256 #define SERVER_NAME_OFFSET              44
257 #define SERVER_NAME_LEN                 64
258 #define FILE_NAME_OFFSET                108
259 #define FILE_NAME_LEN                   128
260 #define VENDOR_INFO_OFFSET              236
261
262 /* Returns the number of bytes consumed by this option. */
263 static int
264 bootp_option(tvbuff_t *tvb, proto_tree *bp_tree, int voff, int eoff,
265     gboolean first_pass, gboolean *at_end, const char **dhcp_type_p,
266     const guint8 **vendor_class_id_p)
267 {
268         char                    *text;
269         enum field_type         ftype;
270         guchar                  code = tvb_get_guint8(tvb, voff);
271         int                     optlen;
272         guchar                  byte;
273         int                     i, consumed;
274         int                     optoff, optleft, optend;
275         gulong                  time_secs;
276         proto_tree              *v_tree, *o52tree, *flags_tree, *ft;
277         proto_item              *vti;
278         guint8                  protocol;
279         guint8                  algorithm;
280         guint8                  rdm;
281         guint8                  fqdn_flags;
282         int                     o52voff, o52eoff;
283         gboolean                o52at_end;
284         gboolean                skip_opaque = FALSE;
285
286         static const value_string nbnt_vals[] = {
287             {0x1,   "B-node" },
288             {0x2,   "P-node" },
289             {0x4,   "M-node" },
290             {0x8,   "H-node" },
291             {0,     NULL     } };
292
293         static const value_string slpda_vals[] = {
294             {0x00,   "Dynamic Discovery" },
295             {0x01,   "Static Discovery" },
296             {0x80,   "Backwards compatibility" },
297             {0,     NULL     } };
298
299         static const value_string slp_scope_vals[] = {
300             {0x00,   "Preferred Scope" },
301             {0x01,   "Mandatory Scope" },
302             {0,     NULL     } };
303
304         static const value_string authen_protocol_vals[] = {
305             {AUTHEN_PROTO_CONFIG_TOKEN,   "configuration token" },
306             {AUTHEN_PROTO_DELAYED_AUTHEN, "delayed authentication" },
307             {0,                           NULL     } };
308
309         static const value_string authen_da_algo_vals[] = {
310             {AUTHEN_DELAYED_ALGO_HMAC_MD5, "HMAC_MD5" },
311             {0,                            NULL     } };
312
313         static const value_string authen_rdm_vals[] = {
314             {AUTHEN_RDM_MONOTONIC_COUNTER, "Monotonically-increasing counter" },
315             {0,                            NULL     } };
316
317         static const value_string opt_overload_vals[] = {
318             { OPT_OVERLOAD_FILE,  "Boot file name holds options",                },
319             { OPT_OVERLOAD_SNAME, "Server host name holds options",              },
320             { OPT_OVERLOAD_BOTH,  "Boot file and server host names hold options" },
321             { 0,                  NULL                                           } };
322
323         static struct opt_info opt[] = {
324                 /*   0 */ { "Padding",                                  none },
325                 /*   1 */ { "Subnet Mask",                              ipv4_list },
326                 /*   2 */ { "Time Offset",                              time_in_secs },
327                 /*   3 */ { "Router",                                   ipv4_list },
328                 /*   4 */ { "Time Server",                              ipv4_list },
329                 /*   5 */ { "Name Server",                              ipv4_list },
330                 /*   6 */ { "Domain Name Server",                       ipv4_list },
331                 /*   7 */ { "Log Server",                               ipv4_list },
332                 /*   8 */ { "Cookie Server",                            ipv4_list },
333                 /*   9 */ { "LPR Server",                               ipv4_list },
334                 /*  10 */ { "Impress Server",                           ipv4_list },
335                 /*  11 */ { "Resource Location Server",                 ipv4_list },
336                 /*  12 */ { "Host Name",                                string },
337                 /*  13 */ { "Boot File Size",                           val_u_short },
338                 /*  14 */ { "Merit Dump File",                          string },
339                 /*  15 */ { "Domain Name",                              string },
340                 /*  16 */ { "Swap Server",                              ipv4_list },
341                 /*  17 */ { "Root Path",                                string },
342                 /*  18 */ { "Extensions Path",                          string },
343                 /*  19 */ { "IP Forwarding",                            toggle },
344                 /*  20 */ { "Non-Local Source Routing",                 toggle },
345                 /*  21 */ { "Policy Filter",                            special },
346                 /*  22 */ { "Maximum Datagram Reassembly Size",         val_u_short },
347                 /*  23 */ { "Default IP Time-to-Live",                  val_u_byte },
348                 /*  24 */ { "Path MTU Aging Timeout",                   time_in_secs },
349                 /*  25 */ { "Path MTU Plateau Table",                   val_u_short },
350                 /*  26 */ { "Interface MTU",                            val_u_short },
351                 /*  27 */ { "All Subnets are Local",                    yes_no },
352                 /*  28 */ { "Broadcast Address",                        ipv4_list },
353                 /*  29 */ { "Perform Mask Discovery",                   toggle },
354                 /*  30 */ { "Mask Supplier",                            yes_no },
355                 /*  31 */ { "Perform Router Discover",                  toggle },
356                 /*  32 */ { "Router Solicitation Address",              ipv4_list },
357                 /*  33 */ { "Static Route",                             special },
358                 /*  34 */ { "Trailer Encapsulation",                    toggle },
359                 /*  35 */ { "ARP Cache Timeout",                        time_in_secs },
360                 /*  36 */ { "Ethernet Encapsulation",                   toggle },
361                 /*  37 */ { "TCP Default TTL",                          val_u_byte },
362                 /*  38 */ { "TCP Keepalive Interval",                   time_in_secs },
363                 /*  39 */ { "TCP Keepalive Garbage",                    toggle },
364                 /*  40 */ { "Network Information Service Domain",       string },
365                 /*  41 */ { "Network Information Service Servers",      ipv4_list },
366                 /*  42 */ { "Network Time Protocol Servers",            ipv4_list },
367                 /*  43 */ { "Vendor-Specific Information",              special },
368                 /*  44 */ { "NetBIOS over TCP/IP Name Server",          ipv4_list },
369                 /*  45 */ { "NetBIOS over TCP/IP Datagram Distribution Name Server", ipv4_list },
370                 /*  46 */ { "NetBIOS over TCP/IP Node Type",            special },
371                 /*  47 */ { "NetBIOS over TCP/IP Scope",                string },
372                 /*  48 */ { "X Window System Font Server",              ipv4_list },
373                 /*  49 */ { "X Window System Display Manager",          ipv4_list },
374                 /*  50 */ { "Requested IP Address",                     ipv4_list },
375                 /*  51 */ { "IP Address Lease Time",                    time_in_secs },
376                 /*  52 */ { "Option Overload",                          special },
377                 /*  53 */ { "DHCP Message Type",                        special },
378                 /*  54 */ { "Server Identifier",                        ipv4_list },
379                 /*  55 */ { "Parameter Request List",                   special },
380                 /*  56 */ { "Message",                                  string },
381                 /*  57 */ { "Maximum DHCP Message Size",                val_u_short },
382                 /*  58 */ { "Renewal Time Value",                       time_in_secs },
383                 /*  59 */ { "Rebinding Time Value",                     time_in_secs },
384                 /*  60 */ { "Vendor class identifier",                  special },
385                 /*  61 */ { "Client identifier",                        special },
386                 /*  62 */ { "Novell/Netware IP domain",                 string },
387                 /*  63 */ { "Novell Options",                           special },
388                 /*  64 */ { "Network Information Service+ Domain",      string },
389                 /*  65 */ { "Network Information Service+ Servers",     ipv4_list },
390                 /*  66 */ { "TFTP Server Name",                         string },
391                 /*  67 */ { "Bootfile name",                            string },
392                 /*  68 */ { "Mobile IP Home Agent",                     ipv4_list },
393                 /*  69 */ { "SMTP Server",                              ipv4_list },
394                 /*  70 */ { "POP3 Server",                              ipv4_list },
395                 /*  71 */ { "NNTP Server",                              ipv4_list },
396                 /*  72 */ { "Default WWW Server",                       ipv4_list },
397                 /*  73 */ { "Default Finger Server",                    ipv4_list },
398                 /*  74 */ { "Default IRC Server",                       ipv4_list },
399                 /*  75 */ { "StreetTalk Server",                        ipv4_list },
400                 /*  76 */ { "StreetTalk Directory Assistance Server",   ipv4_list },
401                 /*  77 */ { "User Class Information",                   opaque },
402                 /*  78 */ { "Directory Agent Information",              special },
403                 /*  79 */ { "Service Location Agent Scope",             special },
404                 /*  80 */ { "Naming Authority",                         opaque },
405                 /*  81 */ { "Client Fully Qualified Domain Name",       special },
406                 /*  82 */ { "Agent Information Option",                 special },
407                 /*  83 */ { "Unassigned",                               opaque },
408                 /*  84 */ { "Unassigned",                               opaque },
409                 /*  85 */ { "Novell Directory Services Servers",        special },
410                 /*  86 */ { "Novell Directory Services Tree Name",      string },
411                 /*  87 */ { "Novell Directory Services Context",        string },
412                 /*  88 */ { "IEEE 1003.1 POSIX Timezone",               opaque },
413                 /*  89 */ { "Fully Qualified Domain Name",              opaque },
414                 /*  90 */ { "Authentication",                           special },
415                 /*  91 */ { "Vines TCP/IP Server Option",               opaque },
416                 /*  92 */ { "Server Selection Option",                  opaque },
417                 /*  93 */ { "Client System Architecture",               opaque },
418                 /*  94 */ { "Client Network Device Interface",          opaque },
419                 /*  95 */ { "Lightweight Directory Access Protocol",    opaque },
420                 /*  96 */ { "IPv6 Transitions",                         opaque },
421                 /*  97 */ { "UUID/GUID-based Client Identifier",        opaque },
422                 /*  98 */ { "Open Group's User Authentication",         opaque },
423                 /*  99 */ { "Unassigned",                               opaque },
424                 /* 100 */ { "Printer Name",                             opaque },
425                 /* 101 */ { "MDHCP multicast address",                  opaque },
426                 /* 102 */ { "Removed/unassigned",                       opaque },
427                 /* 103 */ { "Removed/unassigned",                       opaque },
428                 /* 104 */ { "Removed/unassigned",                       opaque },
429                 /* 105 */ { "Removed/unassigned",                       opaque },
430                 /* 106 */ { "Removed/unassigned",                       opaque },
431                 /* 107 */ { "Removed/unassigned",                       opaque },
432                 /* 108 */ { "Swap Path Option",                         opaque },
433                 /* 109 */ { "Unassigned",                               opaque },
434                 /* 110 */ { "IPX Compability",                          opaque },
435                 /* 111 */ { "Unassigned",                               opaque },
436                 /* 112 */ { "NetInfo Parent Server Address",            ipv4_list },
437                 /* 113 */ { "NetInfo Parent Server Tag",                string },
438                 /* 114 */ { "URL",                                      opaque },
439                 /* 115 */ { "DHCP Failover Protocol",                   opaque },
440                 /* 116 */ { "DHCP Auto-Configuration",                  opaque },
441                 /* 117 */ { "Name Service Search",                      opaque },
442                 /* 118 */ { "Subnet Selection Option",                  opaque },
443                 /* 119 */ { "Domain Search",                            opaque },
444                 /* 120 */ { "SIP Servers",                              opaque },
445                 /* 121 */ { "Classless Static Route",                   opaque },
446                 /* 122 */ { "CableLabs Client Configuration",           opaque },
447                 /* 123 */ { "Unassigned",                               opaque },
448                 /* 124 */ { "Unassigned",                               opaque },
449                 /* 125 */ { "Unassigned",                               opaque },
450                 /* 126 */ { "Extension",                                opaque },
451                 /* 127 */ { "Extension",                                opaque },
452                 /* 128 */ { "Private",                                  opaque },
453                 /* 129 */ { "Private",                                  opaque },
454                 /* 130 */ { "Private",                                  opaque },
455                 /* 131 */ { "Private",                                  opaque },
456                 /* 132 */ { "Private",                                  opaque },
457                 /* 133 */ { "Private",                                  opaque },
458                 /* 134 */ { "Private",                                  opaque },
459                 /* 135 */ { "Private",                                  opaque },
460                 /* 136 */ { "Private",                                  opaque },
461                 /* 137 */ { "Private",                                  opaque },
462                 /* 138 */ { "Private",                                  opaque },
463                 /* 139 */ { "Private",                                  opaque },
464                 /* 140 */ { "Private",                                  opaque },
465                 /* 141 */ { "Private",                                  opaque },
466                 /* 142 */ { "Private",                                  opaque },
467                 /* 143 */ { "Private",                                  opaque },
468                 /* 144 */ { "Private",                                  opaque },
469                 /* 145 */ { "Private",                                  opaque },
470                 /* 146 */ { "Private",                                  opaque },
471                 /* 147 */ { "Private",                                  opaque },
472                 /* 148 */ { "Private",                                  opaque },
473                 /* 149 */ { "Private",                                  opaque },
474                 /* 150 */ { "Private",                                  opaque },
475                 /* 151 */ { "Private",                                  opaque },
476                 /* 152 */ { "Private",                                  opaque },
477                 /* 153 */ { "Private",                                  opaque },
478                 /* 154 */ { "Private",                                  opaque },
479                 /* 155 */ { "Private",                                  opaque },
480                 /* 156 */ { "Private",                                  opaque },
481                 /* 157 */ { "Private",                                  opaque },
482                 /* 158 */ { "Private",                                  opaque },
483                 /* 159 */ { "Private",                                  opaque },
484                 /* 160 */ { "Private",                                  opaque },
485                 /* 161 */ { "Private",                                  opaque },
486                 /* 162 */ { "Private",                                  opaque },
487                 /* 163 */ { "Private",                                  opaque },
488                 /* 164 */ { "Private",                                  opaque },
489                 /* 165 */ { "Private",                                  opaque },
490                 /* 166 */ { "Private",                                  opaque },
491                 /* 167 */ { "Private",                                  opaque },
492                 /* 168 */ { "Private",                                  opaque },
493                 /* 169 */ { "Private",                                  opaque },
494                 /* 170 */ { "Private",                                  opaque },
495                 /* 171 */ { "Private",                                  opaque },
496                 /* 172 */ { "Private",                                  opaque },
497                 /* 173 */ { "Private",                                  opaque },
498                 /* 174 */ { "Private",                                  opaque },
499                 /* 175 */ { "Private",                                  opaque },
500                 /* 176 */ { "Private",                                  opaque },
501                 /* 177 */ { "Private",                                  opaque },
502                 /* 178 */ { "Private",                                  opaque },
503                 /* 179 */ { "Private",                                  opaque },
504                 /* 180 */ { "Private",                                  opaque },
505                 /* 181 */ { "Private",                                  opaque },
506                 /* 182 */ { "Private",                                  opaque },
507                 /* 183 */ { "Private",                                  opaque },
508                 /* 184 */ { "Private",                                  opaque },
509                 /* 185 */ { "Private",                                  opaque },
510                 /* 186 */ { "Private",                                  opaque },
511                 /* 187 */ { "Private",                                  opaque },
512                 /* 188 */ { "Private",                                  opaque },
513                 /* 189 */ { "Private",                                  opaque },
514                 /* 190 */ { "Private",                                  opaque },
515                 /* 191 */ { "Private",                                  opaque },
516                 /* 192 */ { "Private",                                  opaque },
517                 /* 193 */ { "Private",                                  opaque },
518                 /* 194 */ { "Private",                                  opaque },
519                 /* 195 */ { "Private",                                  opaque },
520                 /* 196 */ { "Private",                                  opaque },
521                 /* 197 */ { "Private",                                  opaque },
522                 /* 198 */ { "Private",                                  opaque },
523                 /* 199 */ { "Private",                                  opaque },
524                 /* 200 */ { "Private",                                  opaque },
525                 /* 201 */ { "Private",                                  opaque },
526                 /* 202 */ { "Private",                                  opaque },
527                 /* 203 */ { "Private",                                  opaque },
528                 /* 204 */ { "Private",                                  opaque },
529                 /* 205 */ { "Private",                                  opaque },
530                 /* 206 */ { "Private",                                  opaque },
531                 /* 207 */ { "Private",                                  opaque },
532                 /* 208 */ { "Private",                                  opaque },
533                 /* 209 */ { "Private",                                  opaque },
534                 /* 210 */ { "Authentication",                           special }
535         };
536
537         /* Options whose length isn't "optlen + 2". */
538         switch (code) {
539
540         case 0:         /* Padding */
541                 /* check how much padding we have */
542                 for (i = voff + 1; i < eoff; i++ ) {
543                         if (tvb_get_guint8(tvb, i) != 0) {
544                                 break;
545                         }
546                 }
547                 i = i - voff;
548                 if (!first_pass) {
549                         if (bp_tree != NULL) {
550                                 proto_tree_add_text(bp_tree, tvb, voff, i,
551                                     "Padding");
552                         }
553                 }
554                 consumed = i;
555                 return consumed;
556                 break;
557
558         case 255:       /* End Option */
559                 if (!first_pass) {
560                         if (bp_tree != NULL) {
561                                 proto_tree_add_text(bp_tree, tvb, voff, 1,
562                                     "End Option");
563                         }
564                 }
565                 *at_end = TRUE;
566                 consumed = 1;
567                 return consumed;
568         }
569
570         /*
571          * Get the length of the option, and the number of bytes it
572          * consumes (the length doesn't include the option code or
573          * length bytes).
574          *
575          * On the first pass, check first whether we have the length
576          * byte, so that we don't throw an exception; if we throw an
577          * exception in the first pass, which is only checking for options
578          * whose values we need in order to properly dissect the packet
579          * on the second pass, we won't actually dissect the options, so
580          * you won't be able to see which option had the problem.
581          */
582         if (first_pass) {
583                 if (!tvb_bytes_exist(tvb, voff+1, 1)) {
584                         /*
585                          * We don't have the length byte; just return 1
586                          * as the number of bytes we consumed, to count
587                          * the code byte.
588                          */
589                         return 1;
590                 }
591         }
592         optlen = tvb_get_guint8(tvb, voff+1);
593         consumed = optlen + 2;
594
595         /*
596          * In the first pass, we don't put anything into the protocol
597          * tree; we just check for some options we have to look at
598          * in order to properly process the packet:
599          *
600          *      53 (DHCP message type) - if this is present, this is DHCP
601          *
602          *      60 (Vendor class identifier) - we need this in order to
603          *         interpret the vendor-specific info
604          *
605          * We also check, before fetching anything, to make sure we
606          * have the entire item we're fetching, so that we don't throw
607          * an exception.
608          */
609         if (first_pass) {
610                 if (tvb_bytes_exist(tvb, voff+2, consumed-2)) {
611                         switch (code) {
612
613                         case 53:
614                                 *dhcp_type_p =
615                                     get_dhcp_type(tvb_get_guint8(tvb, voff+2));
616                                 break;
617
618                         case 60:
619                                 *vendor_class_id_p =
620                                     tvb_get_ptr(tvb, voff+2, consumed-2);
621                                 break;
622                         }
623                 }
624
625                 /*
626                  * We don't do anything else here.
627                  */
628                 return consumed;
629         }
630
631         /*
632          * This is the second pass - if there's a protocol tree to be
633          * built, we put stuff into it, otherwise we just return.
634          */
635         if (bp_tree == NULL) {
636                 /* Don't put anything in the protocol tree. */
637                 return consumed;
638         }
639
640         optoff = voff+2;
641
642         text = opt[code].text;
643         /* Special cases */
644         switch (code) {
645
646         case 21:        /* Policy Filter */
647                 if (optlen == 8) {
648                         /* one IP address pair */
649                         proto_tree_add_text(bp_tree, tvb, voff, consumed,
650                                 "Option %d: %s = %s/%s", code, text,
651                                 ip_to_str(tvb_get_ptr(tvb, optoff, 4)),
652                                 ip_to_str(tvb_get_ptr(tvb, optoff+4, 4)));
653                 } else {
654                         /* > 1 IP address pair. Let's make a sub-tree */
655                         vti = proto_tree_add_text(bp_tree, tvb, voff,
656                                 consumed, "Option %d: %s", code, text);
657                         v_tree = proto_item_add_subtree(vti, ett_bootp_option);
658                         for (i = optoff, optleft = optlen;
659                             optleft > 0; i += 8, optleft -= 8) {
660                                 if (optleft < 8) {
661                                         proto_tree_add_text(v_tree, tvb, i, optleft,
662                                             "Option length isn't a multiple of 8");
663                                         break;
664                                 }
665                                 proto_tree_add_text(v_tree, tvb, i, 8, "IP Address/Mask: %s/%s",
666                                         ip_to_str(tvb_get_ptr(tvb, i, 4)),
667                                         ip_to_str(tvb_get_ptr(tvb, i+4, 4)));
668                         }
669                 }
670                 break;
671
672         case 33:        /* Static Route */
673                 if (optlen == 8) {
674                         /* one IP address pair */
675                         proto_tree_add_text(bp_tree, tvb, voff, consumed,
676                                 "Option %d: %s = %s/%s", code, text,
677                                 ip_to_str(tvb_get_ptr(tvb, optoff, 4)),
678                                 ip_to_str(tvb_get_ptr(tvb, optoff+4, 4)));
679                 } else {
680                         /* > 1 IP address pair. Let's make a sub-tree */
681                         vti = proto_tree_add_text(bp_tree, tvb, voff,
682                                 consumed, "Option %d: %s", code, text);
683                         v_tree = proto_item_add_subtree(vti, ett_bootp_option);
684                         for (i = optoff, optleft = optlen; optleft > 0;
685                             i += 8, optleft -= 8) {
686                                 if (optleft < 8) {
687                                         proto_tree_add_text(v_tree, tvb, i, optleft,
688                                             "Option length isn't a multiple of 8");
689                                         break;
690                                 }
691                                 proto_tree_add_text(v_tree, tvb, i, 8,
692                                         "Destination IP Address/Router: %s/%s",
693                                         ip_to_str(tvb_get_ptr(tvb, i, 4)),
694                                         ip_to_str(tvb_get_ptr(tvb, i+4, 4)));
695                         }
696                 }
697                 break;
698
699         case 43:        /* Vendor-Specific Info */
700                 /* PXE protocol 2.1 as described in the intel specs */
701                 if (*vendor_class_id_p != NULL &&
702                     strncmp(*vendor_class_id_p, "PXEClient", strlen("PXEClient")) == 0) {
703                         vti = proto_tree_add_text(bp_tree, tvb, voff,
704                                 consumed, "Option %d: %s (PXEClient)", code, text);
705                         v_tree = proto_item_add_subtree(vti, ett_bootp_option);
706
707                         optend = optoff + optlen;
708                         while (optoff < optend) {
709                                 optoff = dissect_vendor_pxeclient_suboption(v_tree,
710                                         tvb, optoff, optend);
711                         }
712                 } else if (*vendor_class_id_p != NULL &&
713                            ((strncmp(*vendor_class_id_p, "pktc", strlen("pktc")) == 0) ||
714                             (strncmp(*vendor_class_id_p, "docsis", strlen("docsis")) == 0) ||
715                             (strncmp(*vendor_class_id_p, "CableHome", strlen("CableHome")) == 0))) {
716                         /* CableLabs standard - see www.cablelabs.com/projects */
717                         vti = proto_tree_add_text(bp_tree, tvb, voff,
718                                 consumed, "Option %d: %s (CableLabs)", code, text);
719                         v_tree = proto_item_add_subtree(vti, ett_bootp_option);
720
721                         optend = optoff + optlen;
722                         while (optoff < optend) {
723                                 optoff = dissect_vendor_cablelabs_suboption(v_tree,
724                                         tvb, optoff, optend);
725                         }
726                 } else {
727                         proto_tree_add_text(bp_tree, tvb, voff, consumed,
728                                 "Option %d: %s (%d bytes)", code, text, optlen);
729                 }
730                 break;
731
732         case 46:        /* NetBIOS-over-TCP/IP Node Type */
733                 if (optlen != 1) {
734                         proto_tree_add_text(bp_tree, tvb, voff, consumed,
735                                 "Option %d: length isn't 1", code);
736                         break;
737                 }
738                 byte = tvb_get_guint8(tvb, optoff);
739                 proto_tree_add_text(bp_tree, tvb, voff, consumed,
740                                 "Option %d: %s = %s", code, text,
741                                 val_to_str(byte, nbnt_vals,
742                                     "Unknown (0x%02x)"));
743                 break;
744
745         case 52:        /* Option Overload */
746                 if (optlen < 1) {
747                         proto_tree_add_text(bp_tree, tvb, voff, consumed,
748                                 "Option %d: length isn't >= 1", code);
749                         break;
750                 }
751                 byte = tvb_get_guint8(tvb, optoff);
752                 vti = proto_tree_add_text(bp_tree, tvb, voff, consumed,
753                         "Option %d: %s = %s", code, text,
754                         val_to_str(byte, opt_overload_vals,
755                             "Unknown (0x%02x)"));
756
757                 /* Just in case we find an option 52 in sname or file */
758                 if (voff > VENDOR_INFO_OFFSET && byte >= 1 && byte <= 3) {
759                         o52tree = proto_item_add_subtree(vti, ett_bootp_option);
760                         if (byte == 1 || byte == 3) {   /* 'file' */
761                                 vti = proto_tree_add_text (o52tree, tvb,
762                                         FILE_NAME_OFFSET, FILE_NAME_LEN,
763                                         "Boot file name option overload");
764                                 v_tree = proto_item_add_subtree(vti, ett_bootp_option);
765                                 o52voff = FILE_NAME_OFFSET;
766                                 o52eoff = FILE_NAME_OFFSET + FILE_NAME_LEN;
767                                 o52at_end = FALSE;
768                                 while (o52voff < o52eoff && !o52at_end) {
769                                         o52voff += bootp_option(tvb, v_tree, o52voff,
770                                                 o52eoff, FALSE, &o52at_end,
771                                                 dhcp_type_p, vendor_class_id_p);
772                                 }
773                         }
774                         if (byte == 2 || byte == 3) {   /* 'sname' */
775                                 vti = proto_tree_add_text (o52tree, tvb,
776                                         SERVER_NAME_OFFSET, SERVER_NAME_LEN,
777                                         "Server host name option overload");
778                                 v_tree = proto_item_add_subtree(vti, ett_bootp_option);
779                                 o52voff = SERVER_NAME_OFFSET;
780                                 o52eoff = SERVER_NAME_OFFSET + SERVER_NAME_LEN;
781                                 o52at_end = FALSE;
782                                 while (o52voff < o52eoff && !o52at_end) {
783                                         o52voff += bootp_option(tvb, v_tree, o52voff,
784                                                 o52eoff, FALSE, &o52at_end,
785                                                 dhcp_type_p, vendor_class_id_p);
786                                 }
787                         }
788                 }
789
790 /*              protocol = tvb_get_guint8(tvb, optoff);
791                 proto_tree_add_text(v_tree, tvb, optoff, 1, "Protocol: %s (%u)",
792                                     val_to_str(protocol, authen_protocol_vals, "Unknown"),
793                                     protocol); */
794                 break;
795         case 53:        /* DHCP Message Type */
796                 if (optlen != 1) {
797                         proto_tree_add_text(bp_tree, tvb, voff, consumed,
798                                 "Option %d: length isn't 1", code);
799                         break;
800                 }
801                 proto_tree_add_text(bp_tree, tvb, voff, 3, "Option %d: %s = DHCP %s",
802                         code, text, get_dhcp_type(tvb_get_guint8(tvb, optoff)));
803                 break;
804
805         case 55:        /* Parameter Request List */
806                 vti = proto_tree_add_text(bp_tree, tvb, voff,
807                         consumed, "Option %d: %s", code, text);
808                 v_tree = proto_item_add_subtree(vti, ett_bootp_option);
809                 for (i = 0; i < optlen; i++) {
810                         byte = tvb_get_guint8(tvb, optoff+i);
811                         if (byte < array_length(opt)) {
812                                 proto_tree_add_text(v_tree, tvb, optoff+i, 1, "%d = %s",
813                                                 byte, opt[byte].text);
814                         } else {
815                                 proto_tree_add_text(vti, tvb, optoff+i, 1,
816                                         "Unknown Option Code: %d", byte);
817                         }
818                 }
819                 break;
820
821         case 60:        /* Vendor class identifier */
822                 /*
823                  * XXX - RFC 2132 says this is a string of octets;
824                  * should we check for non-printables?
825                  */
826                 vti = proto_tree_add_text(bp_tree, tvb, voff, consumed,
827                         "Option %d: %s = \"%s\"", code, text,
828                         tvb_format_stringzpad(tvb, optoff, consumed-2));
829                 if ((tvb_memeql(tvb, optoff, PACKETCABLE_MTA_CAP10, strlen(PACKETCABLE_MTA_CAP10)) == 0) ||
830                         (tvb_memeql(tvb, optoff, PACKETCABLE_MTA_CAP15, strlen(PACKETCABLE_MTA_CAP10)) == 0)) {
831                         v_tree = proto_item_add_subtree(vti, ett_bootp_option);
832                         dissect_packetcable_mta_cap(v_tree, tvb, optoff, optlen);
833                 } else if (tvb_memeql(tvb, optoff, PACKETCABLE_CM_CAP11, strlen(PACKETCABLE_CM_CAP11)) == 0 ||
834                                 tvb_memeql(tvb, optoff, PACKETCABLE_CM_CAP20, strlen(PACKETCABLE_CM_CAP20)) == 0 ) {
835                         v_tree = proto_item_add_subtree(vti, ett_bootp_option);
836                         dissect_docsis_cm_cap(v_tree, tvb, optoff, optlen);
837                 }
838                 break;
839
840         case 61:        /* Client Identifier */
841                 if (optlen > 0)
842                         byte = tvb_get_guint8(tvb, optoff);
843                 else
844                         byte = 0;
845
846                 /* We *MAY* use hwtype/hwaddr. If we have 7 bytes, I'll
847                    guess that the first is the hwtype, and the last 6
848                    are the hw addr */
849                 /* See http://www.iana.org/assignments/arp-parameters */
850                 /* RFC2132 9.14 Client-identifier has the following to say:
851                    A hardware type of 0 (zero) should be used when the value
852                    field contains an identifier other than a hardware address
853                    (e.g. a fully qualified domain name). */
854
855                 if (optlen == 7 && byte > 0 && byte < 48) {
856
857                         vti = proto_tree_add_text(bp_tree, tvb, voff,
858                                 consumed, "Option %d: %s", code, text);
859                         v_tree = proto_item_add_subtree(vti, ett_bootp_option);
860                         proto_tree_add_text(v_tree, tvb, optoff, 1,
861                                 "Hardware type: %s",
862                                 arphrdtype_to_str(byte,
863                                         "Unknown (0x%02x)"));
864                         proto_tree_add_text(v_tree, tvb, optoff+1, 6,
865                                 "Client hardware address: %s",
866                                 arphrdaddr_to_str(tvb_get_ptr(tvb, optoff+1, 6),
867                                         6, byte));
868                 } else {
869                         /* otherwise, it's opaque data */
870                         proto_tree_add_text(bp_tree, tvb, voff, consumed,
871                                 "Option %d: %s (%d bytes)", code, text, optlen);
872                 }
873                 break;
874
875         case 63:        /* NetWare/IP options (RFC 2242) */
876                 vti = proto_tree_add_text(bp_tree, tvb, voff,
877                     consumed, "Option %d: %s", code, text);
878                 v_tree = proto_item_add_subtree(vti, ett_bootp_option);
879
880                 optend = optoff + optlen;
881                 while (optoff < optend)
882                         optoff = dissect_netware_ip_suboption(v_tree, tvb, optoff, optend);
883                 break;
884
885         case 78:        /* SLP Directory Agent Option RFC2610 Added by Greg Morris (gmorris@novell.com)*/
886                 if (optlen < 1) {
887                         proto_tree_add_text(bp_tree, tvb, voff, consumed,
888                                 "Option %d: length isn't >= 1", code);
889                         break;
890                 }
891                 optleft = optlen;
892                 byte = tvb_get_guint8(tvb, optoff);
893                 vti = proto_tree_add_text(bp_tree, tvb, voff, consumed,
894                                 "Option %d: %s = %s", code, text,
895                                 val_to_str(byte, slpda_vals,
896                                     "Unknown (0x%02x)"));
897                 optoff++;
898                 optleft--;
899                 if (byte == 0x80) {
900                         if (optleft == 0)
901                                 break;
902                         optoff++;
903                         optleft--;
904                 }
905                 v_tree = proto_item_add_subtree(vti, ett_bootp_option);
906                 for (i = optoff; optleft > 0; i += 4, optleft -= 4) {
907                         if (optleft < 4) {
908                                 proto_tree_add_text(v_tree, tvb, i, optleft,
909                                     "Option length isn't a multiple of 4");
910                                 break;
911                         }
912                         proto_tree_add_text(v_tree, tvb, i, 4, "SLPDA Address: %s",
913                             ip_to_str(tvb_get_ptr(tvb, i, 4)));
914                 }
915                 break;
916
917         case 79:        /* SLP Service Scope Option RFC2610 Added by Greg Morris (gmorris@novell.com)*/
918                 byte = tvb_get_guint8(tvb, optoff);
919                 vti = proto_tree_add_text(bp_tree, tvb, voff, consumed,
920                                 "Option %d: %s = %s", code, text,
921                                 val_to_str(byte, slp_scope_vals,
922                                     "Unknown (0x%02x)"));
923                 v_tree = proto_item_add_subtree(vti, ett_bootp_option);
924                 optoff++;
925                 optleft = optlen - 1;
926                 proto_tree_add_text(v_tree, tvb, optoff, optleft,
927                     "%s = \"%s\"", text,
928                     tvb_format_stringzpad(tvb, optoff, optleft));
929                 break;
930
931         case 81:        /* Client Fully Qualified Domain Name */
932                 if (optlen < 3) {
933                         proto_tree_add_text(bp_tree, tvb, voff, consumed,
934                                 "Option %d: length isn't >= 3", code);
935                         break;
936                 }
937                 vti = proto_tree_add_text(bp_tree, tvb, voff, consumed,
938                                 "Option %d: FQDN", code);
939                 v_tree = proto_item_add_subtree(vti, ett_bootp_option);
940                 fqdn_flags = tvb_get_guint8(tvb, optoff);
941                 ft = proto_tree_add_text(v_tree, tvb, optoff, 1, "Flags: 0x%02x", fqdn_flags);
942                 flags_tree = proto_item_add_subtree(ft, ett_bootp_fqdn);
943                 proto_tree_add_item(flags_tree, hf_bootp_fqdn_mbz, tvb, optoff, 1, FALSE);
944                 proto_tree_add_item(flags_tree, hf_bootp_fqdn_n, tvb, optoff, 1, FALSE);
945                 proto_tree_add_item(flags_tree, hf_bootp_fqdn_e, tvb, optoff, 1, FALSE);
946                 proto_tree_add_item(flags_tree, hf_bootp_fqdn_o, tvb, optoff, 1, FALSE);
947                 proto_tree_add_item(flags_tree, hf_bootp_fqdn_s, tvb, optoff, 1, FALSE);
948                 /* XXX: use code from packet-dns for return code decoding */
949                 proto_tree_add_item(v_tree, hf_bootp_fqdn_rcode1, tvb, optoff+1, 1, FALSE);
950                 /* XXX: use code from packet-dns for return code decoding */
951                 proto_tree_add_item(v_tree, hf_bootp_fqdn_rcode2, tvb, optoff+2, 1, FALSE);
952                 if (optlen > 3) {
953                         if (fqdn_flags & F_FQDN_E) {
954                                 /* XXX: use code from packet-dns for binary encoded name */
955                                 proto_tree_add_item(v_tree, hf_bootp_fqdn_name,
956                                     tvb, optoff+3, optlen-3, FALSE);
957
958                         } else {
959                                 proto_tree_add_item(v_tree, hf_bootp_fqdn_asciiname,
960                                     tvb, optoff+3, optlen-3, FALSE);
961                         }
962                 }
963                 break;
964
965         case 82:        /* Relay Agent Information Option */
966                 vti = proto_tree_add_text(bp_tree, tvb, voff, consumed,
967                                           "Option %d: %s (%d bytes)",
968                                           code, text, optlen);
969                 v_tree = proto_item_add_subtree(vti, ett_bootp_option);
970                 optend = optoff + optlen;
971                 while (optoff < optend)
972                         optoff = bootp_dhcp_decode_agent_info(v_tree, tvb, optoff, optend);
973                 break;
974
975         case 85:        /* Novell Servers (RFC 2241) */
976                 /* Option 85 can be sent as a string */
977                 /* Added by Greg Morris (gmorris[AT]novell.com) */
978                 if (novell_string) {
979                         proto_tree_add_text(bp_tree, tvb, voff, consumed,
980                             "Option %d: %s = \"%s\"", code, text,
981                             tvb_format_stringzpad(tvb, optoff, optlen));
982                 } else {
983                         if (optlen == 4) {
984                                 /* one IP address */
985                                 proto_tree_add_text(bp_tree, tvb, voff, consumed,
986                                         "Option %d: %s = %s", code, text,
987                                         ip_to_str(tvb_get_ptr(tvb, optoff, 4)));
988                         } else {
989                                 /* > 1 IP addresses. Let's make a sub-tree */
990                                 vti = proto_tree_add_text(bp_tree, tvb, voff,
991                                         consumed, "Option %d: %s", code, text);
992                                 v_tree = proto_item_add_subtree(vti, ett_bootp_option);
993                                 for (i = optoff, optleft = optlen; optleft > 0;
994                                     i += 4, optleft -= 4) {
995                                         if (optleft < 4) {
996                                                 proto_tree_add_text(v_tree, tvb, i, optleft,
997                                                     "Option length isn't a multiple of 4");
998                                                 break;
999                                         }
1000                                         proto_tree_add_text(v_tree, tvb, i, 4, "IP Address: %s",
1001                                                 ip_to_str(tvb_get_ptr(tvb, i, 4)));
1002                                 }
1003                         }
1004                 }
1005                 break;
1006
1007         case 90:        /* DHCP Authentication */
1008         case 210:       /* Was this used for authentication at one time? */
1009                 if (optlen < 11) {
1010                         proto_tree_add_text(bp_tree, tvb, voff, consumed,
1011                                 "Option %d: length isn't >= 11", code);
1012                         break;
1013                 }
1014                 vti = proto_tree_add_text(bp_tree, tvb, voff,
1015                         consumed, "Option %d: %s", code, text);
1016                 v_tree = proto_item_add_subtree(vti, ett_bootp_option);
1017
1018                 optleft = optlen;
1019                 protocol = tvb_get_guint8(tvb, optoff);
1020                 proto_tree_add_text(v_tree, tvb, optoff, 1, "Protocol: %s (%u)",
1021                                     val_to_str(protocol, authen_protocol_vals, "Unknown"),
1022                                     protocol);
1023                 optoff++;
1024                 optleft--;
1025
1026                 algorithm = tvb_get_guint8(tvb, optoff);
1027                 switch (protocol) {
1028
1029                 case AUTHEN_PROTO_DELAYED_AUTHEN:
1030                         proto_tree_add_text(v_tree, tvb, optoff, 1,
1031                                     "Algorithm: %s (%u)",
1032                                     val_to_str(algorithm, authen_da_algo_vals, "Unknown"),
1033                                     algorithm);
1034                         break;
1035
1036                 default:
1037                         proto_tree_add_text(v_tree, tvb, optoff, 1,
1038                                     "Algorithm: %u", algorithm);
1039                         break;
1040                 }
1041                 optoff++;
1042                 optleft--;
1043
1044                 rdm = tvb_get_guint8(tvb, optoff);
1045                 proto_tree_add_text(v_tree, tvb, optoff, 1,
1046                                     "Replay Detection Method: %s (%u)",
1047                                     val_to_str(rdm, authen_rdm_vals, "Unknown"),
1048                                     rdm);
1049                 optoff++;
1050                 optleft--;
1051
1052                 switch (rdm) {
1053
1054                 case AUTHEN_RDM_MONOTONIC_COUNTER:
1055                         proto_tree_add_text(v_tree, tvb, optoff, 8,
1056                                     "Replay Detection Value: %" PRIx64,
1057                                     tvb_get_ntoh64(tvb, optoff));
1058                         break;
1059
1060                 default:
1061                         proto_tree_add_text(v_tree, tvb, optoff, 8,
1062                                     "Replay Detection Value: %s",
1063                                     tvb_bytes_to_str(tvb, optoff, 8));
1064                         break;
1065                 }
1066                 optoff += 8;
1067                 optleft -= 8;
1068
1069                 switch (protocol) {
1070
1071                 case AUTHEN_PROTO_DELAYED_AUTHEN:
1072                         switch (algorithm) {
1073
1074                         case AUTHEN_DELAYED_ALGO_HMAC_MD5:
1075                                 if (optlen < 31) {
1076                                         proto_tree_add_text(bp_tree, tvb, 0, 0,
1077                                                 "Option %d: length isn't >= 31", code);
1078                                         break;
1079                                 }
1080                                 proto_tree_add_text(v_tree, tvb, optoff, 4,
1081                                         "Secret ID: 0x%08x",
1082                                         tvb_get_ntohl(tvb, optoff));
1083                                 optoff += 4;
1084                                 optleft -= 4;
1085                                 proto_tree_add_text(v_tree, tvb, optoff, 16,
1086                                         "HMAC MD5 Hash: %s",
1087                                         tvb_bytes_to_str(tvb, optoff, 16));
1088                                 break;
1089
1090                         default:
1091                                 if (optleft == 0)
1092                                         break;
1093                                 proto_tree_add_text(v_tree, tvb, optoff, optleft,
1094                                         "Authentication Information: %s",
1095                                         tvb_bytes_to_str(tvb, optoff, optleft));
1096                                 break;
1097                         }
1098                         break;
1099
1100                 default:
1101                         if (optleft == 0)
1102                                 break;
1103                         proto_tree_add_text(v_tree, tvb, optoff, optleft,
1104                                 "Authentication Information: %s",
1105                                 tvb_bytes_to_str(tvb, optoff, optleft));
1106                         break;
1107                 }
1108                 break;
1109
1110         default:        /* not special */
1111                 /* The PacketCable CCC option number can vary.  If this is a CCC option,
1112                    handle it and skip the "opaque" case below.
1113                  */
1114                 if (code == pkt_ccc_option) {
1115                         skip_opaque = TRUE;
1116                         vti = proto_tree_add_text(bp_tree, tvb, voff, consumed,
1117                                                   "Option %d: CableLabs Client Configuration (%d bytes)",
1118                                                   code, optlen);
1119                         v_tree = proto_item_add_subtree(vti, ett_bootp_option);
1120                         optend = optoff + optlen;
1121                         while (optoff < optend) {
1122                                 switch (pkt_ccc_protocol_version) {
1123                                         case PACKETCABLE_CCC_I05:
1124                                                 optoff = dissect_packetcable_i05_ccc(v_tree, tvb, optoff, optend);
1125                                                 break;
1126                                         case PACKETCABLE_CCC_DRAFT5:
1127                                         case PACKETCABLE_CCC_RFC_3495:
1128                                                 optoff = dissect_packetcable_ietf_ccc(v_tree, tvb, optoff, optend, pkt_ccc_protocol_version);
1129                                                 break;
1130                                         default: /* XXX Should we do something here? */
1131                                                 break;
1132                                 }
1133                         }
1134                 }
1135
1136                 break;
1137         }
1138
1139         /* Normal cases */
1140         if (code < array_length(opt)) {
1141                 text = opt[code].text;
1142                 ftype = opt[code].ftype;
1143
1144                 switch (ftype) {
1145
1146                 case special:
1147                         return consumed;
1148
1149                 case ipv4_list:
1150                         if (optlen == 4) {
1151                                 /* one IP address */
1152                                 proto_tree_add_text(bp_tree, tvb, voff, consumed,
1153                                         "Option %d: %s = %s", code, text,
1154                                         ip_to_str(tvb_get_ptr(tvb, optoff, 4)));
1155                         } else {
1156                                 /* > 1 IP addresses. Let's make a sub-tree */
1157                                 vti = proto_tree_add_text(bp_tree, tvb, voff,
1158                                         consumed, "Option %d: %s", code, text);
1159                                 v_tree = proto_item_add_subtree(vti, ett_bootp_option);
1160                                 for (i = optoff, optleft = optlen; optleft > 0;
1161                                     i += 4, optleft -= 4) {
1162                                         if (optleft < 4) {
1163                                                 proto_tree_add_text(v_tree, tvb, i, voff + consumed - i,
1164                                                     "Option length isn't a multiple of 4");
1165                                                 break;
1166                                         }
1167                                         proto_tree_add_text(v_tree, tvb, i, 4, "IP Address: %s",
1168                                                 ip_to_str(tvb_get_ptr(tvb, i, 4)));
1169                                 }
1170                         }
1171                         break;
1172
1173                 case string:
1174                         /* Fix for non null-terminated string supplied by
1175                          * John Lines <John.Lines[AT]aeat.co.uk>
1176                          */
1177                         proto_tree_add_text(bp_tree, tvb, voff, consumed,
1178                                         "Option %d: %s = \"%s\"", code, text,
1179                                         tvb_format_stringzpad(tvb, optoff, consumed-2));
1180                         break;
1181
1182                 case opaque:
1183                         if (! skip_opaque) { /* Currently used by PacketCable CCC */
1184                                 proto_tree_add_text(bp_tree, tvb, voff, consumed,
1185                                                 "Option %d: %s (%d bytes)",
1186                                                 code, text, optlen);
1187                         }
1188                         break;
1189
1190                 case val_u_short:
1191                         if (optlen == 2) {
1192                                 /* one gushort */
1193                                 proto_tree_add_text(bp_tree, tvb, voff, consumed,
1194                                                 "Option %d: %s = %d", code, text,
1195                                                 tvb_get_ntohs(tvb, optoff));
1196                         } else {
1197                                 /* > 1 gushort */
1198                                 vti = proto_tree_add_text(bp_tree, tvb, voff,
1199                                         consumed, "Option %d: %s", code, text);
1200                                 v_tree = proto_item_add_subtree(vti, ett_bootp_option);
1201                                 for (i = optoff, optleft = optlen; optleft > 0;
1202                                     i += 2, optleft -= 2) {
1203                                         if (optleft < 2) {
1204                                                 proto_tree_add_text(v_tree, tvb, i, voff + consumed - i,
1205                                                     "Option length isn't a multiple of 2");
1206                                                 break;
1207                                         }
1208                                         proto_tree_add_text(v_tree, tvb, i, 4, "Value: %d",
1209                                                 tvb_get_ntohs(tvb, i));
1210                                 }
1211                         }
1212                         break;
1213
1214                 case val_u_long:
1215                         if (optlen != 4) {
1216                                 proto_tree_add_text(bp_tree, tvb, voff, consumed,
1217                                         "Option %d: length isn't 4", code);
1218                                 break;
1219                         }
1220                         proto_tree_add_text(bp_tree, tvb, voff, consumed,
1221                                         "Option %d: %s = %d", code, text,
1222                                         tvb_get_ntohl(tvb, optoff));
1223                         break;
1224
1225                 case val_u_byte:
1226                         if (optlen != 1) {
1227                                 proto_tree_add_text(bp_tree, tvb, voff, consumed,
1228                                         "Option %d: length isn't 1", code);
1229                                 break;
1230                         }
1231                         proto_tree_add_text(bp_tree, tvb, voff, consumed,
1232                                         "Option %d: %s = %d", code, text,
1233                                         tvb_get_guint8(tvb, optoff));
1234                         break;
1235
1236                 case toggle:
1237                         if (optlen != 1) {
1238                                 proto_tree_add_text(bp_tree, tvb, voff, consumed,
1239                                         "Option %d: length isn't 1", code);
1240                                 break;
1241                         }
1242                         i = tvb_get_guint8(tvb, optoff);
1243                         if (i != 0 && i != 1) {
1244                                 proto_tree_add_text(bp_tree, tvb, voff, consumed,
1245                                                 "Option %d: %s = Invalid Value %d", code, text,
1246                                                 i);
1247                         } else {
1248                                 proto_tree_add_text(bp_tree, tvb, voff, consumed,
1249                                                 "Option %d: %s = %s", code, text,
1250                                                 i == 0 ? "Disabled" : "Enabled");
1251                         }
1252                         break;
1253
1254                 case yes_no:
1255                         if (optlen != 1) {
1256                                 proto_tree_add_text(bp_tree, tvb, voff, consumed,
1257                                         "Option %d: length isn't 1", code);
1258                                 break;
1259                         }
1260                         i = tvb_get_guint8(tvb, optoff);
1261                         if (i != 0 && i != 1) {
1262                                 proto_tree_add_text(bp_tree, tvb, voff, consumed,
1263                                                 "Option %d: %s = Invalid Value %d", code, text,
1264                                                 i);
1265                         } else {
1266                                 proto_tree_add_text(bp_tree, tvb, voff, consumed,
1267                                                 "Option %d: %s = %s", code, text,
1268                                                 i == 0 ? "No" : "Yes");
1269                         }
1270                         break;
1271
1272                 case time_in_secs:
1273                         if (optlen != 4) {
1274                                 proto_tree_add_text(bp_tree, tvb, voff, consumed,
1275                                         "Option %d: length isn't 4", code);
1276                                 break;
1277                         }
1278                         time_secs = tvb_get_ntohl(tvb, optoff);
1279                         proto_tree_add_text(bp_tree, tvb, voff, consumed,
1280                                 "Option %d: %s = %s", code, text,
1281                                 ((time_secs == 0xffffffff) ?
1282                                     "infinity" :
1283                                     time_secs_to_str(time_secs)));
1284                         break;
1285
1286                 default:
1287                         proto_tree_add_text(bp_tree, tvb, voff, consumed,
1288                                         "Option %d: %s (%d bytes)", code, text, optlen);
1289                 }
1290         } else {
1291                 proto_tree_add_text(bp_tree, tvb, voff, consumed,
1292                                 "Unknown Option Code: %d (%d bytes)", code, optlen);
1293         }
1294
1295         return consumed;
1296 }
1297
1298 static int
1299 bootp_dhcp_decode_agent_info(proto_tree *v_tree, tvbuff_t *tvb, int optoff,
1300     int optend)
1301 {
1302         int suboptoff = optoff;
1303         guint8 subopt;
1304         guint8 subopt_len;
1305
1306         subopt = tvb_get_guint8(tvb, optoff);
1307         suboptoff++;
1308
1309         if (suboptoff >= optend) {
1310                 proto_tree_add_text(v_tree, tvb, optoff, 1,
1311                         "Suboption %d: no room left in option for suboption length",
1312                         subopt);
1313                 return (optend);
1314         }
1315         subopt_len = tvb_get_guint8(tvb, suboptoff);
1316         suboptoff++;
1317
1318         if (suboptoff+subopt_len >= optend) {
1319                 proto_tree_add_text(v_tree, tvb, optoff, optend-optoff,
1320                         "Suboption %d: no room left in option for suboption value",
1321                         subopt);
1322                 return (optend);
1323         }
1324         switch (subopt) {
1325         case 1:
1326                 proto_tree_add_text(v_tree, tvb, optoff, subopt_len + 2,
1327                                     "Agent Circuit ID: %s",
1328                                     tvb_bytes_to_str(tvb, suboptoff, subopt_len));
1329                 break;
1330         case 2:
1331                 proto_tree_add_text(v_tree, tvb, optoff, subopt_len + 2,
1332                                     "Agent Remote ID: %s",
1333                                     tvb_bytes_to_str(tvb, suboptoff, subopt_len));
1334                 break;
1335         default:
1336                 proto_tree_add_text(v_tree, tvb, optoff, subopt_len + 2,
1337                                     "Invalid agent suboption %d (%d bytes)",
1338                                     subopt, subopt_len);
1339                 break;
1340         }
1341         optoff += (subopt_len + 2);
1342         return optoff;
1343 }
1344
1345 static int
1346 dissect_vendor_pxeclient_suboption(proto_tree *v_tree, tvbuff_t *tvb,
1347     int optoff, int optend)
1348 {
1349         int suboptoff = optoff;
1350         guint8 subopt;
1351         guint8 subopt_len;
1352         int suboptleft;
1353         proto_tree *o43pxeclient_v_tree;
1354         proto_item *vti;
1355
1356         struct o43pxeclient_opt_info {
1357                 char    *text;
1358                 enum field_type ft;
1359         };
1360
1361         static struct o43pxeclient_opt_info o43pxeclient_opt[]= {
1362                 /* 0 */ {"nop", special},       /* dummy */
1363                 /* 1 */ {"PXE mtftp IP", ipv4_list},
1364                 /* 2 */ {"PXE mtftp client port", val_u_le_short},
1365                 /* 3 */ {"PXE mtftp server port",val_u_le_short},
1366                 /* 4 */ {"PXE mtftp timeout", val_u_byte},
1367                 /* 5 */ {"PXE mtftp delay", val_u_byte},
1368                 /* 6 */ {"PXE discovery control", val_u_byte},
1369                         /*
1370                          * Correct: b0 (lsb): disable broadcast discovery
1371                          *      b1: disable multicast discovery
1372                          *      b2: only use/accept servers in boot servers
1373                          *      b3: download bootfile without prompt/menu/disc
1374                          */
1375                 /* 7 */ {"PXE multicast address", ipv4_list},
1376                 /* 8 */ {"PXE boot servers", special},
1377                 /* 9 */ {"PXE boot menu", special},
1378                 /* 10 */ {"PXE menu prompt", special},
1379                 /* 11 */ {"PXE multicast address alloc", special},
1380                 /* 12 */ {"PXE credential types", special},
1381                 /* 71 {"PXE boot item", special} */
1382                 /* 255 {"PXE end options", special} */
1383         };
1384
1385         subopt = tvb_get_guint8(tvb, suboptoff);
1386         suboptoff++;
1387
1388         if (subopt == 0) {
1389                 proto_tree_add_text(v_tree, tvb, optoff, 1, "Padding");
1390                 return (suboptoff);
1391         } else if (subopt == 255) {     /* End Option */
1392                 proto_tree_add_text(v_tree, tvb, optoff, 1, "End PXEClient option");
1393                 /* Make sure we skip any junk left this option */
1394                 return (optend);
1395         }
1396
1397         if (suboptoff >= optend) {
1398                 proto_tree_add_text(v_tree, tvb, optoff, 1,
1399                         "Suboption %d: no room left in option for suboption length",
1400                         subopt);
1401                 return (optend);
1402         }
1403         subopt_len = tvb_get_guint8(tvb, suboptoff);
1404         suboptoff++;
1405
1406         if (suboptoff+subopt_len >= optend) {
1407                 proto_tree_add_text(v_tree, tvb, optoff, optend-optoff,
1408                         "Suboption %d: no room left in option for suboption value",
1409                         subopt);
1410                 return (optend);
1411         }
1412         if ( subopt == 71 ) {   /* 71 {"PXE boot item", special} */
1413                 /* case special */
1414                 /* I may need to decode that properly one day */
1415                 proto_tree_add_text(v_tree, tvb, optoff, subopt_len+2,
1416                         "Suboption %d: %s (%d byte%s)" ,
1417                         subopt, "PXE boot item",
1418                         subopt_len, plurality(subopt_len, "", "s"));
1419         } else if ((subopt < 1) || (subopt > array_length(o43pxeclient_opt))) {
1420                 proto_tree_add_text(v_tree, tvb, optoff, subopt_len+2,
1421                         "Unknown suboption %d (%d byte%s)", subopt, subopt_len,
1422                         plurality(subopt_len, "", "s"));
1423         } else {
1424                 switch (o43pxeclient_opt[subopt].ft) {
1425
1426 /* XXX          case string:
1427                         proto_tree_add_text(v_tree, tvb, optoff, subopt_len+2,
1428                                 "Suboption %d: %s", subopt, o43pxeclient_opt[subopt].text);
1429                         break;
1430    XXX */
1431                 case special:
1432                         /* I may need to decode that properly one day */
1433                         proto_tree_add_text(v_tree, tvb, optoff, subopt_len+2,
1434                                 "Suboption %d: %s (%d byte%s)",
1435                                 subopt, o43pxeclient_opt[subopt].text,
1436                                 subopt_len, plurality(subopt_len, "", "s"));
1437                         break;
1438
1439                 case val_u_le_short:
1440                         if (subopt_len != 2) {
1441                                 proto_tree_add_text(v_tree, tvb, optoff, subopt_len+2,
1442                                         "Suboption %d: suboption length isn't 2", subopt);
1443                                 break;
1444                         }
1445                         proto_tree_add_text(v_tree, tvb, optoff, 4, "Suboption %d: %s = %u",
1446                             subopt, o43pxeclient_opt[subopt].text,
1447                             tvb_get_letohs(tvb, suboptoff));
1448                         break;
1449
1450                 case val_u_byte:
1451                         if (subopt_len != 1) {
1452                                 proto_tree_add_text(v_tree, tvb, optoff, subopt_len+2,
1453                                         "Suboption %d: suboption length isn't 1", subopt);
1454                                 break;
1455                         }
1456                         proto_tree_add_text(v_tree, tvb, optoff, 3, "Suboption %d: %s = %u",
1457                             subopt, o43pxeclient_opt[subopt].text,
1458                             tvb_get_guint8(tvb, suboptoff));
1459                         break;
1460
1461                 case ipv4_list:
1462                         if (subopt_len == 4) {
1463                                 /* one IP address */
1464                                 proto_tree_add_text(v_tree, tvb, optoff, 6,
1465                                     "Suboption %d : %s = %s",
1466                                     subopt, o43pxeclient_opt[subopt].text,
1467                                     ip_to_str(tvb_get_ptr(tvb, suboptoff, 4)));
1468                         } else {
1469                                 /* > 1 IP addresses. Let's make a sub-tree */
1470                                 vti = proto_tree_add_text(v_tree, tvb, optoff,
1471                                     subopt_len+2, "Suboption %d: %s",
1472                                     subopt, o43pxeclient_opt[subopt].text);
1473                                 o43pxeclient_v_tree = proto_item_add_subtree(vti, ett_bootp_option);
1474                                 for (suboptleft = subopt_len; suboptleft > 0;
1475                                     suboptoff += 4, suboptleft -= 4) {
1476                                         if (suboptleft < 4) {
1477                                                 proto_tree_add_text(o43pxeclient_v_tree,
1478                                                     tvb, suboptoff, suboptleft,
1479                                                     "Suboption length isn't a multiple of 4");
1480                                                 break;
1481                                         }
1482                                         proto_tree_add_text(o43pxeclient_v_tree,
1483                                             tvb, suboptoff, 4, "IP Address: %s",
1484                                             ip_to_str(tvb_get_ptr(tvb, suboptoff, 4)));
1485                                 }
1486                         }
1487                         break;
1488
1489                 default:
1490                         proto_tree_add_text(v_tree, tvb, optoff, subopt_len+2,"ERROR, please report: Unknown subopt type handler %d", subopt);
1491                         break;
1492                 }
1493         }
1494         optoff += (subopt_len + 2);
1495         return optoff;
1496 }
1497
1498
1499 static int
1500 dissect_vendor_cablelabs_suboption(proto_tree *v_tree, tvbuff_t *tvb,
1501     int optoff, int optend)
1502 {
1503         int suboptoff = optoff;
1504         guint8 subopt, byte_val;
1505         guint8 subopt_len;
1506
1507         struct o43cablelabs_opt_info {
1508                 char    *text;
1509                 enum field_type ft;
1510         };
1511
1512         static struct o43cablelabs_opt_info o43cablelabs_opt[]= {
1513                 /* 0 */ {"nop", special},       /* dummy */
1514                 /* 1 */ {"Suboption Request List", string},
1515                 /* 2 */ {"Device Type", string},
1516                 /* 3 */ {"eSAFE Types", string},
1517                 /* 4 */ {"Serial Number", string},
1518                 /* 5 */ {"Hardware Version", string},
1519                 /* 6 */ {"Software Version", string},
1520                 /* 7 */ {"Boot ROM version", string},
1521                 /* 8 */ {"Organizationally Unique Identifier", special},
1522                 /* 9 */ {"Model Number", string},
1523                 /* 10 */ {"Vendor Name", string},
1524                 /* *** 11-30: CableHome *** */
1525                 /* 11 */ {"Address Realm", special},
1526                 /* 12 */ {"CM/PS System Description", string},
1527                 /* 13 */ {"CM/PS Firmware Revision", string},
1528                 /* 14 */ {"Firewall Policy File Version", string},
1529                 /* 15 */ {"Unassigned (CableHome)", special},
1530                 /* 16 */ {"Unassigned (CableHome)", special},
1531                 /* 17 */ {"Unassigned (CableHome)", special},
1532                 /* 18 */ {"Unassigned (CableHome)", special},
1533                 /* 19 */ {"Unassigned (CableHome)", special},
1534                 /* 20 */ {"Unassigned (CableHome)", special},
1535                 /* 21 */ {"Unassigned (CableHome)", special},
1536                 /* 22 */ {"Unassigned (CableHome)", special},
1537                 /* 23 */ {"Unassigned (CableHome)", special},
1538                 /* 24 */ {"Unassigned (CableHome)", special},
1539                 /* 25 */ {"Unassigned (CableHome)", special},
1540                 /* 26 */ {"Unassigned (CableHome)", special},
1541                 /* 27 */ {"Unassigned (CableHome)", special},
1542                 /* 28 */ {"Unassigned (CableHome)", special},
1543                 /* 29 */ {"Unassigned (CableHome)", special},
1544                 /* 30 */ {"Unassigned (CableHome)", special},
1545                 /* *** 31-50: PacketCable *** */
1546                 /* 31 */ {"MTA MAC Address", special},
1547                 /* 32 */ {"Correlation ID", string},
1548                 /* 33-50 {"Unassigned (PacketCable)", special}, */
1549                 /* *** 51-127: CableLabs *** */
1550                 /* 51-127 {"Unassigned (CableLabs)", special}, */
1551                 /* *** 128-254: Vendors *** */
1552                 /* 128-254 {"Unassigned (Vendors)", special}, */
1553                 /* 255 {"end options", special} */
1554         };
1555
1556         static const value_string cablehome_subopt11_vals[] = {
1557                 { 1, "PS WAN-Man" },
1558                 { 2, "PS WAN-Data" },
1559                 { 0, NULL }
1560         };
1561
1562         subopt = tvb_get_guint8(tvb, suboptoff);
1563         suboptoff++;
1564
1565         if (subopt == 0) {
1566                 proto_tree_add_text(v_tree, tvb, optoff, 1, "Padding");
1567                 return (suboptoff);
1568         } else if (subopt == 255) {     /* End Option */
1569                 proto_tree_add_text(v_tree, tvb, optoff, 1, "End CableLabs option");
1570                 /* Make sure we skip any junk left this option */
1571                 return (optend);
1572         }
1573
1574         if (suboptoff >= optend) {
1575                 proto_tree_add_text(v_tree, tvb, optoff, 1,
1576                         "Suboption %d: no room left in option for suboption length",
1577                         subopt);
1578                 return (optend);
1579         }
1580         subopt_len = tvb_get_guint8(tvb, suboptoff);
1581         suboptoff++;
1582
1583         if (suboptoff+subopt_len >= optend) {
1584                 proto_tree_add_text(v_tree, tvb, optoff, optend-optoff,
1585                         "Suboption %d: no room left in option for suboption value",
1586                         subopt);
1587                 return (optend);
1588         }
1589         if ( (subopt < 1 ) || (subopt > array_length(o43cablelabs_opt)) ) {
1590                 proto_tree_add_text(v_tree, tvb, optoff, subopt_len+2,
1591                         "Suboption %d: Unassigned (%d byte%s)", subopt, subopt_len,
1592                         plurality(subopt_len, "", "s"));
1593         } else {
1594                 switch (o43cablelabs_opt[subopt].ft) {
1595
1596                 case string:
1597                         proto_tree_add_text(v_tree, tvb, optoff, subopt_len+2,
1598                                 "Suboption %d: %s = \"%s\"", subopt,
1599                                 o43cablelabs_opt[subopt].text,
1600                                 tvb_format_stringzpad(tvb, optoff, subopt_len));
1601                         break;
1602
1603                 case bytes:
1604                         proto_tree_add_text(v_tree, tvb, optoff, subopt_len+2,
1605                                 "Suboption %d: %s = 0x%s", subopt,
1606                                 o43cablelabs_opt[subopt].text,
1607                                 tvb_bytes_to_str(tvb, suboptoff, subopt_len));
1608                         break;
1609
1610                 case special:
1611                         if ( subopt == 8 ) {    /* OUI */
1612                                 if (subopt_len != 3) {
1613                                         proto_tree_add_text(v_tree, tvb, optoff, subopt_len+2,
1614                                                 "Suboption %d: suboption length isn't 3", subopt);
1615                                         break;
1616                                 }
1617                                 proto_tree_add_text(v_tree, tvb, optoff, subopt_len+2,
1618                                         "Suboption %d: OUI = %s",
1619                                         subopt, bytes_to_str_punct(tvb_get_ptr(tvb, suboptoff, 3), 3, ':'));
1620                         } else if ( subopt == 11 ) { /* Address Realm */
1621                                 if (subopt_len != 1) {
1622                                         proto_tree_add_text(v_tree, tvb, optoff, subopt_len+2,
1623                                                 "Suboption %d: suboption length isn't 1", subopt);
1624                                         break;
1625                                 }
1626                                 byte_val = tvb_get_guint8(tvb, suboptoff);
1627                                 proto_tree_add_text(v_tree, tvb, optoff, subopt_len+2,
1628                                         "Suboption %d: %s = %s (0x%02x)",
1629                                         subopt, o43cablelabs_opt[subopt].text,
1630                                         val_to_str(byte_val, cablehome_subopt11_vals, "Unknown"), byte_val);
1631                         } else if ( subopt == 31 ) { /* MTA MAC address */
1632                                 if (subopt_len != 6) {
1633                                         proto_tree_add_text(v_tree, tvb, optoff, subopt_len+2,
1634                                                 "Suboption %d: suboption length isn't 6", subopt);
1635                                         break;
1636                                 }
1637                                 proto_tree_add_text(v_tree, tvb, optoff, subopt_len+2,
1638                                         "Suboption %d: %s = %s",
1639                                         subopt,  o43cablelabs_opt[subopt].text,
1640                                         bytes_to_str_punct(tvb_get_ptr(tvb, suboptoff, 6), 6, ':'));
1641                         } else {
1642                                 proto_tree_add_text(v_tree, tvb, optoff, subopt_len+2,
1643                                         "Suboption %d: %s (%d byte%s)" ,
1644                                         subopt, o43cablelabs_opt[subopt].text,
1645                                         subopt_len, plurality(subopt_len, "", "s"));
1646                         }
1647                         break;
1648
1649                 default:
1650                         proto_tree_add_text(v_tree, tvb, optoff, subopt_len+2,"ERROR, please report: Unknown subopt type handler %d", subopt);
1651                         break;
1652                 }
1653         }
1654         optoff += (subopt_len + 2);
1655         return optoff;
1656 }
1657
1658
1659
1660 static int
1661 dissect_netware_ip_suboption(proto_tree *v_tree, tvbuff_t *tvb,
1662     int optoff, int optend)
1663 {
1664         int suboptoff = optoff;
1665         guint8 subopt;
1666         guint8 subopt_len;
1667         int suboptleft;
1668         proto_tree *o63_v_tree;
1669         proto_item *vti;
1670
1671         struct o63_opt_info {
1672                 char    *truet;
1673                 char    *falset;
1674                 enum field_type ft;
1675         };
1676
1677         static struct o63_opt_info o63_opt[]= {
1678                 /* 0 */ {"","",none},
1679                 /* 1 */ {"NWIP does not exist on subnet","",presence},
1680                 /* 2 */ {"NWIP exist in options area","",presence},
1681                 /* 3 */ {"NWIP exists in sname/file","",presence},
1682                 /* 4 */ {"NWIP exists, but too big","",presence},
1683                 /* 5 */ {"Broadcast for nearest Netware server","Do NOT Broadcast for nearest Netware server",yes_no},
1684                 /* 6 */ {"Preferred DSS server","",ipv4_list},
1685                 /* 7 */ {"Nearest NWIP server","",ipv4_list},
1686                 /* 8 */ {"Autoretries","",val_u_byte},
1687                 /* 9 */ {"Autoretry delay, secs ","",val_u_byte},
1688                 /* 10*/ {"Support NetWare/IP v1.1","Do NOT support NetWare/IP v1.1",yes_no},
1689                 /* 11*/ {"Primary DSS ", "" , ipv4}
1690         };
1691
1692         subopt = tvb_get_guint8(tvb, optoff);
1693         suboptoff++;
1694
1695         if (suboptoff >= optend) {
1696                 proto_tree_add_text(v_tree, tvb, optoff, 1,
1697                         "Suboption %d: no room left in option for suboption length",
1698                         subopt);
1699                 return (optend);
1700         }
1701         subopt_len = tvb_get_guint8(tvb, suboptoff);
1702         suboptoff++;
1703
1704         if (subopt > array_length(o63_opt)) {
1705                 proto_tree_add_text(v_tree, tvb, optoff, subopt_len + 2, "Unknown suboption %d", subopt);
1706         } else {
1707                 switch (o63_opt[subopt].ft) {
1708
1709                 case presence:
1710                         if (subopt_len != 0) {
1711                                 proto_tree_add_text(v_tree, tvb, optoff, subopt_len + 2,
1712                                         "Suboption %d: length isn't 0", subopt);
1713                                 suboptoff += subopt_len;
1714                                 break;
1715                         }
1716                         proto_tree_add_text(v_tree, tvb, optoff, 2, "Suboption %d: %s", subopt, o63_opt[subopt].truet);
1717                         break;
1718
1719                 case yes_no:
1720                         if (subopt_len != 1) {
1721                                 proto_tree_add_text(v_tree, tvb, optoff, subopt_len + 2,
1722                                         "Suboption %d: length isn't 1", subopt);
1723                                 suboptoff += subopt_len;
1724                                 break;
1725                         }
1726                         if (suboptoff+1 > optend) {
1727                                 proto_tree_add_text(v_tree, tvb, optoff, optend-optoff,
1728                                     "Suboption %d: no room left in option for suboption value",
1729                                     subopt);
1730                                 return (optend);
1731                         }
1732                         if (tvb_get_guint8(tvb, suboptoff)==1) {
1733                                 proto_tree_add_text(v_tree, tvb, optoff, 3, "Suboption %d: %s", subopt, o63_opt[subopt].truet);
1734                         } else {
1735                                 proto_tree_add_text(v_tree, tvb, optoff, 3, "Suboption %d: %s" , subopt, o63_opt[subopt].falset);
1736                         }
1737                         suboptoff += 3;
1738                         break;
1739
1740                 case ipv4:
1741                         if (subopt_len != 4) {
1742                                 proto_tree_add_text(v_tree, tvb, optoff, subopt_len + 2,
1743                                         "Suboption %d: length isn't 4", subopt);
1744                                 suboptoff += subopt_len;
1745                                 break;
1746                         }
1747                         if (suboptoff+4 > optend) {
1748                                 proto_tree_add_text(v_tree, tvb, optoff, optend-optoff,
1749                                     "Suboption %d: no room left in option for suboption value",
1750                                     subopt);
1751                                 return (optend);
1752                         }
1753                         proto_tree_add_text(v_tree, tvb, optoff, 6,
1754                             "Suboption %d: %s = %s" ,
1755                             subopt, o63_opt[subopt].truet,
1756                             ip_to_str(tvb_get_ptr(tvb, suboptoff, 4)));
1757                         suboptoff += 6;
1758                         break;
1759
1760                 case val_u_byte:
1761                         if (subopt_len != 1) {
1762                                 proto_tree_add_text(v_tree, tvb, optoff, subopt_len + 2,
1763                                         "Suboption %d: length isn't 1", subopt);
1764                                 suboptoff += subopt_len;
1765                                 break;
1766                         }
1767                         if (suboptoff+1 > optend) {
1768                                 proto_tree_add_text(v_tree, tvb, optoff, optend-optoff,
1769                                     "Suboption %d: no room left in option for suboption value",
1770                                     subopt);
1771                                 return (optend);
1772                         }
1773                         proto_tree_add_text(v_tree, tvb, optoff, 3, "Suboption %d: %s = %u",
1774                             subopt, o63_opt[subopt].truet,
1775                             tvb_get_guint8(tvb, suboptoff));
1776                         suboptoff += 1;
1777                         break;
1778
1779                 case ipv4_list:
1780                         if (subopt_len == 4) {
1781                                 /* one IP address */
1782                                 proto_tree_add_text(v_tree, tvb, optoff, 6,
1783                                     "Suboption %d : %s = %s",
1784                                     subopt, o63_opt[subopt].truet,
1785                                     ip_to_str(tvb_get_ptr(tvb, suboptoff, 4)));
1786                                 suboptoff += 4;
1787                         } else {
1788                                 /* > 1 IP addresses. Let's make a sub-tree */
1789                                 vti = proto_tree_add_text(v_tree, tvb, optoff,
1790                                     subopt_len+2, "Suboption %d: %s",
1791                                     subopt, o63_opt[subopt].truet);
1792                                 o63_v_tree = proto_item_add_subtree(vti, ett_bootp_option);
1793                                 for (suboptleft = subopt_len; suboptleft > 0;
1794                                     suboptoff += 4, suboptleft -= 4) {
1795                                         if (suboptleft < 4) {
1796                                                 proto_tree_add_text(o63_v_tree,
1797                                                     tvb, suboptoff, suboptleft,
1798                                                     "Suboption length isn't a multiple of 4");
1799                                                 suboptoff += suboptleft;
1800                                                 break;
1801                                         }
1802                                         proto_tree_add_text(o63_v_tree, tvb, suboptoff, 4, "IP Address: %s",
1803                                             ip_to_str(tvb_get_ptr(tvb, suboptoff, 4)));
1804                                 }
1805                         }
1806                         break;
1807
1808                 default:
1809                         proto_tree_add_text(v_tree, tvb, optoff, subopt_len + 2,"Unknown suboption %d", subopt);
1810                         suboptoff += subopt_len;
1811                         break;
1812                 }
1813         }
1814         return suboptoff;
1815 }
1816
1817
1818 /* PacketCable Multimedia Terminal Adapter device capabilities (option 60).
1819    Ref: PKT-SP-I05-021127 sections 8.2 and 10 */
1820
1821 #define PKT_MDC_TLV_OFF 10
1822
1823
1824 /* These are ASCII-encoded hexadecimal digits.  We use the raw hex equivalent for
1825    convenience. */
1826 #define PKT_MDC_VERSION                 0x3031  /* "01" */
1827 #define PKT_MDC_TEL_END                 0x3032  /* "02" */
1828 #define PKT_MDC_TGT                     0x3033  /* "03" */
1829 #define PKT_MDC_HTTP_ACC                0x3034  /* "04" */
1830 #define PKT_MDC_SYSLOG                  0x3035  /* "05" */
1831 #define PKT_MDC_NCS                     0x3036  /* "06" */
1832 #define PKT_MDC_PRI_LINE                0x3037  /* "07" */
1833 #define PKT_MDC_VENDOR_TLV              0x3038  /* "08" */
1834 #define PKT_MDC_NVRAM_STOR              0x3039  /* "09" */
1835 #define PKT_MDC_PROV_REP                0x3041  /* "0A" */
1836 #define PKT_MDC_PROV_REP_LC             0x3061  /* "0A" */
1837 #define PKT_MDC_SUPP_CODECS             0x3042  /* "0B" */
1838 #define PKT_MDC_SUPP_CODECS_LC          0x3062  /* "0b" */
1839 #define PKT_MDC_SILENCE                 0x3043  /* "0C" */
1840 #define PKT_MDC_SILENCE_LC              0x3063  /* "0c" */
1841 #define PKT_MDC_ECHO_CANCEL             0x3044  /* "0D" */
1842 #define PKT_MDC_ECHO_CANCEL_LC          0x3064  /* "0d" */
1843 #define PKT_MDC_RSVP                    0x3045  /* "0E" */
1844 #define PKT_MDC_RSVP_LC                 0x3065  /* "0e" */
1845 #define PKT_MDC_UGS_AD                  0x3046  /* "0F" */
1846 #define PKT_MDC_UGS_AD_LC               0x3066  /* "0f" */
1847 #define PKT_MDC_IF_INDEX                0x3130  /* "10" */
1848 #define PKT_MDC_FLOW_LOG                0x3131  /* "11" */
1849 #define PKT_MDC_PROV_FLOWS              0x3132  /* "12" */
1850 /* PacketCable 1.5: */
1851 #define PKT_MDC_T38_VERSION             0x3133  /* "13" */
1852 #define PKT_MDC_T38_EC                  0x3134  /* "14" */
1853 #define PKT_MDC_RFC2833_DTMF            0x3135  /* "15" */
1854 #define PKT_MDC_VOICE_METRICS           0x3136  /* "16" */
1855 #define PKT_MDC_MIBS                    0x3137  /* "17" */
1856 #define PKT_MDC_MGPI                    0x3138  /* "18" */
1857
1858 static const value_string pkt_mdc_type_vals[] = {
1859         { PKT_MDC_VERSION,              "PacketCable Version" },
1860         { PKT_MDC_TEL_END,              "Number Of Telephony Endpoints" },
1861         { PKT_MDC_TGT,                  "TGT Support" },
1862         { PKT_MDC_HTTP_ACC,             "HTTP Download File Access Method Support" },
1863         { PKT_MDC_SYSLOG,               "MTA-24 Event SYSLOG Notification Support" },
1864         { PKT_MDC_NCS,                  "NCS Service Flow Support" },
1865         { PKT_MDC_PRI_LINE,             "Primary Line Support" },
1866         { PKT_MDC_VENDOR_TLV,           "Vendor Specific TLV Type(s)" },
1867         { PKT_MDC_NVRAM_STOR,           "NVRAM Ticket/Session Keys Storage Support" },
1868         { PKT_MDC_PROV_REP,             "Provisioning Event Reporting Support" },
1869         { PKT_MDC_PROV_REP_LC,          "Provisioning Event Reporting Support" },
1870         { PKT_MDC_SUPP_CODECS,          "Supported CODEC(s)" },
1871         { PKT_MDC_SUPP_CODECS_LC,       "Supported CODEC(s)" },
1872         { PKT_MDC_SILENCE,              "Silence Suppression Support" },
1873         { PKT_MDC_SILENCE_LC,           "Silence Suppression Support" },
1874         { PKT_MDC_ECHO_CANCEL,          "Echo Cancellation Support" },
1875         { PKT_MDC_ECHO_CANCEL_LC,       "Echo Cancellation Support" },
1876         { PKT_MDC_RSVP,                 "RSVP Support/ Reserved" },
1877         { PKT_MDC_RSVP_LC,              "RSVP Support/ Reserved" },
1878         { PKT_MDC_UGS_AD,               "UGS-AD Support" },
1879         { PKT_MDC_UGS_AD_LC,            "UGS-AD Support" },
1880         { PKT_MDC_IF_INDEX,             "MTA's \"ifIndex\" starting number in \"ifTable\"" },
1881         { PKT_MDC_FLOW_LOG,             "Provisioning Flow Logging Support" },
1882         { PKT_MDC_PROV_FLOWS,           "Supported Provisioning Flows" },
1883         /* PacketCable 1.5: */
1884         { PKT_MDC_T38_VERSION,          "T38 Version Support" },
1885         { PKT_MDC_T38_EC,               "T38 Error Correction Support" },
1886         { PKT_MDC_RFC2833_DTMF,         "RFC 2833 DTMF Support" },
1887         { PKT_MDC_VOICE_METRICS,        "Voice Metrics Support" },
1888         { PKT_MDC_MIBS,                 "MIB Support" },
1889         { PKT_MDC_MGPI,                 "Multiple Grants Per Interval Support" },
1890         { 0,                                    NULL }
1891 };
1892
1893 static const value_string pkt_mdc_version_vals[] = {
1894         { 0x3030,       "PacketCable 1.0" },
1895         { 0x3031,       "PacketCable 1.1/1.5" }, /* 1.5 replaces 1.1-1.3 */
1896         { 0x3032,       "PacketCable 1.2" },
1897         { 0x3033,       "PacketCable 1.3" },
1898         { 0,            NULL }
1899 };
1900
1901 static const value_string pkt_mdc_boolean_vals[] = {
1902         { 0x3030,       "No" },
1903         { 0x3031,       "Yes" },
1904         { 0,            NULL }
1905 };
1906
1907 static const value_string pkt_mdc_codec_vals[] = {
1908         { 0x3031,       "other" },           /* "01" */
1909         { 0x3032,       "unknown" },
1910         { 0x3033,       "G.729" },
1911         { 0x3034,       "reserved" },
1912         { 0x3035,       "G.729E" },
1913         { 0x3036,       "PCMU" },
1914         { 0x3037,       "G.726-32" },
1915         { 0x3038,       "G.728" },
1916         { 0x3039,       "PCMA" },            /* "09" */
1917         { 0x3041,       "G.726-16" },        /* "0A" */
1918         { 0x3042,       "G.726-24" },
1919         { 0x3043,       "G.726-40" },
1920         { 0x3044,       "iLBC" },
1921         { 0x3045,       "BV16" },
1922         { 0x3046,       "telephone-event" }, /* "0F" */
1923         { 0,            NULL }
1924 };
1925
1926 static const value_string pkt_mdc_t38_version_vals[] = {
1927         { 0x3030,       "Unsupported" },
1928         { 0x3031,       "T.38 Version Zero" }, /* default */
1929         { 0x3032,       "T.38 Version One" },
1930         { 0x3033,       "T.38 Version Two" },
1931         { 0x3035,       "T.38 Version Three" },
1932         { 0,            NULL }
1933 };
1934
1935 static const value_string pkt_mdc_t38_ec_vals[] = {
1936         { 0x3030,       "None" },
1937         { 0x3031,       "Redundancy" }, /* default */
1938         { 0x3032,       "FEC" },
1939         { 0,            NULL }
1940 };
1941
1942 static const value_string pkt_mdc_mibs_vals[] = {
1943         { 0x3030,       "PacketCable 1.0" },
1944         { 0x3031,       "PacketCable 1.5" },
1945         { 0x3032,       "Reserved" },
1946         { 0x3033,       "Reserved" },
1947         { 0x3034,       "Reserved" },
1948         { 0x3035,       "IETF" },
1949         { 0,            NULL }
1950 };
1951
1952 /* DOCSIS Cable Modem device capabilities (option 60). */
1953 /* XXX we should rename all PKT_CM_* variables to DOCSIS_CM_* */
1954 #define PKT_CM_TLV_OFF 12
1955
1956 #define PKT_CM_CONCAT_SUP       0x3031  /* "01" */
1957 #define PKT_CM_DOCSIS_VER       0x3032  /* "02" */
1958 #define PKT_CM_FRAG_SUP         0x3033  /* "03" */
1959 #define PKT_CM_PHS_SUP          0x3034  /* "04" */
1960 #define PKT_CM_IGMP_SUP         0x3035  /* "05" */
1961 #define PKT_CM_PRIV_SUP         0x3036  /* "06" */
1962 #define PKT_CM_DSAID_SUP        0x3037  /* "07" */
1963 #define PKT_CM_USID_SUP         0x3038  /* "08" */
1964 #define PKT_CM_FILT_SUP         0x3039  /* "09" */
1965 #define PKT_CM_TET_MI           0x3041  /* "0A" */
1966 #define PKT_CM_TET_MI_LC        0x3061  /* "0a" */
1967 #define PKT_CM_TET              0x3042  /* "0B" */
1968 #define PKT_CM_TET_LC           0x3062  /* "0b" */
1969 #define PKT_CM_DCC_SUP          0x3043  /* "0C" */
1970 #define PKT_CM_DCC_SUP_LC       0x3063  /* "0c" */
1971
1972 static const value_string pkt_cm_type_vals[] = {
1973         { PKT_CM_CONCAT_SUP,    "Concatenation Support" },
1974         { PKT_CM_DOCSIS_VER,    "DOCSIS Version" },
1975         { PKT_CM_FRAG_SUP,      "Fragmentation Support" },
1976         { PKT_CM_PHS_SUP,       "PHS Support" },
1977         { PKT_CM_IGMP_SUP,      "IGMP Support" },
1978         { PKT_CM_PRIV_SUP,      "Privacy Support" },
1979         { PKT_CM_DSAID_SUP,     "Downstream SAID Support" },
1980         { PKT_CM_USID_SUP,      "Upstream SID Support" },
1981         { PKT_CM_FILT_SUP,      "Optional Filtering Support" },
1982         { PKT_CM_TET_MI,        "Transmit Equalizer Taps per Modulation Interval" },
1983         { PKT_CM_TET_MI_LC,     "Transmit Equalizer Taps per Modulation Interval" },
1984         { PKT_CM_TET,           "Number of Transmit Equalizer Taps" },
1985         { PKT_CM_TET_LC,        "Number of Transmit Equalizer Taps" },
1986         { PKT_CM_DCC_SUP,       "DCC Support" },
1987         { PKT_CM_DCC_SUP_LC,    "DCC Support" }
1988 };
1989
1990 static const value_string pkt_cm_version_vals[] = {
1991         { 0x3030,       "DOCSIS 1.0" },
1992         { 0x3031,       "DOCSIS 1.1" },
1993         { 0x3032,       "DOCSIS 2.0" },
1994         { 0,            NULL }
1995 };
1996
1997 static const value_string pkt_cm_privacy_vals[] = {
1998         { 0x3030,       "BPI Support" },
1999         { 0x3031,       "BPI Plus Support" },
2000         { 0,            NULL }
2001 };
2002
2003
2004 static const value_string pkt_mdc_supp_flow_vals[] = {
2005         { 1 << 0, "Secure Flow (Full Secure Provisioning Flow)" },
2006         { 1 << 1, "Hybrid Flow" },
2007         { 1 << 2, "Basic Flow" },
2008         { 0, NULL }
2009 };
2010
2011
2012 static void
2013 dissect_packetcable_mta_cap(proto_tree *v_tree, tvbuff_t *tvb, int voff, int len)
2014 {
2015         guint16 raw_val;
2016         unsigned long flow_val = 0;
2017         guint off = PKT_MDC_TLV_OFF + voff;
2018         guint tlv_len, i;
2019         guint8 asc_val[3] = "  ", flow_val_str[5];
2020         static GString *tlv_str = NULL;
2021         char bit_fld[64];
2022         proto_item *ti;
2023         proto_tree *subtree;
2024
2025         if (! tlv_str)
2026                 tlv_str = g_string_new("");
2027
2028         tvb_memcpy (tvb, asc_val, off, 2);
2029         if (sscanf(asc_val, "%x", &tlv_len) != 1) {
2030                 proto_tree_add_text(v_tree, tvb, off, len - off,
2031                         "Bogus length: %s", asc_val);
2032                 return;
2033         } else {
2034                 proto_tree_add_uint_format(v_tree, hf_bootp_pkt_mtacap_len, tvb, off, 2,
2035                                 tlv_len, "MTA DC Length: %d", tlv_len);
2036                 off += 2;
2037
2038                 while ((int) off - voff < len) {
2039                         /* Type */
2040                         raw_val = tvb_get_ntohs (tvb, off);
2041                         g_string_sprintf(tlv_str, "0x%.2s: %s = ",
2042                                         tvb_get_ptr(tvb, off, 2),
2043                                         val_to_str(raw_val, pkt_mdc_type_vals, "unknown"));
2044
2045                         /* Length */
2046                         tvb_memcpy(tvb, asc_val, off + 2, 2);
2047                         if (sscanf(asc_val, "%x", &tlv_len) != 1) {
2048                                 proto_tree_add_text(v_tree, tvb, off, len - off,
2049                                                         "[Bogus length: %s]", asc_val);
2050                                 return;
2051                         } else {
2052                                 /* Value(s) */
2053                                 /*g_string_sprintfa(tlv_str, "Length: %d, Value: ", tlv_len);*/
2054
2055                                 switch (raw_val) {
2056                                         case PKT_MDC_VERSION:
2057                                                 raw_val = tvb_get_ntohs(tvb, off + 4);
2058                                                 g_string_sprintfa(tlv_str, "%s (%.2s)",
2059                                                                 val_to_str(raw_val, pkt_mdc_version_vals, "Reserved"),
2060                                                                 tvb_get_ptr(tvb, off + 4, 2) );
2061                                                 break;
2062                                         case PKT_MDC_TEL_END:
2063                                         case PKT_MDC_IF_INDEX:
2064                                                 g_string_sprintfa(tlv_str, "%.2s",
2065                                                                 tvb_get_ptr(tvb, off + 4, 2) );
2066                                                 break;
2067                                         case PKT_MDC_TGT:
2068                                         case PKT_MDC_HTTP_ACC:
2069                                         case PKT_MDC_SYSLOG:
2070                                         case PKT_MDC_NCS:
2071                                         case PKT_MDC_PRI_LINE:
2072                                         case PKT_MDC_NVRAM_STOR:
2073                                         case PKT_MDC_PROV_REP:
2074                                         case PKT_MDC_PROV_REP_LC:
2075                                         case PKT_MDC_SILENCE:
2076                                         case PKT_MDC_SILENCE_LC:
2077                                         case PKT_MDC_ECHO_CANCEL:
2078                                         case PKT_MDC_ECHO_CANCEL_LC:
2079                                         case PKT_MDC_RSVP:
2080                                         case PKT_MDC_RSVP_LC:
2081                                         case PKT_MDC_UGS_AD:
2082                                         case PKT_MDC_UGS_AD_LC:
2083                                         case PKT_MDC_FLOW_LOG:
2084                                         case PKT_MDC_RFC2833_DTMF:
2085                                         case PKT_MDC_VOICE_METRICS:
2086                                                 raw_val = tvb_get_ntohs(tvb, off + 4);
2087                                                 g_string_sprintfa(tlv_str, "%s (%.2s)",
2088                                                                 val_to_str(raw_val, pkt_mdc_boolean_vals, "unknown"),
2089                                                                 tvb_get_ptr(tvb, off + 4, 2) );
2090                                                 break;
2091                                         case PKT_MDC_SUPP_CODECS:
2092                                         case PKT_MDC_SUPP_CODECS_LC:
2093                                                 for (i = 0; i < tlv_len; i++) {
2094                                                         raw_val = tvb_get_ntohs(tvb, off + 4 + (i * 2) );
2095                                                         g_string_sprintfa(tlv_str, "%s%s (%.2s)",
2096                                                                         plurality(i + 1, "", ", "),
2097                                                                         val_to_str(raw_val, pkt_mdc_codec_vals, "unknown"),
2098                                                                         tvb_get_ptr(tvb, off + 4 + (i * 2), 2) );
2099                                                 }
2100                                                 break;
2101                                         case PKT_MDC_PROV_FLOWS:
2102                                                 tvb_memcpy(tvb, flow_val_str, off + 4, 4);
2103                                                 flow_val_str[4] = '\0';
2104                                                 flow_val = strtoul(flow_val_str, NULL, 16);
2105                                                 g_string_sprintfa(tlv_str, "0x%04lx", flow_val);
2106                                                 break;
2107                                         case PKT_MDC_T38_VERSION:
2108                                                 raw_val = tvb_get_ntohs(tvb, off + 4);
2109                                                 g_string_sprintfa(tlv_str, "%s (%.2s)",
2110                                                                 val_to_str(raw_val, pkt_mdc_t38_version_vals, "unknown"),
2111                                                                 tvb_get_ptr(tvb, off + 4, 2) );
2112                                                 break;
2113                                         case PKT_MDC_T38_EC:
2114                                                 raw_val = tvb_get_ntohs(tvb, off + 4);
2115                                                 g_string_sprintfa(tlv_str, "%s (%.2s)",
2116                                                                 val_to_str(raw_val, pkt_mdc_t38_ec_vals, "unknown"),
2117                                                                 tvb_get_ptr(tvb, off + 4, 2) );
2118                                                 break;
2119                                         case PKT_MDC_MIBS:
2120                                                 raw_val = tvb_get_ntohs(tvb, off + 4);
2121                                                 g_string_sprintfa(tlv_str, "%s (%.2s)",
2122                                                                 val_to_str(raw_val, pkt_mdc_mibs_vals, "unknown"),
2123                                                                 tvb_get_ptr(tvb, off + 4, 2) );
2124                                                 break;
2125                                         case PKT_MDC_VENDOR_TLV:
2126                                         default:
2127                                                 g_string_sprintfa(tlv_str, "%s",
2128                                                                 tvb_format_stringzpad(tvb, off + 4, tlv_len * 2) );
2129                                                 break;
2130                                 }
2131                         }
2132                         ti = proto_tree_add_text(v_tree, tvb, off, (tlv_len * 2) + 4, tlv_str->str);
2133                         subtree = proto_item_add_subtree(ti, ett_bootp_option);
2134                         if (raw_val == PKT_MDC_PROV_FLOWS) {
2135                                 for (i = 0 ; i < 3; i++) {
2136                                         if (flow_val & pkt_mdc_supp_flow_vals[i].value) {
2137                                                 decode_bitfield_value(bit_fld, flow_val, pkt_mdc_supp_flow_vals[i].value, 16);
2138                                                 proto_tree_add_text(ti, tvb, off + 4, 4, "%s%s",
2139                                                         bit_fld, pkt_mdc_supp_flow_vals[i].strptr);
2140                                         }
2141                                 }
2142                         }
2143                         off += (tlv_len * 2) + 4;
2144                 }
2145         }
2146 }
2147
2148 static void
2149 dissect_docsis_cm_cap(proto_tree *v_tree, tvbuff_t *tvb, int voff, int len)
2150 {
2151         unsigned long raw_val;
2152         guint off = PKT_CM_TLV_OFF + voff;
2153         guint tlv_len, i;
2154         guint8 asc_val[3] = "  ";
2155         static GString *tlv_str = NULL;
2156
2157         if (! tlv_str)
2158                 tlv_str = g_string_new("");
2159
2160         tvb_memcpy (tvb, asc_val, off, 2);
2161         if (sscanf(asc_val, "%x", &tlv_len) != 1) {
2162                 proto_tree_add_text(v_tree, tvb, off, len - off,
2163                                     "Bogus length: %s", asc_val);
2164                 return;
2165         } else {
2166                 proto_tree_add_uint_format(v_tree, hf_bootp_docsis_cmcap_len, tvb, off, 2,
2167                                 tlv_len, "CM DC Length: %d", tlv_len);
2168                 off += 2;
2169
2170                 while ((int) off - voff < len) {
2171                         /* Type */
2172                         raw_val = tvb_get_ntohs (tvb, off);
2173                         g_string_sprintf(tlv_str, "0x%.2s: %s = ",
2174                                         tvb_get_ptr(tvb, off, 2),
2175                                         val_to_str(raw_val, pkt_cm_type_vals, "unknown"));
2176
2177                         /* Length */
2178                         tvb_memcpy(tvb, asc_val, off + 2, 2);
2179                         if (sscanf(asc_val, "%x", &tlv_len) != 1) {
2180                                 proto_tree_add_text(v_tree, tvb, off, len - off,
2181                                                         "[Bogus length: %s]", asc_val);
2182                                 return;
2183                         } else {
2184                                 /* Value(s) */
2185                                 /*g_string_sprintfa(tlv_str, "Length: %d, Value%s: ", tlv_len,
2186                                                 plurality(tlv_len, "", "s") );*/
2187
2188                                 switch (raw_val) {
2189                                         case PKT_CM_CONCAT_SUP:
2190                                         case PKT_CM_FRAG_SUP:
2191                                         case PKT_CM_PHS_SUP:
2192                                         case PKT_CM_IGMP_SUP:
2193                                         case PKT_CM_DCC_SUP:
2194                                         case PKT_CM_DCC_SUP_LC:
2195                                                 for (i = 0; i < tlv_len; i++) {
2196                                                         raw_val = tvb_get_ntohs(tvb, off + 4 + (i * 2) );
2197                                                         g_string_sprintfa(tlv_str, "%s%s (%.2s)",
2198                                                                         plurality(i + 1, "", ", "),
2199                                                                         val_to_str(raw_val, pkt_mdc_boolean_vals, "unknown"),
2200                                                                         tvb_get_ptr(tvb, off + 4 + (i * 2), 2) );
2201                                                 }
2202                                                 break;
2203                                         case PKT_CM_DOCSIS_VER:
2204                                                 raw_val = tvb_get_ntohs(tvb, off + 4);
2205                                                 g_string_sprintfa(tlv_str, "%s (%.2s)",
2206                                                                 val_to_str(raw_val, pkt_cm_version_vals, "Reserved"),
2207                                                                 tvb_get_ptr(tvb, off + 4, 2) );
2208                                                 break;
2209                                         case PKT_CM_PRIV_SUP:
2210                                                 raw_val = tvb_get_ntohs(tvb, off + 4);
2211                                                 g_string_sprintfa(tlv_str, "%s (%.2s)",
2212                                                                 val_to_str(raw_val, pkt_cm_privacy_vals, "Reserved"),
2213                                                                 tvb_get_ptr(tvb, off + 4, 2) );
2214                                                 break;
2215                                         case PKT_CM_DSAID_SUP:
2216                                         case PKT_CM_USID_SUP:
2217                                         case PKT_CM_TET_MI:
2218                                         case PKT_CM_TET_MI_LC:
2219                                         case PKT_CM_TET:
2220                                         case PKT_CM_TET_LC:
2221                                                 tvb_memcpy (tvb, asc_val, off + 4, 2);
2222                                                 raw_val = strtoul(asc_val, NULL, 16);
2223                                                 g_string_sprintfa(tlv_str, "%lu", raw_val);
2224                                                 break;
2225                                         case PKT_CM_FILT_SUP:
2226                                                 tvb_memcpy (tvb, asc_val, off + 4, 2);
2227                                                 raw_val = strtoul(asc_val, NULL, 16);
2228                                                 if (raw_val & 0x01)
2229                                                         g_string_append(tlv_str, "802.1P filtering");
2230                                                 if (raw_val & 0x02) {
2231                                                         if (raw_val & 0x01)
2232                                                                 g_string_append(tlv_str, ", ");
2233                                                         g_string_append(tlv_str, "802.1Q filtering");
2234                                                 }
2235                                                 if (! raw_val & 0x03)
2236                                                         g_string_append(tlv_str, "None");
2237                                                 g_string_sprintfa(tlv_str, " (0x%02lx)", raw_val);
2238                                                 break;
2239                                 }
2240                         }
2241                         proto_tree_add_text(v_tree, tvb, off, (tlv_len * 2) + 4, tlv_str->str);
2242                         off += (tlv_len * 2) + 4;
2243                 }
2244         }
2245 }
2246
2247
2248 /* Definitions specific to PKT-SP-PROV-I05-021127 begin with "PKT_CCC_I05".
2249    Definitions specific to IETF draft 5 and RFC 3495 begin with "PKT_CCC_IETF".
2250    Shared definitions begin with "PKT_CCC".
2251  */
2252 #define PKT_CCC_PRI_DHCP       1
2253 #define PKT_CCC_SEC_DHCP       2
2254 #define PKT_CCC_I05_SNMP       3
2255 #define PKT_CCC_IETF_PROV_SRV  3
2256 #define PKT_CCC_I05_PRI_DNS    4
2257 #define PKT_CCC_IETF_AS_KRB    4
2258 #define PKT_CCC_I05_SEC_DNS    5
2259 #define PKT_CCC_IETF_AP_KRB    5
2260 #define PKT_CCC_KRB_REALM      6
2261 #define PKT_CCC_TGT_FLAG       7
2262 #define PKT_CCC_PROV_TIMER     8
2263 #define PKT_CCC_CMS_FQDN       9
2264 #define PKT_CCC_IETF_SEC_TKT   9
2265 #define PKT_CCC_AS_KRB        10
2266 #define PKT_CCC_AP_KRB        11
2267 #define PKT_CCC_MTA_KRB_CLEAR 12
2268
2269 static const value_string pkt_i05_ccc_opt_vals[] = {
2270         { PKT_CCC_PRI_DHCP,             "Primary DHCP Server" },
2271         { PKT_CCC_SEC_DHCP,             "Secondary DHCP Server" },
2272         { PKT_CCC_I05_SNMP,             "SNMP Entity" },
2273         { PKT_CCC_I05_PRI_DNS,          "Primary DNS Server" },
2274         { PKT_CCC_I05_SEC_DNS,          "Secondary DNS Server" },
2275         { PKT_CCC_KRB_REALM,            "Kerberos Realm" },
2276         { PKT_CCC_TGT_FLAG,             "MTA should fetch TGT?" },
2277         { PKT_CCC_PROV_TIMER,           "Provisioning Timer" },
2278         { PKT_CCC_CMS_FQDN,             "CMS FQDN" },
2279         { PKT_CCC_AS_KRB,               "AS-REQ/AS-REP Backoff and Retry" },
2280         { PKT_CCC_AP_KRB,               "AP-REQ/AP-REP Backoff and Retry" },
2281         { PKT_CCC_MTA_KRB_CLEAR,        "MTA should clear Kerberos tickets?" },
2282         { 0, NULL },
2283 };
2284
2285 static const value_string pkt_draft5_ccc_opt_vals[] = {
2286         { PKT_CCC_PRI_DHCP,             "TSP's Primary DHCP Server" },
2287         { PKT_CCC_SEC_DHCP,             "TSP's Secondary DHCP Server" },
2288         { PKT_CCC_IETF_PROV_SRV,        "TSP's Provisioning Server" },
2289         { PKT_CCC_IETF_AS_KRB,          "TSP's AS-REQ/AS-REP Backoff and Retry" },
2290         { PKT_CCC_IETF_AP_KRB,          "TSP's AP-REQ/AP-REP Backoff and Retry" },
2291         { PKT_CCC_KRB_REALM,            "TSP's Kerberos Realm Name" },
2292         { PKT_CCC_TGT_FLAG,             "TSP's Ticket Granting Server Utilization" },
2293         { PKT_CCC_PROV_TIMER,           "TSP's Provisioning Timer Value" },
2294         { PKT_CCC_IETF_SEC_TKT,         "PacketCable Security Ticket Control" },
2295         { 0, NULL },
2296 };
2297
2298 static const value_string pkt_i05_ccc_ticket_ctl_vals[] = {
2299         { 1, "Invalidate Provisioning Application Server's ticket" },
2300         { 2, "Invalidate all CMS Application Server tickets" },
2301         { 3, "Invalidate all Application Server tickets" },
2302         { 0, NULL },
2303 };
2304
2305 static int
2306 dissect_packetcable_i05_ccc(proto_tree *v_tree, tvbuff_t *tvb, int optoff,
2307     int optend)
2308 {
2309         int suboptoff = optoff;
2310         guint8 subopt, subopt_len, fetch_tgt, timer_val, ticket_ctl;
2311         proto_tree *pkt_s_tree;
2312         proto_item *vti;
2313         static GString *opt_str = NULL;
2314
2315         if (! opt_str)
2316                 opt_str = g_string_new("");
2317
2318         subopt = tvb_get_guint8(tvb, optoff);
2319         suboptoff++;
2320
2321         if (suboptoff >= optend) {
2322                 proto_tree_add_text(v_tree, tvb, optoff, 1,
2323                         "Suboption %d: no room left in option for suboption length",
2324                         subopt);
2325                 return (optend);
2326         }
2327         subopt_len = tvb_get_guint8(tvb, optoff);
2328         suboptoff++;
2329
2330         g_string_sprintf(opt_str, "Suboption %u: %s: ", subopt,
2331                         val_to_str(subopt, pkt_i05_ccc_opt_vals, "unknown/reserved") );
2332
2333         switch (subopt) {
2334                 case PKT_CCC_PRI_DHCP:  /* String values */
2335                 case PKT_CCC_SEC_DHCP:
2336                 case PKT_CCC_I05_SNMP:
2337                 case PKT_CCC_I05_PRI_DNS:
2338                 case PKT_CCC_I05_SEC_DNS:
2339                 case PKT_CCC_KRB_REALM:
2340                 case PKT_CCC_CMS_FQDN:
2341                         g_string_sprintfa(opt_str, "%s (%u byte%s)",
2342                                         tvb_format_stringzpad(tvb, suboptoff, subopt_len),
2343                                         subopt_len,
2344                                         plurality(subopt_len, "", "s") );
2345                         proto_tree_add_text(v_tree, tvb, optoff, subopt_len + 2, opt_str->str);
2346                         suboptoff += subopt_len;
2347                         break;
2348
2349                 case PKT_CCC_TGT_FLAG:
2350                         if (suboptoff+1 > optend) {
2351                                 proto_tree_add_text(v_tree, tvb, optoff, optend-optoff,
2352                                     "Suboption %d: no room left in option for suboption value",
2353                                     subopt);
2354                                 return (optend);
2355                         }
2356                         fetch_tgt = tvb_get_guint8(tvb, suboptoff);
2357                         g_string_sprintfa(opt_str, "%s (%u byte%s%s)",
2358                                         fetch_tgt ? "Yes" : "No",
2359                                         subopt_len,
2360                                         plurality(subopt_len, "", "s"),
2361                                         subopt_len != 1 ? " [Invalid]" : "");
2362                         proto_tree_add_text(v_tree, tvb, optoff, subopt_len + 2, opt_str->str);
2363                         suboptoff += subopt_len;
2364                         break;
2365
2366                 case PKT_CCC_PROV_TIMER:
2367                         if (suboptoff+1 > optend) {
2368                                 proto_tree_add_text(v_tree, tvb, optoff, optend-optoff,
2369                                     "Suboption %d: no room left in option for suboption value",
2370                                     subopt);
2371                                 return (optend);
2372                         }
2373                         timer_val = tvb_get_guint8(tvb, suboptoff);
2374                         g_string_sprintfa(opt_str, "%u%s (%u byte%s%s)", timer_val,
2375                                         timer_val > 30 ? " [Invalid]" : "",
2376                                         subopt_len,
2377                                         plurality(subopt_len, "", "s"),
2378                                         subopt_len != 1 ? " [Invalid]" : "");
2379                         proto_tree_add_text(v_tree, tvb, optoff, subopt_len + 2, opt_str->str);
2380                         suboptoff += subopt_len;
2381                         break;
2382
2383                 case PKT_CCC_AS_KRB:
2384                         if (suboptoff+12 > optend) {
2385                                 proto_tree_add_text(v_tree, tvb, optoff, optend-optoff,
2386                                     "Suboption %d: no room left in option for suboption value",
2387                                     subopt);
2388                                 return (optend);
2389                         }
2390                         g_string_sprintfa(opt_str, "(%u byte%s%s)", subopt_len,
2391                                         plurality(subopt_len, "", "s"),
2392                                         subopt_len != 12 ? " [Invalid]" : "");
2393                         vti = proto_tree_add_text(v_tree, tvb, optoff, subopt_len + 2, opt_str->str);
2394                         if (subopt_len == 12) {
2395                                 pkt_s_tree = proto_item_add_subtree(vti, ett_bootp_option);
2396                                 proto_tree_add_text(pkt_s_tree, tvb, suboptoff, 4,
2397                                                 "pktcMtaDevRealmUnsolicitedKeyNomTimeout: %u",
2398                                                 tvb_get_ntohl(tvb, suboptoff));
2399                                 proto_tree_add_text(pkt_s_tree, tvb, suboptoff + 4, 4,
2400                                                 "pktcMtaDevRealmUnsolicitedKeyMaxTimeout: %u",
2401                                                 tvb_get_ntohl(tvb, suboptoff + 4));
2402                                 proto_tree_add_text(pkt_s_tree, tvb, suboptoff + 8, 4,
2403                                                 "pktcMtaDevRealmUnsolicitedKeyMaxRetries: %u",
2404                                                 tvb_get_ntohl(tvb, suboptoff + 8));
2405                         }
2406                         suboptoff += subopt_len;
2407                         break;
2408
2409                 case PKT_CCC_AP_KRB:
2410                         if (suboptoff+12 > optend) {
2411                                 proto_tree_add_text(v_tree, tvb, optoff, optend-optoff,
2412                                     "Suboption %d: no room left in option for suboption value",
2413                                     subopt);
2414                                 return (optend);
2415                         }
2416                         g_string_sprintfa(opt_str, "(%u byte%s%s)", subopt_len,
2417                                         plurality(subopt_len, "", "s"),
2418                                         subopt_len != 12 ? " [Invalid]" : "");
2419                         vti = proto_tree_add_text(v_tree, tvb, optoff, subopt_len + 2, opt_str->str);
2420                         if (subopt_len == 12) {
2421                                 pkt_s_tree = proto_item_add_subtree(vti, ett_bootp_option);
2422                                 proto_tree_add_text(pkt_s_tree, tvb, suboptoff, 4,
2423                                                 "pktcMtaDevProvUnsolicitedKeyNomTimeout: %u",
2424                                                 tvb_get_ntohl(tvb, suboptoff));
2425                                 proto_tree_add_text(pkt_s_tree, tvb, suboptoff + 4, 4,
2426                                                 "pktcMtaDevProvUnsolicitedKeyMaxTimeout: %u",
2427                                                 tvb_get_ntohl(tvb, suboptoff + 4));
2428                                 proto_tree_add_text(pkt_s_tree, tvb, suboptoff + 8, 4,
2429                                                 "pktcMtaDevProvUnsolicitedKeyMaxRetries: %u",
2430                                                 tvb_get_ntohl(tvb, suboptoff + 8));
2431                         }
2432                         suboptoff += subopt_len;
2433                         break;
2434
2435                 case PKT_CCC_MTA_KRB_CLEAR:
2436                         if (suboptoff+1 > optend) {
2437                                 proto_tree_add_text(v_tree, tvb, optoff, optend-optoff,
2438                                     "Suboption %d: no room left in option for suboption value",
2439                                     subopt);
2440                                 return (optend);
2441                         }
2442                         ticket_ctl = tvb_get_guint8(tvb, suboptoff);
2443                         g_string_sprintfa(opt_str, "%s (%u) (%u byte%s%s)",
2444                                         val_to_str (ticket_ctl, pkt_i05_ccc_ticket_ctl_vals, "unknown/invalid"),
2445                                         ticket_ctl,
2446                                         subopt_len,
2447                                         plurality(subopt_len, "", "s"),
2448                                         subopt_len != 1 ? " [Invalid]" : "");
2449                         proto_tree_add_text(v_tree, tvb, optoff, subopt_len + 2, opt_str->str);
2450                         suboptoff += subopt_len;
2451                         break;
2452
2453                 default:
2454                         proto_tree_add_text(v_tree, tvb, optoff, subopt_len + 2, opt_str->str);
2455                         suboptoff += subopt_len;
2456                         break;
2457
2458         }
2459         return suboptoff;
2460 }
2461
2462
2463 static const value_string sec_tcm_vals[] = {
2464         { 1 << 0, "PacketCable Provisioning Server" },
2465         { 1 << 1, "All PacketCable Call Management Servers" },
2466         { 0, NULL }
2467 };
2468
2469 static int
2470 dissect_packetcable_ietf_ccc(proto_tree *v_tree, tvbuff_t *tvb, int optoff,
2471     int optend, int revision)
2472 {
2473         int suboptoff = optoff;
2474         guint8 subopt, subopt_len, ipv4_addr[4];
2475         guint8 prov_type, fetch_tgt, timer_val;
2476         guint16 sec_tcm;
2477         proto_tree *pkt_s_tree;
2478         proto_item *vti;
2479         static GString *opt_str = NULL;
2480         int max_timer_val = 255, i;
2481         char dns_name[255], bit_fld[24];
2482
2483         if (! opt_str)
2484                 opt_str = g_string_new("");
2485
2486         subopt = tvb_get_guint8(tvb, suboptoff);
2487         suboptoff++;
2488
2489         if (suboptoff >= optend) {
2490                 proto_tree_add_text(v_tree, tvb, optoff, 1,
2491                         "Suboption %d: no room left in option for suboption length",
2492                         subopt);
2493                 return (optend);
2494         }
2495         subopt_len = tvb_get_guint8(tvb, suboptoff);
2496         suboptoff++;
2497
2498         g_string_sprintf(opt_str, "Suboption %u: %s: ", subopt,
2499                         val_to_str(subopt, pkt_draft5_ccc_opt_vals, "unknown/reserved") );
2500
2501         switch (subopt) {
2502                 case PKT_CCC_PRI_DHCP:  /* IPv4 values */
2503                 case PKT_CCC_SEC_DHCP:
2504                         if (suboptoff+4 > optend) {
2505                                 proto_tree_add_text(v_tree, tvb, optoff, optend-optoff,
2506                                     "Suboption %d: no room left in option for suboption value",
2507                                     subopt);
2508                                 return (optend);
2509                         }