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