Skip to content

Commit

Permalink
Add ProxyDHCP support.
Browse files Browse the repository at this point in the history
  • Loading branch information
Michael Brown committed Nov 21, 2007
1 parent fa0bd77 commit 0becbf5
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 26 deletions.
6 changes: 5 additions & 1 deletion src/include/gpxe/dhcp.h
Expand Up @@ -12,6 +12,7 @@
#include <gpxe/in.h>
#include <gpxe/refcnt.h>
#include <gpxe/tables.h>
#include <latch.h>

struct net_device;
struct job_interface;
Expand Down Expand Up @@ -505,13 +506,16 @@ dhcpopt_get ( struct dhcp_option_block *options ) {
/**
* Drop reference to DHCP options block
*
* @v options DHCP options block
* @v options DHCP options block, or NULL
*/
static inline __attribute__ (( always_inline )) void
dhcpopt_put ( struct dhcp_option_block *options ) {
ref_put ( &options->refcnt );
}

/** Maximum time that we will wait for ProxyDHCP offers */
#define PROXYDHCP_WAIT_TIME ( TICKS_PER_SEC * 2 )

extern struct list_head dhcp_option_blocks;

extern unsigned long dhcp_num_option ( struct dhcp_option *option );
Expand Down
79 changes: 54 additions & 25 deletions src/net/udp/dhcp.c
Expand Up @@ -693,10 +693,14 @@ struct dhcp_session {
* (e.g. @c DHCPDISCOVER).
*/
int state;
/** Options obtained from server */
/** Options obtained from DHCP server */
struct dhcp_option_block *options;
/** Options obtained from ProxyDHCP server */
struct dhcp_option_block *proxy_options;
/** Retransmission timer */
struct retry_timer timer;
/** Session start time (in ticks) */
unsigned long start;
};

/**
Expand All @@ -710,6 +714,7 @@ static void dhcp_free ( struct refcnt *refcnt ) {

netdev_put ( dhcp->netdev );
dhcpopt_put ( dhcp->options );
dhcpopt_put ( dhcp->proxy_options );
free ( dhcp );
}

Expand Down Expand Up @@ -826,7 +831,10 @@ static int dhcp_deliver_raw ( struct xfer_interface *xfer,
container_of ( xfer, struct dhcp_session, xfer );
const struct dhcphdr *dhcphdr = data;
struct dhcp_option_block *options;
struct dhcp_option_block **store_options;
int is_proxy;
unsigned int msgtype;
unsigned long elapsed;

/* Check for matching transaction ID */
if ( dhcphdr->xid != dhcp_xid ( dhcp->netdev ) ) {
Expand All @@ -843,41 +851,61 @@ static int dhcp_deliver_raw ( struct xfer_interface *xfer,
return -EINVAL;
}

/* Determine message type */
/* Determine and verify message type */
is_proxy = ( dhcphdr->yiaddr.s_addr == 0 );
msgtype = find_dhcp_num_option ( options, DHCP_MESSAGE_TYPE );
DBGC ( dhcp, "DHCP %p received %s\n",
dhcp, dhcp_msgtype_name ( msgtype ) );
DBGC ( dhcp, "DHCP %p received %s%s\n", dhcp,
( is_proxy ? "Proxy" : "" ), dhcp_msgtype_name ( msgtype ) );
if ( ( ( dhcp->state != DHCPDISCOVER ) || ( msgtype != DHCPOFFER ) ) &&
( ( dhcp->state != DHCPREQUEST ) || ( msgtype != DHCPACK ) ) ) {
DBGC ( dhcp, "DHCP %p discarding %s while in %s state\n",
dhcp, dhcp_msgtype_name ( msgtype ),
dhcp_msgtype_name ( dhcp->state ) );
goto out_discard;
}

/* Handle DHCP reply */
/* Update stored standard/ProxyDHCP options, if the new
* options have equal or higher priority than the
* currently-stored options.
*/
store_options = ( is_proxy ? &dhcp->proxy_options : &dhcp->options );
if ( ( ! *store_options ) ||
( find_dhcp_num_option ( options, DHCP_EB_PRIORITY ) >=
find_dhcp_num_option ( *store_options, DHCP_EB_PRIORITY ) ) ) {
dhcpopt_put ( *store_options );
*store_options = options;
} else {
dhcpopt_put ( options );
}

/* Handle DHCP response */
switch ( dhcp->state ) {
case DHCPDISCOVER:
if ( msgtype != DHCPOFFER )
goto out_discard;
dhcp->state = DHCPREQUEST;
/* If we have received a valid standard DHCP response
* (i.e. one with an IP address), and we have allowed
* sufficient time for ProxyDHCP reponses, then
* transition to making the DHCPREQUEST.
*/
elapsed = ( currticks() - dhcp->start );
if ( dhcp->options &&
( elapsed > PROXYDHCP_WAIT_TIME ) ) {
stop_timer ( &dhcp->timer );
dhcp->state = DHCPREQUEST;
dhcp_send_request ( dhcp );
}
break;
case DHCPREQUEST:
if ( msgtype != DHCPACK )
goto out_discard;
dhcp->state = DHCPACK;
/* DHCP finished; register options and exit */
if ( dhcp->proxy_options )
dhcp->register_options ( dhcp->netdev,
dhcp->proxy_options );
dhcp->register_options ( dhcp->netdev, dhcp->options );
dhcp_finished ( dhcp, 0 );
break;
default:
assert ( 0 );
goto out_discard;
}

/* Stop timer and update stored options */
stop_timer ( &dhcp->timer );
if ( dhcp->options )
dhcpopt_put ( dhcp->options );
dhcp->options = options;

/* Transmit next packet, or terminate session */
if ( dhcp->state < DHCPACK ) {
dhcp_send_request ( dhcp );
} else {
dhcp->register_options ( dhcp->netdev, dhcp->options );
dhcp_finished ( dhcp, 0 );
}
return 0;

out_discard:
Expand Down Expand Up @@ -965,6 +993,7 @@ int start_dhcp ( struct job_interface *job, struct net_device *netdev,
dhcp->register_options = register_options;
dhcp->timer.expired = dhcp_timer_expired;
dhcp->state = DHCPDISCOVER;
dhcp->start = currticks();

/* Instantiate child objects and attach to our interfaces */
if ( ( rc = xfer_open_socket ( &dhcp->xfer, SOCK_DGRAM,
Expand Down

0 comments on commit 0becbf5

Please sign in to comment.