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