int no_pxedhcp;
/** ProxyDHCP server */
struct in_addr proxy_server;
- /** ProxyDHCP port */
- uint16_t proxy_port;
- /** ProxyDHCP server priority */
+ /** ProxyDHCP offer */
+ struct dhcp_packet *proxy_offer;
+ /** ProxyDHCP offer priority */
int proxy_priority;
/** PXE Boot Server type */
container_of ( refcnt, struct dhcp_session, refcnt );
netdev_put ( dhcp->netdev );
+ dhcppkt_put ( dhcp->proxy_offer );
free ( dhcp );
}
start_timer_nodelay ( &dhcp->timer );
}
+/**
+ * Check if DHCP packet contains PXE options
+ *
+ * @v dhcppkt DHCP packet
+ * @ret has_pxeopts DHCP packet contains PXE options
+ *
+ * It is assumed that the packet is already known to contain option 60
+ * set to "PXEClient".
+ */
+static int dhcp_has_pxeopts ( struct dhcp_packet *dhcppkt ) {
+
+ /* Check for a boot filename */
+ if ( dhcppkt_fetch ( dhcppkt, DHCP_BOOTFILE_NAME, NULL, 0 ) > 0 )
+ return 1;
+
+ /* Check for a PXE boot menu */
+ if ( dhcppkt_fetch ( dhcppkt, DHCP_PXE_BOOT_MENU, NULL, 0 ) > 0 )
+ return 1;
+
+ return 0;
+}
+
/****************************************************************************
*
* DHCP state machine
char vci[9]; /* "PXEClient" */
int vci_len;
int has_pxeclient;
- int pxeopts_len;
- int has_pxeopts;
int8_t priority = 0;
uint8_t no_pxedhcp = 0;
unsigned long elapsed;
vci, sizeof ( vci ) );
has_pxeclient = ( ( vci_len >= ( int ) sizeof ( vci ) ) &&
( strncmp ( "PXEClient", vci, sizeof (vci) ) == 0 ));
-
- /* Identify presence of PXE-specific options */
- pxeopts_len = dhcppkt_fetch ( dhcppkt, DHCP_PXE_BOOT_MENU, NULL, 0 );
- has_pxeopts = ( pxeopts_len >= 0 );
- if ( has_pxeclient )
- DBGC ( dhcp, "%s", ( has_pxeopts ? " pxe" : " proxy" ) );
+ if ( has_pxeclient ) {
+ DBGC ( dhcp, "%s",
+ ( dhcp_has_pxeopts ( dhcppkt ) ? " pxe" : " proxy" ) );
+ }
/* Identify priority */
dhcppkt_fetch ( dhcppkt, DHCP_EB_PRIORITY, &priority,
}
/* Select as ProxyDHCP offer, if applicable */
- if ( has_pxeclient && ( msgtype == DHCPOFFER ) &&
+ if ( server_id.s_addr && has_pxeclient &&
( priority >= dhcp->proxy_priority ) ) {
- /* If the offer already includes the PXE options, then
- * assume that we can send the ProxyDHCPREQUEST to
- * port 67 (since the DHCPDISCOVER that triggered this
- * ProxyDHCPOFFER was sent to port 67). Otherwise,
- * send the ProxyDHCPREQUEST to port 4011.
- */
+ dhcppkt_put ( dhcp->proxy_offer );
dhcp->proxy_server = server_id;
- dhcp->proxy_port = ( has_pxeopts ? htons ( BOOTPS_PORT )
- : htons ( PXE_PORT ) );
+ dhcp->proxy_offer = dhcppkt_get ( dhcppkt );
dhcp->proxy_priority = priority;
}
/* If we can't yet transition to DHCPREQUEST, do nothing */
elapsed = ( currticks() - dhcp->start );
- if ( ! ( dhcp->no_pxedhcp || dhcp->proxy_server.s_addr ||
+ if ( ! ( dhcp->no_pxedhcp || dhcp->proxy_offer ||
( elapsed > PROXYDHCP_MAX_TIMEOUT ) ) )
return;
struct in_addr server_id ) {
struct in_addr ip;
struct settings *parent;
+ struct settings *settings;
int rc;
DBGC ( dhcp, "DHCP %p %s from %s:%d", dhcp,
/* Register settings */
parent = netdev_settings ( dhcp->netdev );
- if ( ( rc = register_settings ( &dhcppkt->settings, parent ) ) != 0 ){
+ settings = &dhcppkt->settings;
+ if ( ( rc = register_settings ( settings, parent ) ) != 0 ) {
DBGC ( dhcp, "DHCP %p could not register settings: %s\n",
dhcp, strerror ( rc ) );
dhcp_finished ( dhcp, rc );
return;
}
- /* Start ProxyDHCPREQUEST if applicable */
- if ( dhcp->proxy_server.s_addr /* Have ProxyDHCP server */ &&
- ( ! dhcp->no_pxedhcp ) /* ProxyDHCP not disabled */ &&
- ( /* ProxyDHCP server is not just the DHCP server itself */
- ( dhcp->proxy_server.s_addr != dhcp->server.s_addr ) ||
- ( dhcp->proxy_port != htons ( BOOTPS_PORT ) ) ) ) {
- dhcp_set_state ( dhcp, &dhcp_state_proxy );
- return;
+ /* Perform ProxyDHCP if applicable */
+ if ( dhcp->proxy_offer /* Have ProxyDHCP offer */ &&
+ ( ! dhcp->no_pxedhcp ) /* ProxyDHCP not disabled */ ) {
+ if ( dhcp_has_pxeopts ( dhcp->proxy_offer ) ) {
+ /* PXE options already present; register settings
+ * without performing a ProxyDHCPREQUEST
+ */
+ settings = &dhcp->proxy_offer->settings;
+ settings->name = PROXYDHCP_SETTINGS_NAME;
+ if ( ( rc = register_settings ( settings,
+ NULL ) ) != 0 ) {
+ DBGC ( dhcp, "DHCP %p could not register "
+ "proxy settings: %s\n",
+ dhcp, strerror ( rc ) );
+ dhcp_finished ( dhcp, rc );
+ return;
+ }
+ } else {
+ /* PXE options not present; use a ProxyDHCPREQUEST */
+ dhcp_set_state ( dhcp, &dhcp_state_proxy );
+ return;
+ }
}
/* Terminate DHCP */
struct sockaddr_in *peer ) {
int rc;
- DBGC ( dhcp, "DHCP %p ProxyDHCP REQUEST to %s:%d\n", dhcp,
- inet_ntoa ( dhcp->proxy_server ), ntohs ( dhcp->proxy_port ) );
+ DBGC ( dhcp, "DHCP %p ProxyDHCP REQUEST to %s\n", dhcp,
+ inet_ntoa ( dhcp->proxy_server ) );
/* Set server ID */
if ( ( rc = dhcppkt_store ( dhcppkt, DHCP_SERVER_IDENTIFIER,
/* Set server address */
peer->sin_addr = dhcp->proxy_server;
- peer->sin_port = dhcp->proxy_port;
+ peer->sin_port = htons ( PXE_PORT );
return 0;
}
struct dhcp_packet *dhcppkt,
struct sockaddr_in *peer, uint8_t msgtype,
struct in_addr server_id ) {
+ struct settings *settings = &dhcppkt->settings;
int rc;
DBGC ( dhcp, "DHCP %p %s from %s:%d", dhcp,
DBGC ( dhcp, "\n" );
/* Filter out unacceptable responses */
- if ( peer->sin_port != dhcp->proxy_port )
+ if ( peer->sin_port != ntohs ( PXE_PORT ) )
return;
if ( ( msgtype != DHCPOFFER ) && ( msgtype != DHCPACK ) )
return;
return;
/* Register settings */
- dhcppkt->settings.name = PROXYDHCP_SETTINGS_NAME;
- if ( ( rc = register_settings ( &dhcppkt->settings, NULL ) ) != 0 ) {
- DBGC ( dhcp, "DHCP %p could not register settings: %s\n",
+ settings->name = PROXYDHCP_SETTINGS_NAME;
+ if ( ( rc = register_settings ( settings, NULL ) ) != 0 ) {
+ DBGC ( dhcp, "DHCP %p could not register proxy settings: %s\n",
dhcp, strerror ( rc ) );
dhcp_finished ( dhcp, rc );
return;