Use "%u", not "%d", to print unsigned integral quantities.
[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.40 2000/08/13 14:08:03 deniel 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  * BOOTP and DHCP Parameters
14  *     http://www.isi.edu/in-notes/iana/assignments/bootp-dhcp-parameters
15  *
16  * Ethereal - Network traffic analyzer
17  * By Gerald Combs <gerald@zing.org>
18  * Copyright 1998 Gerald Combs
19  *
20  * 
21  * This program is free software; you can redistribute it and/or
22  * modify it under the terms of the GNU General Public License
23  * as published by the Free Software Foundation; either version 2
24  * of the License, or (at your option) any later version.
25  * 
26  * This program is distributed in the hope that it will be useful,
27  * but WITHOUT ANY WARRANTY; without even the implied warranty of
28  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
29  * GNU General Public License for more details.
30  * 
31  * You should have received a copy of the GNU General Public License
32  * along with this program; if not, write to the Free Software
33  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
34  */
35
36 #ifdef HAVE_CONFIG_H
37 # include "config.h"
38 #endif
39
40 #ifdef HAVE_SYS_TYPES_H
41 # include <sys/types.h>
42 #endif
43
44 #include <glib.h>
45 #include "packet.h"
46 #include "packet-arp.h"
47
48 static int proto_bootp = -1;
49 static int hf_bootp_type = -1;
50 static int hf_bootp_hw_type = -1;
51 static int hf_bootp_hw_len = -1;
52 static int hf_bootp_hops = -1;
53 static int hf_bootp_id = -1;
54 static int hf_bootp_secs = -1;
55 static int hf_bootp_flag = -1;
56 static int hf_bootp_ip_client = -1;
57 static int hf_bootp_ip_your = -1;
58 static int hf_bootp_ip_server = -1;
59 static int hf_bootp_ip_relay = -1;
60 static int hf_bootp_hw_addr = -1;
61 static int hf_bootp_server = -1;
62 static int hf_bootp_file = -1;
63 static int hf_bootp_cookie = -1;
64 static int hf_bootp_dhcp = -1;
65
66 static guint ett_bootp = -1;
67 static guint ett_bootp_option = -1;
68
69 #define UDP_PORT_BOOTPS  67
70
71 enum field_type { none, ipv4, string, toggle, yes_no, special, opaque,
72         time_in_secs,
73         val_u_byte, val_u_short, val_u_long,
74         val_s_long };
75
76 struct opt_info {
77         char    *text;
78         enum field_type ftype;
79 };
80
81 #define NUM_OPT_INFOS 128
82 #define NUM_O63_SUBOPTS 11
83
84 static int dissect_netware_ip_suboption(proto_tree *v_tree, const u_char *pd,
85     int optp);
86
87 static const char *
88 get_dhcp_type(guint8 byte)
89 {
90         static const char       *opt53_text[] = {
91                 "Unknown Message Type",
92                 "Discover",
93                 "Offer",
94                 "Request",
95                 "Decline",
96                 "ACK",
97                 "NAK",
98                 "Release",
99                 "Inform"
100         };
101         int i;
102
103         if (byte > 0 && byte < (sizeof opt53_text / sizeof opt53_text[0]))
104                 i = byte;
105         else
106                 i = 0;
107         return opt53_text[i];
108 }
109
110 /* Returns the number of bytes consumed by this option. */
111 static int
112 bootp_option(const u_char *pd, proto_tree *bp_tree, int voff, int eoff)
113 {
114         char                    *text;
115         enum field_type         ftype;
116         u_char                  code = pd[voff];
117         int                     vlen = pd[voff+1];
118         u_char                  byte;
119         int                     i,optp, consumed = vlen + 2;
120         u_long                  time_secs;
121         proto_tree              *v_tree;
122         proto_item              *vti;
123
124         static const value_string nbnt_vals[] = {
125             {0x1,   "B-node" },
126             {0x2,   "P-node" },
127             {0x4,   "M-node" },
128             {0x8,   "H-node" },
129             {0,     NULL     } };
130
131         static struct opt_info opt[] = {
132                 /*   0 */ { "Padding",                                                          none },
133                 /*   1 */ { "Subnet Mask",                                                      ipv4 },
134                 /*   2 */ { "Time Offset",                                                      val_s_long },
135                 /*   3 */ { "Router",                                                           ipv4 },
136                 /*   4 */ { "Time Server",                                                      ipv4 },
137                 /*   5 */ { "Name Server",                                                      ipv4 },
138                 /*   6 */ { "Domain Name Server",                                       ipv4 },
139                 /*   7 */ { "Log Server",                                                       ipv4 },
140                 /*   8 */ { "Cookie Server",                                            ipv4 },
141                 /*   9 */ { "LPR Server",                                                       ipv4 },
142                 /*  10 */ { "Impress Server",                                           ipv4 },
143                 /*  11 */ { "Resource Location Server",                         ipv4 },
144                 /*  12 */ { "Host Name",                                                        string },
145                 /*  13 */ { "Boot File Size",                                           val_u_short },
146                 /*  14 */ { "Merit Dump File",                                          string },
147                 /*  15 */ { "Domain Name",                                                      string },
148                 /*  16 */ { "Swap Server",                                                      ipv4 },
149                 /*  17 */ { "Root Path",                                                        string },
150                 /*  18 */ { "Extensions Path",                                          string },
151                 /*  19 */ { "IP Forwarding",                                            toggle },
152                 /*  20 */ { "Non-Local Source Routing",                         toggle },
153                 /*  21 */ { "Policy Filter",                                            special },
154                 /*  22 */ { "Maximum Datagram Reassembly Size",         val_u_short },
155                 /*  23 */ { "Default IP Time-to-Live",                          val_u_byte },
156                 /*  24 */ { "Path MTU Aging Timeout",                           time_in_secs },
157                 /*  25 */ { "Path MTU Plateau Table",                           val_u_short },
158                 /*  26 */ { "Interface MTU",                                            val_u_short },
159                 /*  27 */ { "All Subnets are Local",                            yes_no },
160                 /*  28 */ { "Broadcast Address",                                        ipv4 },
161                 /*  29 */ { "Perform Mask Discovery",                           toggle },
162                 /*  30 */ { "Mask Supplier",                                            yes_no },
163                 /*  31 */ { "Perform Router Discover",                          toggle },
164                 /*  32 */ { "Router Solicitation Address",                      ipv4 },
165                 /*  33 */ { "Static Route",                                                     special },
166                 /*  34 */ { "Trailer Encapsulation",                            toggle },
167                 /*  35 */ { "ARP Cache Timeout",                                        time_in_secs },
168                 /*  36 */ { "Ethernet Encapsulation",                           toggle },
169                 /*  37 */ { "TCP Default TTL",                                          val_u_byte },
170                 /*  38 */ { "TCP Keepalive Interval",                           time_in_secs },
171                 /*  39 */ { "TCP Keepalive Garbage",                            toggle },
172                 /*  40 */ { "Network Information Service Domain",       string },
173                 /*  41 */ { "Network Information Service Servers",      ipv4 },
174                 /*  42 */ { "Network Time Protocol Servers",            ipv4 },
175                 /*  43 */ { "Vendor-Specific Information",                      special },
176                 /*  44 */ { "NetBIOS over TCP/IP Name Server",          ipv4 },
177                 /*  45 */ { "NetBIOS over TCP/IP Datagram Distribution Name Server", ipv4 },
178                 /*  46 */ { "NetBIOS over TCP/IP Node Type",            special },
179                 /*  47 */ { "NetBIOS over TCP/IP Scope",                        string },
180                 /*  48 */ { "X Window System Font Server",                      ipv4 },
181                 /*  49 */ { "X Window System Display Manager",          ipv4 },
182                 /*  50 */ { "Requested IP Address",                                     ipv4 },
183                 /*  51 */ { "IP Address Lease Time",                            time_in_secs },
184                 /*  52 */ { "Option Overload",                                          special },
185                 /*  53 */ { "DHCP Message Type",                                        special },
186                 /*  54 */ { "Server Identifier",                                        ipv4 },
187                 /*  55 */ { "Parameter Request List",                           special },
188                 /*  56 */ { "Message",                                                          string },
189                 /*  57 */ { "Maximum DHCP Message Size",                        val_u_short },
190                 /*  58 */ { "Renewal Time Value",                                       time_in_secs },
191                 /*  59 */ { "Rebinding Time Value",                                     time_in_secs },
192                 /*  60 */ { "Vendor class identifier",                          opaque },
193                 /*  61 */ { "Client identifier",                                        special },
194                 /*  62 */ { "Novell/Netware IP domain",                                 string },
195                 /*  63 */ { "Novell Options",   special },
196                 /*  64 */ { "Network Information Service+ Domain",      string },
197                 /*  65 */ { "Network Information Service+ Servers",     ipv4 },
198                 /*  66 */ { "TFTP Server Name",                                         string },
199                 /*  67 */ { "Bootfile name",                                            string },
200                 /*  68 */ { "Mobile IP Home Agent",                                     ipv4 },
201                 /*  69 */ { "SMTP Server",                                                      ipv4 },
202                 /*  70 */ { "POP3 Server",                                                      ipv4 },
203                 /*  71 */ { "NNTP Server",                                                      ipv4 },
204                 /*  72 */ { "Default WWW Server",                                       ipv4 },
205                 /*  73 */ { "Default Finger Server",                            ipv4 },
206                 /*  74 */ { "Default IRC Server",                                       ipv4 },
207                 /*  75 */ { "StreetTalk Server",                                        ipv4 },
208                 /*  76 */ { "StreetTalk Directory Assistance Server", ipv4 },
209                 /*  77 */ { "User Class Information",                           opaque },
210                 /*  78 */ { "Directory Agent Information",                      opaque },
211                 /*  79 */ { "Service Location Agent Scope",                     opaque },
212                 /*  80 */ { "Naming Authority",                                         opaque },
213                 /*  81 */ { "Client Fully Qualified Domain Name",       opaque },
214                 /*  82 */ { "Agent Circuit ID",                                         opaque },
215                 /*  83 */ { "Agent Remote ID",                                          opaque },
216                 /*  84 */ { "Agent Subnet Mask",                                        opaque },
217                 /*  85 */ { "Novell Directory Services Servers",        opaque },
218                 /*  86 */ { "Novell Directory Services Tree Name",      opaque },
219                 /*  87 */ { "Novell Directory Services Context",        opaque },
220                 /*  88 */ { "IEEE 1003.1 POSIX Timezone",                       opaque },
221                 /*  89 */ { "Fully Qualified Domain Name",                      opaque },
222                 /*  90 */ { "Authentication",                                           opaque },
223                 /*  91 */ { "Vines TCP/IP Server Option",                       opaque },
224                 /*  92 */ { "Server Selection Option",                          opaque },
225                 /*  93 */ { "Client System Architecture",                       opaque },
226                 /*  94 */ { "Client Network Device Interface",          opaque },
227                 /*  95 */ { "Lightweight Directory Access Protocol",    opaque },
228                 /*  96 */ { "IPv6 Transitions",                                         opaque },
229                 /*  97 */ { "UUID/GUID-based Client Identifier",        opaque },
230                 /*  98 */ { "Open Group's User Authentication",         opaque },
231                 /*  99 */ { "Unassigned",                                                       opaque },
232                 /* 100 */ { "Printer Name",                                                     opaque },
233                 /* 101 */ { "MDHCP multicast address",                          opaque },
234                 /* 102 */ { "Removed/unassigned",                                       opaque },
235                 /* 103 */ { "Removed/unassigned",                                       opaque },
236                 /* 104 */ { "Removed/unassigned",                                       opaque },
237                 /* 105 */ { "Removed/unassigned",                                       opaque },
238                 /* 106 */ { "Removed/unassigned",                                       opaque },
239                 /* 107 */ { "Removed/unassigned",                                       opaque },
240                 /* 108 */ { "Swap Path Option",                                         opaque },
241                 /* 109 */ { "Unassigned",                                                       opaque },
242                 /* 110 */ { "IPX Compability",                                          opaque },
243                 /* 111 */ { "Unassigned",                                                       opaque },
244                 /* 112 */ { "Netinfo Parent Server Address",            opaque },
245                 /* 113 */ { "Netinfo Parent Server Tag",                        opaque },
246                 /* 114 */ { "URL",                                                                      opaque },
247                 /* 115 */ { "DHCP Failover Protocol",                           opaque },
248                 /* 116 */ { "DHCP Auto-Configuration",                          opaque },
249                 /* 117 */ { "Unassigned",                                                       opaque },
250                 /* 118 */ { "Unassigned",                                                       opaque },
251                 /* 119 */ { "Unassigned",                                                       opaque },
252                 /* 120 */ { "Unassigned",                                                       opaque },
253                 /* 121 */ { "Unassigned",                                                       opaque },
254                 /* 122 */ { "Unassigned",                                                       opaque },
255                 /* 123 */ { "Unassigned",                                                       opaque },
256                 /* 124 */ { "Unassigned",                                                       opaque },
257                 /* 125 */ { "Unassigned",                                                       opaque },
258                 /* 126 */ { "Extension",                                                        opaque },
259                 /* 127 */ { "Extension",                                                        opaque }
260         };
261
262         /* Options whose length isn't "vlen + 2". */
263         switch (code) {
264
265         case 0:         /* Padding */
266                 /* check how much padding we have */
267                 for (i = voff + 1; i < eoff; i++ ) {
268                         if (pd[i] != 0) {
269                                 break;
270                         }
271                 }
272                 i = i - voff;
273                 if (bp_tree != NULL)
274                         proto_tree_add_text(bp_tree, NullTVB, voff, i, "Padding");
275                 consumed = i;
276                 return consumed;
277                 break;
278
279         case 255:       /* End Option */
280                 if (bp_tree != NULL)
281                         proto_tree_add_text(bp_tree, NullTVB, voff, 1, "End Option");
282                 consumed = 1;
283                 return consumed;
284         }
285
286         if (bp_tree == NULL) {
287                 /* Don't put anything in the protocol tree. */
288                 return consumed;
289         }
290
291         text = opt[code].text;
292         /* Special cases */
293         switch (code) {
294
295         case 21:        /* Policy Filter */
296                 if (vlen == 8) {
297                         /* one IP address pair */
298                         proto_tree_add_text(bp_tree, NullTVB, voff, consumed,
299                                 "Option %d: %s = %s/%s", code, text,
300                                 ip_to_str((guint8*)&pd[voff+2]),
301                                 ip_to_str((guint8*)&pd[voff+6]));
302                 } else {
303                         /* > 1 IP address pair. Let's make a sub-tree */
304                         vti = proto_tree_add_text(bp_tree, NullTVB, voff,
305                                 consumed, "Option %d: %s", code, text);
306                         v_tree = proto_item_add_subtree(vti, ett_bootp_option);
307                         for (i = voff + 2; i < voff + consumed; i += 8) {
308                                 proto_tree_add_text(v_tree, NullTVB, i, 8, "IP Address/Mask: %s/%s",
309                                         ip_to_str((guint8*)&pd[i]),
310                                         ip_to_str((guint8*)&pd[i+4]));
311                         }
312                 }
313                 break;
314
315         case 33:        /* Static Route */
316                 if (vlen == 8) {
317                         /* one IP address pair */
318                         proto_tree_add_text(bp_tree, NullTVB, voff, consumed,
319                                 "Option %d: %s = %s/%s", code, text,
320                                 ip_to_str((guint8*)&pd[voff+2]),
321                                 ip_to_str((guint8*)&pd[voff+6]));
322                 } else {
323                         /* > 1 IP address pair. Let's make a sub-tree */
324                         vti = proto_tree_add_text(bp_tree, NullTVB, voff,
325                                 consumed, "Option %d: %s", code, text);
326                         v_tree = proto_item_add_subtree(vti, ett_bootp_option);
327                         for (i = voff + 2; i < voff + consumed; i += 8) {
328                                 proto_tree_add_text(v_tree, NullTVB, i, 8,
329                                         "Destination IP Address/Router: %s/%s",
330                                         ip_to_str((guint8*)&pd[i]),
331                                         ip_to_str((guint8*)&pd[i+4]));
332                         }
333                 }
334                 break;
335
336         case 43:        /* Vendor-Specific Info */
337                 proto_tree_add_text(bp_tree, NullTVB, voff, consumed,
338                                 "Option %d: %s", code, text);
339                 break;
340
341         case 46:        /* NetBIOS-over-TCP/IP Node Type */
342                 byte = pd[voff+2];
343                 proto_tree_add_text(bp_tree, NullTVB, voff, consumed,
344                                 "Option %d: %s = %s", code, text,
345                                 val_to_str(byte, nbnt_vals,
346                                     "Unknown (0x%02x)"));
347                 break;
348                                 
349         case 53:        /* DHCP Message Type */
350                 proto_tree_add_text(bp_tree, NullTVB, voff, 3, "Option %d: %s = DHCP %s",
351                         code, text, get_dhcp_type(pd[voff+2]));
352                 break;
353
354         case 55:        /* Parameter Request List */
355                 vti = proto_tree_add_text(bp_tree, NullTVB, voff,
356                         vlen + 2, "Option %d: %s", code, text);
357                 v_tree = proto_item_add_subtree(vti, ett_bootp_option);
358                 for (i = 0; i < vlen; i++) {
359                         byte = pd[voff+2+i];
360                         if (byte < NUM_OPT_INFOS) {
361                                 proto_tree_add_text(v_tree, NullTVB, voff+2+i, 1, "%d = %s",
362                                                 byte, opt[byte].text);
363                         } else {
364                                 proto_tree_add_text(vti, NullTVB, voff+2+i, 1,
365                                         "Unknown Option Code: %d", byte);
366                         }
367                 }
368                 break;
369
370         case 61:        /* Client Identifier */
371                 /* We *MAY* use hwtype/hwaddr. If we have 7 bytes, I'll
372                    guess that the first is the hwtype, and the last 6
373                    are the hw addr */
374                 if (vlen == 7) {
375                         vti = proto_tree_add_text(bp_tree, NullTVB, voff,
376                                 consumed, "Option %d: %s", code, text);
377                         v_tree = proto_item_add_subtree(vti, ett_bootp_option);
378                         proto_tree_add_text(v_tree, NullTVB, voff+2, 1,
379                                 "Hardware type: %s",
380                                 arphrdtype_to_str(pd[voff+2],
381                                         "Unknown (0x%02x)"));
382                         proto_tree_add_text(v_tree, NullTVB, voff+3, 6,
383                                 "Client hardware address: %s",
384                                 arphrdaddr_to_str((guint8*)&pd[voff+3],
385                                         6, pd[voff+2]));
386                 } else {
387                         /* otherwise, it's opaque data */
388                         proto_tree_add_text(bp_tree, NullTVB, voff, consumed,
389                                 "Option %d: %s (%d bytes)", code, text, vlen);
390                 }
391                 break;
392
393         case 63:        /* NetWare/IP options */
394                 vti = proto_tree_add_text(bp_tree, NullTVB, voff,
395                     consumed, "Option %d: %s", code, text);
396                 v_tree = proto_item_add_subtree(vti, ett_bootp_option);
397
398                 optp = voff+2;
399                 while (optp < voff+consumed)
400                         optp = dissect_netware_ip_suboption(v_tree, pd, optp);
401                 break;
402
403         default:        /* not special */
404                 break;
405         }
406
407         /* Normal cases */
408         if (code < NUM_OPT_INFOS) {
409                 text = opt[code].text;
410                 ftype = opt[code].ftype;
411
412                 switch (ftype) {
413
414                 case special:
415                         return consumed;
416
417                 case ipv4:
418                         if (vlen == 4) {
419                                 /* one IP address */
420                                 proto_tree_add_text(bp_tree, NullTVB, voff, consumed,
421                                         "Option %d: %s = %s", code, text,
422                                         ip_to_str((guint8*)&pd[voff+2]));
423                         } else {
424                                 /* > 1 IP addresses. Let's make a sub-tree */
425                                 vti = proto_tree_add_text(bp_tree, NullTVB, voff,
426                                         consumed, "Option %d: %s", code, text);
427                                 v_tree = proto_item_add_subtree(vti, ett_bootp_option);
428                                 for (i = voff + 2; i < voff + consumed; i += 4) {
429                                         proto_tree_add_text(v_tree, NullTVB, i, 4, "IP Address: %s",
430                                                 ip_to_str((guint8*)&pd[i]));
431                                 }
432                         }
433                         break;
434
435                 case string:
436                         /* Fix for non null-terminated string supplied by
437                          * John Lines <John.Lines@aeat.co.uk>
438                          */
439                         proto_tree_add_text(bp_tree, NullTVB, voff, consumed,
440                                         "Option %d: %s = %.*s", code, text, vlen, &pd[voff+2]);
441                         break;
442
443                 case opaque:
444                         proto_tree_add_text(bp_tree, NullTVB, voff, consumed,
445                                         "Option %d: %s (%d bytes)",
446                                         code, text, vlen);
447                         break;
448
449                 case val_u_short:
450                         if (vlen == 2) {
451                                 /* one u_short */
452                                 proto_tree_add_text(bp_tree, NullTVB, voff, consumed,
453                                                 "Option %d: %s = %d", code, text,
454                                                 pntohs(&pd[voff+2]));
455                         } else {
456                                 /* > 1 u_short */
457                                 vti = proto_tree_add_text(bp_tree, NullTVB, voff,
458                                         consumed, "Option %d: %s", code, text);
459                                 v_tree = proto_item_add_subtree(vti, ett_bootp_option);
460                                 for (i = voff + 2; i < voff + consumed; i += 2) {
461                                         proto_tree_add_text(v_tree, NullTVB, i, 4, "Value: %d",
462                                                 pntohs(&pd[i]));
463                                 }
464                         }
465                         break;
466
467                 case val_u_long:
468                         proto_tree_add_text(bp_tree, NullTVB, voff, consumed,
469                                         "Option %d: %s = %d", code, text,
470                                         pntohl(&pd[voff+2]));
471                         break;
472
473                 case val_u_byte:
474                         proto_tree_add_text(bp_tree, NullTVB, voff, consumed,
475                                         "Option %d: %s = %d", code, text, pd[voff+2]);
476                         break;
477
478                 case toggle:
479                         i = pd[voff+2];
480                         if (i != 0 && i != 1) {
481                                 proto_tree_add_text(bp_tree, NullTVB, voff, consumed,
482                                                 "Option %d: %s = Invalid Value %d", code, text,
483                                                 pd[voff+2]);
484                         } else {
485                                 proto_tree_add_text(bp_tree, NullTVB, voff, consumed,
486                                                 "Option %d: %s = %s", code, text,
487                                                 pd[voff+2] == 0 ? "Disabled" : "Enabled");
488                         }
489                         break;
490
491                 case yes_no:
492                         i = pd[voff+2];
493                         if (i != 0 && i != 1) {
494                                 proto_tree_add_text(bp_tree, NullTVB, voff, consumed,
495                                                 "Option %d: %s = Invalid Value %d", code, text,
496                                                 pd[voff+2]);
497                         } else {
498                                 proto_tree_add_text(bp_tree, NullTVB, voff, consumed,
499                                                 "Option %d: %s = %s", code, text,
500                                                 pd[voff+2] == 0 ? "No" : "Yes");
501                         }
502                         break;
503
504                 case time_in_secs:
505                         time_secs = pntohl(&pd[voff+2]);
506                         proto_tree_add_text(bp_tree, NullTVB, voff, consumed,
507                                 "Option %d: %s = %s", code, text,
508                                 ((time_secs == 0xffffffff) ?
509                                     "infinity" :
510                                     time_secs_to_str(time_secs)));
511                         break;
512
513                 default:
514                         proto_tree_add_text(bp_tree, NullTVB, voff, consumed,
515                                         "Option %d: %s (%d bytes)", code, text, vlen);
516                 }
517         } else {
518                 proto_tree_add_text(bp_tree, NullTVB, voff, consumed,
519                                 "Unknown Option Code: %d (%d bytes)", code, vlen);
520         }
521
522         return consumed;
523 }
524
525 static int
526 dissect_netware_ip_suboption(proto_tree *v_tree, const u_char *pd, int optp)
527 {
528         int slask;
529         proto_tree *o63_v_tree;
530         proto_item *vti;
531
532         struct o63_opt_info { 
533                 char    *truet;
534                 char    *falset;
535                 enum field_type ft;
536         };
537
538         static struct o63_opt_info o63_opt[]= {
539                 /* 0 */ {"","",none},
540                 /* 1 */ {"NWIP does not exist on subnet","",string},
541                 /* 2 */ {"NWIP exist in options area","",string},
542                 /* 3 */ {"NWIP exists in sname/file","",string},
543                 /* 4 */ {"NWIP exists, but too big","",string},
544                 /* 5 */ {"Broadcast for nearest Netware server","Do NOT Broadcast for nearest Netware server",yes_no}, 
545                 /* 6 */ {"Preferred DSS server","",ipv4},
546                 /* 7 */ {"Nearest NWIP server","",ipv4},
547                 /* 8 */ {"Autoretries","",val_u_short},
548                 /* 9 */ {"Autoretry delay, secs ","",val_u_short},
549                 /* 10*/ {"Support NetWare/IP v1.1","Do NOT support NetWare/IP v1.1",yes_no},
550                 /* 11*/ {"Primary DSS ", "" , special}
551         };
552                 
553         if (pd[optp] > NUM_O63_SUBOPTS) {
554                 proto_tree_add_text(v_tree, NullTVB,optp,1,"Unknown suboption %d", pd[optp]);
555                 optp++;
556         } else {
557                 switch (o63_opt[pd[optp]].ft) {
558
559                 case string:
560                         proto_tree_add_text(v_tree, NullTVB, optp, 2, "Suboption %d: %s", pd[optp], o63_opt[pd[optp]].truet);
561                         optp+=2;
562                         break;
563
564                 case yes_no:
565                         if (pd[optp+2]==1) {
566                                 proto_tree_add_text(v_tree, NullTVB, optp, 3, "Suboption %d: %s", pd[optp], o63_opt[pd[optp]].truet);
567                         } else {
568                                 proto_tree_add_text(v_tree, NullTVB, optp, 3, "Suboption %d: %s" , pd[optp], o63_opt[pd[optp]].falset);
569                         }
570                         optp+=3;
571                         break;
572
573                 case special:   
574                         proto_tree_add_text(v_tree, NullTVB, optp, 6,
575                             "Suboption %d: %s = %s" ,
576                             pd[optp], o63_opt[pd[optp]].truet,
577                             ip_to_str((guint8*)&pd[optp+2]));
578                         optp=optp+6;
579                         break;
580
581                 case val_u_short:
582                         proto_tree_add_text(v_tree, NullTVB, optp, 3, "Suboption %d: %s = %d",pd[optp], o63_opt[pd[optp]].truet, pd[optp+2]);
583                         optp+=3;
584                         break;
585                                                         
586                 case ipv4:
587                         if (pd[optp+1] == 4) {
588                                 /* one IP address */
589                                 proto_tree_add_text(v_tree, NullTVB, optp, 6,
590                                     "Suboption %d : %s = %s",
591                                     pd[optp], o63_opt[pd[optp]].truet,
592                                     ip_to_str((guint8*)&pd[optp+2]));
593                                 optp=optp+6;
594                         } else {
595                                 /* > 1 IP addresses. Let's make a sub-tree */
596                                 vti = proto_tree_add_text(v_tree, NullTVB, optp,
597                                     pd[optp+1]+2, "Suboption %d: %s",
598                                     pd[optp], o63_opt[pd[optp]].truet);
599                                 o63_v_tree = proto_item_add_subtree(vti, ett_bootp_option);
600                                 for (slask = optp + 2 ; slask < optp+pd[optp+1]; slask += 4) {
601                                         proto_tree_add_text(o63_v_tree, NullTVB, slask, 4, "IP Address: %s",
602                                         ip_to_str((guint8*)&pd[slask]));
603                                 }
604                                 optp=slask;
605                         }
606                         break;
607                 default:
608                         proto_tree_add_text(v_tree, NullTVB,optp,1,"Unknown suboption %d", pd[optp]);
609                         optp++;
610                         break;
611                 }
612         }
613         return optp;
614 }
615
616 static void
617 dissect_bootp(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
618 {
619         proto_tree      *bp_tree = NULL;
620         proto_item      *ti;
621         int             voff, eoff; /* vender offset, end offset */
622         guint32         ip_addr;
623         const char      *dhcp_type;
624
625         OLD_CHECK_DISPLAY_AS_DATA(proto_bootp, pd, offset, fd, tree);
626
627         dhcp_type = NULL;
628
629         if (check_col(fd, COL_PROTOCOL))
630                 col_add_str(fd, COL_PROTOCOL, "BOOTP");
631
632         if (check_col(fd, COL_INFO)) {
633                 if (pd[offset] == 1) {
634                         col_add_fstr(fd, COL_INFO, "Boot Request from %s",
635                                 arphrdaddr_to_str((guint8*)&pd[offset+28],
636                                         pd[offset+2], pd[offset+1]));
637                 }
638                 else {
639                         col_add_str(fd, COL_INFO, "Boot Reply");
640                 }
641         }
642
643         if (tree) {
644                 ti = proto_tree_add_item(tree, proto_bootp, NullTVB, offset, END_OF_FRAME, FALSE);
645                 bp_tree = proto_item_add_subtree(ti, ett_bootp);
646
647                 proto_tree_add_uint_format(bp_tree, hf_bootp_type, NullTVB, 
648                                            offset, 1,
649                                            pd[offset], 
650                                            pd[offset] == 1 ?
651                                            "Boot Request" : "Boot Reply");
652                 proto_tree_add_uint_format(bp_tree, hf_bootp_hw_type, NullTVB,
653                                            offset + 1, 1,
654                                            pd[offset+1],
655                                            "Hardware type: %s",
656                                            arphrdtype_to_str(pd[offset+1],
657                                                              "Unknown (0x%02x)"));
658                 proto_tree_add_uint(bp_tree, hf_bootp_hw_len, NullTVB,
659                                     offset + 2, 1, pd[offset+2]);
660                 proto_tree_add_uint(bp_tree, hf_bootp_hops, NullTVB,
661                                     offset + 3, 1, pd[offset+3]);
662                 proto_tree_add_uint(bp_tree, hf_bootp_id, NullTVB,
663                                    offset + 4, 4, pntohl(&pd[offset+4]));
664                 proto_tree_add_uint(bp_tree, hf_bootp_secs, NullTVB,
665                                     offset + 8, 2, pntohs(&pd[offset+8]));
666                 proto_tree_add_uint(bp_tree, hf_bootp_flag, NullTVB,
667                                     offset + 10, 2, pntohs(&pd[offset+10]) & 0x8000);
668
669                 memcpy(&ip_addr, &pd[offset+12], sizeof(ip_addr));
670                 proto_tree_add_ipv4(bp_tree, hf_bootp_ip_client, NullTVB, 
671                                     offset + 12, 4, ip_addr);
672                 memcpy(&ip_addr, &pd[offset+16], sizeof(ip_addr));
673                 proto_tree_add_ipv4(bp_tree, hf_bootp_ip_your, NullTVB, 
674                                     offset + 16, 4, ip_addr);
675                 memcpy(&ip_addr, &pd[offset+20], sizeof(ip_addr));
676                 proto_tree_add_ipv4(bp_tree, hf_bootp_ip_server, NullTVB,
677                                     offset + 20, 4, ip_addr);
678                 memcpy(&ip_addr, &pd[offset+24], sizeof(ip_addr));
679                 proto_tree_add_ipv4(bp_tree, hf_bootp_ip_relay, NullTVB,
680                                     offset + 24, 4, ip_addr);
681
682                 if (pd[offset+2] > 0) {
683                         proto_tree_add_bytes_format(bp_tree, hf_bootp_hw_addr, NullTVB, 
684                                                    offset + 28, pd[offset+2],
685                                                    &pd[offset+28],
686                                                    "Client hardware address: %s",
687                                                    arphrdaddr_to_str((guint8*)&pd[offset+28],
688                                                                      pd[offset+2], pd[offset+1]));
689                 }
690                 else {
691                         proto_tree_add_text(bp_tree,  NullTVB, 
692                                                    offset + 28, 0, "Client address not given");
693                 }
694
695                 /* The server host name is optional */
696                 if (pd[offset+44]) {
697                         proto_tree_add_string_format(bp_tree, hf_bootp_server, NullTVB,
698                                                    offset + 44, 64,
699                                                    &pd[offset+44],
700                                                    "Server host name: %s",
701                                                    &pd[offset+44]);
702                 }
703                 else {
704                         proto_tree_add_string_format(bp_tree, hf_bootp_server, NullTVB,
705                                                    offset + 44, 64,
706                                                    &pd[offset+44],
707                                                    "Server host name not given");
708                 }
709
710                 /* Boot file */
711                 if (pd[offset+108]) {
712                         proto_tree_add_string_format(bp_tree, hf_bootp_file, NullTVB,
713                                                    offset + 108, 128,
714                                                    &pd[offset+108],
715                                                    "Boot file name: %s",
716                                                    &pd[offset+108]);
717                 }
718                 else {
719                         proto_tree_add_string_format(bp_tree, hf_bootp_file, NullTVB,
720                                                    offset + 108, 128,
721                                                    &pd[offset+108],
722                                                    "Boot file name not given");
723                 }
724
725                 memcpy(&ip_addr, &pd[offset + 236], sizeof(ip_addr));
726                 if (pntohl(&pd[offset+236]) == 0x63825363) {
727                         proto_tree_add_ipv4_format(bp_tree, hf_bootp_cookie, NullTVB,
728                                             offset + 236, 4, ip_addr,
729                                             "Magic cookie: (OK)");
730                 }
731                 else {
732                         proto_tree_add_ipv4(bp_tree, hf_bootp_cookie, NullTVB,
733                                             offset + 236, 4, ip_addr);
734                 }
735         }
736
737         voff = offset+240;
738         eoff = pi.captured_len;
739         while (voff < eoff) {
740                 /* Handle the DHCP option specially here, so that we
741                    can flag DHCP packets as such. */
742                 if (pd[voff] == 53)
743                         dhcp_type = get_dhcp_type(pd[voff+2]);
744                 voff += bootp_option(pd, bp_tree, voff, eoff);
745         }
746         if (dhcp_type != NULL ) {
747                 if (check_col(fd, COL_PROTOCOL))
748                         col_add_str(fd, COL_PROTOCOL, "DHCP");
749                 if (check_col(fd, COL_INFO))
750                         col_add_fstr(fd, COL_INFO, "DHCP %-8s - Transaction ID 0x%x",
751                             dhcp_type, pntohl(&pd[offset+4]));
752                 if (tree)
753                         proto_tree_add_boolean_hidden(bp_tree, hf_bootp_dhcp,
754                             NullTVB, 0, 0, 1);
755         }
756 }
757
758 void
759 proto_register_bootp(void)
760 {
761   static hf_register_info hf[] = {
762     { &hf_bootp_dhcp,
763       { "Frame is DHCP",                "bootp.dhcp",    FT_BOOLEAN,  BASE_NONE, NULL, 0x0,
764         "" }},                            
765                       
766     { &hf_bootp_type,
767       { "Message type",                 "bootp.type",    FT_UINT8,  BASE_NONE, NULL, 0x0,
768         "" }},
769
770     { &hf_bootp_hw_type,
771       { "Hardware type",                "bootp.hw.type", FT_UINT8,  BASE_HEX, NULL, 0x0,
772         "" }},
773
774     { &hf_bootp_hw_len,
775       { "Hardware address length",      "bootp.hw.len",  FT_UINT8,  BASE_DEC, NULL, 0x0,
776         "" }},
777
778     { &hf_bootp_hops,
779       { "Hops",                         "bootp.hops",    FT_UINT8,  BASE_DEC, NULL, 0x0,
780         "" }},
781
782     { &hf_bootp_id,
783       { "Transaction ID",               "bootp.id",      FT_UINT32, BASE_HEX, NULL, 0x0,
784         "" }},
785
786     { &hf_bootp_secs,
787       { "Seconds elapsed",              "bootp.secs",    FT_UINT16, BASE_DEC, NULL, 0x0,
788         "" }},
789
790     { &hf_bootp_flag,
791       { "Broadcast flag",               "bootp.flag",    FT_UINT16, BASE_HEX, NULL, 0x0,
792         "" }},
793
794     { &hf_bootp_ip_client,
795       { "Client IP address",            "bootp.ip.client",FT_IPv4,  BASE_NONE, NULL, 0x0,
796         "" }},
797
798     { &hf_bootp_ip_your,
799       { "Your (client) IP address",     "bootp.ip.your",  FT_IPv4,  BASE_NONE, NULL, 0x0,
800         "" }},
801
802     { &hf_bootp_ip_server,
803       { "Next server IP address",       "bootp.ip.server",FT_IPv4,  BASE_NONE, NULL, 0x0,
804         "" }},
805
806     { &hf_bootp_ip_relay,
807       { "Relay agent IP address",       "bootp.ip.relay", FT_IPv4,  BASE_NONE, NULL, 0x0,
808         "" }},
809
810     { &hf_bootp_hw_addr,
811       { "Client hardware address",      "bootp.hw.addr", FT_BYTES,  BASE_NONE, NULL, 0x0,
812         "" }},
813
814     { &hf_bootp_server,
815       { "Server host name",             "bootp.server",  FT_STRING, BASE_NONE, NULL, 0x0,
816         "" }},
817
818     { &hf_bootp_file,
819       { "Boot file name",               "bootp.file",    FT_STRING, BASE_NONE, NULL, 0x0,
820         "" }},
821
822     { &hf_bootp_cookie,
823       { "Magic cookie",                 "bootp.cookie",  FT_IPv4,   BASE_NONE, NULL, 0x0,
824         "" }},
825   };
826   static gint *ett[] = {
827     &ett_bootp,
828     &ett_bootp_option,
829   };
830   
831   proto_bootp = proto_register_protocol("Bootstrap Protocol", "bootp");
832   proto_register_field_array(proto_bootp, hf, array_length(hf));
833   proto_register_subtree_array(ett, array_length(ett));
834 }
835
836 void
837 proto_reg_handoff_bootp(void)
838 {
839   old_dissector_add("udp.port", UDP_PORT_BOOTPS, dissect_bootp);
840 }