summaryrefslogtreecommitdiffstats
path: root/qemu/roms/ipxe/src/net/udp/dhcp.c
diff options
context:
space:
mode:
Diffstat (limited to 'qemu/roms/ipxe/src/net/udp/dhcp.c')
-rw-r--r--qemu/roms/ipxe/src/net/udp/dhcp.c133
1 files changed, 92 insertions, 41 deletions
diff --git a/qemu/roms/ipxe/src/net/udp/dhcp.c b/qemu/roms/ipxe/src/net/udp/dhcp.c
index 04fad04c2..aed5ee360 100644
--- a/qemu/roms/ipxe/src/net/udp/dhcp.c
+++ b/qemu/roms/ipxe/src/net/udp/dhcp.c
@@ -15,9 +15,13 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
*/
-FILE_LICENCE ( GPL2_OR_LATER );
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <string.h>
#include <stdlib.h>
@@ -44,6 +48,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
#include <ipxe/dhcppkt.h>
#include <ipxe/dhcp_arch.h>
#include <ipxe/features.h>
+#include <config/dhcp.h>
/** @file
*
@@ -149,30 +154,32 @@ struct dhcp_session_state {
* @v dhcppkt DHCP packet
* @v peer Destination address
*/
- int ( * tx ) ( struct dhcp_session *dhcp,
- struct dhcp_packet *dhcppkt,
+ int ( * tx ) ( struct dhcp_session *dhcp, struct dhcp_packet *dhcppkt,
struct sockaddr_in *peer );
- /** Handle received packet
+ /**
+ * Handle received packet
*
* @v dhcp DHCP session
* @v dhcppkt DHCP packet
* @v peer DHCP server address
* @v msgtype DHCP message type
* @v server_id DHCP server ID
+ * @v pseudo_id DHCP server pseudo-ID
*/
- void ( * rx ) ( struct dhcp_session *dhcp,
- struct dhcp_packet *dhcppkt,
- struct sockaddr_in *peer,
- uint8_t msgtype, struct in_addr server_id );
- /** Handle timer expiry
+ void ( * rx ) ( struct dhcp_session *dhcp, struct dhcp_packet *dhcppkt,
+ struct sockaddr_in *peer, uint8_t msgtype,
+ struct in_addr server_id, struct in_addr pseudo_id );
+ /**
+ * Handle timer expiry
*
* @v dhcp DHCP session
*/
void ( * expired ) ( struct dhcp_session *dhcp );
/** Transmitted message type */
uint8_t tx_msgtype;
- /** Apply minimum timeout */
- uint8_t apply_min_timeout;
+ /** Timeout parameters */
+ uint8_t min_timeout_sec;
+ uint8_t max_timeout_sec;
};
static struct dhcp_session_state dhcp_state_discover;
@@ -272,9 +279,9 @@ static void dhcp_set_state ( struct dhcp_session *dhcp,
dhcp->state = state;
dhcp->start = currticks();
stop_timer ( &dhcp->timer );
- dhcp->timer.min_timeout =
- ( state->apply_min_timeout ? DHCP_MIN_TIMEOUT : 0 );
- dhcp->timer.max_timeout = DHCP_MAX_TIMEOUT;
+ set_timer_limits ( &dhcp->timer,
+ ( state->min_timeout_sec * TICKS_PER_SEC ),
+ ( state->max_timeout_sec * TICKS_PER_SEC ) );
start_timer_nodelay ( &dhcp->timer );
}
@@ -334,11 +341,13 @@ static int dhcp_discovery_tx ( struct dhcp_session *dhcp,
* @v peer DHCP server address
* @v msgtype DHCP message type
* @v server_id DHCP server ID
+ * @v pseudo_id DHCP server pseudo-ID
*/
static void dhcp_discovery_rx ( struct dhcp_session *dhcp,
struct dhcp_packet *dhcppkt,
struct sockaddr_in *peer, uint8_t msgtype,
- struct in_addr server_id ) {
+ struct in_addr server_id,
+ struct in_addr pseudo_id ) {
struct in_addr ip;
char vci[9]; /* "PXEClient" */
int vci_len;
@@ -350,8 +359,11 @@ static void dhcp_discovery_rx ( struct dhcp_session *dhcp,
DBGC ( dhcp, "DHCP %p %s from %s:%d", dhcp,
dhcp_msgtype_name ( msgtype ), inet_ntoa ( peer->sin_addr ),
ntohs ( peer->sin_port ) );
- if ( server_id.s_addr != peer->sin_addr.s_addr )
- DBGC ( dhcp, " (%s)", inet_ntoa ( server_id ) );
+ if ( ( server_id.s_addr != peer->sin_addr.s_addr ) ||
+ ( pseudo_id.s_addr != peer->sin_addr.s_addr ) ) {
+ DBGC ( dhcp, " (%s/", inet_ntoa ( server_id ) );
+ DBGC ( dhcp, "%s)", inet_ntoa ( pseudo_id ) );
+ }
/* Identify offered IP address */
ip = dhcppkt->dhcphdr->yiaddr;
@@ -392,10 +404,10 @@ static void dhcp_discovery_rx ( struct dhcp_session *dhcp,
}
/* Select as ProxyDHCP offer, if applicable */
- if ( server_id.s_addr && has_pxeclient &&
+ if ( pseudo_id.s_addr && has_pxeclient &&
( priority >= dhcp->proxy_priority ) ) {
dhcppkt_put ( dhcp->proxy_offer );
- dhcp->proxy_server = server_id;
+ dhcp->proxy_server = pseudo_id;
dhcp->proxy_offer = dhcppkt_get ( dhcppkt );
dhcp->proxy_priority = priority;
}
@@ -415,7 +427,7 @@ static void dhcp_discovery_rx ( struct dhcp_session *dhcp,
/* If we can't yet transition to DHCPREQUEST, do nothing */
elapsed = ( currticks() - dhcp->start );
if ( ! ( dhcp->no_pxedhcp || dhcp->proxy_offer ||
- ( elapsed > PROXYDHCP_MAX_TIMEOUT ) ) )
+ ( elapsed > DHCP_DISC_PROXY_TIMEOUT_SEC * TICKS_PER_SEC ) ) )
return;
/* Transition to DHCPREQUEST */
@@ -430,8 +442,18 @@ static void dhcp_discovery_rx ( struct dhcp_session *dhcp,
static void dhcp_discovery_expired ( struct dhcp_session *dhcp ) {
unsigned long elapsed = ( currticks() - dhcp->start );
+ /* If link is blocked, defer DHCP discovery (and reset timeout) */
+ if ( netdev_link_blocked ( dhcp->netdev ) ) {
+ DBGC ( dhcp, "DHCP %p deferring discovery\n", dhcp );
+ start_timer_fixed ( &dhcp->timer,
+ ( DHCP_DISC_START_TIMEOUT_SEC *
+ TICKS_PER_SEC ) );
+ return;
+ }
+
/* Give up waiting for ProxyDHCP before we reach the failure point */
- if ( dhcp->offer.s_addr && ( elapsed > PROXYDHCP_MAX_TIMEOUT ) ) {
+ if ( dhcp->offer.s_addr &&
+ ( elapsed > DHCP_DISC_PROXY_TIMEOUT_SEC * TICKS_PER_SEC ) ) {
dhcp_set_state ( dhcp, &dhcp_state_request );
return;
}
@@ -447,7 +469,8 @@ static struct dhcp_session_state dhcp_state_discover = {
.rx = dhcp_discovery_rx,
.expired = dhcp_discovery_expired,
.tx_msgtype = DHCPDISCOVER,
- .apply_min_timeout = 1,
+ .min_timeout_sec = DHCP_DISC_START_TIMEOUT_SEC,
+ .max_timeout_sec = DHCP_DISC_END_TIMEOUT_SEC,
};
/**
@@ -493,11 +516,13 @@ static int dhcp_request_tx ( struct dhcp_session *dhcp,
* @v peer DHCP server address
* @v msgtype DHCP message type
* @v server_id DHCP server ID
+ * @v pseudo_id DHCP server pseudo-ID
*/
static void dhcp_request_rx ( struct dhcp_session *dhcp,
struct dhcp_packet *dhcppkt,
struct sockaddr_in *peer, uint8_t msgtype,
- struct in_addr server_id ) {
+ struct in_addr server_id,
+ struct in_addr pseudo_id ) {
struct in_addr ip;
struct settings *parent;
struct settings *settings;
@@ -506,8 +531,11 @@ static void dhcp_request_rx ( struct dhcp_session *dhcp,
DBGC ( dhcp, "DHCP %p %s from %s:%d", dhcp,
dhcp_msgtype_name ( msgtype ), inet_ntoa ( peer->sin_addr ),
ntohs ( peer->sin_port ) );
- if ( server_id.s_addr != peer->sin_addr.s_addr )
- DBGC ( dhcp, " (%s)", inet_ntoa ( server_id ) );
+ if ( ( server_id.s_addr != peer->sin_addr.s_addr ) ||
+ ( pseudo_id.s_addr != peer->sin_addr.s_addr ) ) {
+ DBGC ( dhcp, " (%s/", inet_ntoa ( server_id ) );
+ DBGC ( dhcp, "%s)", inet_ntoa ( pseudo_id ) );
+ }
/* Identify leased IP address */
ip = dhcppkt->dhcphdr->yiaddr;
@@ -584,7 +612,8 @@ static struct dhcp_session_state dhcp_state_request = {
.rx = dhcp_request_rx,
.expired = dhcp_request_expired,
.tx_msgtype = DHCPREQUEST,
- .apply_min_timeout = 0,
+ .min_timeout_sec = DHCP_REQ_START_TIMEOUT_SEC,
+ .max_timeout_sec = DHCP_REQ_END_TIMEOUT_SEC,
};
/**
@@ -623,19 +652,26 @@ static int dhcp_proxy_tx ( struct dhcp_session *dhcp,
* @v peer DHCP server address
* @v msgtype DHCP message type
* @v server_id DHCP server ID
+ * @v pseudo_id DHCP server pseudo-ID
*/
static void dhcp_proxy_rx ( struct dhcp_session *dhcp,
struct dhcp_packet *dhcppkt,
struct sockaddr_in *peer, uint8_t msgtype,
- struct in_addr server_id ) {
+ struct in_addr server_id,
+ struct in_addr pseudo_id ) {
struct settings *settings = &dhcppkt->settings;
int rc;
DBGC ( dhcp, "DHCP %p %s from %s:%d", dhcp,
dhcp_msgtype_name ( msgtype ), inet_ntoa ( peer->sin_addr ),
ntohs ( peer->sin_port ) );
- if ( server_id.s_addr != peer->sin_addr.s_addr )
- DBGC ( dhcp, " (%s)", inet_ntoa ( server_id ) );
+ if ( ( server_id.s_addr != peer->sin_addr.s_addr ) ||
+ ( pseudo_id.s_addr != peer->sin_addr.s_addr ) ) {
+ DBGC ( dhcp, " (%s/", inet_ntoa ( server_id ) );
+ DBGC ( dhcp, "%s)", inet_ntoa ( pseudo_id ) );
+ }
+ if ( dhcp_has_pxeopts ( dhcppkt ) )
+ DBGC ( dhcp, " pxe" );
DBGC ( dhcp, "\n" );
/* Filter out unacceptable responses */
@@ -643,8 +679,9 @@ static void dhcp_proxy_rx ( struct dhcp_session *dhcp,
return;
if ( ( msgtype != DHCPOFFER ) && ( msgtype != DHCPACK ) )
return;
- if ( server_id.s_addr /* Linux PXE server omits server ID */ &&
- ( server_id.s_addr != dhcp->proxy_server.s_addr ) )
+ if ( ( pseudo_id.s_addr != dhcp->proxy_server.s_addr ) )
+ return;
+ if ( ! dhcp_has_pxeopts ( dhcppkt ) )
return;
/* Register settings */
@@ -669,7 +706,7 @@ static void dhcp_proxy_expired ( struct dhcp_session *dhcp ) {
unsigned long elapsed = ( currticks() - dhcp->start );
/* Give up waiting for ProxyDHCP before we reach the failure point */
- if ( elapsed > PROXYDHCP_MAX_TIMEOUT ) {
+ if ( elapsed > DHCP_REQ_PROXY_TIMEOUT_SEC * TICKS_PER_SEC ) {
dhcp_finished ( dhcp, 0 );
return;
}
@@ -685,7 +722,8 @@ static struct dhcp_session_state dhcp_state_proxy = {
.rx = dhcp_proxy_rx,
.expired = dhcp_proxy_expired,
.tx_msgtype = DHCPREQUEST,
- .apply_min_timeout = 0,
+ .min_timeout_sec = DHCP_PROXY_START_TIMEOUT_SEC,
+ .max_timeout_sec = DHCP_PROXY_END_TIMEOUT_SEC,
};
/**
@@ -753,19 +791,24 @@ static int dhcp_pxebs_accept ( struct dhcp_session *dhcp,
* @v peer DHCP server address
* @v msgtype DHCP message type
* @v server_id DHCP server ID
+ * @v pseudo_id DHCP server pseudo-ID
*/
static void dhcp_pxebs_rx ( struct dhcp_session *dhcp,
struct dhcp_packet *dhcppkt,
struct sockaddr_in *peer, uint8_t msgtype,
- struct in_addr server_id ) {
+ struct in_addr server_id,
+ struct in_addr pseudo_id ) {
struct dhcp_pxe_boot_menu_item menu_item = { 0, 0 };
int rc;
DBGC ( dhcp, "DHCP %p %s from %s:%d", dhcp,
dhcp_msgtype_name ( msgtype ), inet_ntoa ( peer->sin_addr ),
ntohs ( peer->sin_port ) );
- if ( server_id.s_addr != peer->sin_addr.s_addr )
- DBGC ( dhcp, " (%s)", inet_ntoa ( server_id ) );
+ if ( ( server_id.s_addr != peer->sin_addr.s_addr ) ||
+ ( pseudo_id.s_addr != peer->sin_addr.s_addr ) ) {
+ DBGC ( dhcp, " (%s/", inet_ntoa ( server_id ) );
+ DBGC ( dhcp, "%s)", inet_ntoa ( pseudo_id ) );
+ }
/* Identify boot menu item */
dhcppkt_fetch ( dhcppkt, DHCP_PXE_BOOT_MENU_ITEM,
@@ -782,8 +825,7 @@ static void dhcp_pxebs_rx ( struct dhcp_session *dhcp,
return;
if ( menu_item.type != dhcp->pxe_type )
return;
- if ( ! dhcp_pxebs_accept ( dhcp, ( server_id.s_addr ?
- server_id : peer->sin_addr ) ) )
+ if ( ! dhcp_pxebs_accept ( dhcp, pseudo_id ) )
return;
/* Register settings */
@@ -810,7 +852,7 @@ static void dhcp_pxebs_expired ( struct dhcp_session *dhcp ) {
/* Give up waiting before we reach the failure point, and fail
* over to the next server in the attempt list
*/
- if ( elapsed > PXEBS_MAX_TIMEOUT ) {
+ if ( elapsed > PXEBS_MAX_TIMEOUT_SEC * TICKS_PER_SEC ) {
dhcp->pxe_attempt++;
if ( dhcp->pxe_attempt->s_addr ) {
dhcp_set_state ( dhcp, &dhcp_state_pxebs );
@@ -832,7 +874,8 @@ static struct dhcp_session_state dhcp_state_pxebs = {
.rx = dhcp_pxebs_rx,
.expired = dhcp_pxebs_expired,
.tx_msgtype = DHCPREQUEST,
- .apply_min_timeout = 1,
+ .min_timeout_sec = PXEBS_START_TIMEOUT_SEC,
+ .max_timeout_sec = PXEBS_END_TIMEOUT_SEC,
};
/****************************************************************************
@@ -1114,6 +1157,7 @@ static int dhcp_deliver ( struct dhcp_session *dhcp,
struct dhcphdr *dhcphdr;
uint8_t msgtype = 0;
struct in_addr server_id = { 0 };
+ struct in_addr pseudo_id;
int rc = 0;
/* Sanity checks */
@@ -1148,6 +1192,13 @@ static int dhcp_deliver ( struct dhcp_session *dhcp,
dhcppkt_fetch ( dhcppkt, DHCP_SERVER_IDENTIFIER,
&server_id, sizeof ( server_id ) );
+ /* Identify server pseudo-ID */
+ pseudo_id = server_id;
+ if ( ! pseudo_id.s_addr )
+ pseudo_id = dhcppkt->dhcphdr->siaddr;
+ if ( ! pseudo_id.s_addr )
+ pseudo_id = peer->sin_addr;
+
/* Check for matching transaction ID */
if ( dhcphdr->xid != dhcp->xid ) {
DBGC ( dhcp, "DHCP %p %s from %s:%d has bad transaction "
@@ -1170,7 +1221,7 @@ static int dhcp_deliver ( struct dhcp_session *dhcp,
}
/* Handle packet based on current state */
- dhcp->state->rx ( dhcp, dhcppkt, peer, msgtype, server_id );
+ dhcp->state->rx ( dhcp, dhcppkt, peer, msgtype, server_id, pseudo_id );
err_chaddr:
err_xid: