DHCP support for Intel PXEclient DHCP requests, from Joerg Mayer.

svn path=/trunk/; revision=3445
This commit is contained in:
Guy Harris 2001-05-24 19:21:15 +00:00
parent 3f6e57c5c2
commit d3fbbef9c0
2 changed files with 170 additions and 7 deletions

View File

@ -74,6 +74,7 @@ Simon Wilkinson <sxw@dcs.ed.ac.uk> {
Joerg Mayer <jmayer@loplof.de> {
Banyan Vines support
NTP fixes
DHCP support for Intel PXEclient DHCP requests
}
Martin Maciaszek <fastjack@i-s-o.net> {

View File

@ -2,7 +2,7 @@
* Routines for BOOTP/DHCP packet disassembly
* Gilbert Ramirez <gram@xiexie.org>
*
* $Id: packet-bootp.c,v 1.51 2001/05/03 07:02:50 girlich Exp $
* $Id: packet-bootp.c,v 1.52 2001/05/24 19:21:15 guy Exp $
*
* The information used comes from:
* RFC 951: Bootstrap Protocol
@ -68,11 +68,13 @@ static int hf_bootp_dhcp = -1;
static guint ett_bootp = -1;
static guint ett_bootp_option = -1;
static const guint8 *vendor_class_id = NULL;
#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_u_byte, val_u_short, val_u_le_short, val_u_long,
val_s_long };
struct opt_info {
@ -83,6 +85,8 @@ struct opt_info {
#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,
@ -195,7 +199,7 @@ bootp_option(tvbuff_t *tvb, proto_tree *bp_tree, int voff, int eoff)
/* 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 },
@ -379,6 +383,14 @@ bootp_option(tvbuff_t *tvb, proto_tree *bp_tree, int voff, int eoff)
*/
vlen = tvb_get_guint8(tvb, voff+1);
consumed = vlen + 2;
/* Handling of options we need to scan for first:
* 60 (Vendor class identifier)
* This is ugly but I don't have any better ideas
* -- Joerg Mayer
*/
if ( (code == 60) && (bp_tree == NULL) ) {
vendor_class_id = tvb_get_ptr(tvb, voff+2, consumed-2);
}
if (bp_tree == NULL) {
/* Don't put anything in the protocol tree. */
return consumed;
@ -430,8 +442,21 @@ bootp_option(tvbuff_t *tvb, proto_tree *bp_tree, int voff, int eoff)
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 (strncmp(vendor_class_id, "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 */
@ -463,6 +488,13 @@ bootp_option(tvbuff_t *tvb, proto_tree *bp_tree, int voff, int eoff)
}
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
@ -588,7 +620,7 @@ bootp_option(tvbuff_t *tvb, proto_tree *bp_tree, int voff, int eoff)
* 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;
@ -701,6 +733,125 @@ bootp_dhcp_decode_agent_info(proto_tree *v_tree, tvbuff_t *tvb, int optp)
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)
{
@ -815,7 +966,7 @@ dissect_bootp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
guint8 op;
guint8 htype, hlen;
const guint8 *haddr;
int voff, eoff; /* vender offset, end offset */
int voff, eoff, tmpvoff; /* vender offset, end offset */
guint32 ip_addr;
gboolean is_dhcp = FALSE;
const char *dhcp_type;
@ -939,6 +1090,17 @@ dissect_bootp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
voff = 240;
eoff = tvb_reported_length(tvb);
/*
* If we are displaying the details, we need two passes:
* the first to find out about vendor specific options,
* the second to do the actual decoding (option 60 is needed
* to decode option 43 )
*/
tmpvoff = voff;
if (bp_tree) {
while (tmpvoff < eoff )
tmpvoff += bootp_option(tvb, 0, tmpvoff, eoff);
}
while (voff < eoff) {
/* Handle the DHCP option specially here, so that we
can flag DHCP packets as such. */