Get rid of some unused variables, as per Josef Korelus.
[obnox/wireshark/wip.git] / packet-bootp.c
1 /* packet-bootp.c
2  * Routines for BOOTP/DHCP packet disassembly
3  * Gilbert Ramirez <gram@alumni.rice.edu>
4  *
5  * $Id: packet-bootp.c,v 1.77 2003/12/03 20:01:20 guy Exp $
6  *
7  * The information used comes from:
8  * RFC  951: Bootstrap Protocol
9  * RFC 1497: BOOTP extensions
10  * RFC 1542: Clarifications and Extensions for the Bootstrap Protocol
11  * RFC 2131: Dynamic Host Configuration Protocol
12  * RFC 2132: DHCP Options and BOOTP Vendor Extensions
13  * RFC 2489: Procedure for Defining New DHCP Options
14  * RFC 2610: DHCP Options for Service Location Protocol
15  * RFC 3046: DHCP Relay Agent Information Option
16  * RFC 3118: Authentication for DHCP Messages
17  * RFC 3203: DHCP reconfigure extension
18  * BOOTP and DHCP Parameters
19  *     http://www.iana.org/assignments/bootp-dhcp-parameters
20  *
21  * Ethereal - Network traffic analyzer
22  * By Gerald Combs <gerald@ethereal.com>
23  * Copyright 1998 Gerald Combs
24  *
25  * This program is free software; you can redistribute it and/or
26  * modify it under the terms of the GNU General Public License
27  * as published by the Free Software Foundation; either version 2
28  * of the License, or (at your option) any later version.
29  *
30  * This program is distributed in the hope that it will be useful,
31  * but WITHOUT ANY WARRANTY; without even the implied warranty of
32  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
33  * GNU General Public License for more details.
34  *
35  * You should have received a copy of the GNU General Public License
36  * along with this program; if not, write to the Free Software
37  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
38  */
39
40 #ifdef HAVE_CONFIG_H
41 # include "config.h"
42 #endif
43
44 #include <string.h>
45 #include <glib.h>
46 #include <epan/int-64bit.h>
47 #include <epan/packet.h>
48 #include "packet-arp.h"
49
50 #include "prefs.h"
51 #include "tap.h"
52  
53 static int bootp_dhcp_tap = -1;
54 static int proto_bootp = -1;
55 static int hf_bootp_type = -1;
56 static int hf_bootp_hw_type = -1;
57 static int hf_bootp_hw_len = -1;
58 static int hf_bootp_hops = -1;
59 static int hf_bootp_id = -1;
60 static int hf_bootp_secs = -1;
61 static int hf_bootp_flags = -1;
62 static int hf_bootp_flags_broadcast = -1;
63 static int hf_bootp_flags_reserved = -1;
64 static int hf_bootp_ip_client = -1;
65 static int hf_bootp_ip_your = -1;
66 static int hf_bootp_ip_server = -1;
67 static int hf_bootp_ip_relay = -1;
68 static int hf_bootp_hw_addr = -1;
69 static int hf_bootp_server = -1;
70 static int hf_bootp_file = -1;
71 static int hf_bootp_cookie = -1;
72 static int hf_bootp_vendor = -1;
73 static int hf_bootp_dhcp = -1;
74
75 static guint ett_bootp = -1;
76 static guint ett_bootp_flags = -1;
77 static guint ett_bootp_option = -1;
78
79 gboolean novell_string = FALSE;
80
81 #define UDP_PORT_BOOTPS  67
82 #define UDP_PORT_BOOTPC  68
83
84 #define BOOTP_BC        0x8000
85 #define BOOTP_MBZ       0x7FFF
86
87 enum field_type { none, ipv4, string, toggle, yes_no, special, opaque,
88         time_in_secs,
89         val_u_byte, val_u_short, val_u_le_short, val_u_long,
90         val_s_long };
91
92 struct opt_info {
93         char    *text;
94         enum field_type ftype;
95 };
96
97 static const true_false_string flag_set_broadcast = {
98   "Broadcast",
99   "Unicast"
100 };
101
102 #define NUM_OPT_INFOS 211
103 #define NUM_O63_SUBOPTS 11
104
105 static int dissect_vendor_pxeclient_suboption(proto_tree *v_tree, tvbuff_t *tvb,
106     int optp);
107 static int dissect_netware_ip_suboption(proto_tree *v_tree, tvbuff_t *tvb,
108     int optp);
109 static int bootp_dhcp_decode_agent_info(proto_tree *v_tree, tvbuff_t *tvb,
110     int optp);
111
112 static const char *
113 get_dhcp_type(guint8 byte)
114 {
115         static const char       *opt53_text[] = {
116                 "Unknown Message Type",
117                 "Discover",
118                 "Offer",
119                 "Request",
120                 "Decline",
121                 "ACK",
122                 "NAK",
123                 "Release",
124                 "Inform",
125                 "Force Renew"
126         };
127         int i;
128
129         if (byte > 0 && byte < (sizeof opt53_text / sizeof opt53_text[0]))
130                 i = byte;
131         else
132                 i = 0;
133         return opt53_text[i];
134 }
135
136 /* DHCP Authentication protocols */
137 #define AUTHEN_PROTO_CONFIG_TOKEN       0
138 #define AUTHEN_PROTO_DELAYED_AUTHEN     1
139
140 /* DHCP Authentication algorithms for delayed authentication */
141 #define AUTHEN_DELAYED_ALGO_HMAC_MD5    1
142
143 /* DHCP Authentication Replay Detection Methods */
144 #define AUTHEN_RDM_MONOTONIC_COUNTER    0x00
145
146 /* DHCP Option Overload (option code 52) */
147 #define OPT_OVERLOAD_FILE               1
148 #define OPT_OVERLOAD_SNAME              2
149 #define OPT_OVERLOAD_BOTH               3
150
151 /* Server name and boot file offsets and lengths */
152 #define SERVER_NAME_OFFSET              44
153 #define SERVER_NAME_LEN                 64
154 #define FILE_NAME_OFFSET                108
155 #define FILE_NAME_LEN                   128
156 #define VENDOR_INFO_OFFSET              236
157
158 /* Returns the number of bytes consumed by this option. */
159 static int
160 bootp_option(tvbuff_t *tvb, proto_tree *bp_tree, int voff, int eoff,
161     gboolean first_pass, gboolean *at_end, const char **dhcp_type_p,
162     const guint8 **vendor_class_id_p)
163 {
164         char                    *text;
165         enum field_type         ftype;
166         guchar                  code = tvb_get_guint8(tvb, voff);
167         int                     vlen;
168         guchar                  byte;
169         int                     i,optp, consumed;
170         gulong                  time_secs;
171         proto_tree              *v_tree, *o52tree;
172         proto_item              *vti;
173         guint8                  protocol;
174         guint8                  algorithm;
175         guint8                  rdm;
176         int                     o52voff, o52eoff;
177         gboolean                o52at_end;
178
179         static const value_string nbnt_vals[] = {
180             {0x1,   "B-node" },
181             {0x2,   "P-node" },
182             {0x4,   "M-node" },
183             {0x8,   "H-node" },
184             {0,     NULL     } };
185
186     static const value_string slpda_vals[] = {
187         {0x00,   "Dynamic Discovery" },
188         {0x01,   "Static Discovery" },
189         {0x80,   "Backwards compatibility" },
190         {0,     NULL     } };
191
192     static const value_string slp_scope_vals[] = {
193         {0x00,   "Preferred Scope" },
194         {0x01,   "Mandatory Scope" },
195         {0,     NULL     } };
196
197         static const value_string authen_protocol_vals[] = {
198             {AUTHEN_PROTO_CONFIG_TOKEN,   "configuration token" },
199             {AUTHEN_PROTO_DELAYED_AUTHEN, "delayed authentication" },
200             {0,                           NULL     } };
201
202         static const value_string authen_da_algo_vals[] = {
203             {AUTHEN_DELAYED_ALGO_HMAC_MD5, "HMAC_MD5" },
204             {0,                            NULL     } };
205
206         static const value_string authen_rdm_vals[] = {
207             {AUTHEN_RDM_MONOTONIC_COUNTER, "Monotonically-increasing counter" },
208             {0,                            NULL     } };
209
210         static const value_string opt_overload_vals[] = {
211             { OPT_OVERLOAD_FILE,  "Boot file name holds options",                },
212             { OPT_OVERLOAD_SNAME, "Server host name holds options",              },
213             { OPT_OVERLOAD_BOTH,  "Boot file and server host names hold options" },
214             { 0,                  NULL                                           } };
215
216         static struct opt_info opt[] = {
217                 /*   0 */ { "Padding",                                  none },
218                 /*   1 */ { "Subnet Mask",                              ipv4 },
219                 /*   2 */ { "Time Offset",                              val_s_long },
220                 /*   3 */ { "Router",                                   ipv4 },
221                 /*   4 */ { "Time Server",                              ipv4 },
222                 /*   5 */ { "Name Server",                              ipv4 },
223                 /*   6 */ { "Domain Name Server",                       ipv4 },
224                 /*   7 */ { "Log Server",                               ipv4 },
225                 /*   8 */ { "Cookie Server",                            ipv4 },
226                 /*   9 */ { "LPR Server",                               ipv4 },
227                 /*  10 */ { "Impress Server",                           ipv4 },
228                 /*  11 */ { "Resource Location Server",                 ipv4 },
229                 /*  12 */ { "Host Name",                                string },
230                 /*  13 */ { "Boot File Size",                           val_u_short },
231                 /*  14 */ { "Merit Dump File",                          string },
232                 /*  15 */ { "Domain Name",                              string },
233                 /*  16 */ { "Swap Server",                              ipv4 },
234                 /*  17 */ { "Root Path",                                string },
235                 /*  18 */ { "Extensions Path",                          string },
236                 /*  19 */ { "IP Forwarding",                            toggle },
237                 /*  20 */ { "Non-Local Source Routing",                 toggle },
238                 /*  21 */ { "Policy Filter",                            special },
239                 /*  22 */ { "Maximum Datagram Reassembly Size",         val_u_short },
240                 /*  23 */ { "Default IP Time-to-Live",                  val_u_byte },
241                 /*  24 */ { "Path MTU Aging Timeout",                   time_in_secs },
242                 /*  25 */ { "Path MTU Plateau Table",                   val_u_short },
243                 /*  26 */ { "Interface MTU",                            val_u_short },
244                 /*  27 */ { "All Subnets are Local",                    yes_no },
245                 /*  28 */ { "Broadcast Address",                        ipv4 },
246                 /*  29 */ { "Perform Mask Discovery",                   toggle },
247                 /*  30 */ { "Mask Supplier",                            yes_no },
248                 /*  31 */ { "Perform Router Discover",                  toggle },
249                 /*  32 */ { "Router Solicitation Address",              ipv4 },
250                 /*  33 */ { "Static Route",                             special },
251                 /*  34 */ { "Trailer Encapsulation",                    toggle },
252                 /*  35 */ { "ARP Cache Timeout",                        time_in_secs },
253                 /*  36 */ { "Ethernet Encapsulation",                   toggle },
254                 /*  37 */ { "TCP Default TTL",                          val_u_byte },
255                 /*  38 */ { "TCP Keepalive Interval",                   time_in_secs },
256                 /*  39 */ { "TCP Keepalive Garbage",                    toggle },
257                 /*  40 */ { "Network Information Service Domain",       string },
258                 /*  41 */ { "Network Information Service Servers",      ipv4 },
259                 /*  42 */ { "Network Time Protocol Servers",            ipv4 },
260                 /*  43 */ { "Vendor-Specific Information",              special },
261                 /*  44 */ { "NetBIOS over TCP/IP Name Server",          ipv4 },
262                 /*  45 */ { "NetBIOS over TCP/IP Datagram Distribution Name Server", ipv4 },
263                 /*  46 */ { "NetBIOS over TCP/IP Node Type",            special },
264                 /*  47 */ { "NetBIOS over TCP/IP Scope",                string },
265                 /*  48 */ { "X Window System Font Server",              ipv4 },
266                 /*  49 */ { "X Window System Display Manager",          ipv4 },
267                 /*  50 */ { "Requested IP Address",                     ipv4 },
268                 /*  51 */ { "IP Address Lease Time",                    time_in_secs },
269                 /*  52 */ { "Option Overload",                          special },
270                 /*  53 */ { "DHCP Message Type",                        special },
271                 /*  54 */ { "Server Identifier",                        ipv4 },
272                 /*  55 */ { "Parameter Request List",                   special },
273                 /*  56 */ { "Message",                                  string },
274                 /*  57 */ { "Maximum DHCP Message Size",                val_u_short },
275                 /*  58 */ { "Renewal Time Value",                       time_in_secs },
276                 /*  59 */ { "Rebinding Time Value",                     time_in_secs },
277                 /*  60 */ { "Vendor class identifier",                  special },
278                 /*  61 */ { "Client identifier",                        special },
279                 /*  62 */ { "Novell/Netware IP domain",                 string },
280                 /*  63 */ { "Novell Options",                           special },
281                 /*  64 */ { "Network Information Service+ Domain",      string },
282                 /*  65 */ { "Network Information Service+ Servers",     ipv4 },
283                 /*  66 */ { "TFTP Server Name",                         string },
284                 /*  67 */ { "Bootfile name",                            string },
285                 /*  68 */ { "Mobile IP Home Agent",                     ipv4 },
286                 /*  69 */ { "SMTP Server",                              ipv4 },
287                 /*  70 */ { "POP3 Server",                              ipv4 },
288                 /*  71 */ { "NNTP Server",                              ipv4 },
289                 /*  72 */ { "Default WWW Server",                       ipv4 },
290                 /*  73 */ { "Default Finger Server",                    ipv4 },
291                 /*  74 */ { "Default IRC Server",                       ipv4 },
292                 /*  75 */ { "StreetTalk Server",                        ipv4 },
293                 /*  76 */ { "StreetTalk Directory Assistance Server",   ipv4 },
294                 /*  77 */ { "User Class Information",                   opaque },
295                 /*  78 */ { "Directory Agent Information",              special },
296                 /*  79 */ { "Service Location Agent Scope",             special },
297                 /*  80 */ { "Naming Authority",                         opaque },
298                 /*  81 */ { "Client Fully Qualified Domain Name",       opaque },
299                 /*  82 */ { "Agent Information Option",                 special },
300                 /*  83 */ { "Unassigned",                               opaque },
301                 /*  84 */ { "Unassigned",                               opaque },
302                 /*  85 */ { "Novell Directory Services Servers",        special },
303                 /*  86 */ { "Novell Directory Services Tree Name",      string },
304                 /*  87 */ { "Novell Directory Services Context",        string },
305                 /*  88 */ { "IEEE 1003.1 POSIX Timezone",               opaque },
306                 /*  89 */ { "Fully Qualified Domain Name",              opaque },
307                 /*  90 */ { "Authentication",                           special },
308                 /*  91 */ { "Vines TCP/IP Server Option",               opaque },
309                 /*  92 */ { "Server Selection Option",                  opaque },
310                 /*  93 */ { "Client System Architecture",               opaque },
311                 /*  94 */ { "Client Network Device Interface",          opaque },
312                 /*  95 */ { "Lightweight Directory Access Protocol",    opaque },
313                 /*  96 */ { "IPv6 Transitions",                         opaque },
314                 /*  97 */ { "UUID/GUID-based Client Identifier",        opaque },
315                 /*  98 */ { "Open Group's User Authentication",         opaque },
316                 /*  99 */ { "Unassigned",                               opaque },
317                 /* 100 */ { "Printer Name",                             opaque },
318                 /* 101 */ { "MDHCP multicast address",                  opaque },
319                 /* 102 */ { "Removed/unassigned",                       opaque },
320                 /* 103 */ { "Removed/unassigned",                       opaque },
321                 /* 104 */ { "Removed/unassigned",                       opaque },
322                 /* 105 */ { "Removed/unassigned",                       opaque },
323                 /* 106 */ { "Removed/unassigned",                       opaque },
324                 /* 107 */ { "Removed/unassigned",                       opaque },
325                 /* 108 */ { "Swap Path Option",                         opaque },
326                 /* 109 */ { "Unassigned",                               opaque },
327                 /* 110 */ { "IPX Compability",                          opaque },
328                 /* 111 */ { "Unassigned",                               opaque },
329                 /* 112 */ { "NetInfo Parent Server Address",            ipv4 },
330                 /* 113 */ { "NetInfo Parent Server Tag",                string },
331                 /* 114 */ { "URL",                                      opaque },
332                 /* 115 */ { "DHCP Failover Protocol",                   opaque },
333                 /* 116 */ { "DHCP Auto-Configuration",                  opaque },
334                 /* 117 */ { "Unassigned",                               opaque },
335                 /* 118 */ { "Unassigned",                               opaque },
336                 /* 119 */ { "Unassigned",                               opaque },
337                 /* 120 */ { "Unassigned",                               opaque },
338                 /* 121 */ { "Unassigned",                               opaque },
339                 /* 122 */ { "Unassigned",                               opaque },
340                 /* 123 */ { "Unassigned",                               opaque },
341                 /* 124 */ { "Unassigned",                               opaque },
342                 /* 125 */ { "Unassigned",                               opaque },
343                 /* 126 */ { "Extension",                                opaque },
344                 /* 127 */ { "Extension",                                opaque },
345                 /* 128 */ { "Private",                                  opaque },
346                 /* 129 */ { "Private",                                  opaque },
347                 /* 130 */ { "Private",                                  opaque },
348                 /* 131 */ { "Private",                                  opaque },
349                 /* 132 */ { "Private",                                  opaque },
350                 /* 133 */ { "Private",                                  opaque },
351                 /* 134 */ { "Private",                                  opaque },
352                 /* 135 */ { "Private",                                  opaque },
353                 /* 136 */ { "Private",                                  opaque },
354                 /* 137 */ { "Private",                                  opaque },
355                 /* 138 */ { "Private",                                  opaque },
356                 /* 139 */ { "Private",                                  opaque },
357                 /* 140 */ { "Private",                                  opaque },
358                 /* 141 */ { "Private",                                  opaque },
359                 /* 142 */ { "Private",                                  opaque },
360                 /* 143 */ { "Private",                                  opaque },
361                 /* 144 */ { "Private",                                  opaque },
362                 /* 145 */ { "Private",                                  opaque },
363                 /* 146 */ { "Private",                                  opaque },
364                 /* 147 */ { "Private",                                  opaque },
365                 /* 148 */ { "Private",                                  opaque },
366                 /* 149 */ { "Private",                                  opaque },
367                 /* 150 */ { "Private",                                  opaque },
368                 /* 151 */ { "Private",                                  opaque },
369                 /* 152 */ { "Private",                                  opaque },
370                 /* 153 */ { "Private",                                  opaque },
371                 /* 154 */ { "Private",                                  opaque },
372                 /* 155 */ { "Private",                                  opaque },
373                 /* 156 */ { "Private",                                  opaque },
374                 /* 157 */ { "Private",                                  opaque },
375                 /* 158 */ { "Private",                                  opaque },
376                 /* 159 */ { "Private",                                  opaque },
377                 /* 160 */ { "Private",                                  opaque },
378                 /* 161 */ { "Private",                                  opaque },
379                 /* 162 */ { "Private",                                  opaque },
380                 /* 163 */ { "Private",                                  opaque },
381                 /* 164 */ { "Private",                                  opaque },
382                 /* 165 */ { "Private",                                  opaque },
383                 /* 166 */ { "Private",                                  opaque },
384                 /* 167 */ { "Private",                                  opaque },
385                 /* 168 */ { "Private",                                  opaque },
386                 /* 169 */ { "Private",                                  opaque },
387                 /* 170 */ { "Private",                                  opaque },
388                 /* 171 */ { "Private",                                  opaque },
389                 /* 172 */ { "Private",                                  opaque },
390                 /* 173 */ { "Private",                                  opaque },
391                 /* 174 */ { "Private",                                  opaque },
392                 /* 175 */ { "Private",                                  opaque },
393                 /* 176 */ { "Private",                                  opaque },
394                 /* 177 */ { "Private",                                  opaque },
395                 /* 178 */ { "Private",                                  opaque },
396                 /* 179 */ { "Private",                                  opaque },
397                 /* 180 */ { "Private",                                  opaque },
398                 /* 181 */ { "Private",                                  opaque },
399                 /* 182 */ { "Private",                                  opaque },
400                 /* 183 */ { "Private",                                  opaque },
401                 /* 184 */ { "Private",                                  opaque },
402                 /* 185 */ { "Private",                                  opaque },
403                 /* 186 */ { "Private",                                  opaque },
404                 /* 187 */ { "Private",                                  opaque },
405                 /* 188 */ { "Private",                                  opaque },
406                 /* 189 */ { "Private",                                  opaque },
407                 /* 190 */ { "Private",                                  opaque },
408                 /* 191 */ { "Private",                                  opaque },
409                 /* 192 */ { "Private",                                  opaque },
410                 /* 193 */ { "Private",                                  opaque },
411                 /* 194 */ { "Private",                                  opaque },
412                 /* 195 */ { "Private",                                  opaque },
413                 /* 196 */ { "Private",                                  opaque },
414                 /* 197 */ { "Private",                                  opaque },
415                 /* 198 */ { "Private",                                  opaque },
416                 /* 199 */ { "Private",                                  opaque },
417                 /* 200 */ { "Private",                                  opaque },
418                 /* 201 */ { "Private",                                  opaque },
419                 /* 202 */ { "Private",                                  opaque },
420                 /* 203 */ { "Private",                                  opaque },
421                 /* 204 */ { "Private",                                  opaque },
422                 /* 205 */ { "Private",                                  opaque },
423                 /* 206 */ { "Private",                                  opaque },
424                 /* 207 */ { "Private",                                  opaque },
425                 /* 208 */ { "Private",                                  opaque },
426                 /* 209 */ { "Private",                                  opaque },
427                 /* 210 */ { "Authentication",                           special }
428         };
429
430         /* Options whose length isn't "vlen + 2". */
431         switch (code) {
432
433         case 0:         /* Padding */
434                 /* check how much padding we have */
435                 for (i = voff + 1; i < eoff; i++ ) {
436                         if (tvb_get_guint8(tvb, i) != 0) {
437                                 break;
438                         }
439                 }
440                 i = i - voff;
441                 if (!first_pass) {
442                         if (bp_tree != NULL) {
443                                 proto_tree_add_text(bp_tree, tvb, voff, i,
444                                     "Padding");
445                         }
446                 }
447                 consumed = i;
448                 return consumed;
449                 break;
450
451         case 255:       /* End Option */
452                 if (!first_pass) {
453                         if (bp_tree != NULL) {
454                                 proto_tree_add_text(bp_tree, tvb, voff, 1,
455                                     "End Option");
456                         }
457                 }
458                 *at_end = TRUE;
459                 consumed = 1;
460                 return consumed;
461         }
462
463         /*
464          * Get the length of the option, and the number of bytes it
465          * consumes (the length doesn't include the option code or
466          * length bytes).
467          *
468          * On the first pass, check first whether we have the length
469          * byte, so that we don't throw an exception; if we throw an
470          * exception in the first pass, which is only checking for options
471          * whose values we need in order to properly dissect the packet
472          * on the second pass, we won't actually dissect the options, so
473          * you won't be able to see which option had the problem.
474          */
475         if (first_pass) {
476                 if (!tvb_bytes_exist(tvb, voff+1, 1)) {
477                         /*
478                          * We don't have the length byte; just return 1
479                          * as the number of bytes we consumed, to count
480                          * the code byte.
481                          */
482                         return 1;
483                 }
484         }
485         vlen = tvb_get_guint8(tvb, voff+1);
486         consumed = vlen + 2;
487
488         /*
489          * In the first pass, we don't put anything into the protocol
490          * tree; we just check for some options we have to look at
491          * in order to properly process the packet:
492          *
493          *      53 (DHCP message type) - if this is present, this is DHCP
494          *
495          *      60 (Vendor class identifier) - we need this in order to
496          *         interpret the vendor-specific info
497          *
498          * We also check, before fetching anything, to make sure we
499          * have the entire item we're fetching, so that we don't throw
500          * an exception.
501          */
502         if (first_pass) {
503                 if (tvb_bytes_exist(tvb, voff+2, consumed-2)) {
504                         switch (code) {
505
506                         case 53:
507                                 *dhcp_type_p =
508                                     get_dhcp_type(tvb_get_guint8(tvb, voff+2));
509                                 break;
510
511                         case 60:
512                                 *vendor_class_id_p =
513                                     tvb_get_ptr(tvb, voff+2, consumed-2);
514                                 break;
515                         }
516                 }
517
518                 /*
519                  * We don't do anything else here.
520                  */
521                 return consumed;
522         }
523
524         /*
525          * This is the second pass - if there's a protocol tree to be
526          * built, we put stuff into it, otherwise we just return.
527          */
528         if (bp_tree == NULL) {
529                 /* Don't put anything in the protocol tree. */
530                 return consumed;
531         }
532
533         text = opt[code].text;
534         /* Special cases */
535         switch (code) {
536
537         case 21:        /* Policy Filter */
538                 if (vlen == 8) {
539                         /* one IP address pair */
540                         proto_tree_add_text(bp_tree, tvb, voff, consumed,
541                                 "Option %d: %s = %s/%s", code, text,
542                                 ip_to_str(tvb_get_ptr(tvb, voff+2, 4)),
543                                 ip_to_str(tvb_get_ptr(tvb, voff+6, 4)));
544                 } else {
545                         /* > 1 IP address pair. Let's make a sub-tree */
546                         vti = proto_tree_add_text(bp_tree, tvb, voff,
547                                 consumed, "Option %d: %s", code, text);
548                         v_tree = proto_item_add_subtree(vti, ett_bootp_option);
549                         for (i = voff + 2; i < voff + consumed; i += 8) {
550                                 proto_tree_add_text(v_tree, tvb, i, 8, "IP Address/Mask: %s/%s",
551                                         ip_to_str(tvb_get_ptr(tvb, i, 4)),
552                                         ip_to_str(tvb_get_ptr(tvb, i+4, 4)));
553                         }
554                 }
555                 break;
556
557         case 33:        /* Static Route */
558                 if (vlen == 8) {
559                         /* one IP address pair */
560                         proto_tree_add_text(bp_tree, tvb, voff, consumed,
561                                 "Option %d: %s = %s/%s", code, text,
562                                 ip_to_str(tvb_get_ptr(tvb, voff+2, 4)),
563                                 ip_to_str(tvb_get_ptr(tvb, voff+6, 4)));
564                 } else {
565                         /* > 1 IP address pair. Let's make a sub-tree */
566                         vti = proto_tree_add_text(bp_tree, tvb, voff,
567                                 consumed, "Option %d: %s", code, text);
568                         v_tree = proto_item_add_subtree(vti, ett_bootp_option);
569                         for (i = voff + 2; i < voff + consumed; i += 8) {
570                                 proto_tree_add_text(v_tree, tvb, i, 8,
571                                         "Destination IP Address/Router: %s/%s",
572                                         ip_to_str(tvb_get_ptr(tvb, i, 4)),
573                                         ip_to_str(tvb_get_ptr(tvb, i+4, 4)));
574                         }
575                 }
576                 break;
577
578         case 43:        /* Vendor-Specific Info */
579                 /* PXE protocol 2.1 as described in the intel specs */
580                 if (*vendor_class_id_p != NULL &&
581                     strncmp(*vendor_class_id_p, "PXEClient", strlen("PXEClient")) == 0) {
582                         vti = proto_tree_add_text(bp_tree, tvb, voff,
583                                 consumed, "Option %d: %s (PXEClient)", code, text);
584                         v_tree = proto_item_add_subtree(vti, ett_bootp_option);
585
586                         optp = voff+2;
587                         while (optp < voff+consumed) {
588                                 optp = dissect_vendor_pxeclient_suboption(v_tree,
589                                         tvb, optp);
590                         }
591                 } else {
592                         proto_tree_add_text(bp_tree, tvb, voff, consumed,
593                                 "Option %d: %s (%d bytes)", code, text, vlen);
594                 }
595                 break;
596
597         case 46:        /* NetBIOS-over-TCP/IP Node Type */
598                 byte = tvb_get_guint8(tvb, voff+2);
599                 proto_tree_add_text(bp_tree, tvb, voff, consumed,
600                                 "Option %d: %s = %s", code, text,
601                                 val_to_str(byte, nbnt_vals,
602                                     "Unknown (0x%02x)"));
603                 break;
604
605         case 52:        /* Option Overload */
606                 byte = tvb_get_guint8(tvb, voff+2);
607                 vti = proto_tree_add_text(bp_tree, tvb, voff, consumed,
608                         "Option %d: %s = %s", code, text,
609                         val_to_str(byte, opt_overload_vals,
610                             "Unknown (0x%02x)"));
611                             
612                 /* Just in case we find an option 52 in sname or file */
613                 if (voff > VENDOR_INFO_OFFSET && byte >= 1 && byte <= 3) {
614                         o52tree = proto_item_add_subtree(vti, ett_bootp_option);
615                         if (byte == 1 || byte == 3) {   /* 'file' */
616                                 vti = proto_tree_add_text (o52tree, tvb,
617                                         FILE_NAME_OFFSET, FILE_NAME_LEN,
618                                         "Boot file name option overload");
619                                 v_tree = proto_item_add_subtree(vti, ett_bootp_option);
620                                 o52voff = FILE_NAME_OFFSET;
621                                 o52eoff = FILE_NAME_OFFSET + FILE_NAME_LEN;
622                                 o52at_end = FALSE;
623                                 while (o52voff < o52eoff && !o52at_end) {
624                                         o52voff += bootp_option(tvb, v_tree, o52voff,
625                                                 o52eoff, FALSE, &o52at_end,
626                                                 dhcp_type_p, vendor_class_id_p);
627                                 }
628                         }
629                         if (byte == 2 || byte == 3) {   /* 'sname' */
630                                 vti = proto_tree_add_text (o52tree, tvb,
631                                         SERVER_NAME_OFFSET, SERVER_NAME_LEN, 
632                                         "Server host name option overload");
633                                 v_tree = proto_item_add_subtree(vti, ett_bootp_option);
634                                 o52voff = SERVER_NAME_OFFSET;
635                                 o52eoff = SERVER_NAME_OFFSET + SERVER_NAME_LEN;
636                                 o52at_end = FALSE;
637                                 while (o52voff < o52eoff && !o52at_end) {
638                                         o52voff += bootp_option(tvb, v_tree, o52voff,
639                                                 o52eoff, FALSE, &o52at_end,
640                                                 dhcp_type_p, vendor_class_id_p);
641                                 }
642                         }
643                 }
644
645 /*              protocol = tvb_get_guint8(tvb, voff+2);
646                 proto_tree_add_text(v_tree, tvb, voff+2, 1, "Protocol: %s (%u)",
647                                     val_to_str(protocol, authen_protocol_vals, "Unknown"),
648                                     protocol); */
649                 break;
650         case 53:        /* DHCP Message Type */
651                 proto_tree_add_text(bp_tree, tvb, voff, 3, "Option %d: %s = DHCP %s",
652                         code, text, get_dhcp_type(tvb_get_guint8(tvb, voff+2)));
653                 break;
654
655         case 55:        /* Parameter Request List */
656                 vti = proto_tree_add_text(bp_tree, tvb, voff,
657                         vlen + 2, "Option %d: %s", code, text);
658                 v_tree = proto_item_add_subtree(vti, ett_bootp_option);
659                 for (i = 0; i < vlen; i++) {
660                         byte = tvb_get_guint8(tvb, voff+2+i);
661                         if (byte < NUM_OPT_INFOS) {
662                                 proto_tree_add_text(v_tree, tvb, voff+2+i, 1, "%d = %s",
663                                                 byte, opt[byte].text);
664                         } else {
665                                 proto_tree_add_text(vti, tvb, voff+2+i, 1,
666                                         "Unknown Option Code: %d", byte);
667                         }
668                 }
669                 break;
670
671         case 60:        /* Vendor class identifier */
672                 proto_tree_add_text(bp_tree, tvb, voff, consumed,
673                         "Option %d: %s = \"%.*s\"", code, text, vlen,
674                         tvb_get_ptr(tvb, voff+2, consumed-2));
675                 break;
676
677         case 61:        /* Client Identifier */
678                 /* We *MAY* use hwtype/hwaddr. If we have 7 bytes, I'll
679                    guess that the first is the hwtype, and the last 6
680                    are the hw addr */
681                 if (vlen == 7) {
682                         guint8 htype;
683
684                         vti = proto_tree_add_text(bp_tree, tvb, voff,
685                                 consumed, "Option %d: %s", code, text);
686                         v_tree = proto_item_add_subtree(vti, ett_bootp_option);
687                         htype = tvb_get_guint8(tvb, voff+2);
688                         proto_tree_add_text(v_tree, tvb, voff+2, 1,
689                                 "Hardware type: %s",
690                                 arphrdtype_to_str(htype,
691                                         "Unknown (0x%02x)"));
692                         proto_tree_add_text(v_tree, tvb, voff+3, 6,
693                                 "Client hardware address: %s",
694                                 arphrdaddr_to_str(tvb_get_ptr(tvb, voff+3, 6),
695                                         6, htype));
696                 } else {
697                         /* otherwise, it's opaque data */
698                         proto_tree_add_text(bp_tree, tvb, voff, consumed,
699                                 "Option %d: %s (%d bytes)", code, text, vlen);
700                 }
701                 break;
702
703         case 63:        /* NetWare/IP options */
704                 vti = proto_tree_add_text(bp_tree, tvb, voff,
705                     consumed, "Option %d: %s", code, text);
706                 v_tree = proto_item_add_subtree(vti, ett_bootp_option);
707
708                 optp = voff+2;
709                 while (optp < voff+consumed)
710                         optp = dissect_netware_ip_suboption(v_tree, tvb, optp);
711                 break;
712
713     case 78:    /* SLP Directory Agent Option RFC2610 Added by Greg Morris (gmorris@novell.com)*/
714                 byte = tvb_get_guint8(tvb, voff+2);
715                 vti = proto_tree_add_text(bp_tree, tvb, voff, consumed,
716                                 "Option %d: %s = %s", code, text,
717                                 val_to_str(byte, slpda_vals,
718                                     "Unknown (0x%02x)"));
719         if (byte == 0x80) {
720             voff++;
721             consumed--;
722         }
723                 v_tree = proto_item_add_subtree(vti, ett_bootp_option);
724         for (i = voff + 3; i < voff + consumed; i += 4) {
725             proto_tree_add_text(v_tree, tvb, i, 4, "SLPDA Address: %s",
726                 ip_to_str(tvb_get_ptr(tvb, i, 4)));
727         }
728         if (byte == 0x80) {
729             consumed++;
730         }
731                 break;
732
733     case 79:    /* SLP Service Scope Option RFC2610 Added by Greg Morris (gmorris@novell.com)*/
734                 byte = tvb_get_guint8(tvb, voff+2);
735                 vti = proto_tree_add_text(bp_tree, tvb, voff, consumed,
736                                 "Option %d: %s = %s", code, text,
737                                 val_to_str(byte, slp_scope_vals,
738                                     "Unknown (0x%02x)"));
739                 v_tree = proto_item_add_subtree(vti, ett_bootp_option);
740         proto_tree_add_text(v_tree, tvb, voff+3, consumed-3,
741                 "%s = \"%.*s\"", text, vlen-1,
742                 tvb_get_ptr(tvb, voff+3, vlen-1));
743                 break;
744
745         case 82:        /* Relay Agent Information Option */
746                 vti = proto_tree_add_text(bp_tree, tvb, voff, consumed,
747                                           "Option %d: %s (%d bytes)",
748                                           code, text, vlen);
749                 v_tree = proto_item_add_subtree(vti, ett_bootp_option);
750                 optp = voff+2;
751                 while (optp < voff+consumed) {
752                         optp = bootp_dhcp_decode_agent_info(v_tree, tvb, optp);
753                 }
754                 break;
755
756         case 85:        /* Novell Servers */
757         /* Option 85 can be sent as a string */
758         /* Added by Greg Morris (gmorris@novell.com) */
759         if (novell_string && code==85) {
760             proto_tree_add_text(bp_tree, tvb, voff, consumed,
761                     "Option %d: %s = \"%.*s\"", code, text, vlen,
762                     tvb_get_ptr(tvb, voff+2, consumed-2));
763         }
764         else
765         {
766                         if (vlen == 4) {
767                                 /* one IP address */
768                                 proto_tree_add_text(bp_tree, tvb, voff, consumed,
769                                         "Option %d: %s = %s", code, text,
770                                         ip_to_str(tvb_get_ptr(tvb, voff+2, 4)));
771                         } else {
772                                 /* > 1 IP addresses. Let's make a sub-tree */
773                                 vti = proto_tree_add_text(bp_tree, tvb, voff,
774                                         consumed, "Option %d: %s", code, text);
775                                 v_tree = proto_item_add_subtree(vti, ett_bootp_option);
776                                 for (i = voff + 2; i < voff + consumed; i += 4) {
777                                         proto_tree_add_text(v_tree, tvb, i, 4, "IP Address: %s",
778                                                 ip_to_str(tvb_get_ptr(tvb, i, 4)));
779                                 }
780                         }
781         }
782         break;
783
784         case 90:        /* DHCP Authentication */
785         case 210:       /* Was this used for authentication at one time? */
786                 vti = proto_tree_add_text(bp_tree, tvb, voff,
787                         vlen + 2, "Option %d: %s", code, text);
788                 v_tree = proto_item_add_subtree(vti, ett_bootp_option);
789
790                 protocol = tvb_get_guint8(tvb, voff+2);
791                 proto_tree_add_text(v_tree, tvb, voff+2, 1, "Protocol: %s (%u)",
792                                     val_to_str(protocol, authen_protocol_vals, "Unknown"),
793                                     protocol);
794
795                 algorithm = tvb_get_guint8(tvb, voff+3);
796                 switch (protocol) {
797
798                 case AUTHEN_PROTO_DELAYED_AUTHEN:
799                         proto_tree_add_text(v_tree, tvb, voff+3, 1,
800                                     "Algorithm: %s (%u)",
801                                     val_to_str(algorithm, authen_da_algo_vals, "Unknown"),
802                                     algorithm);
803                         break;
804
805                 default:
806                         proto_tree_add_text(v_tree, tvb, voff+3, 1,
807                                     "Algorithm: %u", algorithm);
808                         break;
809                 }
810
811                 rdm = tvb_get_guint8(tvb, voff+4);
812                 proto_tree_add_text(v_tree, tvb, voff+4, 1,
813                                     "Replay Detection Method: %s (%u)",
814                                     val_to_str(rdm, authen_rdm_vals, "Unknown"),
815                                     rdm);
816
817                 switch (rdm) {
818
819                 case AUTHEN_RDM_MONOTONIC_COUNTER:
820                         proto_tree_add_text(v_tree, tvb, voff+5, 8,
821                                     "Replay Detection Value: %s",
822                                     u64toh(tvb_get_ptr(tvb, voff+5, 8)));
823                         break;
824
825                 default:
826                         proto_tree_add_text(v_tree, tvb, voff+5, 8,
827                                     "Replay Detection Value: %s",
828                                     tvb_bytes_to_str(tvb, voff+5, 8));
829                         break;
830                 }
831
832                 switch (protocol) {
833
834                 case AUTHEN_PROTO_DELAYED_AUTHEN:
835                         switch (algorithm) {
836
837                         case AUTHEN_DELAYED_ALGO_HMAC_MD5:
838                                 proto_tree_add_text(v_tree, tvb, voff+13, 4,
839                                         "Secret ID: 0x%08x",
840                                         tvb_get_ntohl(tvb, voff+13));
841                                 proto_tree_add_text(v_tree, tvb, voff+17, 16,
842                                         "HMAC MD5 Hash: %s",
843                                         tvb_bytes_to_str(tvb, voff+17, 16));
844                                 break;
845
846                         default:
847                                 proto_tree_add_text(v_tree, tvb, voff+13, vlen-11,
848                                         "Authentication Information: %s",
849                                         tvb_bytes_to_str(tvb, voff+17, vlen-11));
850                                 break;
851                         }
852                         break;
853
854                 default:
855                         proto_tree_add_text(v_tree, tvb, voff+13, vlen-11,
856                                 "Authentication Information: %s",
857                                 tvb_bytes_to_str(tvb, voff+17, vlen-11));
858                         break;
859                 }
860                 break;
861
862         default:        /* not special */
863                 break;
864         }
865
866         /* Normal cases */
867         if (code < NUM_OPT_INFOS) {
868                 text = opt[code].text;
869                 ftype = opt[code].ftype;
870
871                 switch (ftype) {
872
873                 case special:
874                         return consumed;
875
876                 case ipv4:
877                         if (vlen == 4) {
878                                 /* one IP address */
879                                 proto_tree_add_text(bp_tree, tvb, voff, consumed,
880                                         "Option %d: %s = %s", code, text,
881                                         ip_to_str(tvb_get_ptr(tvb, voff+2, 4)));
882                         } else {
883                                 /* > 1 IP addresses. Let's make a sub-tree */
884                                 vti = proto_tree_add_text(bp_tree, tvb, voff,
885                                         consumed, "Option %d: %s", code, text);
886                                 v_tree = proto_item_add_subtree(vti, ett_bootp_option);
887                                 for (i = voff + 2; i < voff + consumed; i += 4) {
888                                         proto_tree_add_text(v_tree, tvb, i, 4, "IP Address: %s",
889                                                 ip_to_str(tvb_get_ptr(tvb, i, 4)));
890                                 }
891                         }
892                         break;
893
894                 case string:
895                         /* Fix for non null-terminated string supplied by
896                          * John Lines <John.Lines@aeat.co.uk>
897                          */
898                         proto_tree_add_text(bp_tree, tvb, voff, consumed,
899                                         "Option %d: %s = \"%.*s\"", code, text, vlen,
900                                         tvb_get_ptr(tvb, voff+2, consumed-2));
901                         break;
902
903                 case opaque:
904                         proto_tree_add_text(bp_tree, tvb, voff, consumed,
905                                         "Option %d: %s (%d bytes)",
906                                         code, text, vlen);
907                         break;
908
909                 case val_u_short:
910                         if (vlen == 2) {
911                                 /* one gushort */
912                                 proto_tree_add_text(bp_tree, tvb, voff, consumed,
913                                                 "Option %d: %s = %d", code, text,
914                                                 tvb_get_ntohs(tvb, voff+2));
915                         } else {
916                                 /* > 1 gushort */
917                                 vti = proto_tree_add_text(bp_tree, tvb, voff,
918                                         consumed, "Option %d: %s", code, text);
919                                 v_tree = proto_item_add_subtree(vti, ett_bootp_option);
920                                 for (i = voff + 2; i < voff + consumed; i += 2) {
921                                         proto_tree_add_text(v_tree, tvb, i, 4, "Value: %d",
922                                                 tvb_get_ntohs(tvb, i));
923                                 }
924                         }
925                         break;
926
927                 case val_u_long:
928                         proto_tree_add_text(bp_tree, tvb, voff, consumed,
929                                         "Option %d: %s = %d", code, text,
930                                         tvb_get_ntohl(tvb, voff+2));
931                         break;
932
933                 case val_u_byte:
934                         proto_tree_add_text(bp_tree, tvb, voff, consumed,
935                                         "Option %d: %s = %d", code, text,
936                                         tvb_get_guint8(tvb, voff+2));
937                         break;
938
939                 case toggle:
940                         i = tvb_get_guint8(tvb, voff+2);
941                         if (i != 0 && i != 1) {
942                                 proto_tree_add_text(bp_tree, tvb, voff, consumed,
943                                                 "Option %d: %s = Invalid Value %d", code, text,
944                                                 i);
945                         } else {
946                                 proto_tree_add_text(bp_tree, tvb, voff, consumed,
947                                                 "Option %d: %s = %s", code, text,
948                                                 i == 0 ? "Disabled" : "Enabled");
949                         }
950                         break;
951
952                 case yes_no:
953                         i = tvb_get_guint8(tvb, voff+2);
954                         if (i != 0 && i != 1) {
955                                 proto_tree_add_text(bp_tree, tvb, voff, consumed,
956                                                 "Option %d: %s = Invalid Value %d", code, text,
957                                                 i);
958                         } else {
959                                 proto_tree_add_text(bp_tree, tvb, voff, consumed,
960                                                 "Option %d: %s = %s", code, text,
961                                                 i == 0 ? "No" : "Yes");
962                         }
963                         break;
964
965                 case time_in_secs:
966                         time_secs = tvb_get_ntohl(tvb, voff+2);
967                         proto_tree_add_text(bp_tree, tvb, voff, consumed,
968                                 "Option %d: %s = %s", code, text,
969                                 ((time_secs == 0xffffffff) ?
970                                     "infinity" :
971                                     time_secs_to_str(time_secs)));
972                         break;
973
974                 default:
975                         proto_tree_add_text(bp_tree, tvb, voff, consumed,
976                                         "Option %d: %s (%d bytes)", code, text, vlen);
977                 }
978         } else {
979                 proto_tree_add_text(bp_tree, tvb, voff, consumed,
980                                 "Unknown Option Code: %d (%d bytes)", code, vlen);
981         }
982
983         return consumed;
984 }
985
986 static int
987 bootp_dhcp_decode_agent_info(proto_tree *v_tree, tvbuff_t *tvb, int optp)
988 {
989         guint8 subopt;
990         guint8 subopt_len;
991
992         subopt = tvb_get_guint8(tvb, optp);
993         subopt_len = tvb_get_guint8(tvb, optp+1);
994         switch (subopt) {
995         case 1:
996                 proto_tree_add_text(v_tree, tvb, optp, subopt_len + 2,
997                                     "Agent Circuit ID (%d bytes)", subopt_len);
998                 break;
999         case 2:
1000                 proto_tree_add_text(v_tree, tvb, optp, subopt_len + 2,
1001                                     "Agent Remote ID (%d bytes)", subopt_len);
1002                 break;
1003         default:
1004                 proto_tree_add_text(v_tree, tvb, optp, subopt_len + 2,
1005                                     "Unknown agent option: %d", subopt);
1006                 break;
1007         }
1008         optp += (subopt_len + 2);
1009         return optp;
1010 }
1011
1012 static int
1013 dissect_vendor_pxeclient_suboption(proto_tree *v_tree, tvbuff_t *tvb, int optp)
1014 {
1015         guint8 subopt;
1016         guint8 subopt_len;
1017         int slask;
1018         proto_tree *o43pxeclient_v_tree;
1019         proto_item *vti;
1020
1021         struct o43pxeclient_opt_info {
1022                 char    *text;
1023                 enum field_type ft;
1024         };
1025
1026         static struct o43pxeclient_opt_info o43pxeclient_opt[]= {
1027                 /* 0 */ {"nop", special},       /* dummy */
1028                 /* 1 */ {"PXE mtftp IP", ipv4},
1029                 /* 2 */ {"PXE mtftp client port", val_u_le_short},
1030                 /* 3 */ {"PXE mtftp server port",val_u_le_short},
1031                 /* 4 */ {"PXE mtftp timeout", val_u_byte},
1032                 /* 5 */ {"PXE mtftp delay", val_u_byte},
1033                 /* 6 */ {"PXE discovery control", val_u_byte},
1034                         /*
1035                          * Correct: b0 (lsb): disable broadcast discovery
1036                          *      b1: disable multicast discovery
1037                          *      b2: only use/accept servers in boot servers
1038                          *      b3: download bootfile without prompt/menu/disc
1039                          */
1040                 /* 7 */ {"PXE multicast address", ipv4},
1041                 /* 8 */ {"PXE boot servers", special},
1042                 /* 9 */ {"PXE boot menu", special},
1043                 /* 10 */ {"PXE menu prompt", special},
1044                 /* 11 */ {"PXE multicast address alloc", special},
1045                 /* 12 */ {"PXE credential types", special},
1046                 /* 71 {"PXE boot item", special} */
1047                 /* 255 {"PXE end options", special} */
1048         };
1049 #define NUM_O43PXECLIENT_SUBOPTS (12)
1050
1051         subopt = tvb_get_guint8(tvb, optp);
1052
1053         if (subopt == 0 ) {
1054                 proto_tree_add_text(v_tree, tvb, optp, 1, "Padding");
1055                 return (optp+1);
1056         } else if (subopt == 255) {     /* End Option */
1057                 proto_tree_add_text(v_tree, tvb, optp, 1, "End PXEClient option");
1058                 /* Make sure we skip any junk left this option */
1059                 return (optp+255);
1060         }
1061
1062         subopt_len = tvb_get_guint8(tvb, optp+1);
1063
1064         if ( subopt == 71 ) {   /* 71 {"PXE boot item", special} */
1065                 /* case special */
1066                 /* I may need to decode that properly one day */
1067                 proto_tree_add_text(v_tree, tvb, optp, subopt_len+2,
1068                         "Suboption %d: %s (%d byte%s)" ,
1069                         subopt, "PXE boot item",
1070                         subopt_len, (subopt_len != 1)?"s":"");
1071         } else if ( (subopt < 1 ) || (subopt > NUM_O43PXECLIENT_SUBOPTS) ) {
1072                 proto_tree_add_text(v_tree, tvb, optp, subopt_len+2,
1073                         "Unknown suboption %d (%d byte%s)", subopt, subopt_len,
1074                         (subopt_len != 1)?"s":"");
1075         } else {
1076                 switch (o43pxeclient_opt[subopt].ft) {
1077
1078 /* XXX          case string:
1079                         proto_tree_add_text(v_tree, tvb, optp, subopt_len+2,
1080                                 "Suboption %d: %s", subopt, o43pxeclient_opt[subopt].text);
1081                         break;
1082    XXX */
1083                 case special:
1084                         /* I may need to decode that properly one day */
1085                         proto_tree_add_text(v_tree, tvb, optp, subopt_len+2,
1086                                 "Suboption %d: %s (%d byte%s)" ,
1087                                 subopt, o43pxeclient_opt[subopt].text,
1088                                 subopt_len, (subopt_len != 1)?"s":"");
1089                         break;
1090
1091                 case val_u_le_short:
1092                         proto_tree_add_text(v_tree, tvb, optp, 4, "Suboption %d: %s = %u",
1093                             subopt, o43pxeclient_opt[subopt].text,
1094                             tvb_get_letohs(tvb, optp+2));
1095                         break;
1096
1097                 case val_u_byte:
1098                         proto_tree_add_text(v_tree, tvb, optp, 3, "Suboption %d: %s = %u",
1099                             subopt, o43pxeclient_opt[subopt].text,
1100                             tvb_get_guint8(tvb, optp+2));
1101                         break;
1102
1103                 case ipv4:
1104                         if (subopt_len == 4) {
1105                                 /* one IP address */
1106                                 proto_tree_add_text(v_tree, tvb, optp, 6,
1107                                     "Suboption %d : %s = %s",
1108                                     subopt, o43pxeclient_opt[subopt].text,
1109                                     ip_to_str(tvb_get_ptr(tvb, optp+2, 4)));
1110                         } else {
1111                                 /* > 1 IP addresses. Let's make a sub-tree */
1112                                 vti = proto_tree_add_text(v_tree, tvb, optp,
1113                                     subopt_len+2, "Suboption %d: %s",
1114                                     subopt, o43pxeclient_opt[subopt].text);
1115                                 o43pxeclient_v_tree = proto_item_add_subtree(vti, ett_bootp_option);
1116                                 for (slask = optp + 2 ; slask < optp+subopt_len; slask += 4) {
1117                                         proto_tree_add_text(o43pxeclient_v_tree, tvb, slask, 4, "IP Address: %s",
1118                                             ip_to_str(tvb_get_ptr(tvb, slask, 4)));
1119                                 }
1120                         }
1121                         break;
1122                 default:
1123                         proto_tree_add_text(v_tree, tvb, optp, subopt_len+2,"ERROR, please report: Unknown subopt type handler %d", subopt);
1124                         break;
1125                 }
1126         }
1127         optp += (subopt_len + 2);
1128         return optp;
1129 }
1130
1131 static int
1132 dissect_netware_ip_suboption(proto_tree *v_tree, tvbuff_t *tvb, int optp)
1133 {
1134         guint8 subopt;
1135         guint8 subopt_len;
1136         int slask;
1137         proto_tree *o63_v_tree;
1138         proto_item *vti;
1139
1140         struct o63_opt_info {
1141                 char    *truet;
1142                 char    *falset;
1143                 enum field_type ft;
1144         };
1145
1146         static struct o63_opt_info o63_opt[]= {
1147                 /* 0 */ {"","",none},
1148                 /* 1 */ {"NWIP does not exist on subnet","",string},
1149                 /* 2 */ {"NWIP exist in options area","",string},
1150                 /* 3 */ {"NWIP exists in sname/file","",string},
1151                 /* 4 */ {"NWIP exists, but too big","",string},
1152                 /* 5 */ {"Broadcast for nearest Netware server","Do NOT Broadcast for nearest Netware server",yes_no},
1153                 /* 6 */ {"Preferred DSS server","",ipv4},
1154                 /* 7 */ {"Nearest NWIP server","",ipv4},
1155                 /* 8 */ {"Autoretries","",val_u_short},
1156                 /* 9 */ {"Autoretry delay, secs ","",val_u_short},
1157                 /* 10*/ {"Support NetWare/IP v1.1","Do NOT support NetWare/IP v1.1",yes_no},
1158                 /* 11*/ {"Primary DSS ", "" , special}
1159         };
1160
1161         subopt = tvb_get_guint8(tvb, optp);
1162         if (subopt > NUM_O63_SUBOPTS) {
1163                 proto_tree_add_text(v_tree, tvb,optp,1,"Unknown suboption %d", subopt);
1164                 optp++;
1165         } else {
1166                 switch (o63_opt[subopt].ft) {
1167
1168                 case string:
1169                         proto_tree_add_text(v_tree, tvb, optp, 2, "Suboption %d: %s", subopt, o63_opt[subopt].truet);
1170                         optp+=2;
1171                         break;
1172
1173                 case yes_no:
1174                         if (tvb_get_guint8(tvb, optp+2)==1) {
1175                                 proto_tree_add_text(v_tree, tvb, optp, 3, "Suboption %d: %s", subopt, o63_opt[subopt].truet);
1176                         } else {
1177                                 proto_tree_add_text(v_tree, tvb, optp, 3, "Suboption %d: %s" , subopt, o63_opt[subopt].falset);
1178                         }
1179                         optp+=3;
1180                         break;
1181
1182                 case special:
1183                         proto_tree_add_text(v_tree, tvb, optp, 6,
1184                             "Suboption %d: %s = %s" ,
1185                             subopt, o63_opt[subopt].truet,
1186                             ip_to_str(tvb_get_ptr(tvb, optp+2, 4)));
1187                         optp=optp+6;
1188                         break;
1189
1190                 case val_u_short:
1191                         proto_tree_add_text(v_tree, tvb, optp, 3, "Suboption %d: %s = %u",
1192                             subopt, o63_opt[subopt].truet,
1193                             tvb_get_guint8(tvb, optp+2));       /* XXX - 1 byte? */
1194                         optp+=3;
1195                         break;
1196
1197                 case ipv4:
1198                         subopt_len = tvb_get_guint8(tvb, optp+1);
1199                         if (subopt_len == 4) {
1200                                 /* one IP address */
1201                                 proto_tree_add_text(v_tree, tvb, optp, 6,
1202                                     "Suboption %d : %s = %s",
1203                                     subopt, o63_opt[subopt].truet,
1204                                     ip_to_str(tvb_get_ptr(tvb, optp+2, 4)));
1205                                 optp=optp+6;
1206                         } else {
1207                                 /* > 1 IP addresses. Let's make a sub-tree */
1208                                 vti = proto_tree_add_text(v_tree, tvb, optp,
1209                                     subopt_len+2, "Suboption %d: %s",
1210                                     subopt, o63_opt[subopt].truet);
1211                                 o63_v_tree = proto_item_add_subtree(vti, ett_bootp_option);
1212                                 for (slask = optp + 2 ; slask < optp+subopt_len; slask += 4) {
1213                                         proto_tree_add_text(o63_v_tree, tvb, slask, 4, "IP Address: %s",
1214                                             ip_to_str(tvb_get_ptr(tvb, slask, 4)));
1215                                 }
1216                                 optp=slask;
1217                         }
1218                         break;
1219                 default:
1220                         proto_tree_add_text(v_tree, tvb,optp,1,"Unknown suboption %d", subopt);
1221                         optp++;
1222                         break;
1223                 }
1224         }
1225         return optp;
1226 }
1227
1228 #define BOOTREQUEST     1
1229 #define BOOTREPLY       2
1230
1231 static const value_string op_vals[] = {
1232         { BOOTREQUEST,  "Boot Request" },
1233         { BOOTREPLY,    "Boot Reply" },
1234         { 0,            NULL }
1235 };
1236
1237 static void
1238 dissect_bootp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1239 {
1240         proto_tree      *bp_tree = NULL;
1241         proto_item      *ti;
1242         proto_tree      *flag_tree = NULL;
1243         proto_item      *fi;
1244         guint8          op;
1245         guint8          htype, hlen;
1246         const guint8    *haddr;
1247         int             voff, eoff, tmpvoff; /* vendor offset, end offset */
1248         guint32         ip_addr;
1249         gboolean        at_end;
1250         const char      *dhcp_type = NULL;
1251         const guint8    *vendor_class_id = NULL;
1252         guint16         flags;
1253
1254         if (check_col(pinfo->cinfo, COL_PROTOCOL))
1255                 col_set_str(pinfo->cinfo, COL_PROTOCOL, "BOOTP");
1256         if (check_col(pinfo->cinfo, COL_INFO)) {
1257                 /*
1258                  * In case we throw an exception fetching the opcode, etc.
1259                  */
1260                 col_clear(pinfo->cinfo, COL_INFO);
1261         }
1262
1263         op = tvb_get_guint8(tvb, 0);
1264         htype = tvb_get_guint8(tvb, 1);
1265         hlen = tvb_get_guint8(tvb, 2);
1266         if (check_col(pinfo->cinfo, COL_INFO)) {
1267                 switch (op) {
1268
1269                 case BOOTREQUEST:
1270                         col_add_fstr(pinfo->cinfo, COL_INFO, "Boot Request from %s",
1271                                 arphrdaddr_to_str(tvb_get_ptr(tvb, 28, hlen),
1272                                         hlen, htype));
1273                         break;
1274
1275                 case BOOTREPLY:
1276                         col_set_str(pinfo->cinfo, COL_INFO, "Boot Reply");
1277                         break;
1278
1279                 default:
1280                         col_add_fstr(pinfo->cinfo, COL_INFO, "Unknown BOOTP message type (%u)",
1281                             op);
1282                         break;
1283                 }
1284         }
1285
1286         if (tree) {
1287                 ti = proto_tree_add_item(tree, proto_bootp, tvb, 0, -1, FALSE);
1288                 bp_tree = proto_item_add_subtree(ti, ett_bootp);
1289
1290                 proto_tree_add_uint(bp_tree, hf_bootp_type, tvb,
1291                                            0, 1,
1292                                            op);
1293                 proto_tree_add_uint_format(bp_tree, hf_bootp_hw_type, tvb,
1294                                            1, 1,
1295                                            htype,
1296                                            "Hardware type: %s",
1297                                            arphrdtype_to_str(htype,
1298                                                              "Unknown (0x%02x)"));
1299                 proto_tree_add_uint(bp_tree, hf_bootp_hw_len, tvb,
1300                                     2, 1, hlen);
1301                 proto_tree_add_item(bp_tree, hf_bootp_hops, tvb,
1302                                     3, 1, FALSE);
1303                 proto_tree_add_item(bp_tree, hf_bootp_id, tvb,
1304                                     4, 4, FALSE);
1305                 proto_tree_add_item(bp_tree, hf_bootp_secs, tvb,
1306                                     8, 2, FALSE);
1307                 flags = tvb_get_ntohs(tvb, 10);
1308                 fi = proto_tree_add_uint(bp_tree, hf_bootp_flags, tvb,
1309                                     10, 2, flags);
1310                 proto_item_append_text(fi, " (%s)",
1311                     (flags & BOOTP_BC) ? "Broadcast" : "Unicast");
1312                 flag_tree = proto_item_add_subtree(fi, ett_bootp_flags);
1313                 proto_tree_add_boolean(flag_tree, hf_bootp_flags_broadcast, tvb,
1314                                     10, 2, flags);
1315                 proto_tree_add_uint(flag_tree, hf_bootp_flags_reserved, tvb,
1316                                     10, 2, flags);
1317                 proto_tree_add_item(bp_tree, hf_bootp_ip_client, tvb,
1318                                     12, 4, FALSE);
1319                 proto_tree_add_item(bp_tree, hf_bootp_ip_your, tvb,
1320                                     16, 4, FALSE);
1321                 proto_tree_add_item(bp_tree, hf_bootp_ip_server, tvb,
1322                                     20, 4, FALSE);
1323                 proto_tree_add_item(bp_tree, hf_bootp_ip_relay, tvb,
1324                                     24, 4, FALSE);
1325
1326                 if (hlen > 0) {
1327                         haddr = tvb_get_ptr(tvb, 28, hlen);
1328                         proto_tree_add_bytes_format(bp_tree, hf_bootp_hw_addr, tvb,
1329                                                    28, hlen,
1330                                                    haddr,
1331                                                    "Client hardware address: %s",
1332                                                    arphrdaddr_to_str(haddr,
1333                                                                      hlen,
1334                                                                      htype));
1335                 }
1336                 else {
1337                         proto_tree_add_text(bp_tree,  tvb,
1338                                                    28, 0, "Client address not given");
1339                 }
1340
1341                 /* The server host name is optional */
1342                 if (tvb_get_guint8(tvb, 44) != '\0') {
1343                         proto_tree_add_item(bp_tree, hf_bootp_server, tvb,
1344                                                    SERVER_NAME_OFFSET, 
1345                                                    SERVER_NAME_LEN, FALSE);
1346                 }
1347                 else {
1348                         proto_tree_add_string_format(bp_tree, hf_bootp_server, tvb,
1349                                                    SERVER_NAME_OFFSET, 
1350                                                    SERVER_NAME_LEN,
1351                                                    tvb_get_ptr(tvb, SERVER_NAME_OFFSET, 1),
1352                                                    "Server host name not given");
1353                 }
1354
1355                 /* Boot file */
1356                 if (tvb_get_guint8(tvb, 108) != '\0') {
1357                         proto_tree_add_item(bp_tree, hf_bootp_file, tvb,
1358                                                    FILE_NAME_OFFSET,
1359                                                    FILE_NAME_LEN, FALSE);
1360                 }
1361                 else {
1362                         proto_tree_add_string_format(bp_tree, hf_bootp_file, tvb,
1363                                                    FILE_NAME_OFFSET,
1364                                                    FILE_NAME_LEN,
1365                                                    tvb_get_ptr(tvb, FILE_NAME_OFFSET, 1),
1366                                                    "Boot file name not given");
1367                 }
1368         }
1369
1370         voff = VENDOR_INFO_OFFSET;
1371
1372         /* rfc2132 says it SHOULD exist, not that it MUST exist */
1373         if (tvb_bytes_exist(tvb, voff, 4)) {
1374                 if (tvb_get_ntohl(tvb, voff) == 0x63825363) {
1375                         if (tree) {
1376                                 tvb_memcpy(tvb, (void *)&ip_addr, voff, sizeof(ip_addr));
1377                                 proto_tree_add_ipv4_format(bp_tree, hf_bootp_cookie, tvb,
1378                                     voff, 4, ip_addr,
1379                                     "Magic cookie: (OK)");
1380                         }
1381                         voff += 4;
1382                 }
1383                 else {
1384                         if (tree) {
1385                                 proto_tree_add_text(bp_tree,  tvb,
1386                                         voff, 64, "Bootp vendor specific options");
1387                         }
1388                         voff += 64;
1389                 }
1390         }
1391
1392         eoff = tvb_reported_length(tvb);
1393
1394         /*
1395          * In the first pass, we just look for the DHCP message type
1396          * and Vendor class identifier options.
1397          */
1398         tmpvoff = voff;
1399         at_end = FALSE;
1400         while (tmpvoff < eoff && !at_end) {
1401                 tmpvoff += bootp_option(tvb, 0, tmpvoff, eoff, TRUE, &at_end,
1402                     &dhcp_type, &vendor_class_id);
1403         }
1404
1405         /*
1406          * If there was a DHCP message type option, flag this packet
1407          * as DHCP.
1408          */
1409         if (dhcp_type != NULL) {
1410                 /*
1411                  * Yes, this is a DHCP packet, and "dhcp_type" is the
1412                  * packet type.
1413                  */
1414                 if (check_col(pinfo->cinfo, COL_PROTOCOL))
1415                         col_set_str(pinfo->cinfo, COL_PROTOCOL, "DHCP");
1416                 if (check_col(pinfo->cinfo, COL_INFO))
1417                         col_add_fstr(pinfo->cinfo, COL_INFO, "DHCP %-8s - Transaction ID 0x%x",
1418                             dhcp_type, tvb_get_ntohl(tvb, 4));
1419                 if (tree)
1420                         proto_tree_add_boolean_hidden(bp_tree, hf_bootp_dhcp,
1421                             tvb, 0, 0, 1);
1422                 tap_queue_packet( bootp_dhcp_tap, pinfo, (gpointer) dhcp_type);
1423         }
1424
1425         /*
1426          * If we're not building the protocol tree, we don't need to
1427          * make a second pass.
1428          */
1429         if (tree == NULL)
1430                 return;
1431
1432         /*
1433          * OK, now build the protocol tree.
1434          */
1435         at_end = FALSE;
1436         while (voff < eoff && !at_end) {
1437                 voff += bootp_option(tvb, bp_tree, voff, eoff, FALSE, &at_end,
1438                     &dhcp_type, &vendor_class_id);
1439         }
1440         if (voff < eoff) {
1441                 /*
1442                  * Padding after the end option.
1443                  */
1444                 proto_tree_add_text(bp_tree, tvb, voff, eoff - voff, "Padding");
1445         }
1446 }
1447
1448 void
1449 proto_register_bootp(void)
1450 {
1451   static hf_register_info hf[] = {
1452     { &hf_bootp_dhcp,
1453       { "Frame is DHCP",                "bootp.dhcp",    FT_BOOLEAN,
1454         BASE_NONE,                      NULL,            0x0,
1455         "", HFILL }},
1456
1457     { &hf_bootp_type,
1458       { "Message type",                 "bootp.type",    FT_UINT8,
1459          BASE_DEC,                      VALS(op_vals),   0x0,
1460         "", HFILL }},
1461
1462     { &hf_bootp_hw_type,
1463       { "Hardware type",                "bootp.hw.type", FT_UINT8,
1464         BASE_HEX,                       NULL,            0x0,
1465         "", HFILL }},
1466
1467     { &hf_bootp_hw_len,
1468       { "Hardware address length",      "bootp.hw.len",  FT_UINT8,
1469         BASE_DEC,                       NULL,            0x0,
1470         "", HFILL }},
1471
1472     { &hf_bootp_hops,
1473       { "Hops",                         "bootp.hops",    FT_UINT8,
1474         BASE_DEC,                       NULL,            0x0,
1475         "", HFILL }},
1476
1477     { &hf_bootp_id,
1478       { "Transaction ID",               "bootp.id",      FT_UINT32,
1479         BASE_HEX,                        NULL,           0x0,
1480         "", HFILL }},
1481
1482     { &hf_bootp_secs,
1483       { "Seconds elapsed",              "bootp.secs",    FT_UINT16,
1484         BASE_DEC,                        NULL,           0x0,
1485         "", HFILL }},
1486
1487     { &hf_bootp_flags,
1488       { "Bootp flags",                  "bootp.flags",   FT_UINT16,
1489         BASE_HEX,                       NULL,            0x0,
1490         "", HFILL }},
1491
1492     { &hf_bootp_flags_broadcast,
1493       { "Broadcast flag",               "bootp.flags.bc", FT_BOOLEAN,
1494         16,                     TFS(&flag_set_broadcast), BOOTP_BC,
1495         "", HFILL }},
1496
1497     { &hf_bootp_flags_reserved,
1498       { "Reserved flags",               "bootp.flags.reserved", FT_UINT16,
1499         BASE_HEX,                       NULL,           BOOTP_MBZ,
1500         "", HFILL }},
1501
1502     { &hf_bootp_ip_client,
1503       { "Client IP address",            "bootp.ip.client",FT_IPv4,
1504         BASE_NONE,                      NULL,             0x0,
1505         "", HFILL }},
1506
1507     { &hf_bootp_ip_your,
1508       { "Your (client) IP address",     "bootp.ip.your",  FT_IPv4,
1509         BASE_NONE,                      NULL,             0x0,
1510         "", HFILL }},
1511
1512     { &hf_bootp_ip_server,
1513       { "Next server IP address",       "bootp.ip.server",FT_IPv4,
1514         BASE_NONE,                      NULL,             0x0,
1515         "", HFILL }},
1516
1517     { &hf_bootp_ip_relay,
1518       { "Relay agent IP address",       "bootp.ip.relay", FT_IPv4,
1519         BASE_NONE,                      NULL,             0x0,
1520         "", HFILL }},
1521
1522     { &hf_bootp_hw_addr,
1523       { "Client hardware address",      "bootp.hw.addr", FT_BYTES,
1524         BASE_NONE,                      NULL,            0x0,
1525         "", HFILL }},
1526
1527     { &hf_bootp_server,
1528       { "Server host name",             "bootp.server",  FT_STRING,
1529         BASE_NONE,                      NULL,            0x0,
1530         "", HFILL }},
1531
1532     { &hf_bootp_file,
1533       { "Boot file name",               "bootp.file",    FT_STRING,
1534         BASE_NONE,                      NULL,            0x0,
1535         "", HFILL }},
1536
1537     { &hf_bootp_cookie,
1538       { "Magic cookie",                 "bootp.cookie",  FT_IPv4,
1539          BASE_NONE,                     NULL,            0x0,
1540         "", HFILL }},
1541
1542     { &hf_bootp_vendor,
1543       { "Bootp Vendor Options",         "bootp.vendor", FT_BYTES,
1544         BASE_NONE,                      NULL,            0x0,
1545         "", HFILL }},
1546   };
1547   static gint *ett[] = {
1548     &ett_bootp,
1549     &ett_bootp_flags,
1550     &ett_bootp_option,
1551   };
1552
1553   module_t *bootp_module;
1554
1555   proto_bootp = proto_register_protocol("Bootstrap Protocol", "BOOTP/DHCP",
1556                                         "bootp");
1557   proto_register_field_array(proto_bootp, hf, array_length(hf));
1558   proto_register_subtree_array(ett, array_length(ett));
1559   bootp_dhcp_tap = register_tap("bootp");
1560
1561   bootp_module = prefs_register_protocol(proto_bootp, NULL);
1562
1563   prefs_register_bool_preference(bootp_module, "novellserverstring",
1564     "Decode Option 85 as String",
1565     "Novell Servers option 85 can be configured as a string instead of address",
1566     &novell_string);
1567 }
1568
1569 void
1570 proto_reg_handoff_bootp(void)
1571 {
1572   dissector_handle_t bootp_handle;
1573
1574   bootp_handle = create_dissector_handle(dissect_bootp, proto_bootp);
1575   dissector_add("udp.port", UDP_PORT_BOOTPS, bootp_handle);
1576   dissector_add("udp.port", UDP_PORT_BOOTPC, bootp_handle);
1577 }