mirror of https://github.com/ipxe/ipxe.git
[pxe] Obey lists of PXE Boot Servers and associated Discovery Control bits
Various combinations of options 43.6, 43.7 and 43.8 dictate which servers we send Boot Server Discovery requests to, and which servers we should accept responses from. Obey these options, and remove the explicit specification of a single Boot Server from start_pxebs() and dependent functions.pull/1/head
parent
ff2b308506
commit
881f1f59ef
|
@ -109,7 +109,7 @@ static int dhcp_exec ( int argc, char **argv ) {
|
||||||
*/
|
*/
|
||||||
static void pxebs_syntax ( char **argv ) {
|
static void pxebs_syntax ( char **argv ) {
|
||||||
printf ( "Usage:\n"
|
printf ( "Usage:\n"
|
||||||
" %s <interface> <discovery_ip> <server_type>\n"
|
" %s <interface> <server_type>\n"
|
||||||
"\n"
|
"\n"
|
||||||
"Perform PXE Boot Server discovery\n",
|
"Perform PXE Boot Server discovery\n",
|
||||||
argv[0] );
|
argv[0] );
|
||||||
|
@ -128,10 +128,8 @@ static int pxebs_exec ( int argc, char **argv ) {
|
||||||
{ NULL, 0, NULL, 0 },
|
{ NULL, 0, NULL, 0 },
|
||||||
};
|
};
|
||||||
const char *netdev_txt;
|
const char *netdev_txt;
|
||||||
const char *pxe_server_txt;
|
|
||||||
const char *pxe_type_txt;
|
const char *pxe_type_txt;
|
||||||
struct net_device *netdev;
|
struct net_device *netdev;
|
||||||
struct in_addr pxe_server;
|
|
||||||
unsigned int pxe_type;
|
unsigned int pxe_type;
|
||||||
char *end;
|
char *end;
|
||||||
int c;
|
int c;
|
||||||
|
@ -148,15 +146,12 @@ static int pxebs_exec ( int argc, char **argv ) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if ( optind != ( argc - 2 ) ) {
|
||||||
/* Need exactly one interface name remaining after the options */
|
|
||||||
if ( optind != ( argc - 3 ) ) {
|
|
||||||
pxebs_syntax ( argv );
|
pxebs_syntax ( argv );
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
netdev_txt = argv[optind];
|
netdev_txt = argv[optind];
|
||||||
pxe_server_txt = argv[ optind + 1 ];
|
pxe_type_txt = argv[ optind + 1 ];
|
||||||
pxe_type_txt = argv[ optind + 2 ];
|
|
||||||
|
|
||||||
/* Parse arguments */
|
/* Parse arguments */
|
||||||
netdev = find_netdev ( netdev_txt );
|
netdev = find_netdev ( netdev_txt );
|
||||||
|
@ -164,10 +159,6 @@ static int pxebs_exec ( int argc, char **argv ) {
|
||||||
printf ( "No such interface: %s\n", netdev_txt );
|
printf ( "No such interface: %s\n", netdev_txt );
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
if ( inet_aton ( pxe_server_txt, &pxe_server ) == 0 ) {
|
|
||||||
printf ( "Bad discovery IP address: %s\n", pxe_server_txt );
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
pxe_type = strtoul ( pxe_type_txt, &end, 0 );
|
pxe_type = strtoul ( pxe_type_txt, &end, 0 );
|
||||||
if ( *end ) {
|
if ( *end ) {
|
||||||
printf ( "Bad server type: %s\n", pxe_type_txt );
|
printf ( "Bad server type: %s\n", pxe_type_txt );
|
||||||
|
@ -175,7 +166,7 @@ static int pxebs_exec ( int argc, char **argv ) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Perform Boot Server Discovery */
|
/* Perform Boot Server Discovery */
|
||||||
if ( ( rc = pxebs ( netdev, pxe_server, pxe_type ) ) != 0 ) {
|
if ( ( rc = pxebs ( netdev, pxe_type ) ) != 0 ) {
|
||||||
printf ( "Could not discover boot server on %s: %s\n",
|
printf ( "Could not discover boot server on %s: %s\n",
|
||||||
netdev->name, strerror ( rc ) );
|
netdev->name, strerror ( rc ) );
|
||||||
return 1;
|
return 1;
|
||||||
|
|
|
@ -100,6 +100,19 @@ enum dhcp_pxe_discovery_control {
|
||||||
/** PXE boot server multicast address */
|
/** PXE boot server multicast address */
|
||||||
#define DHCP_PXE_BOOT_SERVER_MCAST DHCP_ENCAP_OPT ( DHCP_VENDOR_ENCAP, 7 )
|
#define DHCP_PXE_BOOT_SERVER_MCAST DHCP_ENCAP_OPT ( DHCP_VENDOR_ENCAP, 7 )
|
||||||
|
|
||||||
|
/** PXE boot servers */
|
||||||
|
#define DHCP_PXE_BOOT_SERVERS DHCP_ENCAP_OPT ( DHCP_VENDOR_ENCAP, 8 )
|
||||||
|
|
||||||
|
/** PXE boot server */
|
||||||
|
struct dhcp_pxe_boot_server {
|
||||||
|
/** "Type" */
|
||||||
|
uint16_t type;
|
||||||
|
/** Number of IPv4 addresses */
|
||||||
|
uint8_t num_ip;
|
||||||
|
/** IPv4 addresses */
|
||||||
|
struct in_addr ip[0];
|
||||||
|
} __attribute__ (( packed ));
|
||||||
|
|
||||||
/** PXE boot menu */
|
/** PXE boot menu */
|
||||||
#define DHCP_PXE_BOOT_MENU DHCP_ENCAP_OPT ( DHCP_VENDOR_ENCAP, 9 )
|
#define DHCP_PXE_BOOT_MENU DHCP_ENCAP_OPT ( DHCP_VENDOR_ENCAP, 9 )
|
||||||
|
|
||||||
|
@ -574,6 +587,9 @@ struct dhcphdr {
|
||||||
/** Maximum time that we will wait for ProxyDHCP responses */
|
/** Maximum time that we will wait for ProxyDHCP responses */
|
||||||
#define PROXYDHCP_MAX_TIMEOUT ( 2 * TICKS_PER_SEC )
|
#define PROXYDHCP_MAX_TIMEOUT ( 2 * TICKS_PER_SEC )
|
||||||
|
|
||||||
|
/** Maximum time that we will wait for Boot Server responses */
|
||||||
|
#define PXEBS_MAX_TIMEOUT ( 3 * TICKS_PER_SEC )
|
||||||
|
|
||||||
/** Settings block name used for DHCP responses */
|
/** Settings block name used for DHCP responses */
|
||||||
#define DHCP_SETTINGS_NAME "dhcp"
|
#define DHCP_SETTINGS_NAME "dhcp"
|
||||||
|
|
||||||
|
@ -593,6 +609,6 @@ extern int dhcp_create_request ( struct dhcp_packet *dhcppkt,
|
||||||
void *data, size_t max_len );
|
void *data, size_t max_len );
|
||||||
extern int start_dhcp ( struct job_interface *job, struct net_device *netdev );
|
extern int start_dhcp ( struct job_interface *job, struct net_device *netdev );
|
||||||
extern int start_pxebs ( struct job_interface *job, struct net_device *netdev,
|
extern int start_pxebs ( struct job_interface *job, struct net_device *netdev,
|
||||||
struct in_addr pxe_server, unsigned int pxe_type );
|
unsigned int pxe_type );
|
||||||
|
|
||||||
#endif /* _GPXE_DHCP_H */
|
#endif /* _GPXE_DHCP_H */
|
||||||
|
|
|
@ -10,7 +10,6 @@
|
||||||
struct net_device;
|
struct net_device;
|
||||||
|
|
||||||
extern int dhcp ( struct net_device *netdev );
|
extern int dhcp ( struct net_device *netdev );
|
||||||
extern int pxebs ( struct net_device *netdev, struct in_addr pxe_server,
|
extern int pxebs ( struct net_device *netdev, unsigned int pxe_type );
|
||||||
unsigned int pxe_type );
|
|
||||||
|
|
||||||
#endif /* _USR_DHCPMGMT_H */
|
#endif /* _USR_DHCPMGMT_H */
|
||||||
|
|
|
@ -175,11 +175,12 @@ struct dhcp_session_state {
|
||||||
* @v dhcppkt DHCP packet
|
* @v dhcppkt DHCP packet
|
||||||
* @v peer DHCP server address
|
* @v peer DHCP server address
|
||||||
* @v msgtype DHCP message type
|
* @v msgtype DHCP message type
|
||||||
|
* @v server_id DHCP server ID
|
||||||
*/
|
*/
|
||||||
void ( * rx ) ( struct dhcp_session *dhcp,
|
void ( * rx ) ( struct dhcp_session *dhcp,
|
||||||
struct dhcp_packet *dhcppkt,
|
struct dhcp_packet *dhcppkt,
|
||||||
struct sockaddr_in *peer,
|
struct sockaddr_in *peer,
|
||||||
uint8_t msgtype );
|
uint8_t msgtype, struct in_addr server_id );
|
||||||
/** Handle timer expiry
|
/** Handle timer expiry
|
||||||
*
|
*
|
||||||
* @v dhcp DHCP session
|
* @v dhcp DHCP session
|
||||||
|
@ -226,10 +227,12 @@ struct dhcp_session {
|
||||||
/** ProxyDHCP server priority */
|
/** ProxyDHCP server priority */
|
||||||
int proxy_priority;
|
int proxy_priority;
|
||||||
|
|
||||||
/** PXE Boot Server */
|
|
||||||
struct in_addr pxe_server;
|
|
||||||
/** PXE Boot Server type */
|
/** PXE Boot Server type */
|
||||||
uint16_t pxe_type;
|
uint16_t pxe_type;
|
||||||
|
/** List of PXE Boot Servers to attempt */
|
||||||
|
struct in_addr *pxe_attempt;
|
||||||
|
/** List of PXE Boot Servers to accept */
|
||||||
|
struct in_addr *pxe_accept;
|
||||||
|
|
||||||
/** Retransmission timer */
|
/** Retransmission timer */
|
||||||
struct retry_timer timer;
|
struct retry_timer timer;
|
||||||
|
@ -322,11 +325,12 @@ static int dhcp_discovery_tx ( struct dhcp_session *dhcp,
|
||||||
* @v dhcppkt DHCP packet
|
* @v dhcppkt DHCP packet
|
||||||
* @v peer DHCP server address
|
* @v peer DHCP server address
|
||||||
* @v msgtype DHCP message type
|
* @v msgtype DHCP message type
|
||||||
|
* @v server_id DHCP server ID
|
||||||
*/
|
*/
|
||||||
static void dhcp_discovery_rx ( struct dhcp_session *dhcp,
|
static void dhcp_discovery_rx ( struct dhcp_session *dhcp,
|
||||||
struct dhcp_packet *dhcppkt,
|
struct dhcp_packet *dhcppkt,
|
||||||
struct sockaddr_in *peer, uint8_t msgtype ) {
|
struct sockaddr_in *peer, uint8_t msgtype,
|
||||||
struct in_addr server_id = { 0 };
|
struct in_addr server_id ) {
|
||||||
struct in_addr ip;
|
struct in_addr ip;
|
||||||
char vci[9]; /* "PXEClient" */
|
char vci[9]; /* "PXEClient" */
|
||||||
int vci_len;
|
int vci_len;
|
||||||
|
@ -338,10 +342,6 @@ static void dhcp_discovery_rx ( struct dhcp_session *dhcp,
|
||||||
DBGC ( dhcp, "DHCP %p %s from %s:%d", dhcp,
|
DBGC ( dhcp, "DHCP %p %s from %s:%d", dhcp,
|
||||||
dhcp_msgtype_name ( msgtype ), inet_ntoa ( peer->sin_addr ),
|
dhcp_msgtype_name ( msgtype ), inet_ntoa ( peer->sin_addr ),
|
||||||
ntohs ( peer->sin_port ) );
|
ntohs ( peer->sin_port ) );
|
||||||
|
|
||||||
/* Identify server ID */
|
|
||||||
dhcppkt_fetch ( dhcppkt, DHCP_SERVER_IDENTIFIER,
|
|
||||||
&server_id, sizeof ( server_id ) );
|
|
||||||
if ( server_id.s_addr != peer->sin_addr.s_addr )
|
if ( server_id.s_addr != peer->sin_addr.s_addr )
|
||||||
DBGC ( dhcp, " (%s)", inet_ntoa ( server_id ) );
|
DBGC ( dhcp, " (%s)", inet_ntoa ( server_id ) );
|
||||||
|
|
||||||
|
@ -480,11 +480,12 @@ static int dhcp_request_tx ( struct dhcp_session *dhcp,
|
||||||
* @v dhcppkt DHCP packet
|
* @v dhcppkt DHCP packet
|
||||||
* @v peer DHCP server address
|
* @v peer DHCP server address
|
||||||
* @v msgtype DHCP message type
|
* @v msgtype DHCP message type
|
||||||
|
* @v server_id DHCP server ID
|
||||||
*/
|
*/
|
||||||
static void dhcp_request_rx ( struct dhcp_session *dhcp,
|
static void dhcp_request_rx ( struct dhcp_session *dhcp,
|
||||||
struct dhcp_packet *dhcppkt,
|
struct dhcp_packet *dhcppkt,
|
||||||
struct sockaddr_in *peer, uint8_t msgtype ) {
|
struct sockaddr_in *peer, uint8_t msgtype,
|
||||||
struct in_addr server_id = { 0 };
|
struct in_addr server_id ) {
|
||||||
struct in_addr ip;
|
struct in_addr ip;
|
||||||
struct settings *parent;
|
struct settings *parent;
|
||||||
int rc;
|
int rc;
|
||||||
|
@ -492,10 +493,6 @@ static void dhcp_request_rx ( struct dhcp_session *dhcp,
|
||||||
DBGC ( dhcp, "DHCP %p %s from %s:%d", dhcp,
|
DBGC ( dhcp, "DHCP %p %s from %s:%d", dhcp,
|
||||||
dhcp_msgtype_name ( msgtype ), inet_ntoa ( peer->sin_addr ),
|
dhcp_msgtype_name ( msgtype ), inet_ntoa ( peer->sin_addr ),
|
||||||
ntohs ( peer->sin_port ) );
|
ntohs ( peer->sin_port ) );
|
||||||
|
|
||||||
/* Identify server ID */
|
|
||||||
dhcppkt_fetch ( dhcppkt, DHCP_SERVER_IDENTIFIER,
|
|
||||||
&server_id, sizeof ( server_id ) );
|
|
||||||
if ( server_id.s_addr != peer->sin_addr.s_addr )
|
if ( server_id.s_addr != peer->sin_addr.s_addr )
|
||||||
DBGC ( dhcp, " (%s)", inet_ntoa ( server_id ) );
|
DBGC ( dhcp, " (%s)", inet_ntoa ( server_id ) );
|
||||||
|
|
||||||
|
@ -591,20 +588,17 @@ static int dhcp_proxy_tx ( struct dhcp_session *dhcp,
|
||||||
* @v dhcppkt DHCP packet
|
* @v dhcppkt DHCP packet
|
||||||
* @v peer DHCP server address
|
* @v peer DHCP server address
|
||||||
* @v msgtype DHCP message type
|
* @v msgtype DHCP message type
|
||||||
|
* @v server_id DHCP server ID
|
||||||
*/
|
*/
|
||||||
static void dhcp_proxy_rx ( struct dhcp_session *dhcp,
|
static void dhcp_proxy_rx ( struct dhcp_session *dhcp,
|
||||||
struct dhcp_packet *dhcppkt,
|
struct dhcp_packet *dhcppkt,
|
||||||
struct sockaddr_in *peer, uint8_t msgtype ) {
|
struct sockaddr_in *peer, uint8_t msgtype,
|
||||||
struct in_addr server_id = { 0 };
|
struct in_addr server_id ) {
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
DBGC ( dhcp, "DHCP %p %s from %s:%d", dhcp,
|
DBGC ( dhcp, "DHCP %p %s from %s:%d", dhcp,
|
||||||
dhcp_msgtype_name ( msgtype ), inet_ntoa ( peer->sin_addr ),
|
dhcp_msgtype_name ( msgtype ), inet_ntoa ( peer->sin_addr ),
|
||||||
ntohs ( peer->sin_port ) );
|
ntohs ( peer->sin_port ) );
|
||||||
|
|
||||||
/* Identify server ID */
|
|
||||||
dhcppkt_fetch ( dhcppkt, DHCP_SERVER_IDENTIFIER,
|
|
||||||
&server_id, sizeof ( server_id ) );
|
|
||||||
if ( server_id.s_addr != peer->sin_addr.s_addr )
|
if ( server_id.s_addr != peer->sin_addr.s_addr )
|
||||||
DBGC ( dhcp, " (%s)", inet_ntoa ( server_id ) );
|
DBGC ( dhcp, " (%s)", inet_ntoa ( server_id ) );
|
||||||
DBGC ( dhcp, "\n" );
|
DBGC ( dhcp, "\n" );
|
||||||
|
@ -673,7 +667,7 @@ static int dhcp_pxebs_tx ( struct dhcp_session *dhcp,
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
DBGC ( dhcp, "DHCP %p PXEBS REQUEST to %s:%d for type %d\n",
|
DBGC ( dhcp, "DHCP %p PXEBS REQUEST to %s:%d for type %d\n",
|
||||||
dhcp, inet_ntoa ( dhcp->pxe_server ), PXE_PORT,
|
dhcp, inet_ntoa ( *(dhcp->pxe_attempt) ), PXE_PORT,
|
||||||
ntohs ( dhcp->pxe_type ) );
|
ntohs ( dhcp->pxe_type ) );
|
||||||
|
|
||||||
/* Set boot menu item */
|
/* Set boot menu item */
|
||||||
|
@ -683,12 +677,38 @@ static int dhcp_pxebs_tx ( struct dhcp_session *dhcp,
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
/* Set server address */
|
/* Set server address */
|
||||||
peer->sin_addr = dhcp->pxe_server;
|
peer->sin_addr = *(dhcp->pxe_attempt);
|
||||||
peer->sin_port = htons ( PXE_PORT );
|
peer->sin_port = htons ( PXE_PORT );
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check to see if PXE Boot Server address is acceptable
|
||||||
|
*
|
||||||
|
* @v dhcp DHCP session
|
||||||
|
* @v bs Boot Server address
|
||||||
|
* @ret accept Boot Server is acceptable
|
||||||
|
*/
|
||||||
|
static int dhcp_pxebs_accept ( struct dhcp_session *dhcp,
|
||||||
|
struct in_addr bs ) {
|
||||||
|
struct in_addr *accept;
|
||||||
|
|
||||||
|
/* Accept if we have no acceptance filter */
|
||||||
|
if ( ! dhcp->pxe_accept )
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
/* Scan through acceptance list */
|
||||||
|
for ( accept = dhcp->pxe_accept ; accept->s_addr ; accept++ ) {
|
||||||
|
if ( accept->s_addr == bs.s_addr )
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
DBGC ( dhcp, "DHCP %p rejecting server %s\n",
|
||||||
|
dhcp, inet_ntoa ( bs ) );
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle received packet during PXE Boot Server Discovery
|
* Handle received packet during PXE Boot Server Discovery
|
||||||
*
|
*
|
||||||
|
@ -696,16 +716,20 @@ static int dhcp_pxebs_tx ( struct dhcp_session *dhcp,
|
||||||
* @v dhcppkt DHCP packet
|
* @v dhcppkt DHCP packet
|
||||||
* @v peer DHCP server address
|
* @v peer DHCP server address
|
||||||
* @v msgtype DHCP message type
|
* @v msgtype DHCP message type
|
||||||
|
* @v server_id DHCP server ID
|
||||||
*/
|
*/
|
||||||
static void dhcp_pxebs_rx ( struct dhcp_session *dhcp,
|
static void dhcp_pxebs_rx ( struct dhcp_session *dhcp,
|
||||||
struct dhcp_packet *dhcppkt,
|
struct dhcp_packet *dhcppkt,
|
||||||
struct sockaddr_in *peer, uint8_t msgtype ) {
|
struct sockaddr_in *peer, uint8_t msgtype,
|
||||||
|
struct in_addr server_id ) {
|
||||||
struct dhcp_pxe_boot_menu_item menu_item = { 0, 0 };
|
struct dhcp_pxe_boot_menu_item menu_item = { 0, 0 };
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
DBGC ( dhcp, "DHCP %p %s from %s:%d", dhcp,
|
DBGC ( dhcp, "DHCP %p %s from %s:%d", dhcp,
|
||||||
dhcp_msgtype_name ( msgtype ), inet_ntoa ( peer->sin_addr ),
|
dhcp_msgtype_name ( msgtype ), inet_ntoa ( peer->sin_addr ),
|
||||||
ntohs ( peer->sin_port ) );
|
ntohs ( peer->sin_port ) );
|
||||||
|
if ( server_id.s_addr != peer->sin_addr.s_addr )
|
||||||
|
DBGC ( dhcp, " (%s)", inet_ntoa ( server_id ) );
|
||||||
|
|
||||||
/* Identify boot menu item */
|
/* Identify boot menu item */
|
||||||
dhcppkt_fetch ( dhcppkt, DHCP_PXE_BOOT_MENU_ITEM,
|
dhcppkt_fetch ( dhcppkt, DHCP_PXE_BOOT_MENU_ITEM,
|
||||||
|
@ -721,6 +745,9 @@ static void dhcp_pxebs_rx ( struct dhcp_session *dhcp,
|
||||||
return;
|
return;
|
||||||
if ( menu_item.type != dhcp->pxe_type )
|
if ( menu_item.type != dhcp->pxe_type )
|
||||||
return;
|
return;
|
||||||
|
if ( ! dhcp_pxebs_accept ( dhcp, ( server_id.s_addr ?
|
||||||
|
server_id : peer->sin_addr ) ) )
|
||||||
|
return;
|
||||||
|
|
||||||
/* Register settings */
|
/* Register settings */
|
||||||
dhcppkt->settings.name = PXEBS_SETTINGS_NAME;
|
dhcppkt->settings.name = PXEBS_SETTINGS_NAME;
|
||||||
|
@ -741,6 +768,21 @@ static void dhcp_pxebs_rx ( struct dhcp_session *dhcp,
|
||||||
* @v dhcp DHCP session
|
* @v dhcp DHCP session
|
||||||
*/
|
*/
|
||||||
static void dhcp_pxebs_expired ( struct dhcp_session *dhcp ) {
|
static void dhcp_pxebs_expired ( struct dhcp_session *dhcp ) {
|
||||||
|
unsigned long elapsed = ( currticks() - dhcp->start );
|
||||||
|
|
||||||
|
/* 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 ) {
|
||||||
|
dhcp->pxe_attempt++;
|
||||||
|
if ( dhcp->pxe_attempt->s_addr ) {
|
||||||
|
dhcp_set_state ( dhcp, &dhcp_state_pxebs );
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
dhcp_finished ( dhcp, -ETIMEDOUT );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Retransmit current packet */
|
/* Retransmit current packet */
|
||||||
dhcp_tx ( dhcp );
|
dhcp_tx ( dhcp );
|
||||||
|
@ -1006,6 +1048,7 @@ static int dhcp_deliver_iob ( struct xfer_interface *xfer,
|
||||||
struct dhcp_packet *dhcppkt;
|
struct dhcp_packet *dhcppkt;
|
||||||
struct dhcphdr *dhcphdr;
|
struct dhcphdr *dhcphdr;
|
||||||
uint8_t msgtype = 0;
|
uint8_t msgtype = 0;
|
||||||
|
struct in_addr server_id = { 0 };
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
|
|
||||||
/* Sanity checks */
|
/* Sanity checks */
|
||||||
|
@ -1042,6 +1085,10 @@ static int dhcp_deliver_iob ( struct xfer_interface *xfer,
|
||||||
dhcppkt_fetch ( dhcppkt, DHCP_MESSAGE_TYPE, &msgtype,
|
dhcppkt_fetch ( dhcppkt, DHCP_MESSAGE_TYPE, &msgtype,
|
||||||
sizeof ( msgtype ) );
|
sizeof ( msgtype ) );
|
||||||
|
|
||||||
|
/* Identify server ID */
|
||||||
|
dhcppkt_fetch ( dhcppkt, DHCP_SERVER_IDENTIFIER,
|
||||||
|
&server_id, sizeof ( server_id ) );
|
||||||
|
|
||||||
/* Check for matching transaction ID */
|
/* Check for matching transaction ID */
|
||||||
if ( dhcphdr->xid != dhcp_xid ( dhcp->netdev ) ) {
|
if ( dhcphdr->xid != dhcp_xid ( dhcp->netdev ) ) {
|
||||||
DBGC ( dhcp, "DHCP %p %s from %s:%d has bad transaction "
|
DBGC ( dhcp, "DHCP %p %s from %s:%d has bad transaction "
|
||||||
|
@ -1053,7 +1100,7 @@ static int dhcp_deliver_iob ( struct xfer_interface *xfer,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Handle packet based on current state */
|
/* Handle packet based on current state */
|
||||||
dhcp->state->rx ( dhcp, dhcppkt, peer, msgtype );
|
dhcp->state->rx ( dhcp, dhcppkt, peer, msgtype, server_id );
|
||||||
|
|
||||||
err_xid:
|
err_xid:
|
||||||
dhcppkt_put ( dhcppkt );
|
dhcppkt_put ( dhcppkt );
|
||||||
|
@ -1183,12 +1230,50 @@ int start_dhcp ( struct job_interface *job, struct net_device *netdev ) {
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve list of PXE boot servers for a given server type
|
||||||
|
*
|
||||||
|
* @v dhcp DHCP session
|
||||||
|
* @v raw DHCP PXE boot server list
|
||||||
|
* @v raw_len Length of DHCP PXE boot server list
|
||||||
|
* @v ip IP address list to fill in
|
||||||
|
*
|
||||||
|
* The caller must ensure that the IP address list has sufficient
|
||||||
|
* space.
|
||||||
|
*/
|
||||||
|
static void pxebs_list ( struct dhcp_session *dhcp, void *raw,
|
||||||
|
size_t raw_len, struct in_addr *ip ) {
|
||||||
|
struct dhcp_pxe_boot_server *server = raw;
|
||||||
|
size_t server_len;
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
while ( raw_len ) {
|
||||||
|
if ( raw_len < sizeof ( *server ) ) {
|
||||||
|
DBGC ( dhcp, "DHCP %p malformed PXE server list\n",
|
||||||
|
dhcp );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
server_len = offsetof ( typeof ( *server ),
|
||||||
|
ip[ server->num_ip ] );
|
||||||
|
if ( raw_len < server_len ) {
|
||||||
|
DBGC ( dhcp, "DHCP %p malformed PXE server list\n",
|
||||||
|
dhcp );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if ( server->type == dhcp->pxe_type ) {
|
||||||
|
for ( i = 0 ; i < server->num_ip ; i++ )
|
||||||
|
*(ip++) = server->ip[i];
|
||||||
|
}
|
||||||
|
server = ( ( ( void * ) server ) + server_len );
|
||||||
|
raw_len -= server_len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Start PXE Boot Server Discovery on a network device
|
* Start PXE Boot Server Discovery on a network device
|
||||||
*
|
*
|
||||||
* @v job Job control interface
|
* @v job Job control interface
|
||||||
* @v netdev Network device
|
* @v netdev Network device
|
||||||
* @v pxe_server PXE server (may be a multicast address)
|
|
||||||
* @v pxe_type PXE server type
|
* @v pxe_type PXE server type
|
||||||
* @ret rc Return status code
|
* @ret rc Return status code
|
||||||
*
|
*
|
||||||
|
@ -1197,12 +1282,28 @@ int start_dhcp ( struct job_interface *job, struct net_device *netdev ) {
|
||||||
* source.
|
* source.
|
||||||
*/
|
*/
|
||||||
int start_pxebs ( struct job_interface *job, struct net_device *netdev,
|
int start_pxebs ( struct job_interface *job, struct net_device *netdev,
|
||||||
struct in_addr pxe_server, unsigned int pxe_type ) {
|
unsigned int pxe_type ) {
|
||||||
|
struct setting pxe_discovery_control_setting =
|
||||||
|
{ .tag = DHCP_PXE_DISCOVERY_CONTROL };
|
||||||
|
struct setting pxe_boot_servers_setting =
|
||||||
|
{ .tag = DHCP_PXE_BOOT_SERVERS };
|
||||||
|
struct setting pxe_boot_server_mcast_setting =
|
||||||
|
{ .tag = DHCP_PXE_BOOT_SERVER_MCAST };
|
||||||
|
ssize_t pxebs_list_len;
|
||||||
struct dhcp_session *dhcp;
|
struct dhcp_session *dhcp;
|
||||||
|
struct in_addr *ip;
|
||||||
|
unsigned int pxe_discovery_control;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
|
/* Get upper bound for PXE boot server IP address list */
|
||||||
|
pxebs_list_len = fetch_setting_len ( NULL, &pxe_boot_servers_setting );
|
||||||
|
if ( pxebs_list_len < 0 )
|
||||||
|
pxebs_list_len = 0;
|
||||||
|
|
||||||
/* Allocate and initialise structure */
|
/* Allocate and initialise structure */
|
||||||
dhcp = zalloc ( sizeof ( *dhcp ) );
|
dhcp = zalloc ( sizeof ( *dhcp ) + sizeof ( *ip ) /* mcast */ +
|
||||||
|
sizeof ( *ip ) /* bcast */ + pxebs_list_len +
|
||||||
|
sizeof ( *ip ) /* terminator */ );
|
||||||
if ( ! dhcp )
|
if ( ! dhcp )
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
dhcp->refcnt.free = dhcp_free;
|
dhcp->refcnt.free = dhcp_free;
|
||||||
|
@ -1213,10 +1314,49 @@ int start_pxebs ( struct job_interface *job, struct net_device *netdev,
|
||||||
fetch_ipv4_setting ( netdev_settings ( netdev ), &ip_setting,
|
fetch_ipv4_setting ( netdev_settings ( netdev ), &ip_setting,
|
||||||
&dhcp->local.sin_addr );
|
&dhcp->local.sin_addr );
|
||||||
dhcp->local.sin_port = htons ( BOOTPC_PORT );
|
dhcp->local.sin_port = htons ( BOOTPC_PORT );
|
||||||
dhcp->pxe_server = pxe_server;
|
|
||||||
dhcp->pxe_type = htons ( pxe_type );
|
dhcp->pxe_type = htons ( pxe_type );
|
||||||
dhcp->timer.expired = dhcp_timer_expired;
|
dhcp->timer.expired = dhcp_timer_expired;
|
||||||
|
|
||||||
|
/* Construct PXE boot server IP address lists */
|
||||||
|
pxe_discovery_control =
|
||||||
|
fetch_uintz_setting ( NULL, &pxe_discovery_control_setting );
|
||||||
|
ip = ( ( ( void * ) dhcp ) + sizeof ( *dhcp ) );
|
||||||
|
dhcp->pxe_attempt = ip;
|
||||||
|
if ( ! ( pxe_discovery_control & PXEBS_NO_MULTICAST ) ) {
|
||||||
|
fetch_ipv4_setting ( NULL, &pxe_boot_server_mcast_setting, ip);
|
||||||
|
if ( ip->s_addr )
|
||||||
|
ip++;
|
||||||
|
}
|
||||||
|
if ( ! ( pxe_discovery_control & PXEBS_NO_BROADCAST ) )
|
||||||
|
(ip++)->s_addr = INADDR_BROADCAST;
|
||||||
|
if ( pxe_discovery_control & PXEBS_NO_UNKNOWN_SERVERS )
|
||||||
|
dhcp->pxe_accept = ip;
|
||||||
|
if ( pxebs_list_len ) {
|
||||||
|
uint8_t buf[pxebs_list_len];
|
||||||
|
|
||||||
|
fetch_setting ( NULL, &pxe_boot_servers_setting,
|
||||||
|
buf, sizeof ( buf ) );
|
||||||
|
pxebs_list ( dhcp, buf, sizeof ( buf ), ip );
|
||||||
|
}
|
||||||
|
if ( ! dhcp->pxe_attempt->s_addr ) {
|
||||||
|
DBGC ( dhcp, "DHCP %p has no PXE boot servers for type %04x\n",
|
||||||
|
dhcp, pxe_type );
|
||||||
|
rc = -EINVAL;
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Dump out PXE server lists */
|
||||||
|
DBGC ( dhcp, "DHCP %p attempting", dhcp );
|
||||||
|
for ( ip = dhcp->pxe_attempt ; ip->s_addr ; ip++ )
|
||||||
|
DBGC ( dhcp, " %s", inet_ntoa ( *ip ) );
|
||||||
|
DBGC ( dhcp, "\n" );
|
||||||
|
if ( dhcp->pxe_accept ) {
|
||||||
|
DBGC ( dhcp, "DHCP %p accepting", dhcp );
|
||||||
|
for ( ip = dhcp->pxe_accept ; ip->s_addr ; ip++ )
|
||||||
|
DBGC ( dhcp, " %s", inet_ntoa ( *ip ) );
|
||||||
|
DBGC ( dhcp, "\n" );
|
||||||
|
}
|
||||||
|
|
||||||
/* 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, &dhcp_peer,
|
if ( ( rc = xfer_open_socket ( &dhcp->xfer, SOCK_DGRAM, &dhcp_peer,
|
||||||
( struct sockaddr * ) &dhcp->local ) ) != 0 )
|
( struct sockaddr * ) &dhcp->local ) ) != 0 )
|
||||||
|
|
|
@ -47,15 +47,12 @@ int dhcp ( struct net_device *netdev ) {
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
int pxebs ( struct net_device *netdev, struct in_addr pxe_server,
|
int pxebs ( struct net_device *netdev, unsigned int pxe_type ) {
|
||||||
unsigned int pxe_type ) {
|
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
/* Perform PXE Boot Server Discovery */
|
/* Perform PXE Boot Server Discovery */
|
||||||
printf ( "PXEBS (%s %s type %d)",
|
printf ( "PXEBS (%s type %d)", netdev->name, pxe_type );
|
||||||
netdev->name, inet_ntoa ( pxe_server ), pxe_type );
|
if ( ( rc = start_pxebs ( &monojob, netdev, pxe_type ) ) == 0 )
|
||||||
if ( ( rc = start_pxebs ( &monojob, netdev, pxe_server,
|
|
||||||
pxe_type ) ) == 0 )
|
|
||||||
rc = monojob_wait ( "" );
|
rc = monojob_wait ( "" );
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
|
|
|
@ -57,8 +57,6 @@ struct pxe_menu_item {
|
||||||
* options.
|
* options.
|
||||||
*/
|
*/
|
||||||
struct pxe_menu {
|
struct pxe_menu {
|
||||||
/** Boot Server address */
|
|
||||||
struct in_addr server;
|
|
||||||
/** Timeout (in seconds)
|
/** Timeout (in seconds)
|
||||||
*
|
*
|
||||||
* Negative indicates no timeout (i.e. wait indefinitely)
|
* Negative indicates no timeout (i.e. wait indefinitely)
|
||||||
|
@ -83,7 +81,6 @@ struct pxe_menu {
|
||||||
*/
|
*/
|
||||||
static int pxe_menu_parse ( struct pxe_menu **menu ) {
|
static int pxe_menu_parse ( struct pxe_menu **menu ) {
|
||||||
struct setting tmp_setting = { .name = NULL };
|
struct setting tmp_setting = { .name = NULL };
|
||||||
struct in_addr server;
|
|
||||||
struct dhcp_pxe_boot_menu_prompt prompt = { .timeout = 0 };
|
struct dhcp_pxe_boot_menu_prompt prompt = { .timeout = 0 };
|
||||||
uint8_t raw_menu[256];
|
uint8_t raw_menu[256];
|
||||||
int raw_menu_len;
|
int raw_menu_len;
|
||||||
|
@ -94,10 +91,6 @@ static int pxe_menu_parse ( struct pxe_menu **menu ) {
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
/* Fetch relevant settings */
|
/* Fetch relevant settings */
|
||||||
tmp_setting.tag = DHCP_PXE_BOOT_SERVER_MCAST;
|
|
||||||
fetch_ipv4_setting ( NULL, &tmp_setting, &server );
|
|
||||||
if ( ! server.s_addr )
|
|
||||||
server.s_addr = INADDR_BROADCAST;
|
|
||||||
tmp_setting.tag = DHCP_PXE_BOOT_MENU_PROMPT;
|
tmp_setting.tag = DHCP_PXE_BOOT_MENU_PROMPT;
|
||||||
fetch_setting ( NULL, &tmp_setting, &prompt, sizeof ( prompt ) );
|
fetch_setting ( NULL, &tmp_setting, &prompt, sizeof ( prompt ) );
|
||||||
tmp_setting.tag = DHCP_PXE_BOOT_MENU;
|
tmp_setting.tag = DHCP_PXE_BOOT_MENU;
|
||||||
|
@ -142,7 +135,6 @@ static int pxe_menu_parse ( struct pxe_menu **menu ) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Fill in parsed menu */
|
/* Fill in parsed menu */
|
||||||
(*menu)->server = server;
|
|
||||||
(*menu)->timeout =
|
(*menu)->timeout =
|
||||||
( ( prompt.timeout == 0xff ) ? -1 : prompt.timeout );
|
( ( prompt.timeout == 0xff ) ? -1 : prompt.timeout );
|
||||||
(*menu)->num_items = num_menu_items;
|
(*menu)->num_items = num_menu_items;
|
||||||
|
@ -296,7 +288,6 @@ int pxe_menu_select ( struct pxe_menu *menu ) {
|
||||||
*/
|
*/
|
||||||
int pxe_menu_boot ( struct net_device *netdev ) {
|
int pxe_menu_boot ( struct net_device *netdev ) {
|
||||||
struct pxe_menu *menu;
|
struct pxe_menu *menu;
|
||||||
struct in_addr pxe_server;
|
|
||||||
unsigned int pxe_type;
|
unsigned int pxe_type;
|
||||||
struct settings *pxebs_settings;
|
struct settings *pxebs_settings;
|
||||||
struct in_addr next_server;
|
struct in_addr next_server;
|
||||||
|
@ -312,7 +303,6 @@ int pxe_menu_boot ( struct net_device *netdev ) {
|
||||||
free ( menu );
|
free ( menu );
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
pxe_server = menu->server;
|
|
||||||
pxe_type = menu->items[menu->selection].type;
|
pxe_type = menu->items[menu->selection].type;
|
||||||
|
|
||||||
/* Free boot menu */
|
/* Free boot menu */
|
||||||
|
@ -323,7 +313,7 @@ int pxe_menu_boot ( struct net_device *netdev ) {
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* Attempt PXE Boot Server Discovery */
|
/* Attempt PXE Boot Server Discovery */
|
||||||
if ( ( rc = pxebs ( netdev, pxe_server, pxe_type ) ) != 0 )
|
if ( ( rc = pxebs ( netdev, pxe_type ) ) != 0 )
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
/* Attempt boot */
|
/* Attempt boot */
|
||||||
|
|
Loading…
Reference in New Issue