Break proto_tree_add_item_format() into multiple functions:
[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.27 2000/03/12 04:47:35 gram Exp $
6  *
7  * The information used comes from:
8  * RFC 2132: DHCP Options and BOOTP Vendor Extensions
9  * RFC 1542: Clarifications and Extensions for the Bootstrap Protocol
10  * RFC 2131: Dynamic Host Configuration Protocol
11  *
12  * Ethereal - Network traffic analyzer
13  * By Gerald Combs <gerald@zing.org>
14  * Copyright 1998 Gerald Combs
15  *
16  * 
17  * This program is free software; you can redistribute it and/or
18  * modify it under the terms of the GNU General Public License
19  * as published by the Free Software Foundation; either version 2
20  * of the License, or (at your option) any later version.
21  * 
22  * This program is distributed in the hope that it will be useful,
23  * but WITHOUT ANY WARRANTY; without even the implied warranty of
24  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
25  * GNU General Public License for more details.
26  * 
27  * You should have received a copy of the GNU General Public License
28  * along with this program; if not, write to the Free Software
29  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
30  */
31
32 #ifdef HAVE_CONFIG_H
33 # include "config.h"
34 #endif
35
36 #ifdef HAVE_SYS_TYPES_H
37 # include <sys/types.h>
38 #endif
39
40 #include <glib.h>
41 #include "packet.h"
42 #include "packet-arp.h"
43
44 static int proto_bootp = -1;
45 static int hf_bootp_type = -1;
46 static int hf_bootp_hw_type = -1;
47 static int hf_bootp_hw_len = -1;
48 static int hf_bootp_hops = -1;
49 static int hf_bootp_id = -1;
50 static int hf_bootp_secs = -1;
51 static int hf_bootp_flag = -1;
52 static int hf_bootp_ip_client = -1;
53 static int hf_bootp_ip_your = -1;
54 static int hf_bootp_ip_server = -1;
55 static int hf_bootp_ip_relay = -1;
56 static int hf_bootp_hw_addr = -1;
57 static int hf_bootp_server = -1;
58 static int hf_bootp_file = -1;
59 static int hf_bootp_cookie = -1;
60
61 static guint ett_bootp = -1;
62 static guint ett_bootp_option = -1;
63
64 enum field_type { none, ipv4, string, toggle, yes_no, special, opaque,
65         time_in_secs,
66         val_u_byte, val_u_short, val_u_long,
67         val_s_long };
68
69 struct opt_info {
70         char    *text;
71         enum field_type ftype;
72 };
73
74 #define NUM_OPT_INFOS 77
75
76 /* returns the number of bytes consumed by this option */
77 static int
78 bootp_option(const u_char *pd, proto_tree *bp_tree, int voff, int eoff)
79 {
80         char                    *text;
81         enum field_type ftype;
82         u_char                  code = pd[voff];
83         int                             vlen = pd[voff+1];
84         u_char                  byte;
85         int                             i, consumed = vlen + 2;
86         u_long                  time_secs;
87         proto_tree              *v_tree;
88         proto_item              *vti;
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         static const value_string nbnt_vals[] = {
102             {0x1,   "B-node" },
103             {0x2,   "P-node" },
104             {0x4,   "M-node" },
105             {0x8,   "H-node" },
106             {0,     NULL     } };
107
108         static struct opt_info opt[] = {
109                 /*   0 */ { "Padding",                                                          none },
110                 /*   1 */ { "Subnet Mask",                                                      ipv4 },
111                 /*   2 */ { "Time Offset",                                                      val_s_long },
112                 /*   3 */ { "Router",                                                           ipv4 },
113                 /*   4 */ { "Time Server",                                                      ipv4 },
114                 /*   5 */ { "Name Server",                                                      ipv4 },
115                 /*   6 */ { "Domain Name Server",                                       ipv4 },
116                 /*   7 */ { "Log Server",                                                       ipv4 },
117                 /*   8 */ { "Cookie Server",                                            ipv4 },
118                 /*   9 */ { "LPR Server",                                                       ipv4 },
119                 /*  10 */ { "Impress Server",                                           ipv4 },
120                 /*  11 */ { "Resource Location Server",                         ipv4 },
121                 /*  12 */ { "Host Name",                                                        string },
122                 /*  13 */ { "Boot File Size",                                           val_u_short },
123                 /*  14 */ { "Merit Dump File",                                          string },
124                 /*  15 */ { "Domain Name",                                                      string },
125                 /*  16 */ { "Swap Server",                                                      ipv4 },
126                 /*  17 */ { "Root Path",                                                        string },
127                 /*  18 */ { "Extensions Path",                                          string },
128                 /*  19 */ { "IP Forwarding",                                            toggle },
129                 /*  20 */ { "Non-Local Source Routing",                         toggle },
130                 /*  21 */ { "Policy Filter",                                            special },
131                 /*  22 */ { "Maximum Datagram Reassembly Size",         val_u_short },
132                 /*  23 */ { "Default IP Time-to-Live",                          val_u_byte },
133                 /*  24 */ { "Path MTU Aging Timeout",                           time_in_secs },
134                 /*  25 */ { "Path MTU Plateau Table",                           val_u_short },
135                 /*  26 */ { "Interface MTU",                                            val_u_short },
136                 /*  27 */ { "All Subnets are Local",                            yes_no },
137                 /*  28 */ { "Broadcast Address",                                        ipv4 },
138                 /*  29 */ { "Perform Mask Discovery",                           toggle },
139                 /*  30 */ { "Mask Supplier",                                            yes_no },
140                 /*  31 */ { "Perform Router Discover",                          toggle },
141                 /*  32 */ { "Router Solicitation Address",                      ipv4 },
142                 /*  33 */ { "Static Route",                                                     special },
143                 /*  34 */ { "Trailer Encapsulation",                            toggle },
144                 /*  35 */ { "ARP Cache Timeout",                                        time_in_secs },
145                 /*  36 */ { "Ethernet Encapsulation",                           toggle },
146                 /*  37 */ { "TCP Default TTL",                                          val_u_byte },
147                 /*  38 */ { "TCP Keepalive Interval",                           time_in_secs },
148                 /*  39 */ { "TCP Keepalive Garbage",                            toggle },
149                 /*  40 */ { "Network Information Service Domain",       string },
150                 /*  41 */ { "Network Information Service Servers",      ipv4 },
151                 /*  42 */ { "Network Time Protocol Servers",            ipv4 },
152                 /*  43 */ { "Vendor-Specific Information",                      special },
153                 /*  44 */ { "NetBIOS over TCP/IP Name Server",          ipv4 },
154                 /*  45 */ { "NetBIOS over TCP/IP Datagram Distribution Name Server", ipv4 },
155                 /*  46 */ { "NetBIOS over TCP/IP Node Type",            special },
156                 /*  47 */ { "NetBIOS over TCP/IP Scope",                        string },
157                 /*  48 */ { "X Window System Font Server",                      ipv4 },
158                 /*  49 */ { "X Window System Display Manager",          ipv4 },
159                 /*  50 */ { "Requested IP Address",                                     ipv4 },
160                 /*  51 */ { "IP Address Lease Time",                            time_in_secs },
161                 /*  52 */ { "Option Overload",                                          special },
162                 /*  53 */ { "DHCP Message Type",                                        special },
163                 /*  54 */ { "Server Identifier",                                        ipv4 },
164                 /*  55 */ { "Parameter Request List",                           special },
165                 /*  56 */ { "Message",                                                          string },
166                 /*  57 */ { "Maximum DHCP Message Size",                        val_u_short },
167                 /*  58 */ { "Renewal Time Value",                                       time_in_secs },
168                 /*  59 */ { "Rebinding Time Value",                                     time_in_secs },
169                 /*  60 */ { "Vendor class identifier",                          opaque },
170                 /*  61 */ { "Client identifier",                                        special },
171                 /*  62 */ { "undefined",                                        none },
172                 /*  63 */ { "undefined",                                        none },
173                 /*  64 */ { "Network Information Service+ Domain",      string },
174                 /*  65 */ { "Network Information Service+ Servers",     ipv4 },
175                 /*  66 */ { "TFTP Server Name",                                         string },
176                 /*  67 */ { "Bootfile name",                                            string },
177                 /*  68 */ { "Mobile IP Home Agent",                                     ipv4 },
178                 /*  69 */ { "SMTP Server",                                                      ipv4 },
179                 /*  70 */ { "POP3 Server",                                                      ipv4 },
180                 /*  71 */ { "NNTP Server",                                                      ipv4 },
181                 /*  72 */ { "Default WWW Server",                                       ipv4 },
182                 /*  73 */ { "Default Finger Server",                            ipv4 },
183                 /*  74 */ { "Default IRC Server",                                       ipv4 },
184                 /*  75 */ { "StreetTalk Server",                                        ipv4 },
185                 /*  76 */ { "StreetTalk Directory Assistance Server", ipv4 }
186         };
187
188         text = opt[code].text;
189         /* Special cases */
190         switch (code) {
191                 /* Padding */
192                 case 0:
193                         /* check how much padding we have */
194                         for (i = voff + 1; i < eoff; i++ ) {
195                                 if (pd[i] != 0) {
196                                         break;
197                                 }
198                         }
199                         i = i - voff;
200                         proto_tree_add_text(bp_tree, voff, i, "Padding");
201                         consumed = i;
202                         return consumed;
203
204                 /* Policy Filter */
205                 case 21:
206                         /* one IP address pair */
207                         if (vlen == 8) {
208                                 proto_tree_add_text(bp_tree, voff, consumed,
209                                         "Option %d: %s = %s/%s", code, text,
210                                         ip_to_str((guint8*)&pd[voff+2]),
211                                         ip_to_str((guint8*)&pd[voff+6]));
212                         }
213                         /* > 1 IP address pair. Let's make a sub-tree */
214                         else {
215
216                                 vti = proto_tree_add_text(bp_tree, voff,
217                                         consumed, "Option %d: %s", code, text);
218                                 v_tree = proto_item_add_subtree(vti, ett_bootp_option);
219                                 for (i = voff + 2; i < voff + consumed; i += 8) {
220                                         proto_tree_add_text(v_tree, i, 8, "IP Address/Mask: %s/%s",
221                                                 ip_to_str((guint8*)&pd[i]),
222                                                 ip_to_str((guint8*)&pd[i+4]));
223                                 }
224                         }
225                         break;
226
227                 /* Static Route */
228                 case 33:
229                         /* one IP address pair */
230                         if (vlen == 8) {
231                                 proto_tree_add_text(bp_tree, voff, consumed,
232                                         "Option %d: %s = %s/%s", code, text,
233                                         ip_to_str((guint8*)&pd[voff+2]),
234                                         ip_to_str((guint8*)&pd[voff+6]));
235                         }
236                         /* > 1 IP address pair. Let's make a sub-tree */
237                         else {
238
239                                 vti = proto_tree_add_text(bp_tree, voff,
240                                         consumed, "Option %d: %s", code, text);
241                                 v_tree = proto_item_add_subtree(vti, ett_bootp_option);
242                                 for (i = voff + 2; i < voff + consumed; i += 8) {
243                                         proto_tree_add_text(v_tree, i, 8,
244                                                 "Destination IP Address/Router: %s/%s",
245                                                 ip_to_str((guint8*)&pd[i]),
246                                                 ip_to_str((guint8*)&pd[i+4]));
247                                 }
248                         }
249                         break;
250
251                 /* Vendor-Specific Info */
252                 case 43:
253                         proto_tree_add_text(bp_tree, voff, consumed,
254                                         "Option %d: %s", code, text);
255                         break;
256
257                 /* NetBIOS-over-TCP/IP Node Type */
258                 case 46:
259                         byte = pd[voff+2];
260                         proto_tree_add_text(bp_tree, voff, consumed,
261                                         "Option %d: %s = %s", code, text,
262                                         val_to_str(byte, nbnt_vals,
263                                             "Unknown (0x%02x)"));
264                         break;
265                                 
266                 /* DHCP Message Type */
267                 case 53:
268                         byte = pd[voff+2];
269                         if (byte > 0 && byte < 9) {
270                                 i = byte;
271                         }
272                         else {
273                                 i = 0;
274                         }
275                         proto_tree_add_text(bp_tree, voff, 3, "Option %d: %s = DHCP %s",
276                                 code, text, opt53_text[i]);
277                         break;
278
279                 /* Parameter Request List */
280                 case 55:
281                         vti = proto_tree_add_text(bp_tree, voff,
282                                 vlen + 2, "Option %d: %s", code, text);
283                         v_tree = proto_item_add_subtree(vti, ett_bootp_option);
284                         for (i = 0; i < vlen; i++) {
285                                 byte = pd[voff+2+i];
286                                 if (byte < NUM_OPT_INFOS) {
287                                         proto_tree_add_text(v_tree, voff+2+i, 1, "%d = %s",
288                                                         byte, opt[byte].text);
289                                 }
290                                 else {
291                                         proto_tree_add_text(vti, voff+2+i, 1,
292                                                 "Unknown Option Code: %d", byte);
293                                 }
294                         }
295                         break;
296
297                 /* Client Identifier */
298                 case 61:
299                         /* We *MAY* use hwtype/hwaddr. If we have 7 bytes, I'll
300                                 guess that the first is the hwtype, and the last 6 are
301                                 the hw addr */
302                         if (vlen == 7) {
303                                 vti = proto_tree_add_text(bp_tree, voff,
304                                         consumed, "Option %d: %s", code, text);
305                                 v_tree = proto_item_add_subtree(vti, ett_bootp_option);
306                                 proto_tree_add_text(v_tree, voff+2, 1,
307                                         "Hardware type: %s",
308                                         arphrdtype_to_str(pd[voff+2],
309                                                 "Unknown (0x%02x)"));
310                                 proto_tree_add_text(v_tree, voff+3, 6,
311                                         "Client hardware address: %s",
312                                         arphrdaddr_to_str((guint8*)&pd[voff+3],
313                                                 6, pd[voff+2]));
314                         }
315                         /* otherwise, it's opaque data */
316                         else {
317                                 proto_tree_add_text(bp_tree, voff, consumed,
318                                         "Option %d: %s (%d bytes)", code, text, vlen);
319                         }
320                         break;
321
322                 /* End Option */
323                 case 255:
324                         proto_tree_add_text(bp_tree, voff, 1, "End Option");
325                         consumed = 1;
326                         return consumed;
327
328                 default:
329                         /* nothing */
330                         break;
331         }
332
333         /* Normal cases */
334         if (code < NUM_OPT_INFOS) {
335                 text = opt[code].text;
336                 ftype = opt[code].ftype;
337
338                 switch (ftype) {
339                         case special:
340                                 return consumed;
341
342                         case ipv4:
343                                 /* one IP address */
344                                 if (vlen == 4) {
345                                         proto_tree_add_text(bp_tree, voff, consumed,
346                                                 "Option %d: %s = %s", code, text,
347                                                 ip_to_str((guint8*)&pd[voff+2]));
348                                 }
349                                 /* > 1 IP addresses. Let's make a sub-tree */
350                                 else {
351
352                                         vti = proto_tree_add_text(bp_tree, voff,
353                                                 consumed, "Option %d: %s", code, text);
354                                         v_tree = proto_item_add_subtree(vti, ett_bootp_option);
355                                         for (i = voff + 2; i < voff + consumed; i += 4) {
356                                                 proto_tree_add_text(v_tree, i, 4, "IP Address: %s",
357                                                         ip_to_str((guint8*)&pd[i]));
358                                         }
359                                 }
360                                 break;
361
362                         case string:
363                                 /* Fix for non null-terminated string supplied by
364                                  * John Lines <John.Lines@aeat.co.uk>
365                                  */
366                                 proto_tree_add_text(bp_tree, voff, consumed,
367                                                 "Option %d: %s = %.*s", code, text, vlen, &pd[voff+2]);
368                                 break;
369
370                         case opaque:
371                                 proto_tree_add_text(bp_tree, voff, consumed,
372                                                 "Option %d: %s (%d bytes)",
373                                                 code, text, vlen);
374                                 break;
375
376                         case val_u_short:
377                                 /* one IP address */
378                                 if (vlen == 2) {
379                                         proto_tree_add_text(bp_tree, voff, consumed,
380                                                         "Option %d: %s = %d", code, text,
381                                                         pntohs(&pd[voff+2]));
382                                 }
383                                 /* > 1 u_short */
384                                 else {
385                                         vti = proto_tree_add_text(bp_tree, voff,
386                                                 consumed, "Option %d: %s", code, text);
387                                         v_tree = proto_item_add_subtree(vti, ett_bootp_option);
388                                         for (i = voff + 2; i < voff + consumed; i += 2) {
389                                                 proto_tree_add_text(v_tree, i, 4, "Value: %d",
390                                                         pntohs(&pd[i]));
391                                         }
392                                 }
393                                 break;
394
395                         case val_u_long:
396                                 proto_tree_add_text(bp_tree, voff, consumed,
397                                                 "Option %d: %s = %d", code, text,
398                                                 pntohl(&pd[voff+2]));
399                                 break;
400
401                         case val_u_byte:
402                                 proto_tree_add_text(bp_tree, voff, consumed,
403                                                 "Option %d: %s = %d", code, text, pd[voff+2]);
404                                 break;
405
406                         case toggle:
407                                 i = pd[voff+2];
408                                 if (i != 0 && i != 1) {
409                                         proto_tree_add_text(bp_tree, voff, consumed,
410                                                         "Option %d: %s = Invalid Value %d", code, text,
411                                                         pd[voff+2]);
412                                 }
413                                 else {
414                                         proto_tree_add_text(bp_tree, voff, consumed,
415                                                         "Option %d: %s = %s", code, text,
416                                                         pd[voff+2] == 0 ? "Disabled" : "Enabled");
417                                 }
418                                 break;
419
420                         case yes_no:
421                                 i = pd[voff+2];
422                                 if (i != 0 && i != 1) {
423                                         proto_tree_add_text(bp_tree, voff, consumed,
424                                                         "Option %d: %s = Invalid Value %d", code, text,
425                                                         pd[voff+2]);
426                                 }
427                                 else {
428                                         proto_tree_add_text(bp_tree, voff, consumed,
429                                                         "Option %d: %s = %s", code, text,
430                                                         pd[voff+2] == 0 ? "No" : "Yes");
431                                 }
432                                 break;
433
434                         case time_in_secs:
435                                 time_secs = pntohl(&pd[voff+2]);
436                                 proto_tree_add_text(bp_tree, voff, consumed,
437                                         "Option %d: %s = %s", code, text,
438                                         ((time_secs == 0xffffffff) ?
439                                             "infinity" :
440                                             time_secs_to_str(time_secs)));
441                                 break;
442
443                         default:
444                                 proto_tree_add_text(bp_tree, voff, consumed,
445                                                 "Option %d: %s (%d bytes)", code, text, vlen);
446                 }
447         }
448         else {
449                 proto_tree_add_text(bp_tree, voff, consumed,
450                                 "Unknown Option Code: %d (%d bytes)", code, vlen);
451         }
452
453         return consumed;
454 }
455
456 void
457 dissect_bootp(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
458 {
459         proto_tree      *bp_tree;
460         proto_item      *ti;
461         int                     voff, eoff; /* vender offset, end offset */
462         guint32         ip_addr;
463
464         if (check_col(fd, COL_PROTOCOL))
465                 col_add_str(fd, COL_PROTOCOL, "BOOTP");
466
467         if (check_col(fd, COL_INFO)) {
468                 if (pd[offset] == 1) {
469                         col_add_fstr(fd, COL_INFO, "Boot Request from %s",
470                                 arphrdaddr_to_str((guint8*)&pd[offset+28],
471                                         pd[offset+2], pd[offset+1]));
472                 }
473                 else {
474                         col_add_str(fd, COL_INFO, "Boot Reply");
475                 }
476         }
477
478         if (tree) {
479                 ti = proto_tree_add_item(tree, proto_bootp, offset, END_OF_FRAME, NULL);
480                 bp_tree = proto_item_add_subtree(ti, ett_bootp);
481
482                 proto_tree_add_uint_format(bp_tree, hf_bootp_type, 
483                                            offset, 1,
484                                            pd[offset], 
485                                            pd[offset] == 1 ?
486                                            "Boot Request" : "Boot Reply");
487                 proto_tree_add_uint_format(bp_tree, hf_bootp_hw_type,
488                                            offset + 1, 1,
489                                            pd[offset+1],
490                                            "Hardware type: %s",
491                                            arphrdtype_to_str(pd[offset+1],
492                                                              "Unknown (0x%02x)"));
493                 proto_tree_add_item(bp_tree, hf_bootp_hw_len,
494                                     offset + 2, 1, pd[offset+2]);
495                 proto_tree_add_item(bp_tree, hf_bootp_hops,
496                                     offset + 3, 1, pd[offset+3]);
497                 proto_tree_add_item(bp_tree, hf_bootp_id,
498                                    offset + 4, 4, pntohl(&pd[offset+4]));
499                 proto_tree_add_item(bp_tree, hf_bootp_secs,
500                                     offset + 8, 2, pntohs(&pd[offset+8]));
501                 proto_tree_add_item(bp_tree, hf_bootp_flag,
502                                     offset + 10, 2, pd[offset+10] & 1);
503
504                 memcpy(&ip_addr, &pd[offset+12], sizeof(ip_addr));
505                 proto_tree_add_item(bp_tree, hf_bootp_ip_client, 
506                                     offset + 12, 4, ip_addr);
507                 memcpy(&ip_addr, &pd[offset+16], sizeof(ip_addr));
508                 proto_tree_add_item(bp_tree, hf_bootp_ip_your, 
509                                     offset + 16, 4, ip_addr);
510                 memcpy(&ip_addr, &pd[offset+20], sizeof(ip_addr));
511                 proto_tree_add_item(bp_tree, hf_bootp_ip_server,
512                                     offset + 20, 4, ip_addr);
513                 memcpy(&ip_addr, &pd[offset+24], sizeof(ip_addr));
514                 proto_tree_add_item(bp_tree, hf_bootp_ip_relay,
515                                     offset + 24, 4, ip_addr);
516
517                 proto_tree_add_bytes_format(bp_tree, hf_bootp_hw_addr, 
518                                            offset + 28, pd[offset+2],
519                                            &pd[offset+28],
520                                            "Client hardware address: %s",
521                                            arphrdaddr_to_str((guint8*)&pd[offset+28],
522                                                              pd[offset+2], pd[offset+1]));
523
524                 /* The server host name is optional */
525                 if (pd[offset+44]) {
526                         proto_tree_add_string_format(bp_tree, hf_bootp_server,
527                                                    offset + 44, 64,
528                                                    &pd[offset+44],
529                                                    "Server host name: %s",
530                                                    &pd[offset+44]);
531                 }
532                 else {
533                         proto_tree_add_string_format(bp_tree, hf_bootp_server,
534                                                    offset + 44, 64,
535                                                    &pd[offset+44],
536                                                    "Server host name not given");
537                 }
538
539                 /* Boot file */
540                 if (pd[offset+108]) {
541                         proto_tree_add_string_format(bp_tree, hf_bootp_file,
542                                                    offset + 108, 128,
543                                                    &pd[offset+108],
544                                                    "Boot file name: %s",
545                                                    &pd[offset+108]);
546                 }
547                 else {
548                         proto_tree_add_string_format(bp_tree, hf_bootp_file,
549                                                    offset + 108, 128,
550                                                    &pd[offset+108],
551                                                    "Boot file name not given");
552                 }
553
554                 if (pntohl(&pd[offset+236]) == 0x63825363) {
555                         proto_tree_add_ipv4_format(bp_tree, hf_bootp_cookie,
556                                                    offset + 236, 4,
557                                                    pd[offset+236],
558                                                    "Magic cookie: (OK)");
559                 }
560                 else {
561                         memcpy(&ip_addr, &pd[offset + 236], sizeof(ip_addr));
562                         proto_tree_add_item(bp_tree, hf_bootp_cookie,
563                                             offset + 236, 4, ip_addr);
564                 }
565
566                 voff = offset+240;
567                 eoff = pi.captured_len;
568
569                 while (voff < eoff) {
570                         voff += bootp_option(pd, bp_tree, voff, eoff);
571                 }
572         }
573 }
574
575 void
576 proto_register_bootp(void)
577 {
578   static hf_register_info hf[] = {
579     { &hf_bootp_type,
580       { "Message type",                 "bootp.type",    FT_UINT8,  BASE_NONE, NULL, 0x0,
581         "" }},
582
583     { &hf_bootp_hw_type,
584       { "Hardware type",                "bootp.hw.type", FT_UINT8,  BASE_HEX, NULL, 0x0,
585         "" }},
586
587     { &hf_bootp_hw_len,
588       { "Hardware address length",      "bootp.hw.len",  FT_UINT8,  BASE_DEC, NULL, 0x0,
589         "" }},
590
591     { &hf_bootp_hops,
592       { "Hops",                         "bootp.hops",    FT_UINT8,  BASE_DEC, NULL, 0x0,
593         "" }},
594
595     { &hf_bootp_id,
596       { "Transaction ID",               "bootp.id",      FT_UINT32, BASE_HEX, NULL, 0x0,
597         "" }},
598
599     { &hf_bootp_secs,
600       { "Seconds elapsed",              "bootp.secs",    FT_UINT16, BASE_DEC, NULL, 0x0,
601         "" }},
602
603     { &hf_bootp_flag,
604       { "Broadcast flag",               "bootp.flag",    FT_UINT16, BASE_DEC, NULL, 0x0,
605         "" }},
606
607     { &hf_bootp_ip_client,
608       { "Client IP address",            "bootp.ip.client",FT_IPv4,  BASE_NONE, NULL, 0x0,
609         "" }},
610
611     { &hf_bootp_ip_your,
612       { "Your (client) IP address",     "bootp.ip.your",  FT_IPv4,  BASE_NONE, NULL, 0x0,
613         "" }},
614
615     { &hf_bootp_ip_server,
616       { "Next server IP address",       "bootp.ip.server",FT_IPv4,  BASE_NONE, NULL, 0x0,
617         "" }},
618
619     { &hf_bootp_ip_relay,
620       { "Relay agent IP address",       "bootp.ip.relay", FT_IPv4,  BASE_NONE, NULL, 0x0,
621         "" }},
622
623     { &hf_bootp_hw_addr,
624       { "Client hardware address",      "bootp.hw.addr", FT_BYTES,  BASE_NONE, NULL, 0x0,
625         "" }},
626
627     { &hf_bootp_server,
628       { "Server host name",             "bootp.server",  FT_STRING, BASE_NONE, NULL, 0x0,
629         "" }},
630
631     { &hf_bootp_file,
632       { "Boot file name",               "bootp.file",    FT_STRING, BASE_NONE, NULL, 0x0,
633         "" }},
634
635     { &hf_bootp_cookie,
636       { "Magic cookie",                 "bootp.cookie",  FT_IPv4,   BASE_NONE, NULL, 0x0,
637         "" }},
638   };
639   static gint *ett[] = {
640     &ett_bootp,
641     &ett_bootp_option,
642   };
643   
644   proto_bootp = proto_register_protocol("Bootstrap Protocol", "bootp");
645   proto_register_field_array(proto_bootp, hf, array_length(hf));
646   proto_register_subtree_array(ett, array_length(ett));
647 }