Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
[dhcp] Add preliminary support for PXE Boot Servers
Some PXE configurations require us to perform a third DHCP transaction
(in addition to the real DHCP transaction and the ProxyDHCP
transaction) in order to retrieve information from a "Boot Server".

This is an experimental implementation, since the actual behaviour is
not well specified in the PXE spec.
  • Loading branch information
Michael Brown committed Jan 21, 2009
1 parent d230b53 commit 6941793
Show file tree
Hide file tree
Showing 3 changed files with 109 additions and 1 deletion.
6 changes: 6 additions & 0 deletions src/include/gpxe/dhcp.h
Expand Up @@ -81,6 +81,9 @@ struct dhcp_packet;
/** Vendor encapsulated options */
#define DHCP_VENDOR_ENCAP 43

/** PXE boot server multicast address */
#define DHCP_PXE_BOOT_SERVER_MCAST DHCP_ENCAP_OPT ( DHCP_VENDOR_ENCAP, 7 )

/** Requested IP address */
#define DHCP_REQUESTED_ADDRESS 50

Expand Down Expand Up @@ -480,6 +483,9 @@ struct dhcphdr {
/** Settings block name used for ProxyDHCP responses */
#define PROXYDHCP_SETTINGS_NAME "proxydhcp"

/** Setting block name used for BootServerDHCP responses */
#define BSDHCP_SETTINGS_NAME "bs"

extern int dhcp_create_packet ( struct dhcp_packet *dhcppkt,
struct net_device *netdev, uint8_t msgtype,
struct dhcp_options *options,
Expand Down
11 changes: 11 additions & 0 deletions src/net/fakedhcp.c
Expand Up @@ -176,6 +176,7 @@ int create_fakeproxydhcpack ( struct net_device *netdev,
void *data, size_t max_len ) {
struct dhcp_packet dhcppkt;
struct settings *settings;
struct settings *bs_settings;
int rc;

/* Identify ProxyDHCP settings */
Expand All @@ -200,5 +201,15 @@ int create_fakeproxydhcpack ( struct net_device *netdev,
return rc;
}

/* Merge in BootServerDHCP options, if present */
bs_settings = find_settings ( BSDHCP_SETTINGS_NAME );
if ( bs_settings ) {
if ( ( rc = copy_settings ( &dhcppkt, bs_settings ) ) != 0 ) {
DBG ( "Could not set BootServerDHCPACK settings: "
"%s\n", strerror ( rc ) );
return rc;
}
}

return 0;
}
93 changes: 92 additions & 1 deletion src/net/udp/dhcp.c
Expand Up @@ -287,6 +287,8 @@ enum dhcp_session_state {
DHCP_STATE_REQUEST,
/** Sending ProxyDHCPREQUESTs, waiting for ProxyDHCPACK */
DHCP_STATE_PROXYREQUEST,
/** Sending BootServerDHCPREQUESTs, waiting for BootServerDHCPACK */
DHCP_STATE_BSREQUEST,
};

/**
Expand All @@ -300,6 +302,7 @@ static inline const char * dhcp_state_name ( enum dhcp_session_state state ) {
case DHCP_STATE_DISCOVER: return "DHCPDISCOVER";
case DHCP_STATE_REQUEST: return "DHCPREQUEST";
case DHCP_STATE_PROXYREQUEST: return "ProxyDHCPREQUEST";
case DHCP_STATE_BSREQUEST: return "BootServerREQUEST";
default: return "<invalid>";
}
}
Expand All @@ -326,6 +329,12 @@ struct dhcp_session {
struct dhcp_settings *dhcpoffer;
/** ProxyDHCPOFFER obtained during DHCPDISCOVER */
struct dhcp_settings *proxydhcpoffer;
/** DHCPACK obtained during DHCPREQUEST */
struct dhcp_settings *dhcpack;
/** ProxyDHCPACK obtained during ProxyDHCPREQUEST */
struct dhcp_settings *proxydhcpack;
/** BootServerDHCPACK obtained during BootServerDHCPREQUEST */
struct dhcp_settings *bsdhcpack;
/** Retransmission timer */
struct retry_timer timer;
/** Start time of the current state (in ticks) */
Expand All @@ -344,6 +353,9 @@ static void dhcp_free ( struct refcnt *refcnt ) {
netdev_put ( dhcp->netdev );
dhcpset_put ( dhcp->dhcpoffer );
dhcpset_put ( dhcp->proxydhcpoffer );
dhcpset_put ( dhcp->dhcpack );
dhcpset_put ( dhcp->proxydhcpack );
dhcpset_put ( dhcp->bsdhcpack );
free ( dhcp );
}

Expand Down Expand Up @@ -555,6 +567,10 @@ static int dhcp_tx ( struct dhcp_session *dhcp ) {
.sin_family = AF_INET,
.sin_port = htons ( PROXYDHCP_PORT ),
};
static struct sockaddr_in client = {
.sin_family = AF_INET,
.sin_port = htons ( BOOTPC_PORT ),
};
struct xfer_metadata meta = {
.netdev = dhcp->netdev,
};
Expand Down Expand Up @@ -584,6 +600,7 @@ static int dhcp_tx ( struct dhcp_session *dhcp ) {
DBGC ( dhcp, "DHCP %p transmitting ProxyDHCPREQUEST\n", dhcp );
assert ( dhcp->dhcpoffer );
assert ( dhcp->proxydhcpoffer );
assert ( dhcp->dhcpack );
offer = &dhcp->proxydhcpoffer->dhcppkt;
ciaddr = dhcp->dhcpoffer->dhcppkt.dhcphdr->yiaddr;
check_len = dhcppkt_fetch ( offer, DHCP_SERVER_IDENTIFIER,
Expand All @@ -594,6 +611,24 @@ static int dhcp_tx ( struct dhcp_session *dhcp ) {
assert ( proxydhcp_server.sin_addr.s_addr != 0 );
assert ( check_len == sizeof ( proxydhcp_server.sin_addr ) );
break;
case DHCP_STATE_BSREQUEST:
DBGC ( dhcp, "DHCP %p transmitting BootServerREQUEST\n",
dhcp );
assert ( dhcp->dhcpoffer );
assert ( dhcp->proxydhcpoffer );
assert ( dhcp->dhcpack );
assert ( dhcp->proxydhcpack );
offer = &dhcp->proxydhcpoffer->dhcppkt;
ciaddr = dhcp->dhcpoffer->dhcppkt.dhcphdr->yiaddr;
check_len = dhcppkt_fetch ( &dhcp->proxydhcpack->dhcppkt,
DHCP_PXE_BOOT_SERVER_MCAST,
&proxydhcp_server.sin_addr,
sizeof(proxydhcp_server.sin_addr));
meta.dest = ( struct sockaddr * ) &proxydhcp_server;
assert ( ciaddr.s_addr != 0 );
assert ( proxydhcp_server.sin_addr.s_addr != 0 );
assert ( check_len == sizeof ( proxydhcp_server.sin_addr ) );
break;
default:
assert ( 0 );
break;
Expand All @@ -613,6 +648,12 @@ static int dhcp_tx ( struct dhcp_session *dhcp ) {
goto done;
}

/* Explicitly specify source address, if available. */
if ( ciaddr.s_addr ) {
client.sin_addr = ciaddr;
meta.src = ( struct sockaddr * ) &client;
}

/* Transmit the packet */
iob_put ( iobuf, dhcppkt.len );
rc = xfer_deliver_iob_meta ( &dhcp->xfer, iobuf, &meta );
Expand Down Expand Up @@ -650,6 +691,7 @@ static void dhcp_set_state ( struct dhcp_session *dhcp,
* @v dhcp DHCP session
*/
static void dhcp_next_state ( struct dhcp_session *dhcp ) {
struct in_addr bs_mcast = { 0 };

switch ( dhcp->state ) {
case DHCP_STATE_DISCOVER:
Expand All @@ -662,6 +704,17 @@ static void dhcp_next_state ( struct dhcp_session *dhcp ) {
}
/* Fall through */
case DHCP_STATE_PROXYREQUEST:
if ( dhcp->proxydhcpack ) {
dhcppkt_fetch ( &dhcp->proxydhcpack->dhcppkt,
DHCP_PXE_BOOT_SERVER_MCAST,
&bs_mcast, sizeof ( bs_mcast ) );
if ( bs_mcast.s_addr ) {
dhcp_set_state ( dhcp, DHCP_STATE_BSREQUEST );
break;
}
}
/* Fall through */
case DHCP_STATE_BSREQUEST:
dhcp_finished ( dhcp, 0 );
break;
default:
Expand Down Expand Up @@ -845,9 +898,13 @@ static void dhcp_rx_dhcpack ( struct dhcp_session *dhcp,
return;
}

/* Record DHCPACK */
assert ( dhcp->dhcpack == NULL );
dhcp->dhcpack = dhcpset_get ( dhcpack );

/* Register settings */
parent = netdev_settings ( dhcp->netdev );
if ( ( rc = dhcp_store_dhcpack ( dhcp, dhcpack, parent ) ) !=0 )
if ( ( rc = dhcp_store_dhcpack ( dhcp, dhcpack, parent ) ) != 0 )
return;

/* Transition to next state */
Expand Down Expand Up @@ -885,6 +942,10 @@ static void dhcp_rx_proxydhcpack ( struct dhcp_session *dhcp,
/* Rename settings */
proxydhcpack->settings.name = PROXYDHCP_SETTINGS_NAME;

/* Record ProxyDHCPACK */
assert ( dhcp->proxydhcpack == NULL );
dhcp->proxydhcpack = dhcpset_get ( proxydhcpack );

/* Register settings */
if ( ( rc = dhcp_store_dhcpack ( dhcp, proxydhcpack, NULL ) ) != 0 )
return;
Expand All @@ -893,6 +954,31 @@ static void dhcp_rx_proxydhcpack ( struct dhcp_session *dhcp,
dhcp_next_state ( dhcp );
}

/**
* Handle received BootServerDHCPACK
*
* @v dhcp DHCP session
* @v bsdhcpack Received BootServerDHCPACK
*/
static void dhcp_rx_bsdhcpack ( struct dhcp_session *dhcp,
struct dhcp_settings *bsdhcpack ) {
int rc;

/* Rename settings */
bsdhcpack->settings.name = BSDHCP_SETTINGS_NAME;

/* Record ProxyDHCPACK */
assert ( dhcp->bsdhcpack == NULL );
dhcp->bsdhcpack = dhcpset_get ( bsdhcpack );

/* Register settings */
if ( ( rc = dhcp_store_dhcpack ( dhcp, bsdhcpack, NULL ) ) != 0 )
return;

/* Transition to next state */
dhcp_next_state ( dhcp );
}

/**
* Receive new data
*
Expand Down Expand Up @@ -969,6 +1055,11 @@ static int dhcp_deliver_iob ( struct xfer_interface *xfer,
( src_port == htons ( PROXYDHCP_PORT ) ) )
dhcp_rx_proxydhcpack ( dhcp, dhcpset );
break;
case DHCP_STATE_BSREQUEST:
if ( ( msgtype == DHCPACK ) &&
( src_port == htons ( PROXYDHCP_PORT ) ) )
dhcp_rx_bsdhcpack ( dhcp, dhcpset );
break;
default:
assert ( 0 );
break;
Expand Down

0 comments on commit 6941793

Please sign in to comment.