/* packet-bootp.c
* Routines for BOOTP/DHCP packet disassembly
- * Gilbert Ramirez <gram@verdict.uthscsa.edu>
+ * Gilbert Ramirez <gram@xiexie.org>
*
- * $Id: packet-bootp.c,v 1.12 1998/11/18 23:58:54 gerald Exp $
+ * $Id: packet-bootp.c,v 1.33 2000/05/19 04:54:32 gram Exp $
*
* The information used comes from:
* RFC 2132: DHCP Options and BOOTP Vendor Extensions
* RFC 2131: Dynamic Host Configuration Protocol
*
* Ethereal - Network traffic analyzer
- * By Gerald Combs <gerald@unicom.net>
+ * By Gerald Combs <gerald@zing.org>
* Copyright 1998 Gerald Combs
*
*
# include "config.h"
#endif
-#include <gtk/gtk.h>
-
-#include <stdio.h>
-
#ifdef HAVE_SYS_TYPES_H
# include <sys/types.h>
#endif
-#ifdef HAVE_NETINET_IN_H
-# include <netinet/in.h>
-#endif
-
-
-#include "ethereal.h"
+#include <glib.h>
#include "packet.h"
-#include "etypes.h"
+#include "packet-arp.h"
+
+static int proto_bootp = -1;
+static int hf_bootp_type = -1;
+static int hf_bootp_hw_type = -1;
+static int hf_bootp_hw_len = -1;
+static int hf_bootp_hops = -1;
+static int hf_bootp_id = -1;
+static int hf_bootp_secs = -1;
+static int hf_bootp_flag = -1;
+static int hf_bootp_ip_client = -1;
+static int hf_bootp_ip_your = -1;
+static int hf_bootp_ip_server = -1;
+static int hf_bootp_ip_relay = -1;
+static int hf_bootp_hw_addr = -1;
+static int hf_bootp_server = -1;
+static int hf_bootp_file = -1;
+static int hf_bootp_cookie = -1;
+static int hf_bootp_dhcp = -1;
+
+static guint ett_bootp = -1;
+static guint ett_bootp_option = -1;
+
+static char * is_dhcp ;
+
+#define UDP_PORT_BOOTPS 67
enum field_type { none, ipv4, string, toggle, yes_no, special, opaque,
+ time_in_secs,
val_u_byte, val_u_short, val_u_long,
val_s_long };
};
#define NUM_OPT_INFOS 77
+#define NUM_O63_SUBOPTS 11
/* returns the number of bytes consumed by this option */
-int
-bootp_option(const u_char *pd, GtkWidget *bp_tree, int voff, int eoff)
+static int
+bootp_option(const u_char *pd, proto_tree *bp_tree, int voff, int eoff)
{
char *text;
enum field_type ftype;
u_char code = pd[voff];
int vlen = pd[voff+1];
- int i, consumed = 1; /* if code is unknown, consume 1 byte */
- GtkWidget *vti, *v_tree;
+ u_char byte;
+ int i,slask,optp, consumed = vlen + 2;
+ u_long time_secs;
+ proto_tree *v_tree,*o63_v_tree;
+ proto_item *vti;
+
- char *opt53_text[] = {
+ static const char *opt53_text[] = {
"Unknown Message Type",
"Discover",
"Offer",
"Release",
"Inform"
};
+ static const value_string nbnt_vals[] = {
+ {0x1, "B-node" },
+ {0x2, "P-node" },
+ {0x4, "M-node" },
+ {0x8, "H-node" },
+ {0, NULL } };
+
+ struct o63_opt_info {
+ char *truet;
+ char *falset;
+ enum field_type ft;
+ };
+
+ static struct o63_opt_info o63_opt[]= {
+ /* 0 */ {"","",none},
+ /* 1 */ {"NWIP does not exist on subnet","",string},
+ /* 2 */ {"NWIP exist in options area","",string},
+ /* 3 */ {"NWIP exists in sname/file","",string},
+ /* 4 */ {"NWIP exists, but too big","",string},
+ /* 5 */ {"Broadcast for nearest Netware server","Do NOT Broadcast for nearest Netware server",yes_no},
+ /* 6 */ {"Preferred DSS server","",ipv4},
+ /* 7 */ {"Nearest NWIP server","",ipv4},
+ /* 8 */ {"Autoretries","",val_u_short},
+ /* 9 */ {"Autoretry delay, secs ","",val_u_short},
+ /* 10*/ {"Support NetWare/IP v1.1","Do NOT support NetWare/IP v1.1",yes_no},
+ /* 11*/ {"Primary DSS ", "" , special} };
+
static struct opt_info opt[] = {
/* 0 */ { "Padding", none },
/* 21 */ { "Policy Filter", special },
/* 22 */ { "Maximum Datagram Reassembly Size", val_u_short },
/* 23 */ { "Default IP Time-to-Live", val_u_byte },
- /* 24 */ { "Path MTU Aging Timeout", val_u_long },
+ /* 24 */ { "Path MTU Aging Timeout", time_in_secs },
/* 25 */ { "Path MTU Plateau Table", val_u_short },
/* 26 */ { "Interface MTU", val_u_short },
/* 27 */ { "All Subnets are Local", yes_no },
/* 32 */ { "Router Solicitation Address", ipv4 },
/* 33 */ { "Static Route", special },
/* 34 */ { "Trailer Encapsulation", toggle },
- /* 35 */ { "ARP Cache Timeout", val_u_long },
+ /* 35 */ { "ARP Cache Timeout", time_in_secs },
/* 36 */ { "Ethernet Encapsulation", toggle },
/* 37 */ { "TCP Default TTL", val_u_byte },
- /* 38 */ { "TCP Keepalive Interval", val_u_long },
+ /* 38 */ { "TCP Keepalive Interval", time_in_secs },
/* 39 */ { "TCP Keepalive Garbage", toggle },
/* 40 */ { "Network Information Service Domain", string },
/* 41 */ { "Network Information Service Servers", ipv4 },
/* 48 */ { "X Window System Font Server", ipv4 },
/* 49 */ { "X Window System Display Manager", ipv4 },
/* 50 */ { "Requested IP Address", ipv4 },
- /* 51 */ { "IP Address Lease Time", val_u_long },
+ /* 51 */ { "IP Address Lease Time", time_in_secs },
/* 52 */ { "Option Overload", special },
/* 53 */ { "DHCP Message Type", special },
/* 54 */ { "Server Identifier", ipv4 },
- /* 55 */ { "Parameter Request List", opaque },
+ /* 55 */ { "Parameter Request List", special },
/* 56 */ { "Message", string },
/* 57 */ { "Maximum DHCP Message Size", val_u_short },
- /* 58 */ { "Renewal Time Value", val_u_long },
- /* 59 */ { "Rebinding Time Value", val_u_long },
+ /* 58 */ { "Renewal Time Value", time_in_secs },
+ /* 59 */ { "Rebinding Time Value", time_in_secs },
/* 60 */ { "Vendor class identifier", opaque },
/* 61 */ { "Client identifier", special },
+ /* 62 */ { "Novell/Netware IP domain", string },
+ /* 63 */ { "Novell Options", special },
/* 64 */ { "Network Information Service+ Domain", string },
/* 65 */ { "Network Information Service+ Servers", ipv4 },
/* 66 */ { "TFTP Server Name", string },
}
}
i = i - voff;
- add_item_to_tree(bp_tree, voff, i, "Padding");
+ proto_tree_add_text(bp_tree, NullTVB, voff, i, "Padding");
consumed = i;
return consumed;
case 21:
/* one IP address pair */
if (vlen == 8) {
- add_item_to_tree(bp_tree, voff, consumed,
+ proto_tree_add_text(bp_tree, NullTVB, voff, consumed,
"Option %d: %s = %s/%s", code, text,
ip_to_str((guint8*)&pd[voff+2]),
ip_to_str((guint8*)&pd[voff+6]));
/* > 1 IP address pair. Let's make a sub-tree */
else {
- vti = add_item_to_tree(GTK_WIDGET(bp_tree), voff,
+ vti = proto_tree_add_text(bp_tree, NullTVB, voff,
consumed, "Option %d: %s", code, text);
- v_tree = gtk_tree_new();
- add_subtree(vti, v_tree, ETT_BOOTP_OPTION);
+ v_tree = proto_item_add_subtree(vti, ett_bootp_option);
for (i = voff + 2; i < voff + consumed; i += 8) {
- add_item_to_tree(v_tree, i, 4, "IP Address/Mask: %s/%s",
+ proto_tree_add_text(v_tree, NullTVB, i, 8, "IP Address/Mask: %s/%s",
ip_to_str((guint8*)&pd[i]),
ip_to_str((guint8*)&pd[i+4]));
}
}
+ break;
/* Static Route */
case 33:
/* one IP address pair */
if (vlen == 8) {
- add_item_to_tree(bp_tree, voff, consumed,
+ proto_tree_add_text(bp_tree, NullTVB, voff, consumed,
"Option %d: %s = %s/%s", code, text,
ip_to_str((guint8*)&pd[voff+2]),
ip_to_str((guint8*)&pd[voff+6]));
/* > 1 IP address pair. Let's make a sub-tree */
else {
- vti = add_item_to_tree(GTK_WIDGET(bp_tree), voff,
+ vti = proto_tree_add_text(bp_tree, NullTVB, voff,
consumed, "Option %d: %s", code, text);
- v_tree = gtk_tree_new();
- add_subtree(vti, v_tree, ETT_BOOTP_OPTION);
+ v_tree = proto_item_add_subtree(vti, ett_bootp_option);
for (i = voff + 2; i < voff + consumed; i += 8) {
- add_item_to_tree(v_tree, i, 4,
+ proto_tree_add_text(v_tree, NullTVB, i, 8,
"Destination IP Address/Router: %s/%s",
ip_to_str((guint8*)&pd[i]),
ip_to_str((guint8*)&pd[i+4]));
}
}
+ break;
+
+ /* Vendor-Specific Info */
+ case 43:
+ proto_tree_add_text(bp_tree, NullTVB, voff, consumed,
+ "Option %d: %s", code, text);
+ break;
+ /* NetBIOS-over-TCP/IP Node Type */
+ case 46:
+ byte = pd[voff+2];
+ proto_tree_add_text(bp_tree, NullTVB, voff, consumed,
+ "Option %d: %s = %s", code, text,
+ val_to_str(byte, nbnt_vals,
+ "Unknown (0x%02x)"));
+ break;
+
/* DHCP Message Type */
case 53:
- if (pd[voff+2] > 0 && pd[voff+2] < 9) {
- i = pd[voff + 2];
+ byte = pd[voff+2];
+ if (byte > 0 && byte < 9) {
+ i = byte;
}
else {
i = 0;
}
- add_item_to_tree(bp_tree, voff, 3, "Option %d: %s = DHCP %s",
+ proto_tree_add_text(bp_tree, NullTVB, voff, 3, "Option %d: %s = DHCP %s",
code, text, opt53_text[i]);
- return vlen + 2;
+ is_dhcp = (char *) opt53_text[i];
+ break;
+
+ /* Parameter Request List */
+ case 55:
+ vti = proto_tree_add_text(bp_tree, NullTVB, voff,
+ vlen + 2, "Option %d: %s", code, text);
+ v_tree = proto_item_add_subtree(vti, ett_bootp_option);
+ for (i = 0; i < vlen; i++) {
+ byte = pd[voff+2+i];
+ if (byte < NUM_OPT_INFOS) {
+ proto_tree_add_text(v_tree, NullTVB, voff+2+i, 1, "%d = %s",
+ byte, opt[byte].text);
+ }
+ else {
+ proto_tree_add_text(vti, NullTVB, voff+2+i, 1,
+ "Unknown Option Code: %d", byte);
+ }
+ }
+ break;
/* Client Identifier */
case 61:
- consumed = vlen + 2;
/* We *MAY* use hwtype/hwaddr. If we have 7 bytes, I'll
guess that the first is the hwtype, and the last 6 are
the hw addr */
- if (pd[voff+1] == 7) {
- vti = add_item_to_tree(GTK_WIDGET(bp_tree), voff,
+ if (vlen == 7) {
+ vti = proto_tree_add_text(bp_tree, NullTVB, voff,
consumed, "Option %d: %s", code, text);
- v_tree = gtk_tree_new();
- add_subtree(vti, v_tree, ETT_BOOTP_OPTION);
- add_item_to_tree(v_tree, voff+2, 1,
- "Hardware type: 0x%02x", pd[voff+2]);
- add_item_to_tree(v_tree, voff+3, 6,
+ v_tree = proto_item_add_subtree(vti, ett_bootp_option);
+ proto_tree_add_text(v_tree, NullTVB, voff+2, 1,
+ "Hardware type: %s",
+ arphrdtype_to_str(pd[voff+2],
+ "Unknown (0x%02x)"));
+ proto_tree_add_text(v_tree, NullTVB, voff+3, 6,
"Client hardware address: %s",
- ether_to_str((guint8*)&pd[voff+3]));
+ arphrdaddr_to_str((guint8*)&pd[voff+3],
+ 6, pd[voff+2]));
}
/* otherwise, it's opaque data */
else {
- add_item_to_tree(bp_tree, voff, consumed,
+ proto_tree_add_text(bp_tree, NullTVB, voff, consumed,
"Option %d: %s (%d bytes)", code, text, vlen);
}
- return consumed;
+ break;
+
+ /* NetWare/IP options */
+ case 63:
+ vti = proto_tree_add_text(bp_tree, NullTVB, voff,
+ consumed, "Option %d: %s", code, text);
+ v_tree = proto_item_add_subtree(vti, ett_bootp_option);
+
+ i=1;
+ optp=voff+2;
+ while ( optp < (voff+consumed) ) {
+ if (pd[optp] > NUM_O63_SUBOPTS) {
+ proto_tree_add_text(v_tree, NullTVB,optp,1,"Unknown suboption %d", pd[optp]);
+ optp++;
+ } else {
+
+ switch (o63_opt[pd[optp]].ft) {
+
+ case string:
+ proto_tree_add_text(v_tree, NullTVB, optp, 2, "Suboption %d: %s", pd[optp], o63_opt[pd[optp]].truet);
+ optp+=2;
+ break;
+
+ case yes_no:
+ if (pd[optp+2]==1) {
+ proto_tree_add_text(v_tree, NullTVB, optp, 3, "Suboption %d: %s", pd[optp], o63_opt[pd[optp]].truet);
+ } else {
+ proto_tree_add_text(v_tree, NullTVB, optp, 3, "Suboption %d: %s" , pd[optp], o63_opt[pd[optp]].falset);
+ }
+ optp+=3;
+ break;
+
+ case special:
+ proto_tree_add_text(v_tree, NullTVB, optp, 6,
+ "Suboption %d: %s = %s" ,
+ pd[optp], o63_opt[pd[optp]].truet,
+ ip_to_str((guint8*)&pd[optp+2]));
+ optp=optp+6;
+ break;
+
+ case val_u_short:
+ proto_tree_add_text(v_tree, NullTVB, optp, 3, "Suboption %d: %s = %d",pd[optp], o63_opt[pd[optp]].truet, pd[optp+2]);
+ optp+=3;
+ break;
+
+ case ipv4:
+ /* one IP address */
+ if (pd[optp+1] == 4) {
+ proto_tree_add_text(v_tree, NullTVB, optp, 6,
+ "Suboption %d : %s = %s" ,
+ pd[optp], o63_opt[pd[optp]].truet,
+ ip_to_str((guint8*)&pd[optp+2]));
+ optp=optp+6;
+ }
+ /* > 1 IP addresses. Let's make a sub-tree */
+ else {
+
+ vti = proto_tree_add_text(v_tree, NullTVB, optp,
+ pd[optp+1]+2, "Suboption %d: %s",
+ pd[optp], o63_opt[pd[optp]].truet);
+ o63_v_tree = proto_item_add_subtree(vti, ett_bootp_option);
+ for (slask = optp + 2 ; slask < optp+pd[optp+1]; slask += 4) {
+ proto_tree_add_text(o63_v_tree, NullTVB, slask, 4, "IP Address: %s",
+ ip_to_str((guint8*)&pd[slask]));
+ }
+ optp=slask;
+ }
+ break;
+ default:
+ proto_tree_add_text(v_tree, NullTVB,optp,1,"Unknown suboption %d", pd[optp]);
+ optp++;
+ break;
+ }
+ }
+ i++;
+ }
+ break;
/* End Option */
case 255:
- add_item_to_tree(bp_tree, voff, 1, "End Option");
+ proto_tree_add_text(bp_tree, NullTVB, voff, 1, "End Option");
consumed = 1;
return consumed;
}
/* Normal cases */
- consumed = vlen + 2;
if (code < NUM_OPT_INFOS) {
text = opt[code].text;
ftype = opt[code].ftype;
switch (ftype) {
+ case special:
+ return consumed;
+
case ipv4:
/* one IP address */
if (vlen == 4) {
- add_item_to_tree(bp_tree, voff, consumed,
+ proto_tree_add_text(bp_tree, NullTVB, voff, consumed,
"Option %d: %s = %s", code, text,
ip_to_str((guint8*)&pd[voff+2]));
}
/* > 1 IP addresses. Let's make a sub-tree */
else {
- vti = add_item_to_tree(GTK_WIDGET(bp_tree), voff,
+ vti = proto_tree_add_text(bp_tree, NullTVB, voff,
consumed, "Option %d: %s", code, text);
- v_tree = gtk_tree_new();
- add_subtree(vti, v_tree, ETT_BOOTP_OPTION);
+ v_tree = proto_item_add_subtree(vti, ett_bootp_option);
for (i = voff + 2; i < voff + consumed; i += 4) {
- add_item_to_tree(v_tree, i, 4, "IP Address: %s",
+ proto_tree_add_text(v_tree, NullTVB, i, 4, "IP Address: %s",
ip_to_str((guint8*)&pd[i]));
}
}
break;
case string:
- add_item_to_tree(bp_tree, voff, consumed,
- "Option %d: %s = %.*s", code, text, pd[voff+2], &pd[voff+2]);
+ /* Fix for non null-terminated string supplied by
+ * John Lines <John.Lines@aeat.co.uk>
+ */
+ proto_tree_add_text(bp_tree, NullTVB, voff, consumed,
+ "Option %d: %s = %.*s", code, text, vlen, &pd[voff+2]);
break;
case opaque:
- add_item_to_tree(bp_tree, voff, consumed,
+ proto_tree_add_text(bp_tree, NullTVB, voff, consumed,
"Option %d: %s (%d bytes)",
code, text, vlen);
break;
case val_u_short:
/* one IP address */
if (vlen == 2) {
- add_item_to_tree(bp_tree, voff, consumed,
+ proto_tree_add_text(bp_tree, NullTVB, voff, consumed,
"Option %d: %s = %d", code, text,
pntohs(&pd[voff+2]));
}
/* > 1 u_short */
else {
- vti = add_item_to_tree(GTK_WIDGET(bp_tree), voff,
+ vti = proto_tree_add_text(bp_tree, NullTVB, voff,
consumed, "Option %d: %s", code, text);
- v_tree = gtk_tree_new();
- add_subtree(vti, v_tree, ETT_BOOTP_OPTION);
+ v_tree = proto_item_add_subtree(vti, ett_bootp_option);
for (i = voff + 2; i < voff + consumed; i += 2) {
- add_item_to_tree(v_tree, i, 4, "Value: %d",
+ proto_tree_add_text(v_tree, NullTVB, i, 4, "Value: %d",
pntohs(&pd[i]));
}
}
break;
case val_u_long:
- add_item_to_tree(bp_tree, voff, consumed,
+ proto_tree_add_text(bp_tree, NullTVB, voff, consumed,
"Option %d: %s = %d", code, text,
pntohl(&pd[voff+2]));
break;
case val_u_byte:
- add_item_to_tree(bp_tree, voff, consumed,
+ proto_tree_add_text(bp_tree, NullTVB, voff, consumed,
"Option %d: %s = %d", code, text, pd[voff+2]);
break;
case toggle:
i = pd[voff+2];
if (i != 0 && i != 1) {
- add_item_to_tree(bp_tree, voff, consumed,
+ proto_tree_add_text(bp_tree, NullTVB, voff, consumed,
"Option %d: %s = Invalid Value %d", code, text,
pd[voff+2]);
}
else {
- add_item_to_tree(bp_tree, voff, consumed,
+ proto_tree_add_text(bp_tree, NullTVB, voff, consumed,
"Option %d: %s = %s", code, text,
pd[voff+2] == 0 ? "Disabled" : "Enabled");
}
case yes_no:
i = pd[voff+2];
if (i != 0 && i != 1) {
- add_item_to_tree(bp_tree, voff, consumed,
+ proto_tree_add_text(bp_tree, NullTVB, voff, consumed,
"Option %d: %s = Invalid Value %d", code, text,
pd[voff+2]);
}
else {
- add_item_to_tree(bp_tree, voff, consumed,
+ proto_tree_add_text(bp_tree, NullTVB, voff, consumed,
"Option %d: %s = %s", code, text,
pd[voff+2] == 0 ? "No" : "Yes");
}
break;
+ case time_in_secs:
+ time_secs = pntohl(&pd[voff+2]);
+ proto_tree_add_text(bp_tree, NullTVB, voff, consumed,
+ "Option %d: %s = %s", code, text,
+ ((time_secs == 0xffffffff) ?
+ "infinity" :
+ time_secs_to_str(time_secs)));
+ break;
+
default:
- add_item_to_tree(bp_tree, voff, consumed,
+ proto_tree_add_text(bp_tree, NullTVB, voff, consumed,
"Option %d: %s (%d bytes)", code, text, vlen);
}
}
else {
- add_item_to_tree(bp_tree, voff, consumed,
+ proto_tree_add_text(bp_tree, NullTVB, voff, consumed,
"Unknown Option Code: %d (%d bytes)", code, vlen);
}
return consumed;
}
-void
-dissect_bootp(const u_char *pd, int offset, frame_data *fd, GtkTree *tree)
+static void
+dissect_bootp(const u_char *pd, int offset, frame_data *fd, proto_tree *tree)
{
- GtkWidget *bp_tree, *ti;
+ proto_tree *bp_tree;
+ proto_item *ti;
int voff, eoff; /* vender offset, end offset */
+ guint32 ip_addr;
+
+ is_dhcp = NULL;
if (check_col(fd, COL_PROTOCOL))
col_add_str(fd, COL_PROTOCOL, "BOOTP");
if (check_col(fd, COL_INFO)) {
- /* if hwaddr is 6 bytes, assume MAC */
- if (pd[offset] == 1 && pd[offset+2] == 6) {
+ if (pd[offset] == 1) {
col_add_fstr(fd, COL_INFO, "Boot Request from %s",
- ether_to_str((guint8*)&pd[offset+28]));
+ arphrdaddr_to_str((guint8*)&pd[offset+28],
+ pd[offset+2], pd[offset+1]));
}
else {
- col_add_str(fd, COL_INFO, pd[offset] == 1 ? "Boot Request" :
- "Boot Reply");
+ col_add_str(fd, COL_INFO, "Boot Reply");
}
}
if (tree) {
- ti = add_item_to_tree(GTK_WIDGET(tree), offset, END_OF_FRAME,
- "Bootstrap Protocol");
- bp_tree = gtk_tree_new();
- add_subtree(ti, bp_tree, ETT_BOOTP);
-
- add_item_to_tree(bp_tree, offset, 1, pd[offset] == 1 ?
- "Boot Request" : "Boot Reply");
- add_item_to_tree(bp_tree, offset + 1, 1,
- "Hardware type: 0x%02x", pd[offset+1]);
- add_item_to_tree(bp_tree, offset + 2, 1,
- "Hardware address length: %d", pd[offset+2]);
- add_item_to_tree(bp_tree, offset + 3, 1,
- "Hops: %d", pd[offset+3]);
- add_item_to_tree(bp_tree, offset + 4, 4,
- "Transaction ID: 0x%08x", pntohl(&pd[offset+4]));
- add_item_to_tree(bp_tree, offset + 8, 2,
- "Seconds elapsed: %d", pntohs(&pd[offset+8]));
- add_item_to_tree(bp_tree, offset + 10, 2,
- "Broadcast flag: %d", pd[offset+10] & 1);
- add_item_to_tree(bp_tree, offset + 12, 4,
- "Client IP address: %s", ip_to_str((guint8*)&pd[offset+12]));
- add_item_to_tree(bp_tree, offset + 16, 4,
- "Your (client) IP address: %s", ip_to_str((guint8*)&pd[offset+16]));
- add_item_to_tree(bp_tree, offset + 20, 4,
- "Next server IP address: %s", ip_to_str((guint8*)&pd[offset+20]));
- add_item_to_tree(bp_tree, offset + 24, 4,
- "Relay agent IP address: %s", ip_to_str((guint8*)&pd[offset+24]));
-
- /* If HW address is 6 bytes, assume MAC. */
- if (pd[offset+2] == 6) {
- add_item_to_tree(bp_tree, offset + 28, 6,
- "Client hardware address: %s",
- ether_to_str((guint8*)&pd[offset+28]));
+ ti = proto_tree_add_item(tree, proto_bootp, NullTVB, offset, END_OF_FRAME, NULL);
+ bp_tree = proto_item_add_subtree(ti, ett_bootp);
+
+ proto_tree_add_uint_format(bp_tree, hf_bootp_type, NullTVB,
+ offset, 1,
+ pd[offset],
+ pd[offset] == 1 ?
+ "Boot Request" : "Boot Reply");
+ proto_tree_add_uint_format(bp_tree, hf_bootp_hw_type, NullTVB,
+ offset + 1, 1,
+ pd[offset+1],
+ "Hardware type: %s",
+ arphrdtype_to_str(pd[offset+1],
+ "Unknown (0x%02x)"));
+ proto_tree_add_item(bp_tree, hf_bootp_hw_len, NullTVB,
+ offset + 2, 1, pd[offset+2]);
+ proto_tree_add_item(bp_tree, hf_bootp_hops, NullTVB,
+ offset + 3, 1, pd[offset+3]);
+ proto_tree_add_item(bp_tree, hf_bootp_id, NullTVB,
+ offset + 4, 4, pntohl(&pd[offset+4]));
+ proto_tree_add_item(bp_tree, hf_bootp_secs, NullTVB,
+ offset + 8, 2, pntohs(&pd[offset+8]));
+ proto_tree_add_item(bp_tree, hf_bootp_flag, NullTVB,
+ offset + 10, 2, pntohs(&pd[offset+10]) & 0x8000);
+
+ memcpy(&ip_addr, &pd[offset+12], sizeof(ip_addr));
+ proto_tree_add_item(bp_tree, hf_bootp_ip_client, NullTVB,
+ offset + 12, 4, ip_addr);
+ memcpy(&ip_addr, &pd[offset+16], sizeof(ip_addr));
+ proto_tree_add_item(bp_tree, hf_bootp_ip_your, NullTVB,
+ offset + 16, 4, ip_addr);
+ memcpy(&ip_addr, &pd[offset+20], sizeof(ip_addr));
+ proto_tree_add_item(bp_tree, hf_bootp_ip_server, NullTVB,
+ offset + 20, 4, ip_addr);
+ memcpy(&ip_addr, &pd[offset+24], sizeof(ip_addr));
+ proto_tree_add_item(bp_tree, hf_bootp_ip_relay, NullTVB,
+ offset + 24, 4, ip_addr);
+
+ if (pd[offset+2] > 0) {
+ proto_tree_add_bytes_format(bp_tree, hf_bootp_hw_addr, NullTVB,
+ offset + 28, pd[offset+2],
+ &pd[offset+28],
+ "Client hardware address: %s",
+ arphrdaddr_to_str((guint8*)&pd[offset+28],
+ pd[offset+2], pd[offset+1]));
}
else {
- add_item_to_tree(bp_tree, offset + 28, 16,
- "Client hardware address: %02x:%02x%02x:%02x:%02x:%02x:%02x:%02x%02x:%02x%02x:%02x:%02x:%02x:%02x:%02x",
- pd[offset+28], pd[offset+29], pd[offset+30], pd[offset+31],
- pd[offset+32], pd[offset+33], pd[offset+34], pd[offset+35],
- pd[offset+36], pd[offset+37], pd[offset+38], pd[offset+39],
- pd[offset+40], pd[offset+41], pd[offset+42], pd[offset+43]);
+ proto_tree_add_item(bp_tree, hf_bootp_hw_addr, NullTVB,
+ offset + 28, 0, NULL);
}
/* The server host name is optional */
if (pd[offset+44]) {
- add_item_to_tree(bp_tree, offset + 44, 64,
- "Server host name: %s", &pd[offset+44]);
+ proto_tree_add_string_format(bp_tree, hf_bootp_server, NullTVB,
+ offset + 44, 64,
+ &pd[offset+44],
+ "Server host name: %s",
+ &pd[offset+44]);
}
else {
- add_item_to_tree(bp_tree, offset + 44, 64,
- "Server host name not given");
+ proto_tree_add_string_format(bp_tree, hf_bootp_server, NullTVB,
+ offset + 44, 64,
+ &pd[offset+44],
+ "Server host name not given");
}
/* Boot file */
if (pd[offset+108]) {
- add_item_to_tree(bp_tree, offset + 108, 128,
- "Boot file name: %s", &pd[offset+108]);
+ proto_tree_add_string_format(bp_tree, hf_bootp_file, NullTVB,
+ offset + 108, 128,
+ &pd[offset+108],
+ "Boot file name: %s",
+ &pd[offset+108]);
}
else {
- add_item_to_tree(bp_tree, offset + 108, 128,
- "Boot file name not given");
+ proto_tree_add_string_format(bp_tree, hf_bootp_file, NullTVB,
+ offset + 108, 128,
+ &pd[offset+108],
+ "Boot file name not given");
}
- if (pntohl(&pd[offset+236]) == 0x63538263) {
- add_item_to_tree(bp_tree, offset + 236, 4,
- "Magic cookie: %s (generic)",
- ip_to_str((guint8*)&pd[offset+236]));
+ if (pntohl(&pd[offset+236]) == 0x63825363) {
+ proto_tree_add_ipv4_format(bp_tree, hf_bootp_cookie, NullTVB,
+ offset + 236, 4,
+ pd[offset+236],
+ "Magic cookie: (OK)");
}
else {
- add_item_to_tree(bp_tree, offset + 236, 4,
- "Magic cookie: %s",
- ip_to_str((guint8*)&pd[offset+236]));
+ memcpy(&ip_addr, &pd[offset + 236], sizeof(ip_addr));
+ proto_tree_add_item(bp_tree, hf_bootp_cookie, NullTVB,
+ offset + 236, 4, ip_addr);
}
voff = offset+240;
- eoff = fd->cap_len;
+ eoff = pi.captured_len;
while (voff < eoff) {
voff += bootp_option(pd, bp_tree, voff, eoff);
}
+ if (is_dhcp != NULL ) {
+ if (check_col(fd, COL_PROTOCOL))
+ col_add_str(fd, COL_PROTOCOL, "DHCP");
+ if (check_col(fd, COL_INFO))
+ col_add_fstr(fd, COL_INFO, "DHCP %-8s - Trans. ID 0x%x", is_dhcp, pntohl(&pd[offset+4]) );
+ proto_tree_add_item_hidden(bp_tree, hf_bootp_dhcp, NullTVB, 0, 0, 1);
+ }
}
}
+void
+proto_register_bootp(void)
+{
+ static hf_register_info hf[] = {
+ { &hf_bootp_dhcp,
+ { "Frame is DHCP", "bootp.dhcp", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
+ "" }},
+
+ { &hf_bootp_type,
+ { "Message type", "bootp.type", FT_UINT8, BASE_NONE, NULL, 0x0,
+ "" }},
+
+ { &hf_bootp_hw_type,
+ { "Hardware type", "bootp.hw.type", FT_UINT8, BASE_HEX, NULL, 0x0,
+ "" }},
+
+ { &hf_bootp_hw_len,
+ { "Hardware address length", "bootp.hw.len", FT_UINT8, BASE_DEC, NULL, 0x0,
+ "" }},
+
+ { &hf_bootp_hops,
+ { "Hops", "bootp.hops", FT_UINT8, BASE_DEC, NULL, 0x0,
+ "" }},
+
+ { &hf_bootp_id,
+ { "Transaction ID", "bootp.id", FT_UINT32, BASE_HEX, NULL, 0x0,
+ "" }},
+
+ { &hf_bootp_secs,
+ { "Seconds elapsed", "bootp.secs", FT_UINT16, BASE_DEC, NULL, 0x0,
+ "" }},
+
+ { &hf_bootp_flag,
+ { "Broadcast flag", "bootp.flag", FT_UINT16, BASE_HEX, NULL, 0x0,
+ "" }},
+
+ { &hf_bootp_ip_client,
+ { "Client IP address", "bootp.ip.client",FT_IPv4, BASE_NONE, NULL, 0x0,
+ "" }},
+
+ { &hf_bootp_ip_your,
+ { "Your (client) IP address", "bootp.ip.your", FT_IPv4, BASE_NONE, NULL, 0x0,
+ "" }},
+
+ { &hf_bootp_ip_server,
+ { "Next server IP address", "bootp.ip.server",FT_IPv4, BASE_NONE, NULL, 0x0,
+ "" }},
+
+ { &hf_bootp_ip_relay,
+ { "Relay agent IP address", "bootp.ip.relay", FT_IPv4, BASE_NONE, NULL, 0x0,
+ "" }},
+
+ { &hf_bootp_hw_addr,
+ { "Client hardware address", "bootp.hw.addr", FT_BYTES, BASE_NONE, NULL, 0x0,
+ "" }},
+
+ { &hf_bootp_server,
+ { "Server host name", "bootp.server", FT_STRING, BASE_NONE, NULL, 0x0,
+ "" }},
+
+ { &hf_bootp_file,
+ { "Boot file name", "bootp.file", FT_STRING, BASE_NONE, NULL, 0x0,
+ "" }},
+
+ { &hf_bootp_cookie,
+ { "Magic cookie", "bootp.cookie", FT_IPv4, BASE_NONE, NULL, 0x0,
+ "" }},
+ };
+ static gint *ett[] = {
+ &ett_bootp,
+ &ett_bootp_option,
+ };
+
+ proto_bootp = proto_register_protocol("Bootstrap Protocol", "bootp");
+ proto_register_field_array(proto_bootp, hf, array_length(hf));
+ proto_register_subtree_array(ett, array_length(ett));
+}
+
+void
+proto_reg_handoff_bootp(void)
+{
+ dissector_add("udp.port", UDP_PORT_BOOTPS, dissect_bootp);
+}