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