* Routines for BOOTP/DHCP packet disassembly
* Gilbert Ramirez <gram@xiexie.org>
*
- * $Id: packet-bootp.c,v 1.46 2001/01/22 08:03:44 guy Exp $
+ * $Id: packet-bootp.c,v 1.54 2001/06/18 02:17:45 guy Exp $
*
* The information used comes from:
* RFC 951: Bootstrap Protocol
* RFC 2131: Dynamic Host Configuration Protocol
* RFC 2132: DHCP Options and BOOTP Vendor Extensions
* RFC 2489: Procedure for Defining New DHCP Options
+ * RFC 3046: DHCP Relay Agent Information Option
* BOOTP and DHCP Parameters
* http://www.isi.edu/in-notes/iana/assignments/bootp-dhcp-parameters
*
enum field_type { none, ipv4, string, toggle, yes_no, special, opaque,
time_in_secs,
- val_u_byte, val_u_short, val_u_long,
+ val_u_byte, val_u_short, val_u_le_short, val_u_long,
val_s_long };
struct opt_info {
enum field_type ftype;
};
-#define NUM_OPT_INFOS 128
+#define NUM_OPT_INFOS 211
#define NUM_O63_SUBOPTS 11
+static int dissect_vendor_pxeclient_suboption(proto_tree *v_tree, tvbuff_t *tvb,
+ int optp);
static int dissect_netware_ip_suboption(proto_tree *v_tree, tvbuff_t *tvb,
int optp);
+static int bootp_dhcp_decode_agent_info(proto_tree *v_tree, tvbuff_t *tvb,
+ int optp);
static const char *
get_dhcp_type(guint8 byte)
/* Returns the number of bytes consumed by this option. */
static int
-bootp_option(tvbuff_t *tvb, proto_tree *bp_tree, int voff, int eoff)
+bootp_option(tvbuff_t *tvb, proto_tree *bp_tree, int voff, int eoff,
+ gboolean first_pass, const char **dhcp_type_p,
+ const guint8 **vendor_class_id_p)
{
char *text;
enum field_type ftype;
u_long time_secs;
proto_tree *v_tree;
proto_item *vti;
+ const char *md5_ptr;
+ char md5_str[50];
static const value_string nbnt_vals[] = {
{0x1, "B-node" },
/* 57 */ { "Maximum DHCP Message Size", val_u_short },
/* 58 */ { "Renewal Time Value", time_in_secs },
/* 59 */ { "Rebinding Time Value", time_in_secs },
- /* 60 */ { "Vendor class identifier", opaque },
+ /* 60 */ { "Vendor class identifier", special },
/* 61 */ { "Client identifier", special },
/* 62 */ { "Novell/Netware IP domain", string },
/* 63 */ { "Novell Options", special },
/* 79 */ { "Service Location Agent Scope", opaque },
/* 80 */ { "Naming Authority", opaque },
/* 81 */ { "Client Fully Qualified Domain Name", opaque },
- /* 82 */ { "Agent Circuit ID", opaque },
- /* 83 */ { "Agent Remote ID", opaque },
- /* 84 */ { "Agent Subnet Mask", opaque },
+ /* 82 */ { "Agent Information Option", special },
+ /* 83 */ { "Unassigned", opaque },
+ /* 84 */ { "Unassigned", opaque },
/* 85 */ { "Novell Directory Services Servers", opaque },
/* 86 */ { "Novell Directory Services Tree Name", opaque },
/* 87 */ { "Novell Directory Services Context", opaque },
/* 124 */ { "Unassigned", opaque },
/* 125 */ { "Unassigned", opaque },
/* 126 */ { "Extension", opaque },
- /* 127 */ { "Extension", opaque }
+ /* 127 */ { "Extension", opaque },
+ /* 128 */ { "Private", opaque },
+ /* 129 */ { "Private", opaque },
+ /* 130 */ { "Private", opaque },
+ /* 131 */ { "Private", opaque },
+ /* 132 */ { "Private", opaque },
+ /* 133 */ { "Private", opaque },
+ /* 134 */ { "Private", opaque },
+ /* 135 */ { "Private", opaque },
+ /* 136 */ { "Private", opaque },
+ /* 137 */ { "Private", opaque },
+ /* 138 */ { "Private", opaque },
+ /* 139 */ { "Private", opaque },
+ /* 140 */ { "Private", opaque },
+ /* 141 */ { "Private", opaque },
+ /* 142 */ { "Private", opaque },
+ /* 143 */ { "Private", opaque },
+ /* 144 */ { "Private", opaque },
+ /* 145 */ { "Private", opaque },
+ /* 146 */ { "Private", opaque },
+ /* 147 */ { "Private", opaque },
+ /* 148 */ { "Private", opaque },
+ /* 149 */ { "Private", opaque },
+ /* 150 */ { "Private", opaque },
+ /* 151 */ { "Private", opaque },
+ /* 152 */ { "Private", opaque },
+ /* 153 */ { "Private", opaque },
+ /* 154 */ { "Private", opaque },
+ /* 155 */ { "Private", opaque },
+ /* 156 */ { "Private", opaque },
+ /* 157 */ { "Private", opaque },
+ /* 158 */ { "Private", opaque },
+ /* 159 */ { "Private", opaque },
+ /* 160 */ { "Private", opaque },
+ /* 161 */ { "Private", opaque },
+ /* 162 */ { "Private", opaque },
+ /* 163 */ { "Private", opaque },
+ /* 164 */ { "Private", opaque },
+ /* 165 */ { "Private", opaque },
+ /* 166 */ { "Private", opaque },
+ /* 167 */ { "Private", opaque },
+ /* 168 */ { "Private", opaque },
+ /* 169 */ { "Private", opaque },
+ /* 170 */ { "Private", opaque },
+ /* 171 */ { "Private", opaque },
+ /* 172 */ { "Private", opaque },
+ /* 173 */ { "Private", opaque },
+ /* 174 */ { "Private", opaque },
+ /* 175 */ { "Private", opaque },
+ /* 176 */ { "Private", opaque },
+ /* 177 */ { "Private", opaque },
+ /* 178 */ { "Private", opaque },
+ /* 179 */ { "Private", opaque },
+ /* 180 */ { "Private", opaque },
+ /* 181 */ { "Private", opaque },
+ /* 182 */ { "Private", opaque },
+ /* 183 */ { "Private", opaque },
+ /* 184 */ { "Private", opaque },
+ /* 185 */ { "Private", opaque },
+ /* 186 */ { "Private", opaque },
+ /* 187 */ { "Private", opaque },
+ /* 188 */ { "Private", opaque },
+ /* 189 */ { "Private", opaque },
+ /* 190 */ { "Private", opaque },
+ /* 191 */ { "Private", opaque },
+ /* 192 */ { "Private", opaque },
+ /* 193 */ { "Private", opaque },
+ /* 194 */ { "Private", opaque },
+ /* 195 */ { "Private", opaque },
+ /* 196 */ { "Private", opaque },
+ /* 197 */ { "Private", opaque },
+ /* 198 */ { "Private", opaque },
+ /* 199 */ { "Private", opaque },
+ /* 200 */ { "Private", opaque },
+ /* 201 */ { "Private", opaque },
+ /* 202 */ { "Private", opaque },
+ /* 203 */ { "Private", opaque },
+ /* 204 */ { "Private", opaque },
+ /* 205 */ { "Private", opaque },
+ /* 206 */ { "Private", opaque },
+ /* 207 */ { "Private", opaque },
+ /* 208 */ { "Private", opaque },
+ /* 209 */ { "Private", opaque },
+ /* 210 */ { "Authentication", special }
};
/* Options whose length isn't "vlen + 2". */
}
}
i = i - voff;
- if (bp_tree != NULL)
- proto_tree_add_text(bp_tree, tvb, voff, i, "Padding");
+ if (!first_pass) {
+ if (bp_tree != NULL) {
+ proto_tree_add_text(bp_tree, tvb, voff, i,
+ "Padding");
+ }
+ }
consumed = i;
return consumed;
break;
case 255: /* End Option */
- if (bp_tree != NULL)
- proto_tree_add_text(bp_tree, tvb, voff, 1, "End Option");
+ if (!first_pass) {
+ if (bp_tree != NULL) {
+ proto_tree_add_text(bp_tree, tvb, voff, 1,
+ "End Option");
+ }
+ }
consumed = 1;
return consumed;
}
*/
vlen = tvb_get_guint8(tvb, voff+1);
consumed = vlen + 2;
+
+ /*
+ * In the first pass, we don't put anything into the protocol
+ * tree; we just check for some options we have to look at
+ * in order to properly process the packet:
+ *
+ * 53 (DHCP message type) - if this is present, this is DHCP
+ *
+ * 60 (Vendor class identifier) - we need this in order to
+ * interpret the vendor-specific info
+ */
+ if (first_pass) {
+ switch (code) {
+
+ case 53:
+ *dhcp_type_p =
+ get_dhcp_type(tvb_get_guint8(tvb, voff+2));
+ break;
+
+ case 60:
+ *vendor_class_id_p =
+ tvb_get_ptr(tvb, voff+2, consumed-2);
+ break;
+ }
+
+ /*
+ * We don't do anything else here.
+ */
+ return consumed;
+ }
+
+ /*
+ * This is the second pass - if there's a protocol tree to be
+ * built, we put stuff into it, otherwise we just return.
+ */
if (bp_tree == NULL) {
/* Don't put anything in the protocol tree. */
return consumed;
break;
case 43: /* Vendor-Specific Info */
- proto_tree_add_text(bp_tree, tvb, voff, consumed,
- "Option %d: %s", code, text);
+ /* PXE protocol 2.1 as described in the intel specs */
+ if (*vendor_class_id_p != NULL &&
+ strncmp(*vendor_class_id_p, "PXEClient", strlen("PXEClient")) == 0) {
+ vti = proto_tree_add_text(bp_tree, tvb, voff,
+ consumed, "Option %d: %s (PXEClient)", code, text);
+ v_tree = proto_item_add_subtree(vti, ett_bootp_option);
+
+ optp = voff+2;
+ while (optp < voff+consumed) {
+ optp = dissect_vendor_pxeclient_suboption(v_tree,
+ tvb, optp);
+ }
+ } else {
+ proto_tree_add_text(bp_tree, tvb, voff, consumed,
+ "Option %d: %s (%d bytes)", code, text, vlen);
+ }
break;
case 46: /* NetBIOS-over-TCP/IP Node Type */
}
break;
+ case 60: /* Vendor class identifier */
+ proto_tree_add_text(bp_tree, tvb, voff, consumed,
+ "Option %d: %s = \"%.*s\"", code, text, vlen,
+ tvb_get_ptr(tvb, voff+2, consumed-2));
+ break;
+
case 61: /* Client Identifier */
/* We *MAY* use hwtype/hwaddr. If we have 7 bytes, I'll
guess that the first is the hwtype, and the last 6
optp = dissect_netware_ip_suboption(v_tree, tvb, optp);
break;
+ case 82: /* Relay Agent Information Option */
+ vti = proto_tree_add_text(bp_tree, tvb, voff, consumed,
+ "Option %d: %s (%d bytes)",
+ code, text, vlen);
+ v_tree = proto_item_add_subtree(vti, ett_bootp_option);
+ optp = voff+2;
+ while (optp < voff+consumed) {
+ optp = bootp_dhcp_decode_agent_info(v_tree, tvb, optp);
+ }
+ break;
+
+ case 210: /* DHCP Authentication */
+ vti = proto_tree_add_text(bp_tree, tvb, voff,
+ vlen + 2, "Option %d: %s", code, text);
+ v_tree = proto_item_add_subtree(vti, ett_bootp_option);
+ proto_tree_add_text(v_tree, tvb, voff+2, 1, "Protocol: %d",
+ tvb_get_guint8(tvb, voff+2));
+ proto_tree_add_text(v_tree, tvb, voff+3, 1, "Algorithm: %d",
+ tvb_get_guint8(tvb, voff+3));
+ proto_tree_add_text(v_tree, tvb, voff+4, 1, "Replay Detection Method: %d",
+ tvb_get_guint8(tvb, voff+4));
+ /*
+ * XXX:
+ *
+ * 1) this won't compile if you have a compiler that
+ * doesn't support 64-bit integral quantities;
+ *
+ * 2) there is no standard for the printf format to
+ * be used for 64-bit integral quantities, so
+ * this may not display correctly.
+ *
+ * We need to figure out how to handle 64-bit integral
+ * quantities portably, with some form of fallback if
+ * the compiler doesn't support it, and some way of
+ * handling "%ll{d,o,x}" (most platforms) vs. "%q{d,o.x}"
+ * (FreeBSD, perhaps some versions of other BSDs) vs.
+ * "sorry, we're an LP64 platform, %l{d,o,x} is good enough
+ * for you" (Digital UNIX).
+ */
+ proto_tree_add_text(v_tree, tvb, voff+5, 8, "Replay Detection Value: %0llX",
+ tvb_get_ntohll(tvb, voff+5));
+ if (vlen > 11) {
+ proto_tree_add_text(v_tree, tvb, voff+13, 4, "Secret ID: %0X",
+ tvb_get_ntohl(tvb, voff+13));
+ md5_ptr = tvb_get_ptr(tvb, voff+17, 16);
+ for (i=0; i<16; i++)
+ sprintf(&(md5_str[i*3]), "%02X ", (guint8) md5_ptr[i]);
+ md5_str[48] = 0;
+ proto_tree_add_text(v_tree, tvb, voff+17, 16, "HMAC MD5 Hash: %s", md5_str);
+ }
+ break;
+
default: /* not special */
break;
}
* John Lines <John.Lines@aeat.co.uk>
*/
proto_tree_add_text(bp_tree, tvb, voff, consumed,
- "Option %d: %s = %.*s", code, text, vlen,
+ "Option %d: %s = \"%.*s\"", code, text, vlen,
tvb_get_ptr(tvb, voff+2, consumed-2));
break;
return consumed;
}
+static int
+bootp_dhcp_decode_agent_info(proto_tree *v_tree, tvbuff_t *tvb, int optp)
+{
+ guint8 subopt;
+ guint8 subopt_len;
+
+ subopt = tvb_get_guint8(tvb, optp);
+ subopt_len = tvb_get_guint8(tvb, optp+1);
+ switch (subopt) {
+ case 1:
+ proto_tree_add_text(v_tree, tvb, optp, subopt_len + 2,
+ "Agent Circuit ID (%d bytes)", subopt_len);
+ break;
+ case 2:
+ proto_tree_add_text(v_tree, tvb, optp, subopt_len + 2,
+ "Agent Remote ID (%d bytes)", subopt_len);
+ break;
+ default:
+ proto_tree_add_text(v_tree, tvb, optp, subopt_len + 2,
+ "Unknown agent option: %d", subopt);
+ break;
+ }
+ optp += (subopt_len + 2);
+ return optp;
+}
+
+static int
+dissect_vendor_pxeclient_suboption(proto_tree *v_tree, tvbuff_t *tvb, int optp)
+{
+ guint8 subopt;
+ guint8 subopt_len;
+ int slask;
+ proto_tree *o43pxeclient_v_tree;
+ proto_item *vti;
+
+ struct o43pxeclient_opt_info {
+ char *text;
+ enum field_type ft;
+ };
+
+ static struct o43pxeclient_opt_info o43pxeclient_opt[]= {
+ /* 0 */ {"nop", special}, /* dummy */
+ /* 1 */ {"PXE mtftp IP", ipv4},
+ /* 2 */ {"PXE mtftp client port", val_u_le_short},
+ /* 3 */ {"PXE mtftp server port",val_u_le_short},
+ /* 4 */ {"PXE mtftp timeout", val_u_byte},
+ /* 5 */ {"PXE mtftp delay", val_u_byte},
+ /* 6 */ {"PXE discovery control", val_u_byte},
+ /*
+ * Correct: b0 (lsb): disable broadcast discovery
+ * b1: disable multicast discovery
+ * b2: only use/accept servers in boot servers
+ * b3: download bootfile without prompt/menu/disc
+ */
+ /* 7 */ {"PXE multicast address", ipv4},
+ /* 8 */ {"PXE boot servers", special},
+ /* 9 */ {"PXE boot menu", special},
+ /* 10 */ {"PXE menu prompt", special},
+ /* 11 */ {"PXE multicast address alloc", special},
+ /* 12 */ {"PXE credential types", special},
+ /* 71 {"PXE boot item", special} */
+ /* 255 {"PXE end options", special} */
+ };
+#define NUM_O43PXECLIENT_SUBOPTS (12)
+
+ subopt = tvb_get_guint8(tvb, optp);
+
+ if (subopt == 0 ) {
+ proto_tree_add_text(v_tree, tvb, optp, 1, "Padding");
+ return (optp+1);
+ } else if (subopt == 255) { /* End Option */
+ proto_tree_add_text(v_tree, tvb, optp, 1, "End PXEClient option");
+ /* Make sure we skip any junk left this option */
+ return (optp+255);
+ }
+
+ subopt_len = tvb_get_guint8(tvb, optp+1);
+
+ if ( subopt == 71 ) { /* 71 {"PXE boot item", special} */
+ /* case special */
+ /* I may need to decode that properly one day */
+ proto_tree_add_text(v_tree, tvb, optp, subopt_len+2,
+ "Suboption %d: %s (%d byte%s)" ,
+ subopt, "PXE boot item",
+ subopt_len, (subopt_len != 1)?"s":"");
+ } else if ( (subopt < 1 ) || (subopt > NUM_O43PXECLIENT_SUBOPTS) ) {
+ proto_tree_add_text(v_tree, tvb, optp, subopt_len+2,
+ "Unknown suboption %d (%d byte%s)", subopt, subopt_len,
+ (subopt_len != 1)?"s":"");
+ } else {
+ switch (o43pxeclient_opt[subopt].ft) {
+
+/* XXX case string:
+ proto_tree_add_text(v_tree, tvb, optp, subopt_len+2,
+ "Suboption %d: %s", subopt, o43pxeclient_opt[subopt].text);
+ break;
+ XXX */
+ case special:
+ /* I may need to decode that properly one day */
+ proto_tree_add_text(v_tree, tvb, optp, subopt_len+2,
+ "Suboption %d: %s (%d byte%s)" ,
+ subopt, o43pxeclient_opt[subopt].text,
+ subopt_len, (subopt_len != 1)?"s":"");
+ break;
+
+ case val_u_le_short:
+ proto_tree_add_text(v_tree, tvb, optp, 4, "Suboption %d: %s = %u",
+ subopt, o43pxeclient_opt[subopt].text,
+ tvb_get_letohs(tvb, optp+2));
+ break;
+
+ case val_u_byte:
+ proto_tree_add_text(v_tree, tvb, optp, 3, "Suboption %d: %s = %u",
+ subopt, o43pxeclient_opt[subopt].text,
+ tvb_get_guint8(tvb, optp+2));
+ break;
+
+ case ipv4:
+ if (subopt_len == 4) {
+ /* one IP address */
+ proto_tree_add_text(v_tree, tvb, optp, 6,
+ "Suboption %d : %s = %s",
+ subopt, o43pxeclient_opt[subopt].text,
+ ip_to_str(tvb_get_ptr(tvb, optp+2, 4)));
+ } else {
+ /* > 1 IP addresses. Let's make a sub-tree */
+ vti = proto_tree_add_text(v_tree, tvb, optp,
+ subopt_len+2, "Suboption %d: %s",
+ subopt, o43pxeclient_opt[subopt].text);
+ o43pxeclient_v_tree = proto_item_add_subtree(vti, ett_bootp_option);
+ for (slask = optp + 2 ; slask < optp+subopt_len; slask += 4) {
+ proto_tree_add_text(o43pxeclient_v_tree, tvb, slask, 4, "IP Address: %s",
+ ip_to_str(tvb_get_ptr(tvb, slask, 4)));
+ }
+ }
+ break;
+ default:
+ proto_tree_add_text(v_tree, tvb, optp, subopt_len+2,"ERROR, please report: Unknown subopt type handler %d", subopt);
+ break;
+ }
+ }
+ optp += (subopt_len + 2);
+ return optp;
+}
+
static int
dissect_netware_ip_suboption(proto_tree *v_tree, tvbuff_t *tvb, int optp)
{
proto_item *ti;
guint8 op;
guint8 htype, hlen;
- guint8 *haddr;
- int voff, eoff; /* vender offset, end offset */
+ const guint8 *haddr;
+ int voff, eoff, tmpvoff; /* vendor offset, end offset */
guint32 ip_addr;
- gboolean is_dhcp = FALSE;
- const char *dhcp_type;
+ const char *dhcp_type = NULL;
+ const guint8 *vendor_class_id = NULL;
if (check_col(pinfo->fd, COL_PROTOCOL))
col_set_str(pinfo->fd, COL_PROTOCOL, "BOOTP");
voff = 240;
eoff = tvb_reported_length(tvb);
+
+ /*
+ * In the first pass, we just look for the DHCP message type
+ * and Vendor class identifier options.
+ */
+ tmpvoff = voff;
+ while (tmpvoff < eoff) {
+ tmpvoff += bootp_option(tvb, 0, tmpvoff, eoff, TRUE,
+ &dhcp_type, &vendor_class_id);
+ }
+
+ /*
+ * If there was a DHCP message type option, flag this packet
+ * as DHCP.
+ */
+ if (dhcp_type != NULL) {
+ /*
+ * Yes, this is a DHCP packet, and "dhcp_type" is the
+ * packet type.
+ */
+ if (check_col(pinfo->fd, COL_PROTOCOL))
+ col_set_str(pinfo->fd, COL_PROTOCOL, "DHCP");
+ if (check_col(pinfo->fd, COL_INFO))
+ col_add_fstr(pinfo->fd, COL_INFO, "DHCP %-8s - Transaction ID 0x%x",
+ dhcp_type, tvb_get_ntohl(tvb, 4));
+ if (tree)
+ proto_tree_add_boolean_hidden(bp_tree, hf_bootp_dhcp,
+ tvb, 0, 0, 1);
+ }
+
+ /*
+ * If we're not building the protocol tree, we don't need to
+ * make a second pass.
+ */
+ if (tree == NULL)
+ return;
+
+ /*
+ * OK, now build the protocol tree.
+ */
while (voff < eoff) {
- /* Handle the DHCP option specially here, so that we
- can flag DHCP packets as such. */
- if (!is_dhcp && tvb_get_guint8(tvb, voff) == 53) {
- /*
- * We haven't already seen a DHCP Type option, and
- * this is a DHCP Type option, so flag this packet
- * as DHCP.
- */
- dhcp_type = get_dhcp_type(tvb_get_guint8(tvb, voff+2));
- if (check_col(pinfo->fd, COL_PROTOCOL))
- col_set_str(pinfo->fd, COL_PROTOCOL, "DHCP");
- if (check_col(pinfo->fd, COL_INFO))
- col_add_fstr(pinfo->fd, COL_INFO, "DHCP %-8s - Transaction ID 0x%x",
- dhcp_type, tvb_get_ntohl(tvb, 4));
- if (tree)
- proto_tree_add_boolean_hidden(bp_tree, hf_bootp_dhcp,
- tvb, 0, 0, 1);
- is_dhcp = TRUE;
- }
- voff += bootp_option(tvb, bp_tree, voff, eoff);
+ voff += bootp_option(tvb, bp_tree, voff, eoff, FALSE,
+ &dhcp_type, &vendor_class_id);
}
}
{ &hf_bootp_dhcp,
{ "Frame is DHCP", "bootp.dhcp", FT_BOOLEAN,
BASE_NONE, NULL, 0x0,
- "" }},
+ "", HFILL }},
{ &hf_bootp_type,
{ "Message type", "bootp.type", FT_UINT8,
BASE_DEC, VALS(op_vals), 0x0,
- "" }},
+ "", HFILL }},
{ &hf_bootp_hw_type,
{ "Hardware type", "bootp.hw.type", FT_UINT8,
BASE_HEX, NULL, 0x0,
- "" }},
+ "", HFILL }},
{ &hf_bootp_hw_len,
{ "Hardware address length", "bootp.hw.len", FT_UINT8,
BASE_DEC, NULL, 0x0,
- "" }},
+ "", HFILL }},
{ &hf_bootp_hops,
{ "Hops", "bootp.hops", FT_UINT8,
BASE_DEC, NULL, 0x0,
- "" }},
+ "", HFILL }},
{ &hf_bootp_id,
{ "Transaction ID", "bootp.id", FT_UINT32,
BASE_HEX, NULL, 0x0,
- "" }},
+ "", HFILL }},
{ &hf_bootp_secs,
{ "Seconds elapsed", "bootp.secs", FT_UINT16,
BASE_DEC, NULL, 0x0,
- "" }},
+ "", HFILL }},
{ &hf_bootp_flag,
{ "Broadcast flag", "bootp.flag", FT_UINT16,
BASE_HEX, NULL, 0x0,
- "" }},
+ "", HFILL }},
{ &hf_bootp_ip_client,
{ "Client IP address", "bootp.ip.client",FT_IPv4,
BASE_NONE, NULL, 0x0,
- "" }},
+ "", HFILL }},
{ &hf_bootp_ip_your,
{ "Your (client) IP address", "bootp.ip.your", FT_IPv4,
BASE_NONE, NULL, 0x0,
- "" }},
+ "", HFILL }},
{ &hf_bootp_ip_server,
{ "Next server IP address", "bootp.ip.server",FT_IPv4,
BASE_NONE, NULL, 0x0,
- "" }},
+ "", HFILL }},
{ &hf_bootp_ip_relay,
{ "Relay agent IP address", "bootp.ip.relay", FT_IPv4,
BASE_NONE, NULL, 0x0,
- "" }},
+ "", HFILL }},
{ &hf_bootp_hw_addr,
{ "Client hardware address", "bootp.hw.addr", FT_BYTES,
BASE_NONE, NULL, 0x0,
- "" }},
+ "", HFILL }},
{ &hf_bootp_server,
{ "Server host name", "bootp.server", FT_STRING,
BASE_NONE, NULL, 0x0,
- "" }},
+ "", HFILL }},
{ &hf_bootp_file,
{ "Boot file name", "bootp.file", FT_STRING,
BASE_NONE, NULL, 0x0,
- "" }},
+ "", HFILL }},
{ &hf_bootp_cookie,
{ "Magic cookie", "bootp.cookie", FT_IPv4,
BASE_NONE, NULL, 0x0,
- "" }},
+ "", HFILL }},
};
static gint *ett[] = {
&ett_bootp,