2 * Copyright (C) 2006 Michael Brown <mbrown@fensystems.co.uk>.
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or any later version.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 * You can also choose to distribute this program under the terms of
20 * the Unmodified Binary Distribution Licence (as given in the file
21 * COPYING.UBDL), provided that you have satisfied its requirements.
24 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
33 #include <ipxe/if_ether.h>
34 #include <ipxe/iobuf.h>
35 #include <ipxe/netdevice.h>
36 #include <ipxe/device.h>
37 #include <ipxe/xfer.h>
38 #include <ipxe/open.h>
40 #include <ipxe/retry.h>
41 #include <ipxe/tcpip.h>
43 #include <ipxe/uuid.h>
44 #include <ipxe/timer.h>
45 #include <ipxe/settings.h>
46 #include <ipxe/dhcp.h>
47 #include <ipxe/dhcpopts.h>
48 #include <ipxe/dhcppkt.h>
49 #include <ipxe/dhcp_arch.h>
50 #include <ipxe/features.h>
51 #include <config/dhcp.h>
55 * Dynamic Host Configuration Protocol
60 static int dhcp_tx ( struct dhcp_session *dhcp );
63 * DHCP operation types
65 * This table maps from DHCP message types (i.e. values of the @c
66 * DHCP_MESSAGE_TYPE option) to values of the "op" field within a DHCP
69 static const uint8_t dhcp_op[] = {
70 [DHCPDISCOVER] = BOOTP_REQUEST,
71 [DHCPOFFER] = BOOTP_REPLY,
72 [DHCPREQUEST] = BOOTP_REQUEST,
73 [DHCPDECLINE] = BOOTP_REQUEST,
74 [DHCPACK] = BOOTP_REPLY,
75 [DHCPNAK] = BOOTP_REPLY,
76 [DHCPRELEASE] = BOOTP_REQUEST,
77 [DHCPINFORM] = BOOTP_REQUEST,
80 /** Raw option data for options common to all DHCP requests */
81 static uint8_t dhcp_request_options_data[] = {
82 DHCP_MESSAGE_TYPE, DHCP_BYTE ( 0 ),
83 DHCP_MAX_MESSAGE_SIZE,
84 DHCP_WORD ( ETH_MAX_MTU - 20 /* IP header */ - 8 /* UDP header */ ),
85 DHCP_CLIENT_ARCHITECTURE, DHCP_ARCH_CLIENT_ARCHITECTURE,
86 DHCP_CLIENT_NDI, DHCP_ARCH_CLIENT_NDI,
87 DHCP_VENDOR_CLASS_ID, DHCP_ARCH_VENDOR_CLASS_ID,
88 DHCP_USER_CLASS_ID, DHCP_STRING ( 'i', 'P', 'X', 'E' ),
89 DHCP_PARAMETER_REQUEST_LIST,
90 DHCP_OPTION ( DHCP_SUBNET_MASK, DHCP_ROUTERS, DHCP_DNS_SERVERS,
91 DHCP_LOG_SERVERS, DHCP_HOST_NAME, DHCP_DOMAIN_NAME,
92 DHCP_ROOT_PATH, DHCP_VENDOR_ENCAP, DHCP_VENDOR_CLASS_ID,
93 DHCP_TFTP_SERVER_NAME, DHCP_BOOTFILE_NAME,
95 128, 129, 130, 131, 132, 133, 134, 135, /* for PXE */
96 DHCP_EB_ENCAP, DHCP_ISCSI_INITIATOR_IQN ),
100 /** DHCP server address setting */
101 const struct setting dhcp_server_setting __setting ( SETTING_MISC,
103 .name = "dhcp-server",
104 .description = "DHCP server",
105 .tag = DHCP_SERVER_IDENTIFIER,
106 .type = &setting_type_ipv4,
110 * Most recent DHCP transaction ID
112 * This is exposed for use by the fakedhcp code when reconstructing
113 * DHCP packets for PXE NBPs.
115 uint32_t dhcp_last_xid;
118 * Name a DHCP packet type
120 * @v msgtype DHCP message type
121 * @ret string DHCP mesasge type name
123 static inline const char * dhcp_msgtype_name ( unsigned int msgtype ) {
125 case DHCPNONE: return "BOOTP"; /* Non-DHCP packet */
126 case DHCPDISCOVER: return "DHCPDISCOVER";
127 case DHCPOFFER: return "DHCPOFFER";
128 case DHCPREQUEST: return "DHCPREQUEST";
129 case DHCPDECLINE: return "DHCPDECLINE";
130 case DHCPACK: return "DHCPACK";
131 case DHCPNAK: return "DHCPNAK";
132 case DHCPRELEASE: return "DHCPRELEASE";
133 case DHCPINFORM: return "DHCPINFORM";
134 default: return "DHCP<invalid>";
138 /****************************************************************************
146 /** DHCP session state operations */
147 struct dhcp_session_state {
151 * Construct transmitted packet
153 * @v dhcp DHCP session
154 * @v dhcppkt DHCP packet
155 * @v peer Destination address
157 int ( * tx ) ( struct dhcp_session *dhcp, struct dhcp_packet *dhcppkt,
158 struct sockaddr_in *peer );
160 * Handle received packet
162 * @v dhcp DHCP session
163 * @v dhcppkt DHCP packet
164 * @v peer DHCP server address
165 * @v msgtype DHCP message type
166 * @v server_id DHCP server ID
167 * @v pseudo_id DHCP server pseudo-ID
169 void ( * rx ) ( struct dhcp_session *dhcp, struct dhcp_packet *dhcppkt,
170 struct sockaddr_in *peer, uint8_t msgtype,
171 struct in_addr server_id, struct in_addr pseudo_id );
173 * Handle timer expiry
175 * @v dhcp DHCP session
177 void ( * expired ) ( struct dhcp_session *dhcp );
178 /** Transmitted message type */
180 /** Timeout parameters */
181 uint8_t min_timeout_sec;
182 uint8_t max_timeout_sec;
185 static struct dhcp_session_state dhcp_state_discover;
186 static struct dhcp_session_state dhcp_state_request;
187 static struct dhcp_session_state dhcp_state_proxy;
188 static struct dhcp_session_state dhcp_state_pxebs;
190 /** A DHCP session */
191 struct dhcp_session {
192 /** Reference counter */
193 struct refcnt refcnt;
194 /** Job control interface */
195 struct interface job;
196 /** Data transfer interface */
197 struct interface xfer;
199 /** Network device being configured */
200 struct net_device *netdev;
201 /** Local socket address */
202 struct sockaddr_in local;
203 /** State of the session */
204 struct dhcp_session_state *state;
205 /** Transaction ID (in network-endian order) */
208 /** Offered IP address */
209 struct in_addr offer;
211 struct in_addr server;
212 /** DHCP offer priority */
215 /** ProxyDHCP protocol extensions should be ignored */
217 /** ProxyDHCP server */
218 struct in_addr proxy_server;
219 /** ProxyDHCP offer */
220 struct dhcp_packet *proxy_offer;
221 /** ProxyDHCP offer priority */
224 /** PXE Boot Server type */
226 /** List of PXE Boot Servers to attempt */
227 struct in_addr *pxe_attempt;
228 /** List of PXE Boot Servers to accept */
229 struct in_addr *pxe_accept;
231 /** Retransmission timer */
232 struct retry_timer timer;
233 /** Transmission counter */
235 /** Start time of the current state (in ticks) */
242 * @v refcnt Reference counter
244 static void dhcp_free ( struct refcnt *refcnt ) {
245 struct dhcp_session *dhcp =
246 container_of ( refcnt, struct dhcp_session, refcnt );
248 netdev_put ( dhcp->netdev );
249 dhcppkt_put ( dhcp->proxy_offer );
254 * Mark DHCP session as complete
256 * @v dhcp DHCP session
257 * @v rc Return status code
259 static void dhcp_finished ( struct dhcp_session *dhcp, int rc ) {
261 /* Stop retry timer */
262 stop_timer ( &dhcp->timer );
264 /* Shut down interfaces */
265 intf_shutdown ( &dhcp->xfer, rc );
266 intf_shutdown ( &dhcp->job, rc );
270 * Transition to new DHCP session state
272 * @v dhcp DHCP session
273 * @v state New session state
275 static void dhcp_set_state ( struct dhcp_session *dhcp,
276 struct dhcp_session_state *state ) {
278 DBGC ( dhcp, "DHCP %p entering %s state\n", dhcp, state->name );
280 dhcp->start = currticks();
281 stop_timer ( &dhcp->timer );
282 set_timer_limits ( &dhcp->timer,
283 ( state->min_timeout_sec * TICKS_PER_SEC ),
284 ( state->max_timeout_sec * TICKS_PER_SEC ) );
285 start_timer_nodelay ( &dhcp->timer );
289 * Check if DHCP packet contains PXE options
291 * @v dhcppkt DHCP packet
292 * @ret has_pxeopts DHCP packet contains PXE options
294 * It is assumed that the packet is already known to contain option 60
295 * set to "PXEClient".
297 static int dhcp_has_pxeopts ( struct dhcp_packet *dhcppkt ) {
299 /* Check for a boot filename */
300 if ( dhcppkt_fetch ( dhcppkt, DHCP_BOOTFILE_NAME, NULL, 0 ) > 0 )
303 /* Check for a PXE boot menu */
304 if ( dhcppkt_fetch ( dhcppkt, DHCP_PXE_BOOT_MENU, NULL, 0 ) > 0 )
310 /****************************************************************************
317 * Construct transmitted packet for DHCP discovery
319 * @v dhcp DHCP session
320 * @v dhcppkt DHCP packet
321 * @v peer Destination address
323 static int dhcp_discovery_tx ( struct dhcp_session *dhcp,
324 struct dhcp_packet *dhcppkt __unused,
325 struct sockaddr_in *peer ) {
327 DBGC ( dhcp, "DHCP %p DHCPDISCOVER\n", dhcp );
329 /* Set server address */
330 peer->sin_addr.s_addr = INADDR_BROADCAST;
331 peer->sin_port = htons ( BOOTPS_PORT );
337 * Handle received packet during DHCP discovery
339 * @v dhcp DHCP session
340 * @v dhcppkt DHCP packet
341 * @v peer DHCP server address
342 * @v msgtype DHCP message type
343 * @v server_id DHCP server ID
344 * @v pseudo_id DHCP server pseudo-ID
346 static void dhcp_discovery_rx ( struct dhcp_session *dhcp,
347 struct dhcp_packet *dhcppkt,
348 struct sockaddr_in *peer, uint8_t msgtype,
349 struct in_addr server_id,
350 struct in_addr pseudo_id ) {
352 char vci[9]; /* "PXEClient" */
356 uint8_t no_pxedhcp = 0;
357 unsigned long elapsed;
359 DBGC ( dhcp, "DHCP %p %s from %s:%d", dhcp,
360 dhcp_msgtype_name ( msgtype ), inet_ntoa ( peer->sin_addr ),
361 ntohs ( peer->sin_port ) );
362 if ( ( server_id.s_addr != peer->sin_addr.s_addr ) ||
363 ( pseudo_id.s_addr != peer->sin_addr.s_addr ) ) {
364 DBGC ( dhcp, " (%s/", inet_ntoa ( server_id ) );
365 DBGC ( dhcp, "%s)", inet_ntoa ( pseudo_id ) );
368 /* Identify offered IP address */
369 ip = dhcppkt->dhcphdr->yiaddr;
371 DBGC ( dhcp, " for %s", inet_ntoa ( ip ) );
373 /* Identify "PXEClient" vendor class */
374 vci_len = dhcppkt_fetch ( dhcppkt, DHCP_VENDOR_CLASS_ID,
375 vci, sizeof ( vci ) );
376 has_pxeclient = ( ( vci_len >= ( int ) sizeof ( vci ) ) &&
377 ( strncmp ( "PXEClient", vci, sizeof (vci) ) == 0 ));
378 if ( has_pxeclient ) {
380 ( dhcp_has_pxeopts ( dhcppkt ) ? " pxe" : " proxy" ) );
383 /* Identify priority */
384 dhcppkt_fetch ( dhcppkt, DHCP_EB_PRIORITY, &priority,
385 sizeof ( priority ) );
387 DBGC ( dhcp, " pri %d", priority );
389 /* Identify ignore-PXE flag */
390 dhcppkt_fetch ( dhcppkt, DHCP_EB_NO_PXEDHCP, &no_pxedhcp,
391 sizeof ( no_pxedhcp ) );
393 DBGC ( dhcp, " nopxe" );
396 /* Select as DHCP offer, if applicable */
397 if ( ip.s_addr && ( peer->sin_port == htons ( BOOTPS_PORT ) ) &&
398 ( ( msgtype == DHCPOFFER ) || ( ! msgtype /* BOOTP */ ) ) &&
399 ( priority >= dhcp->priority ) ) {
401 dhcp->server = server_id;
402 dhcp->priority = priority;
403 dhcp->no_pxedhcp = no_pxedhcp;
406 /* Select as ProxyDHCP offer, if applicable */
407 if ( pseudo_id.s_addr && has_pxeclient &&
408 ( priority >= dhcp->proxy_priority ) ) {
409 dhcppkt_put ( dhcp->proxy_offer );
410 dhcp->proxy_server = pseudo_id;
411 dhcp->proxy_offer = dhcppkt_get ( dhcppkt );
412 dhcp->proxy_priority = priority;
415 /* We can exit the discovery state when we have a valid
416 * DHCPOFFER, and either:
418 * o The DHCPOFFER instructs us to ignore ProxyDHCPOFFERs, or
419 * o We have a valid ProxyDHCPOFFER, or
420 * o We have allowed sufficient time for ProxyDHCPOFFERs.
423 /* If we don't yet have a DHCPOFFER, do nothing */
424 if ( ! dhcp->offer.s_addr )
427 /* If we can't yet transition to DHCPREQUEST, do nothing */
428 elapsed = ( currticks() - dhcp->start );
429 if ( ! ( dhcp->no_pxedhcp || dhcp->proxy_offer ||
430 ( elapsed > DHCP_DISC_PROXY_TIMEOUT_SEC * TICKS_PER_SEC ) ) )
433 /* Transition to DHCPREQUEST */
434 dhcp_set_state ( dhcp, &dhcp_state_request );
438 * Handle timer expiry during DHCP discovery
440 * @v dhcp DHCP session
442 static void dhcp_discovery_expired ( struct dhcp_session *dhcp ) {
443 unsigned long elapsed = ( currticks() - dhcp->start );
445 /* If link is blocked, defer DHCP discovery (and reset timeout) */
446 if ( netdev_link_blocked ( dhcp->netdev ) ) {
447 DBGC ( dhcp, "DHCP %p deferring discovery\n", dhcp );
448 start_timer_fixed ( &dhcp->timer,
449 ( DHCP_DISC_START_TIMEOUT_SEC *
454 /* Give up waiting for ProxyDHCP before we reach the failure point */
455 if ( dhcp->offer.s_addr &&
456 ( elapsed > DHCP_DISC_PROXY_TIMEOUT_SEC * TICKS_PER_SEC ) ) {
457 dhcp_set_state ( dhcp, &dhcp_state_request );
461 /* Otherwise, retransmit current packet */
465 /** DHCP discovery state operations */
466 static struct dhcp_session_state dhcp_state_discover = {
468 .tx = dhcp_discovery_tx,
469 .rx = dhcp_discovery_rx,
470 .expired = dhcp_discovery_expired,
471 .tx_msgtype = DHCPDISCOVER,
472 .min_timeout_sec = DHCP_DISC_START_TIMEOUT_SEC,
473 .max_timeout_sec = DHCP_DISC_END_TIMEOUT_SEC,
477 * Construct transmitted packet for DHCP request
479 * @v dhcp DHCP session
480 * @v dhcppkt DHCP packet
481 * @v peer Destination address
483 static int dhcp_request_tx ( struct dhcp_session *dhcp,
484 struct dhcp_packet *dhcppkt,
485 struct sockaddr_in *peer ) {
488 DBGC ( dhcp, "DHCP %p DHCPREQUEST to %s:%d",
489 dhcp, inet_ntoa ( dhcp->server ), BOOTPS_PORT );
490 DBGC ( dhcp, " for %s\n", inet_ntoa ( dhcp->offer ) );
493 if ( ( rc = dhcppkt_store ( dhcppkt, DHCP_SERVER_IDENTIFIER,
495 sizeof ( dhcp->server ) ) ) != 0 )
498 /* Set requested IP address */
499 if ( ( rc = dhcppkt_store ( dhcppkt, DHCP_REQUESTED_ADDRESS,
501 sizeof ( dhcp->offer ) ) ) != 0 )
504 /* Set server address */
505 peer->sin_addr.s_addr = INADDR_BROADCAST;
506 peer->sin_port = htons ( BOOTPS_PORT );
512 * Handle received packet during DHCP request
514 * @v dhcp DHCP session
515 * @v dhcppkt DHCP packet
516 * @v peer DHCP server address
517 * @v msgtype DHCP message type
518 * @v server_id DHCP server ID
519 * @v pseudo_id DHCP server pseudo-ID
521 static void dhcp_request_rx ( struct dhcp_session *dhcp,
522 struct dhcp_packet *dhcppkt,
523 struct sockaddr_in *peer, uint8_t msgtype,
524 struct in_addr server_id,
525 struct in_addr pseudo_id ) {
527 struct settings *parent;
528 struct settings *settings;
531 DBGC ( dhcp, "DHCP %p %s from %s:%d", dhcp,
532 dhcp_msgtype_name ( msgtype ), inet_ntoa ( peer->sin_addr ),
533 ntohs ( peer->sin_port ) );
534 if ( ( server_id.s_addr != peer->sin_addr.s_addr ) ||
535 ( pseudo_id.s_addr != peer->sin_addr.s_addr ) ) {
536 DBGC ( dhcp, " (%s/", inet_ntoa ( server_id ) );
537 DBGC ( dhcp, "%s)", inet_ntoa ( pseudo_id ) );
540 /* Identify leased IP address */
541 ip = dhcppkt->dhcphdr->yiaddr;
543 DBGC ( dhcp, " for %s", inet_ntoa ( ip ) );
546 /* Filter out unacceptable responses */
547 if ( peer->sin_port != htons ( BOOTPS_PORT ) )
549 if ( msgtype /* BOOTP */ && ( msgtype != DHCPACK ) )
551 if ( server_id.s_addr != dhcp->server.s_addr )
553 if ( ip.s_addr != dhcp->offer.s_addr )
556 /* Record assigned address */
557 dhcp->local.sin_addr = ip;
559 /* Register settings */
560 parent = netdev_settings ( dhcp->netdev );
561 settings = &dhcppkt->settings;
562 if ( ( rc = register_settings ( settings, parent,
563 DHCP_SETTINGS_NAME ) ) != 0 ) {
564 DBGC ( dhcp, "DHCP %p could not register settings: %s\n",
565 dhcp, strerror ( rc ) );
566 dhcp_finished ( dhcp, rc );
570 /* Perform ProxyDHCP if applicable */
571 if ( dhcp->proxy_offer /* Have ProxyDHCP offer */ &&
572 ( ! dhcp->no_pxedhcp ) /* ProxyDHCP not disabled */ ) {
573 if ( dhcp_has_pxeopts ( dhcp->proxy_offer ) ) {
574 /* PXE options already present; register settings
575 * without performing a ProxyDHCPREQUEST
577 settings = &dhcp->proxy_offer->settings;
578 if ( ( rc = register_settings ( settings, NULL,
579 PROXYDHCP_SETTINGS_NAME ) ) != 0 ) {
580 DBGC ( dhcp, "DHCP %p could not register "
581 "proxy settings: %s\n",
582 dhcp, strerror ( rc ) );
583 dhcp_finished ( dhcp, rc );
587 /* PXE options not present; use a ProxyDHCPREQUEST */
588 dhcp_set_state ( dhcp, &dhcp_state_proxy );
594 dhcp_finished ( dhcp, 0 );
598 * Handle timer expiry during DHCP discovery
600 * @v dhcp DHCP session
602 static void dhcp_request_expired ( struct dhcp_session *dhcp ) {
604 /* Retransmit current packet */
608 /** DHCP request state operations */
609 static struct dhcp_session_state dhcp_state_request = {
611 .tx = dhcp_request_tx,
612 .rx = dhcp_request_rx,
613 .expired = dhcp_request_expired,
614 .tx_msgtype = DHCPREQUEST,
615 .min_timeout_sec = DHCP_REQ_START_TIMEOUT_SEC,
616 .max_timeout_sec = DHCP_REQ_END_TIMEOUT_SEC,
620 * Construct transmitted packet for ProxyDHCP request
622 * @v dhcp DHCP session
623 * @v dhcppkt DHCP packet
624 * @v peer Destination address
626 static int dhcp_proxy_tx ( struct dhcp_session *dhcp,
627 struct dhcp_packet *dhcppkt,
628 struct sockaddr_in *peer ) {
631 DBGC ( dhcp, "DHCP %p ProxyDHCP REQUEST to %s\n", dhcp,
632 inet_ntoa ( dhcp->proxy_server ) );
635 if ( ( rc = dhcppkt_store ( dhcppkt, DHCP_SERVER_IDENTIFIER,
637 sizeof ( dhcp->proxy_server ) ) ) != 0 )
640 /* Set server address */
641 peer->sin_addr = dhcp->proxy_server;
642 peer->sin_port = htons ( PXE_PORT );
648 * Handle received packet during ProxyDHCP request
650 * @v dhcp DHCP session
651 * @v dhcppkt DHCP packet
652 * @v peer DHCP server address
653 * @v msgtype DHCP message type
654 * @v server_id DHCP server ID
655 * @v pseudo_id DHCP server pseudo-ID
657 static void dhcp_proxy_rx ( struct dhcp_session *dhcp,
658 struct dhcp_packet *dhcppkt,
659 struct sockaddr_in *peer, uint8_t msgtype,
660 struct in_addr server_id,
661 struct in_addr pseudo_id ) {
662 struct settings *settings = &dhcppkt->settings;
665 DBGC ( dhcp, "DHCP %p %s from %s:%d", dhcp,
666 dhcp_msgtype_name ( msgtype ), inet_ntoa ( peer->sin_addr ),
667 ntohs ( peer->sin_port ) );
668 if ( ( server_id.s_addr != peer->sin_addr.s_addr ) ||
669 ( pseudo_id.s_addr != peer->sin_addr.s_addr ) ) {
670 DBGC ( dhcp, " (%s/", inet_ntoa ( server_id ) );
671 DBGC ( dhcp, "%s)", inet_ntoa ( pseudo_id ) );
673 if ( dhcp_has_pxeopts ( dhcppkt ) )
674 DBGC ( dhcp, " pxe" );
677 /* Filter out unacceptable responses */
678 if ( peer->sin_port != ntohs ( PXE_PORT ) )
680 if ( ( msgtype != DHCPOFFER ) && ( msgtype != DHCPACK ) )
682 if ( ( pseudo_id.s_addr != dhcp->proxy_server.s_addr ) )
684 if ( ! dhcp_has_pxeopts ( dhcppkt ) )
687 /* Register settings */
688 if ( ( rc = register_settings ( settings, NULL,
689 PROXYDHCP_SETTINGS_NAME ) ) != 0 ) {
690 DBGC ( dhcp, "DHCP %p could not register proxy settings: %s\n",
691 dhcp, strerror ( rc ) );
692 dhcp_finished ( dhcp, rc );
697 dhcp_finished ( dhcp, 0 );
701 * Handle timer expiry during ProxyDHCP request
703 * @v dhcp DHCP session
705 static void dhcp_proxy_expired ( struct dhcp_session *dhcp ) {
706 unsigned long elapsed = ( currticks() - dhcp->start );
708 /* Give up waiting for ProxyDHCP before we reach the failure point */
709 if ( elapsed > DHCP_REQ_PROXY_TIMEOUT_SEC * TICKS_PER_SEC ) {
710 dhcp_finished ( dhcp, 0 );
714 /* Retransmit current packet */
718 /** ProxyDHCP request state operations */
719 static struct dhcp_session_state dhcp_state_proxy = {
723 .expired = dhcp_proxy_expired,
724 .tx_msgtype = DHCPREQUEST,
725 .min_timeout_sec = DHCP_PROXY_START_TIMEOUT_SEC,
726 .max_timeout_sec = DHCP_PROXY_END_TIMEOUT_SEC,
730 * Construct transmitted packet for PXE Boot Server Discovery
732 * @v dhcp DHCP session
733 * @v dhcppkt DHCP packet
734 * @v peer Destination address
736 static int dhcp_pxebs_tx ( struct dhcp_session *dhcp,
737 struct dhcp_packet *dhcppkt,
738 struct sockaddr_in *peer ) {
739 struct dhcp_pxe_boot_menu_item menu_item = { 0, 0 };
742 /* Set server address */
743 peer->sin_addr = *(dhcp->pxe_attempt);
744 peer->sin_port = ( ( peer->sin_addr.s_addr == INADDR_BROADCAST ) ?
745 htons ( BOOTPS_PORT ) : htons ( PXE_PORT ) );
747 DBGC ( dhcp, "DHCP %p PXEBS REQUEST to %s:%d for type %d\n",
748 dhcp, inet_ntoa ( peer->sin_addr ), ntohs ( peer->sin_port ),
749 le16_to_cpu ( dhcp->pxe_type ) );
751 /* Set boot menu item */
752 menu_item.type = dhcp->pxe_type;
753 if ( ( rc = dhcppkt_store ( dhcppkt, DHCP_PXE_BOOT_MENU_ITEM,
754 &menu_item, sizeof ( menu_item ) ) ) != 0 )
761 * Check to see if PXE Boot Server address is acceptable
763 * @v dhcp DHCP session
764 * @v bs Boot Server address
765 * @ret accept Boot Server is acceptable
767 static int dhcp_pxebs_accept ( struct dhcp_session *dhcp,
768 struct in_addr bs ) {
769 struct in_addr *accept;
771 /* Accept if we have no acceptance filter */
772 if ( ! dhcp->pxe_accept )
775 /* Scan through acceptance list */
776 for ( accept = dhcp->pxe_accept ; accept->s_addr ; accept++ ) {
777 if ( accept->s_addr == bs.s_addr )
781 DBGC ( dhcp, "DHCP %p rejecting server %s\n",
782 dhcp, inet_ntoa ( bs ) );
787 * Handle received packet during PXE Boot Server Discovery
789 * @v dhcp DHCP session
790 * @v dhcppkt DHCP packet
791 * @v peer DHCP server address
792 * @v msgtype DHCP message type
793 * @v server_id DHCP server ID
794 * @v pseudo_id DHCP server pseudo-ID
796 static void dhcp_pxebs_rx ( struct dhcp_session *dhcp,
797 struct dhcp_packet *dhcppkt,
798 struct sockaddr_in *peer, uint8_t msgtype,
799 struct in_addr server_id,
800 struct in_addr pseudo_id ) {
801 struct dhcp_pxe_boot_menu_item menu_item = { 0, 0 };
804 DBGC ( dhcp, "DHCP %p %s from %s:%d", dhcp,
805 dhcp_msgtype_name ( msgtype ), inet_ntoa ( peer->sin_addr ),
806 ntohs ( peer->sin_port ) );
807 if ( ( server_id.s_addr != peer->sin_addr.s_addr ) ||
808 ( pseudo_id.s_addr != peer->sin_addr.s_addr ) ) {
809 DBGC ( dhcp, " (%s/", inet_ntoa ( server_id ) );
810 DBGC ( dhcp, "%s)", inet_ntoa ( pseudo_id ) );
813 /* Identify boot menu item */
814 dhcppkt_fetch ( dhcppkt, DHCP_PXE_BOOT_MENU_ITEM,
815 &menu_item, sizeof ( menu_item ) );
816 if ( menu_item.type )
817 DBGC ( dhcp, " for type %d", ntohs ( menu_item.type ) );
820 /* Filter out unacceptable responses */
821 if ( ( peer->sin_port != htons ( BOOTPS_PORT ) ) &&
822 ( peer->sin_port != htons ( PXE_PORT ) ) )
824 if ( msgtype != DHCPACK )
826 if ( menu_item.type != dhcp->pxe_type )
828 if ( ! dhcp_pxebs_accept ( dhcp, pseudo_id ) )
831 /* Register settings */
832 if ( ( rc = register_settings ( &dhcppkt->settings, NULL,
833 PXEBS_SETTINGS_NAME ) ) != 0 ) {
834 DBGC ( dhcp, "DHCP %p could not register settings: %s\n",
835 dhcp, strerror ( rc ) );
836 dhcp_finished ( dhcp, rc );
841 dhcp_finished ( dhcp, 0 );
845 * Handle timer expiry during PXE Boot Server Discovery
847 * @v dhcp DHCP session
849 static void dhcp_pxebs_expired ( struct dhcp_session *dhcp ) {
850 unsigned long elapsed = ( currticks() - dhcp->start );
852 /* Give up waiting before we reach the failure point, and fail
853 * over to the next server in the attempt list
855 if ( elapsed > PXEBS_MAX_TIMEOUT_SEC * TICKS_PER_SEC ) {
857 if ( dhcp->pxe_attempt->s_addr ) {
858 dhcp_set_state ( dhcp, &dhcp_state_pxebs );
861 dhcp_finished ( dhcp, -ETIMEDOUT );
866 /* Retransmit current packet */
870 /** PXE Boot Server Discovery state operations */
871 static struct dhcp_session_state dhcp_state_pxebs = {
875 .expired = dhcp_pxebs_expired,
876 .tx_msgtype = DHCPREQUEST,
877 .min_timeout_sec = PXEBS_START_TIMEOUT_SEC,
878 .max_timeout_sec = PXEBS_END_TIMEOUT_SEC,
881 /****************************************************************************
883 * Packet construction
888 * Create a DHCP packet
890 * @v dhcppkt DHCP packet structure to fill in
891 * @v netdev Network device
892 * @v msgtype DHCP message type
893 * @v xid Transaction ID (in network-endian order)
894 * @v options Initial options to include (or NULL)
895 * @v options_len Length of initial options
896 * @v data Buffer for DHCP packet
897 * @v max_len Size of DHCP packet buffer
898 * @ret rc Return status code
900 * Creates a DHCP packet in the specified buffer, and initialise a
901 * DHCP packet structure.
903 int dhcp_create_packet ( struct dhcp_packet *dhcppkt,
904 struct net_device *netdev, uint8_t msgtype,
905 uint32_t xid, const void *options, size_t options_len,
906 void *data, size_t max_len ) {
907 struct dhcphdr *dhcphdr = data;
911 if ( max_len < ( sizeof ( *dhcphdr ) + options_len ) )
914 /* Initialise DHCP packet content */
915 memset ( dhcphdr, 0, max_len );
917 dhcphdr->magic = htonl ( DHCP_MAGIC_COOKIE );
918 dhcphdr->htype = ntohs ( netdev->ll_protocol->ll_proto );
919 dhcphdr->op = dhcp_op[msgtype];
920 dhcphdr->hlen = netdev->ll_protocol->ll_addr_len;
921 memcpy ( dhcphdr->chaddr, netdev->ll_addr,
922 netdev->ll_protocol->ll_addr_len );
923 memcpy ( dhcphdr->options, options, options_len );
925 /* If the local link-layer address functions only as a name
926 * (i.e. cannot be used as a destination address), then
927 * request broadcast responses.
929 if ( netdev->ll_protocol->flags & LL_NAME_ONLY )
930 dhcphdr->flags |= htons ( BOOTP_FL_BROADCAST );
932 /* If the network device already has an IPv4 address then
933 * unicast responses from the DHCP server may be rejected, so
934 * request broadcast responses.
936 if ( ipv4_has_any_addr ( netdev ) )
937 dhcphdr->flags |= htons ( BOOTP_FL_BROADCAST );
939 /* Initialise DHCP packet structure */
940 memset ( dhcppkt, 0, sizeof ( *dhcppkt ) );
941 dhcppkt_init ( dhcppkt, data, max_len );
943 /* Set DHCP_MESSAGE_TYPE option */
944 if ( ( rc = dhcppkt_store ( dhcppkt, DHCP_MESSAGE_TYPE,
945 &msgtype, sizeof ( msgtype ) ) ) != 0 )
952 * Create DHCP request packet
954 * @v dhcppkt DHCP packet structure to fill in
955 * @v netdev Network device
956 * @v msgtype DHCP message type
957 * @v xid Transaction ID (in network-endian order)
958 * @v ciaddr Client IP address
959 * @v data Buffer for DHCP packet
960 * @v max_len Size of DHCP packet buffer
961 * @ret rc Return status code
963 * Creates a DHCP request packet in the specified buffer, and
964 * initialise a DHCP packet structure.
966 int dhcp_create_request ( struct dhcp_packet *dhcppkt,
967 struct net_device *netdev, unsigned int msgtype,
968 uint32_t xid, struct in_addr ciaddr,
969 void *data, size_t max_len ) {
970 struct dhcp_netdev_desc dhcp_desc;
971 struct dhcp_client_id client_id;
972 struct dhcp_client_uuid client_uuid;
973 uint8_t *dhcp_features;
974 size_t dhcp_features_len;
980 /* Create DHCP packet */
981 if ( ( rc = dhcp_create_packet ( dhcppkt, netdev, msgtype, xid,
982 dhcp_request_options_data,
983 sizeof ( dhcp_request_options_data ),
984 data, max_len ) ) != 0 ) {
985 DBG ( "DHCP could not create DHCP packet: %s\n",
987 goto err_create_packet;
990 /* Set client IP address */
991 dhcppkt->dhcphdr->ciaddr = ciaddr;
993 /* Add options to identify the feature list */
994 dhcp_features = table_start ( DHCP_FEATURES );
995 dhcp_features_len = table_num_entries ( DHCP_FEATURES );
996 if ( ( rc = dhcppkt_store ( dhcppkt, DHCP_EB_ENCAP, dhcp_features,
997 dhcp_features_len ) ) != 0 ) {
998 DBG ( "DHCP could not set features list option: %s\n",
1000 goto err_store_features;
1003 /* Add options to identify the network device */
1004 fetch_raw_setting ( netdev_settings ( netdev ), &busid_setting,
1005 &dhcp_desc, sizeof ( dhcp_desc ) );
1006 if ( ( rc = dhcppkt_store ( dhcppkt, DHCP_EB_BUS_ID, &dhcp_desc,
1007 sizeof ( dhcp_desc ) ) ) != 0 ) {
1008 DBG ( "DHCP could not set bus ID option: %s\n",
1010 goto err_store_busid;
1013 /* Add DHCP client identifier. Required for Infiniband, and
1014 * doesn't hurt other link layers.
1016 client_id.ll_proto = ntohs ( netdev->ll_protocol->ll_proto );
1017 ll_addr_len = netdev->ll_protocol->ll_addr_len;
1018 assert ( ll_addr_len <= sizeof ( client_id.ll_addr ) );
1019 memcpy ( client_id.ll_addr, netdev->ll_addr, ll_addr_len );
1020 if ( ( rc = dhcppkt_store ( dhcppkt, DHCP_CLIENT_ID, &client_id,
1021 ( ll_addr_len + 1 ) ) ) != 0 ) {
1022 DBG ( "DHCP could not set client ID: %s\n",
1024 goto err_store_client_id;
1027 /* Add client UUID, if we have one. Required for PXE. The
1028 * PXE spec does not specify a byte ordering for UUIDs, but
1029 * RFC4578 suggests that it follows the EFI spec, in which the
1030 * first three fields are little-endian.
1032 client_uuid.type = DHCP_CLIENT_UUID_TYPE;
1033 if ( ( len = fetch_uuid_setting ( NULL, &uuid_setting,
1034 &client_uuid.uuid ) ) >= 0 ) {
1035 uuid_mangle ( &client_uuid.uuid );
1036 if ( ( rc = dhcppkt_store ( dhcppkt, DHCP_CLIENT_UUID,
1038 sizeof ( client_uuid ) ) ) != 0 ) {
1039 DBG ( "DHCP could not set client UUID: %s\n",
1041 goto err_store_client_uuid;
1045 /* Add user class, if we have one. */
1046 if ( ( len = fetch_raw_setting_copy ( NULL, &user_class_setting,
1047 &user_class ) ) >= 0 ) {
1048 if ( ( rc = dhcppkt_store ( dhcppkt, DHCP_USER_CLASS_ID,
1049 user_class, len ) ) != 0 ) {
1050 DBG ( "DHCP could not set user class: %s\n",
1052 goto err_store_user_class;
1056 err_store_user_class:
1057 free ( user_class );
1058 err_store_client_uuid:
1059 err_store_client_id:
1066 /****************************************************************************
1068 * Data transfer interface
1073 * Transmit DHCP request
1075 * @v dhcp DHCP session
1076 * @ret rc Return status code
1078 static int dhcp_tx ( struct dhcp_session *dhcp ) {
1079 static struct sockaddr_in peer = {
1080 .sin_family = AF_INET,
1082 struct xfer_metadata meta = {
1083 .netdev = dhcp->netdev,
1084 .src = ( struct sockaddr * ) &dhcp->local,
1085 .dest = ( struct sockaddr * ) &peer,
1087 struct io_buffer *iobuf;
1088 uint8_t msgtype = dhcp->state->tx_msgtype;
1089 struct dhcp_packet dhcppkt;
1092 /* Start retry timer. Do this first so that failures to
1093 * transmit will be retried.
1095 start_timer ( &dhcp->timer );
1097 /* Allocate buffer for packet */
1098 iobuf = xfer_alloc_iob ( &dhcp->xfer, DHCP_MIN_LEN );
1102 /* Create basic DHCP packet in temporary buffer */
1103 if ( ( rc = dhcp_create_request ( &dhcppkt, dhcp->netdev, msgtype,
1104 dhcp->xid, dhcp->local.sin_addr,
1106 iob_tailroom ( iobuf ) ) ) != 0 ) {
1107 DBGC ( dhcp, "DHCP %p could not construct DHCP request: %s\n",
1108 dhcp, strerror ( rc ) );
1112 /* (Ab)use the "secs" field to convey metadata about the DHCP
1113 * session state into packet traces. Useful for extracting
1114 * debug information from non-debug builds.
1116 dhcppkt.dhcphdr->secs = htons ( ( ++(dhcp->count) << 2 ) |
1117 ( dhcp->offer.s_addr ? 0x02 : 0 ) |
1118 ( dhcp->proxy_offer ? 0x01 : 0 ) );
1120 /* Fill in packet based on current state */
1121 if ( ( rc = dhcp->state->tx ( dhcp, &dhcppkt, &peer ) ) != 0 ) {
1122 DBGC ( dhcp, "DHCP %p could not fill DHCP request: %s\n",
1123 dhcp, strerror ( rc ) );
1127 /* Transmit the packet */
1128 iob_put ( iobuf, dhcppkt_len ( &dhcppkt ) );
1129 if ( ( rc = xfer_deliver ( &dhcp->xfer, iob_disown ( iobuf ),
1131 DBGC ( dhcp, "DHCP %p could not transmit UDP packet: %s\n",
1132 dhcp, strerror ( rc ) );
1144 * @v dhcp DHCP session
1145 * @v iobuf I/O buffer
1146 * @v meta Transfer metadata
1147 * @ret rc Return status code
1149 static int dhcp_deliver ( struct dhcp_session *dhcp,
1150 struct io_buffer *iobuf,
1151 struct xfer_metadata *meta ) {
1152 struct net_device *netdev = dhcp->netdev;
1153 struct ll_protocol *ll_protocol = netdev->ll_protocol;
1154 struct sockaddr_in *peer;
1156 struct dhcp_packet *dhcppkt;
1157 struct dhcphdr *dhcphdr;
1158 uint8_t msgtype = 0;
1159 struct in_addr server_id = { 0 };
1160 struct in_addr pseudo_id;
1164 if ( ! meta->src ) {
1165 DBGC ( dhcp, "DHCP %p received packet without source port\n",
1170 peer = ( struct sockaddr_in * ) meta->src;
1172 /* Create a DHCP packet containing the I/O buffer contents.
1173 * Whilst we could just use the original buffer in situ, that
1174 * would waste the unused space in the packet buffer, and also
1175 * waste a relatively scarce fully-aligned I/O buffer.
1177 data_len = iob_len ( iobuf );
1178 dhcppkt = zalloc ( sizeof ( *dhcppkt ) + data_len );
1181 goto err_alloc_dhcppkt;
1183 dhcphdr = ( ( ( void * ) dhcppkt ) + sizeof ( *dhcppkt ) );
1184 memcpy ( dhcphdr, iobuf->data, data_len );
1185 dhcppkt_init ( dhcppkt, dhcphdr, data_len );
1187 /* Identify message type */
1188 dhcppkt_fetch ( dhcppkt, DHCP_MESSAGE_TYPE, &msgtype,
1189 sizeof ( msgtype ) );
1191 /* Identify server ID */
1192 dhcppkt_fetch ( dhcppkt, DHCP_SERVER_IDENTIFIER,
1193 &server_id, sizeof ( server_id ) );
1195 /* Identify server pseudo-ID */
1196 pseudo_id = server_id;
1197 if ( ! pseudo_id.s_addr )
1198 pseudo_id = dhcppkt->dhcphdr->siaddr;
1199 if ( ! pseudo_id.s_addr )
1200 pseudo_id = peer->sin_addr;
1202 /* Check for matching transaction ID */
1203 if ( dhcphdr->xid != dhcp->xid ) {
1204 DBGC ( dhcp, "DHCP %p %s from %s:%d has bad transaction "
1205 "ID\n", dhcp, dhcp_msgtype_name ( msgtype ),
1206 inet_ntoa ( peer->sin_addr ),
1207 ntohs ( peer->sin_port ) );
1212 /* Check for matching client hardware address */
1213 if ( memcmp ( dhcphdr->chaddr, netdev->ll_addr,
1214 ll_protocol->ll_addr_len ) != 0 ) {
1215 DBGC ( dhcp, "DHCP %p %s from %s:%d has bad chaddr %s\n",
1216 dhcp, dhcp_msgtype_name ( msgtype ),
1217 inet_ntoa ( peer->sin_addr ), ntohs ( peer->sin_port ),
1218 ll_protocol->ntoa ( dhcphdr->chaddr ) );
1223 /* Handle packet based on current state */
1224 dhcp->state->rx ( dhcp, dhcppkt, peer, msgtype, server_id, pseudo_id );
1228 dhcppkt_put ( dhcppkt );
1235 /** DHCP data transfer interface operations */
1236 static struct interface_operation dhcp_xfer_operations[] = {
1237 INTF_OP ( xfer_deliver, struct dhcp_session *, dhcp_deliver ),
1240 /** DHCP data transfer interface descriptor */
1241 static struct interface_descriptor dhcp_xfer_desc =
1242 INTF_DESC ( struct dhcp_session, xfer, dhcp_xfer_operations );
1245 * Handle DHCP retry timer expiry
1247 * @v timer DHCP retry timer
1248 * @v fail Failure indicator
1250 static void dhcp_timer_expired ( struct retry_timer *timer, int fail ) {
1251 struct dhcp_session *dhcp =
1252 container_of ( timer, struct dhcp_session, timer );
1254 /* If we have failed, terminate DHCP */
1256 dhcp_finished ( dhcp, -ETIMEDOUT );
1260 /* Handle timer expiry based on current state */
1261 dhcp->state->expired ( dhcp );
1264 /****************************************************************************
1266 * Job control interface
1270 /** DHCP job control interface operations */
1271 static struct interface_operation dhcp_job_op[] = {
1272 INTF_OP ( intf_close, struct dhcp_session *, dhcp_finished ),
1275 /** DHCP job control interface descriptor */
1276 static struct interface_descriptor dhcp_job_desc =
1277 INTF_DESC ( struct dhcp_session, job, dhcp_job_op );
1279 /****************************************************************************
1286 * DHCP peer address for socket opening
1288 * This is a dummy address; the only useful portion is the socket
1289 * family (so that we get a UDP connection). The DHCP client will set
1290 * the IP address and source port explicitly on each transmission.
1292 static struct sockaddr dhcp_peer = {
1293 .sa_family = AF_INET,
1297 * Start DHCP state machine on a network device
1299 * @v job Job control interface
1300 * @v netdev Network device
1301 * @ret rc Return status code
1303 * Starts DHCP on the specified network device. If successful, the
1304 * DHCPACK (and ProxyDHCPACK, if applicable) will be registered as
1307 int start_dhcp ( struct interface *job, struct net_device *netdev ) {
1308 struct dhcp_session *dhcp;
1311 /* Allocate and initialise structure */
1312 dhcp = zalloc ( sizeof ( *dhcp ) );
1315 ref_init ( &dhcp->refcnt, dhcp_free );
1316 intf_init ( &dhcp->job, &dhcp_job_desc, &dhcp->refcnt );
1317 intf_init ( &dhcp->xfer, &dhcp_xfer_desc, &dhcp->refcnt );
1318 timer_init ( &dhcp->timer, dhcp_timer_expired, &dhcp->refcnt );
1319 dhcp->netdev = netdev_get ( netdev );
1320 dhcp->local.sin_family = AF_INET;
1321 dhcp->local.sin_port = htons ( BOOTPC_PORT );
1322 dhcp->xid = random();
1324 /* Store DHCP transaction ID for fakedhcp code */
1325 dhcp_last_xid = dhcp->xid;
1327 /* Instantiate child objects and attach to our interfaces */
1328 if ( ( rc = xfer_open_socket ( &dhcp->xfer, SOCK_DGRAM, &dhcp_peer,
1329 ( struct sockaddr * ) &dhcp->local ) ) != 0 )
1332 /* Enter DHCPDISCOVER state */
1333 dhcp_set_state ( dhcp, &dhcp_state_discover );
1335 /* Attach parent interface, mortalise self, and return */
1336 intf_plug_plug ( &dhcp->job, job );
1337 ref_put ( &dhcp->refcnt );
1341 dhcp_finished ( dhcp, rc );
1342 ref_put ( &dhcp->refcnt );
1347 * Retrieve list of PXE boot servers for a given server type
1349 * @v dhcp DHCP session
1350 * @v raw DHCP PXE boot server list
1351 * @v raw_len Length of DHCP PXE boot server list
1352 * @v ip IP address list to fill in
1354 * The caller must ensure that the IP address list has sufficient
1357 static void pxebs_list ( struct dhcp_session *dhcp, void *raw,
1358 size_t raw_len, struct in_addr *ip ) {
1359 struct dhcp_pxe_boot_server *server = raw;
1364 if ( raw_len < sizeof ( *server ) ) {
1365 DBGC ( dhcp, "DHCP %p malformed PXE server list\n",
1369 server_len = offsetof ( typeof ( *server ),
1370 ip[ server->num_ip ] );
1371 if ( raw_len < server_len ) {
1372 DBGC ( dhcp, "DHCP %p malformed PXE server list\n",
1376 if ( server->type == dhcp->pxe_type ) {
1377 for ( i = 0 ; i < server->num_ip ; i++ )
1378 *(ip++) = server->ip[i];
1380 server = ( ( ( void * ) server ) + server_len );
1381 raw_len -= server_len;
1386 * Start PXE Boot Server Discovery on a network device
1388 * @v job Job control interface
1389 * @v netdev Network device
1390 * @v pxe_type PXE server type
1391 * @ret rc Return status code
1393 * Starts PXE Boot Server Discovery on the specified network device.
1394 * If successful, the Boot Server ACK will be registered as an option
1397 int start_pxebs ( struct interface *job, struct net_device *netdev,
1398 unsigned int pxe_type ) {
1399 struct setting pxe_discovery_control_setting =
1400 { .tag = DHCP_PXE_DISCOVERY_CONTROL };
1401 struct setting pxe_boot_servers_setting =
1402 { .tag = DHCP_PXE_BOOT_SERVERS };
1403 struct setting pxe_boot_server_mcast_setting =
1404 { .tag = DHCP_PXE_BOOT_SERVER_MCAST };
1405 ssize_t pxebs_list_len;
1406 struct dhcp_session *dhcp;
1408 unsigned int pxe_discovery_control;
1411 /* Get upper bound for PXE boot server IP address list */
1412 pxebs_list_len = fetch_raw_setting ( NULL, &pxe_boot_servers_setting,
1414 if ( pxebs_list_len < 0 )
1417 /* Allocate and initialise structure */
1418 dhcp = zalloc ( sizeof ( *dhcp ) + sizeof ( *ip ) /* mcast */ +
1419 sizeof ( *ip ) /* bcast */ + pxebs_list_len +
1420 sizeof ( *ip ) /* terminator */ );
1423 ref_init ( &dhcp->refcnt, dhcp_free );
1424 intf_init ( &dhcp->job, &dhcp_job_desc, &dhcp->refcnt );
1425 intf_init ( &dhcp->xfer, &dhcp_xfer_desc, &dhcp->refcnt );
1426 timer_init ( &dhcp->timer, dhcp_timer_expired, &dhcp->refcnt );
1427 dhcp->netdev = netdev_get ( netdev );
1428 dhcp->local.sin_family = AF_INET;
1429 fetch_ipv4_setting ( netdev_settings ( netdev ), &ip_setting,
1430 &dhcp->local.sin_addr );
1431 dhcp->local.sin_port = htons ( BOOTPC_PORT );
1432 dhcp->pxe_type = cpu_to_le16 ( pxe_type );
1434 /* Construct PXE boot server IP address lists */
1435 pxe_discovery_control =
1436 fetch_uintz_setting ( NULL, &pxe_discovery_control_setting );
1437 ip = ( ( ( void * ) dhcp ) + sizeof ( *dhcp ) );
1438 dhcp->pxe_attempt = ip;
1439 if ( ! ( pxe_discovery_control & PXEBS_NO_MULTICAST ) ) {
1440 fetch_ipv4_setting ( NULL, &pxe_boot_server_mcast_setting, ip);
1444 if ( ! ( pxe_discovery_control & PXEBS_NO_BROADCAST ) )
1445 (ip++)->s_addr = INADDR_BROADCAST;
1446 if ( pxe_discovery_control & PXEBS_NO_UNKNOWN_SERVERS )
1447 dhcp->pxe_accept = ip;
1448 if ( pxebs_list_len ) {
1449 uint8_t buf[pxebs_list_len];
1451 fetch_raw_setting ( NULL, &pxe_boot_servers_setting,
1452 buf, sizeof ( buf ) );
1453 pxebs_list ( dhcp, buf, sizeof ( buf ), ip );
1455 if ( ! dhcp->pxe_attempt->s_addr ) {
1456 DBGC ( dhcp, "DHCP %p has no PXE boot servers for type %04x\n",
1462 /* Dump out PXE server lists */
1463 DBGC ( dhcp, "DHCP %p attempting", dhcp );
1464 for ( ip = dhcp->pxe_attempt ; ip->s_addr ; ip++ )
1465 DBGC ( dhcp, " %s", inet_ntoa ( *ip ) );
1466 DBGC ( dhcp, "\n" );
1467 if ( dhcp->pxe_accept ) {
1468 DBGC ( dhcp, "DHCP %p accepting", dhcp );
1469 for ( ip = dhcp->pxe_accept ; ip->s_addr ; ip++ )
1470 DBGC ( dhcp, " %s", inet_ntoa ( *ip ) );
1471 DBGC ( dhcp, "\n" );
1474 /* Instantiate child objects and attach to our interfaces */
1475 if ( ( rc = xfer_open_socket ( &dhcp->xfer, SOCK_DGRAM, &dhcp_peer,
1476 ( struct sockaddr * ) &dhcp->local ) ) != 0 )
1479 /* Enter PXEBS state */
1480 dhcp_set_state ( dhcp, &dhcp_state_pxebs );
1482 /* Attach parent interface, mortalise self, and return */
1483 intf_plug_plug ( &dhcp->job, job );
1484 ref_put ( &dhcp->refcnt );
1488 dhcp_finished ( dhcp, rc );
1489 ref_put ( &dhcp->refcnt );
1493 /** DHCP network device configurator */
1494 struct net_device_configurator dhcp_configurator __net_device_configurator = {
1496 .start = start_dhcp,