mirror of https://github.com/ipxe/ipxe.git
Add ProxyDHCP support.
parent
fa0bd77270
commit
0becbf5fba
|
@ -12,6 +12,7 @@
|
||||||
#include <gpxe/in.h>
|
#include <gpxe/in.h>
|
||||||
#include <gpxe/refcnt.h>
|
#include <gpxe/refcnt.h>
|
||||||
#include <gpxe/tables.h>
|
#include <gpxe/tables.h>
|
||||||
|
#include <latch.h>
|
||||||
|
|
||||||
struct net_device;
|
struct net_device;
|
||||||
struct job_interface;
|
struct job_interface;
|
||||||
|
@ -505,13 +506,16 @@ dhcpopt_get ( struct dhcp_option_block *options ) {
|
||||||
/**
|
/**
|
||||||
* Drop reference to DHCP options block
|
* Drop reference to DHCP options block
|
||||||
*
|
*
|
||||||
* @v options DHCP options block
|
* @v options DHCP options block, or NULL
|
||||||
*/
|
*/
|
||||||
static inline __attribute__ (( always_inline )) void
|
static inline __attribute__ (( always_inline )) void
|
||||||
dhcpopt_put ( struct dhcp_option_block *options ) {
|
dhcpopt_put ( struct dhcp_option_block *options ) {
|
||||||
ref_put ( &options->refcnt );
|
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 struct list_head dhcp_option_blocks;
|
||||||
|
|
||||||
extern unsigned long dhcp_num_option ( struct dhcp_option *option );
|
extern unsigned long dhcp_num_option ( struct dhcp_option *option );
|
||||||
|
|
|
@ -693,10 +693,14 @@ struct dhcp_session {
|
||||||
* (e.g. @c DHCPDISCOVER).
|
* (e.g. @c DHCPDISCOVER).
|
||||||
*/
|
*/
|
||||||
int state;
|
int state;
|
||||||
/** Options obtained from server */
|
/** Options obtained from DHCP server */
|
||||||
struct dhcp_option_block *options;
|
struct dhcp_option_block *options;
|
||||||
|
/** Options obtained from ProxyDHCP server */
|
||||||
|
struct dhcp_option_block *proxy_options;
|
||||||
/** Retransmission timer */
|
/** Retransmission timer */
|
||||||
struct retry_timer timer;
|
struct retry_timer timer;
|
||||||
|
/** Session start time (in ticks) */
|
||||||
|
unsigned long start;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -710,6 +714,7 @@ static void dhcp_free ( struct refcnt *refcnt ) {
|
||||||
|
|
||||||
netdev_put ( dhcp->netdev );
|
netdev_put ( dhcp->netdev );
|
||||||
dhcpopt_put ( dhcp->options );
|
dhcpopt_put ( dhcp->options );
|
||||||
|
dhcpopt_put ( dhcp->proxy_options );
|
||||||
free ( dhcp );
|
free ( dhcp );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -826,7 +831,10 @@ static int dhcp_deliver_raw ( struct xfer_interface *xfer,
|
||||||
container_of ( xfer, struct dhcp_session, xfer );
|
container_of ( xfer, struct dhcp_session, xfer );
|
||||||
const struct dhcphdr *dhcphdr = data;
|
const struct dhcphdr *dhcphdr = data;
|
||||||
struct dhcp_option_block *options;
|
struct dhcp_option_block *options;
|
||||||
|
struct dhcp_option_block **store_options;
|
||||||
|
int is_proxy;
|
||||||
unsigned int msgtype;
|
unsigned int msgtype;
|
||||||
|
unsigned long elapsed;
|
||||||
|
|
||||||
/* Check for matching transaction ID */
|
/* Check for matching transaction ID */
|
||||||
if ( dhcphdr->xid != dhcp_xid ( dhcp->netdev ) ) {
|
if ( dhcphdr->xid != dhcp_xid ( dhcp->netdev ) ) {
|
||||||
|
@ -843,41 +851,61 @@ static int dhcp_deliver_raw ( struct xfer_interface *xfer,
|
||||||
return -EINVAL;
|
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 );
|
msgtype = find_dhcp_num_option ( options, DHCP_MESSAGE_TYPE );
|
||||||
DBGC ( dhcp, "DHCP %p received %s\n",
|
DBGC ( dhcp, "DHCP %p received %s%s\n", dhcp,
|
||||||
dhcp, dhcp_msgtype_name ( msgtype ) );
|
( 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 ) {
|
switch ( dhcp->state ) {
|
||||||
case DHCPDISCOVER:
|
case DHCPDISCOVER:
|
||||||
if ( msgtype != DHCPOFFER )
|
/* If we have received a valid standard DHCP response
|
||||||
goto out_discard;
|
* (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->state = DHCPREQUEST;
|
||||||
|
dhcp_send_request ( dhcp );
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case DHCPREQUEST:
|
case DHCPREQUEST:
|
||||||
if ( msgtype != DHCPACK )
|
/* DHCP finished; register options and exit */
|
||||||
goto out_discard;
|
if ( dhcp->proxy_options )
|
||||||
dhcp->state = DHCPACK;
|
dhcp->register_options ( dhcp->netdev,
|
||||||
|
dhcp->proxy_options );
|
||||||
|
dhcp->register_options ( dhcp->netdev, dhcp->options );
|
||||||
|
dhcp_finished ( dhcp, 0 );
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
assert ( 0 );
|
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;
|
return 0;
|
||||||
|
|
||||||
out_discard:
|
out_discard:
|
||||||
|
@ -965,6 +993,7 @@ int start_dhcp ( struct job_interface *job, struct net_device *netdev,
|
||||||
dhcp->register_options = register_options;
|
dhcp->register_options = register_options;
|
||||||
dhcp->timer.expired = dhcp_timer_expired;
|
dhcp->timer.expired = dhcp_timer_expired;
|
||||||
dhcp->state = DHCPDISCOVER;
|
dhcp->state = DHCPDISCOVER;
|
||||||
|
dhcp->start = currticks();
|
||||||
|
|
||||||
/* Instantiate child objects and attach to our interfaces */
|
/* Instantiate child objects and attach to our interfaces */
|
||||||
if ( ( rc = xfer_open_socket ( &dhcp->xfer, SOCK_DGRAM,
|
if ( ( rc = xfer_open_socket ( &dhcp->xfer, SOCK_DGRAM,
|
||||||
|
|
Loading…
Reference in New Issue