iPXE
dhcp.c
Go to the documentation of this file.
1/*
2 * Copyright (C) 2006 Michael Brown <mbrown@fensystems.co.uk>.
3 *
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.
8 *
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.
13 *
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
17 * 02110-1301, USA.
18 *
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.
22 */
23
24FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25FILE_SECBOOT ( PERMITTED );
26
27#include <string.h>
28#include <stdlib.h>
29#include <stdio.h>
30#include <ctype.h>
31#include <errno.h>
32#include <assert.h>
33#include <byteswap.h>
34#include <ipxe/if_ether.h>
35#include <ipxe/iobuf.h>
36#include <ipxe/netdevice.h>
37#include <ipxe/device.h>
38#include <ipxe/xfer.h>
39#include <ipxe/open.h>
40#include <ipxe/job.h>
41#include <ipxe/retry.h>
42#include <ipxe/tcpip.h>
43#include <ipxe/ip.h>
44#include <ipxe/uuid.h>
45#include <ipxe/timer.h>
46#include <ipxe/settings.h>
47#include <ipxe/dhcp.h>
48#include <ipxe/dhcpopts.h>
49#include <ipxe/dhcppkt.h>
50#include <ipxe/dhcparch.h>
51#include <ipxe/features.h>
52#include <config/dhcp.h>
53
54/** @file
55 *
56 * Dynamic Host Configuration Protocol
57 *
58 */
59
60struct dhcp_session;
61static int dhcp_tx ( struct dhcp_session *dhcp );
62
63/**
64 * DHCP operation types
65 *
66 * This table maps from DHCP message types (i.e. values of the @c
67 * DHCP_MESSAGE_TYPE option) to values of the "op" field within a DHCP
68 * packet.
69 */
80
81/** Raw option data for options common to all DHCP requests */
103
104/** Settings copied in to all DHCP requests */
105static const struct setting * dhcp_request_settings[] = {
106 &user_class_setting,
107 &vendor_class_setting,
108};
109
110/** DHCP server address setting */
111const struct setting dhcp_server_setting __setting ( SETTING_MISC,
112 dhcp-server ) = {
113 .name = "dhcp-server",
114 .description = "DHCP server",
116 .type = &setting_type_ipv4,
117};
118
119/**
120 * Most recent DHCP transaction ID
121 *
122 * This is exposed for use by the fakedhcp code when reconstructing
123 * DHCP packets for PXE NBPs.
124 */
126
127/**
128 * Name a DHCP packet type
129 *
130 * @v msgtype DHCP message type
131 * @ret string DHCP mesasge type name
132 */
133static inline const char * dhcp_msgtype_name ( unsigned int msgtype ) {
134 switch ( msgtype ) {
135 case DHCPNONE: return "BOOTP"; /* Non-DHCP packet */
136 case DHCPDISCOVER: return "DHCPDISCOVER";
137 case DHCPOFFER: return "DHCPOFFER";
138 case DHCPREQUEST: return "DHCPREQUEST";
139 case DHCPDECLINE: return "DHCPDECLINE";
140 case DHCPACK: return "DHCPACK";
141 case DHCPNAK: return "DHCPNAK";
142 case DHCPRELEASE: return "DHCPRELEASE";
143 case DHCPINFORM: return "DHCPINFORM";
144 default: return "DHCP<invalid>";
145 }
146}
147
148/****************************************************************************
149 *
150 * DHCP session
151 *
152 */
153
154struct dhcp_session;
155
156/** DHCP session state operations */
158 /** State name */
159 const char *name;
160 /**
161 * Construct transmitted packet
162 *
163 * @v dhcp DHCP session
164 * @v dhcppkt DHCP packet
165 * @v peer Destination address
166 */
167 int ( * tx ) ( struct dhcp_session *dhcp, struct dhcp_packet *dhcppkt,
168 struct sockaddr_in *peer );
169 /**
170 * Handle received packet
171 *
172 * @v dhcp DHCP session
173 * @v dhcppkt DHCP packet
174 * @v peer DHCP server address
175 * @v msgtype DHCP message type
176 * @v server_id DHCP server ID
177 * @v pseudo_id DHCP server pseudo-ID
178 */
179 void ( * rx ) ( struct dhcp_session *dhcp, struct dhcp_packet *dhcppkt,
180 struct sockaddr_in *peer, uint8_t msgtype,
181 struct in_addr server_id, struct in_addr pseudo_id );
182 /**
183 * Handle timer expiry
184 *
185 * @v dhcp DHCP session
186 */
187 void ( * expired ) ( struct dhcp_session *dhcp );
188 /** Transmitted message type */
190 /** Timeout parameters */
193};
194
199
200/** A DHCP session */
202 /** Reference counter */
204 /** Job control interface */
206 /** Data transfer interface */
208
209 /** Network device being configured */
211 /** Local socket address */
213 /** State of the session */
215 /** Transaction ID (in network-endian order) */
217
218 /** Offered IP address */
220 /** DHCP server */
222 /** DHCP offer priority */
224
225 /** ProxyDHCP protocol extensions should be ignored */
227 /** ProxyDHCP server */
229 /** ProxyDHCP offer */
231 /** ProxyDHCP offer priority */
233
234 /** PXE Boot Server type */
236 /** List of PXE Boot Servers to attempt */
238 /** List of PXE Boot Servers to accept */
240
241 /** Retransmission timer */
243 /** Transmission counter */
244 unsigned int count;
245 /** Start time of the current state (in ticks) */
246 unsigned long start;
247};
248
249/**
250 * Free DHCP session
251 *
252 * @v refcnt Reference counter
253 */
254static void dhcp_free ( struct refcnt *refcnt ) {
255 struct dhcp_session *dhcp =
257
258 netdev_put ( dhcp->netdev );
259 dhcppkt_put ( dhcp->proxy_offer );
260 free ( dhcp );
261}
262
263/**
264 * Mark DHCP session as complete
265 *
266 * @v dhcp DHCP session
267 * @v rc Return status code
268 */
269static void dhcp_finished ( struct dhcp_session *dhcp, int rc ) {
270
271 /* Stop retry timer */
272 stop_timer ( &dhcp->timer );
273
274 /* Shut down interfaces */
275 intf_shutdown ( &dhcp->xfer, rc );
276 intf_shutdown ( &dhcp->job, rc );
277}
278
279/**
280 * Transition to new DHCP session state
281 *
282 * @v dhcp DHCP session
283 * @v state New session state
284 */
285static void dhcp_set_state ( struct dhcp_session *dhcp,
286 struct dhcp_session_state *state ) {
287
288 DBGC ( dhcp, "DHCP %p entering %s state\n", dhcp, state->name );
289 dhcp->state = state;
290 dhcp->start = currticks();
291 stop_timer ( &dhcp->timer );
292 set_timer_limits ( &dhcp->timer,
293 ( state->min_timeout_sec * TICKS_PER_SEC ),
294 ( state->max_timeout_sec * TICKS_PER_SEC ) );
295 start_timer_nodelay ( &dhcp->timer );
296}
297
298/**
299 * Check if DHCP packet contains PXE options
300 *
301 * @v dhcppkt DHCP packet
302 * @ret has_pxeopts DHCP packet contains PXE options
303 *
304 * It is assumed that the packet is already known to contain option 60
305 * set to "PXEClient".
306 */
307static int dhcp_has_pxeopts ( struct dhcp_packet *dhcppkt ) {
308
309 /* Check for a next-server and boot filename */
310 if ( dhcppkt->dhcphdr->siaddr.s_addr &&
311 ( dhcppkt_fetch ( dhcppkt, DHCP_BOOTFILE_NAME, NULL, 0 ) > 0 ) )
312 return 1;
313
314 /* Check for a PXE boot menu */
315 if ( dhcppkt_fetch ( dhcppkt, DHCP_PXE_BOOT_MENU, NULL, 0 ) > 0 )
316 return 1;
317
318 return 0;
319}
320
321/****************************************************************************
322 *
323 * DHCP state machine
324 *
325 */
326
327/**
328 * Construct transmitted packet for DHCP discovery
329 *
330 * @v dhcp DHCP session
331 * @v dhcppkt DHCP packet
332 * @v peer Destination address
333 */
334static int dhcp_discovery_tx ( struct dhcp_session *dhcp,
335 struct dhcp_packet *dhcppkt __unused,
336 struct sockaddr_in *peer ) {
337
338 DBGC ( dhcp, "DHCP %p DHCPDISCOVER\n", dhcp );
339
340 /* Set server address */
341 peer->sin_addr.s_addr = INADDR_BROADCAST;
342 peer->sin_port = htons ( BOOTPS_PORT );
343
344 return 0;
345}
346
347/**
348 * Handle received packet during DHCP discovery
349 *
350 * @v dhcp DHCP session
351 * @v dhcppkt DHCP packet
352 * @v peer DHCP server address
353 * @v msgtype DHCP message type
354 * @v server_id DHCP server ID
355 * @v pseudo_id DHCP server pseudo-ID
356 */
357static void dhcp_discovery_rx ( struct dhcp_session *dhcp,
358 struct dhcp_packet *dhcppkt,
359 struct sockaddr_in *peer, uint8_t msgtype,
360 struct in_addr server_id,
361 struct in_addr pseudo_id ) {
362 struct in_addr ip;
363 char vci[9]; /* "PXEClient" */
364 int vci_len;
365 int has_pxeclient;
366 int8_t priority = 0;
367 uint8_t no_pxedhcp = 0;
368 unsigned long elapsed;
369
370 DBGC ( dhcp, "DHCP %p %s from %s:%d", dhcp,
371 dhcp_msgtype_name ( msgtype ), inet_ntoa ( peer->sin_addr ),
372 ntohs ( peer->sin_port ) );
373 if ( ( server_id.s_addr != peer->sin_addr.s_addr ) ||
374 ( pseudo_id.s_addr != peer->sin_addr.s_addr ) ) {
375 DBGC ( dhcp, " (%s/", inet_ntoa ( server_id ) );
376 DBGC ( dhcp, "%s)", inet_ntoa ( pseudo_id ) );
377 }
378
379 /* Identify offered IP address */
380 ip = dhcppkt->dhcphdr->yiaddr;
381 if ( ip.s_addr )
382 DBGC ( dhcp, " for %s", inet_ntoa ( ip ) );
383
384 /* Identify "PXEClient" vendor class */
385 vci_len = dhcppkt_fetch ( dhcppkt, DHCP_VENDOR_CLASS_ID,
386 vci, sizeof ( vci ) );
387 has_pxeclient = ( ( vci_len >= ( int ) sizeof ( vci ) ) &&
388 ( strncmp ( "PXEClient", vci, sizeof (vci) ) == 0 ));
389 if ( has_pxeclient ) {
390 DBGC ( dhcp, "%s",
391 ( dhcp_has_pxeopts ( dhcppkt ) ? " pxe" : " proxy" ) );
392 }
393
394 /* Identify priority */
396 sizeof ( priority ) );
397 if ( priority )
398 DBGC ( dhcp, " pri %d", priority );
399
400 /* Identify ignore-PXE flag */
401 dhcppkt_fetch ( dhcppkt, DHCP_EB_NO_PXEDHCP, &no_pxedhcp,
402 sizeof ( no_pxedhcp ) );
403 if ( no_pxedhcp )
404 DBGC ( dhcp, " nopxe" );
405 DBGC ( dhcp, "\n" );
406
407 /* Select as DHCP offer, if applicable */
408 if ( ip.s_addr && ( peer->sin_port == htons ( BOOTPS_PORT ) ) &&
409 ( ( msgtype == DHCPOFFER ) || ( ! msgtype /* BOOTP */ ) ) &&
410 ( priority >= dhcp->priority ) ) {
411 dhcp->offer = ip;
412 dhcp->server = server_id;
413 dhcp->priority = priority;
414 dhcp->no_pxedhcp = no_pxedhcp;
415 }
416
417 /* Select as ProxyDHCP offer, if applicable */
418 if ( pseudo_id.s_addr && has_pxeclient &&
419 ( priority >= dhcp->proxy_priority ) ) {
420 dhcppkt_put ( dhcp->proxy_offer );
421 dhcp->proxy_server = pseudo_id;
422 dhcp->proxy_offer = dhcppkt_get ( dhcppkt );
423 dhcp->proxy_priority = priority;
424 }
425
426 /* We can exit the discovery state when we have a valid
427 * DHCPOFFER, and either:
428 *
429 * o The DHCPOFFER instructs us to ignore ProxyDHCPOFFERs, or
430 * o We have a valid ProxyDHCPOFFER, or
431 * o We have allowed sufficient time for ProxyDHCPOFFERs.
432 */
433
434 /* If we don't yet have a DHCPOFFER, do nothing */
435 if ( ! dhcp->offer.s_addr )
436 return;
437
438 /* If we can't yet transition to DHCPREQUEST, do nothing */
439 elapsed = ( currticks() - dhcp->start );
440 if ( ! ( dhcp->no_pxedhcp || dhcp->proxy_offer ||
442 return;
443
444 /* Transition to DHCPREQUEST */
446}
447
448/**
449 * Defer DHCP discovery
450 *
451 * @v dhcp DHCP session
452 */
453static void dhcp_defer ( struct dhcp_session *dhcp ) {
454
455 /* Do nothing if we have reached the deferral limit */
456 if ( dhcp->count > DHCP_DISC_MAX_DEFERRALS )
457 return;
458
459 /* Return to discovery state */
460 DBGC ( dhcp, "DHCP %p deferring discovery\n", dhcp );
462
463 /* Delay first DHCPDISCOVER */
464 start_timer_fixed ( &dhcp->timer,
466}
467
468/**
469 * Handle timer expiry during DHCP discovery
470 *
471 * @v dhcp DHCP session
472 */
473static void dhcp_discovery_expired ( struct dhcp_session *dhcp ) {
474 unsigned long elapsed = ( currticks() - dhcp->start );
475
476 /* Give up waiting for ProxyDHCP before we reach the failure point */
477 if ( dhcp->offer.s_addr &&
480 return;
481 }
482
483 /* Retransmit current packet */
484 dhcp_tx ( dhcp );
485
486 /* If link is blocked, defer DHCP discovery timeout */
487 if ( netdev_link_blocked ( dhcp->netdev ) )
488 dhcp_defer ( dhcp );
489}
490
491/** DHCP discovery state operations */
493 .name = "discovery",
494 .tx = dhcp_discovery_tx,
495 .rx = dhcp_discovery_rx,
496 .expired = dhcp_discovery_expired,
497 .tx_msgtype = DHCPDISCOVER,
498 .min_timeout_sec = DHCP_DISC_START_TIMEOUT_SEC,
499 .max_timeout_sec = DHCP_DISC_END_TIMEOUT_SEC,
500};
501
502/**
503 * Construct transmitted packet for DHCP request
504 *
505 * @v dhcp DHCP session
506 * @v dhcppkt DHCP packet
507 * @v peer Destination address
508 */
509static int dhcp_request_tx ( struct dhcp_session *dhcp,
510 struct dhcp_packet *dhcppkt,
511 struct sockaddr_in *peer ) {
512 int rc;
513
514 DBGC ( dhcp, "DHCP %p DHCPREQUEST to %s:%d",
515 dhcp, inet_ntoa ( dhcp->server ), BOOTPS_PORT );
516 DBGC ( dhcp, " for %s\n", inet_ntoa ( dhcp->offer ) );
517
518 /* Set server ID */
519 if ( ( rc = dhcppkt_store ( dhcppkt, DHCP_SERVER_IDENTIFIER,
520 &dhcp->server,
521 sizeof ( dhcp->server ) ) ) != 0 )
522 return rc;
523
524 /* Set requested IP address */
525 if ( ( rc = dhcppkt_store ( dhcppkt, DHCP_REQUESTED_ADDRESS,
526 &dhcp->offer,
527 sizeof ( dhcp->offer ) ) ) != 0 )
528 return rc;
529
530 /* Set server address */
531 peer->sin_addr.s_addr = INADDR_BROADCAST;
532 peer->sin_port = htons ( BOOTPS_PORT );
533
534 return 0;
535}
536
537/**
538 * Handle received packet during DHCP request
539 *
540 * @v dhcp DHCP session
541 * @v dhcppkt DHCP packet
542 * @v peer DHCP server address
543 * @v msgtype DHCP message type
544 * @v server_id DHCP server ID
545 * @v pseudo_id DHCP server pseudo-ID
546 */
547static void dhcp_request_rx ( struct dhcp_session *dhcp,
548 struct dhcp_packet *dhcppkt,
549 struct sockaddr_in *peer, uint8_t msgtype,
550 struct in_addr server_id,
551 struct in_addr pseudo_id ) {
552 struct in_addr ip;
553 struct settings *parent;
554 struct settings *settings;
555 int rc;
556
557 DBGC ( dhcp, "DHCP %p %s from %s:%d", dhcp,
558 dhcp_msgtype_name ( msgtype ), inet_ntoa ( peer->sin_addr ),
559 ntohs ( peer->sin_port ) );
560 if ( ( server_id.s_addr != peer->sin_addr.s_addr ) ||
561 ( pseudo_id.s_addr != peer->sin_addr.s_addr ) ) {
562 DBGC ( dhcp, " (%s/", inet_ntoa ( server_id ) );
563 DBGC ( dhcp, "%s)", inet_ntoa ( pseudo_id ) );
564 }
565
566 /* Identify leased IP address */
567 ip = dhcppkt->dhcphdr->yiaddr;
568 if ( ip.s_addr )
569 DBGC ( dhcp, " for %s", inet_ntoa ( ip ) );
570 DBGC ( dhcp, "\n" );
571
572 /* Filter out invalid port */
573 if ( peer->sin_port != htons ( BOOTPS_PORT ) )
574 return;
575
576 /* Filter out non-selected servers */
577 if ( server_id.s_addr != dhcp->server.s_addr )
578 return;
579
580 /* Handle DHCPNAK */
581 if ( msgtype == DHCPNAK ) {
582 dhcp_defer ( dhcp );
583 return;
584 }
585
586 /* Filter out unacceptable responses */
587 if ( msgtype /* BOOTP */ && ( msgtype != DHCPACK ) )
588 return;
589 if ( ip.s_addr != dhcp->offer.s_addr )
590 return;
591
592 /* Record assigned address */
593 dhcp->local.sin_addr = ip;
594
595 /* Register settings */
596 parent = netdev_settings ( dhcp->netdev );
597 settings = &dhcppkt->settings;
599 DHCP_SETTINGS_NAME ) ) != 0 ) {
600 DBGC ( dhcp, "DHCP %p could not register settings: %s\n",
601 dhcp, strerror ( rc ) );
602 dhcp_finished ( dhcp, rc );
603 return;
604 }
605
606 /* Unregister any existing ProxyDHCP or PXEBS settings */
611
612 /* Perform ProxyDHCP if applicable */
613 if ( dhcp->proxy_offer /* Have ProxyDHCP offer */ &&
614 ( ! dhcp->no_pxedhcp ) /* ProxyDHCP not disabled */ ) {
615 if ( dhcp_has_pxeopts ( dhcp->proxy_offer ) ) {
616 /* PXE options already present; register settings
617 * without performing a ProxyDHCPREQUEST
618 */
619 settings = &dhcp->proxy_offer->settings;
620 if ( ( rc = register_settings ( settings, NULL,
621 PROXYDHCP_SETTINGS_NAME ) ) != 0 ) {
622 DBGC ( dhcp, "DHCP %p could not register "
623 "proxy settings: %s\n",
624 dhcp, strerror ( rc ) );
625 dhcp_finished ( dhcp, rc );
626 return;
627 }
628 } else {
629 /* PXE options not present; use a ProxyDHCPREQUEST */
631 return;
632 }
633 }
634
635 /* Terminate DHCP */
636 dhcp_finished ( dhcp, 0 );
637}
638
639/**
640 * Handle timer expiry during DHCP discovery
641 *
642 * @v dhcp DHCP session
643 */
644static void dhcp_request_expired ( struct dhcp_session *dhcp ) {
645
646 /* Retransmit current packet */
647 dhcp_tx ( dhcp );
648}
649
650/** DHCP request state operations */
652 .name = "request",
653 .tx = dhcp_request_tx,
654 .rx = dhcp_request_rx,
655 .expired = dhcp_request_expired,
656 .tx_msgtype = DHCPREQUEST,
657 .min_timeout_sec = DHCP_REQ_START_TIMEOUT_SEC,
658 .max_timeout_sec = DHCP_REQ_END_TIMEOUT_SEC,
659};
660
661/**
662 * Construct transmitted packet for ProxyDHCP request
663 *
664 * @v dhcp DHCP session
665 * @v dhcppkt DHCP packet
666 * @v peer Destination address
667 */
668static int dhcp_proxy_tx ( struct dhcp_session *dhcp,
669 struct dhcp_packet *dhcppkt,
670 struct sockaddr_in *peer ) {
671 int rc;
672
673 DBGC ( dhcp, "DHCP %p ProxyDHCP REQUEST to %s\n", dhcp,
674 inet_ntoa ( dhcp->proxy_server ) );
675
676 /* Set server ID */
677 if ( ( rc = dhcppkt_store ( dhcppkt, DHCP_SERVER_IDENTIFIER,
678 &dhcp->proxy_server,
679 sizeof ( dhcp->proxy_server ) ) ) != 0 )
680 return rc;
681
682 /* Set server address */
683 peer->sin_addr = dhcp->proxy_server;
684 peer->sin_port = htons ( PXE_PORT );
685
686 return 0;
687}
688
689/**
690 * Handle received packet during ProxyDHCP request
691 *
692 * @v dhcp DHCP session
693 * @v dhcppkt DHCP packet
694 * @v peer DHCP server address
695 * @v msgtype DHCP message type
696 * @v server_id DHCP server ID
697 * @v pseudo_id DHCP server pseudo-ID
698 */
699static void dhcp_proxy_rx ( struct dhcp_session *dhcp,
700 struct dhcp_packet *dhcppkt,
701 struct sockaddr_in *peer, uint8_t msgtype,
702 struct in_addr server_id,
703 struct in_addr pseudo_id ) {
704 struct settings *settings = &dhcppkt->settings;
705 int rc;
706
707 DBGC ( dhcp, "DHCP %p %s from %s:%d", dhcp,
708 dhcp_msgtype_name ( msgtype ), inet_ntoa ( peer->sin_addr ),
709 ntohs ( peer->sin_port ) );
710 if ( ( server_id.s_addr != peer->sin_addr.s_addr ) ||
711 ( pseudo_id.s_addr != peer->sin_addr.s_addr ) ) {
712 DBGC ( dhcp, " (%s/", inet_ntoa ( server_id ) );
713 DBGC ( dhcp, "%s)", inet_ntoa ( pseudo_id ) );
714 }
715 if ( dhcp_has_pxeopts ( dhcppkt ) )
716 DBGC ( dhcp, " pxe" );
717 DBGC ( dhcp, "\n" );
718
719 /* Filter out unacceptable responses */
720 if ( peer->sin_port != ntohs ( PXE_PORT ) )
721 return;
722 if ( ( msgtype != DHCPOFFER ) && ( msgtype != DHCPACK ) )
723 return;
724 if ( ( pseudo_id.s_addr != dhcp->proxy_server.s_addr ) )
725 return;
726 if ( ! dhcp_has_pxeopts ( dhcppkt ) )
727 return;
728
729 /* Register settings */
730 if ( ( rc = register_settings ( settings, NULL,
731 PROXYDHCP_SETTINGS_NAME ) ) != 0 ) {
732 DBGC ( dhcp, "DHCP %p could not register proxy settings: %s\n",
733 dhcp, strerror ( rc ) );
734 dhcp_finished ( dhcp, rc );
735 return;
736 }
737
738 /* Terminate DHCP */
739 dhcp_finished ( dhcp, 0 );
740}
741
742/**
743 * Handle timer expiry during ProxyDHCP request
744 *
745 * @v dhcp DHCP session
746 */
747static void dhcp_proxy_expired ( struct dhcp_session *dhcp ) {
748 unsigned long elapsed = ( currticks() - dhcp->start );
749
750 /* Give up waiting for ProxyDHCP before we reach the failure point */
751 if ( elapsed > DHCP_REQ_PROXY_TIMEOUT_SEC * TICKS_PER_SEC ) {
752 dhcp_finished ( dhcp, 0 );
753 return;
754 }
755
756 /* Retransmit current packet */
757 dhcp_tx ( dhcp );
758}
759
760/** ProxyDHCP request state operations */
761static struct dhcp_session_state dhcp_state_proxy = {
762 .name = "ProxyDHCP",
763 .tx = dhcp_proxy_tx,
764 .rx = dhcp_proxy_rx,
765 .expired = dhcp_proxy_expired,
766 .tx_msgtype = DHCPREQUEST,
767 .min_timeout_sec = DHCP_PROXY_START_TIMEOUT_SEC,
768 .max_timeout_sec = DHCP_PROXY_END_TIMEOUT_SEC,
769};
770
771/**
772 * Construct transmitted packet for PXE Boot Server Discovery
773 *
774 * @v dhcp DHCP session
775 * @v dhcppkt DHCP packet
776 * @v peer Destination address
777 */
778static int dhcp_pxebs_tx ( struct dhcp_session *dhcp,
779 struct dhcp_packet *dhcppkt,
780 struct sockaddr_in *peer ) {
781 struct dhcp_pxe_boot_menu_item menu_item = { 0, 0 };
782 int rc;
783
784 /* Set server address */
785 peer->sin_addr = *(dhcp->pxe_attempt);
786 peer->sin_port = ( ( peer->sin_addr.s_addr == INADDR_BROADCAST ) ?
787 htons ( BOOTPS_PORT ) : htons ( PXE_PORT ) );
788
789 DBGC ( dhcp, "DHCP %p PXEBS REQUEST to %s:%d for type %d\n",
790 dhcp, inet_ntoa ( peer->sin_addr ), ntohs ( peer->sin_port ),
791 le16_to_cpu ( dhcp->pxe_type ) );
792
793 /* Set boot menu item */
794 menu_item.type = dhcp->pxe_type;
795 if ( ( rc = dhcppkt_store ( dhcppkt, DHCP_PXE_BOOT_MENU_ITEM,
796 &menu_item, sizeof ( menu_item ) ) ) != 0 )
797 return rc;
798
799 return 0;
800}
801
802/**
803 * Check to see if PXE Boot Server address is acceptable
804 *
805 * @v dhcp DHCP session
806 * @v bs Boot Server address
807 * @ret accept Boot Server is acceptable
808 */
809static int dhcp_pxebs_accept ( struct dhcp_session *dhcp,
810 struct in_addr bs ) {
811 struct in_addr *accept;
812
813 /* Accept if we have no acceptance filter */
814 if ( ! dhcp->pxe_accept )
815 return 1;
816
817 /* Scan through acceptance list */
818 for ( accept = dhcp->pxe_accept ; accept->s_addr ; accept++ ) {
819 if ( accept->s_addr == bs.s_addr )
820 return 1;
821 }
822
823 DBGC ( dhcp, "DHCP %p rejecting server %s\n",
824 dhcp, inet_ntoa ( bs ) );
825 return 0;
826}
827
828/**
829 * Handle received packet during PXE Boot Server Discovery
830 *
831 * @v dhcp DHCP session
832 * @v dhcppkt DHCP packet
833 * @v peer DHCP server address
834 * @v msgtype DHCP message type
835 * @v server_id DHCP server ID
836 * @v pseudo_id DHCP server pseudo-ID
837 */
838static void dhcp_pxebs_rx ( struct dhcp_session *dhcp,
839 struct dhcp_packet *dhcppkt,
840 struct sockaddr_in *peer, uint8_t msgtype,
841 struct in_addr server_id,
842 struct in_addr pseudo_id ) {
843 struct dhcp_pxe_boot_menu_item menu_item = { 0, 0 };
844 int rc;
845
846 DBGC ( dhcp, "DHCP %p %s from %s:%d", dhcp,
847 dhcp_msgtype_name ( msgtype ), inet_ntoa ( peer->sin_addr ),
848 ntohs ( peer->sin_port ) );
849 if ( ( server_id.s_addr != peer->sin_addr.s_addr ) ||
850 ( pseudo_id.s_addr != peer->sin_addr.s_addr ) ) {
851 DBGC ( dhcp, " (%s/", inet_ntoa ( server_id ) );
852 DBGC ( dhcp, "%s)", inet_ntoa ( pseudo_id ) );
853 }
854
855 /* Identify boot menu item */
857 &menu_item, sizeof ( menu_item ) );
858 if ( menu_item.type )
859 DBGC ( dhcp, " for type %d", ntohs ( menu_item.type ) );
860 DBGC ( dhcp, "\n" );
861
862 /* Filter out unacceptable responses */
863 if ( ( peer->sin_port != htons ( BOOTPS_PORT ) ) &&
864 ( peer->sin_port != htons ( PXE_PORT ) ) )
865 return;
866 if ( msgtype != DHCPACK )
867 return;
868 if ( menu_item.type != dhcp->pxe_type )
869 return;
870 if ( ! dhcp_pxebs_accept ( dhcp, pseudo_id ) )
871 return;
872
873 /* Register settings */
874 if ( ( rc = register_settings ( &dhcppkt->settings, NULL,
875 PXEBS_SETTINGS_NAME ) ) != 0 ) {
876 DBGC ( dhcp, "DHCP %p could not register settings: %s\n",
877 dhcp, strerror ( rc ) );
878 dhcp_finished ( dhcp, rc );
879 return;
880 }
881
882 /* Terminate DHCP */
883 dhcp_finished ( dhcp, 0 );
884}
885
886/**
887 * Handle timer expiry during PXE Boot Server Discovery
888 *
889 * @v dhcp DHCP session
890 */
891static void dhcp_pxebs_expired ( struct dhcp_session *dhcp ) {
892 unsigned long elapsed = ( currticks() - dhcp->start );
893
894 /* Give up waiting before we reach the failure point, and fail
895 * over to the next server in the attempt list
896 */
897 if ( elapsed > PXEBS_MAX_TIMEOUT_SEC * TICKS_PER_SEC ) {
898 dhcp->pxe_attempt++;
899 if ( dhcp->pxe_attempt->s_addr ) {
901 return;
902 } else {
903 dhcp_finished ( dhcp, -ETIMEDOUT );
904 return;
905 }
906 }
907
908 /* Retransmit current packet */
909 dhcp_tx ( dhcp );
910}
911
912/** PXE Boot Server Discovery state operations */
913static struct dhcp_session_state dhcp_state_pxebs = {
914 .name = "PXEBS",
915 .tx = dhcp_pxebs_tx,
916 .rx = dhcp_pxebs_rx,
917 .expired = dhcp_pxebs_expired,
918 .tx_msgtype = DHCPREQUEST,
919 .min_timeout_sec = PXEBS_START_TIMEOUT_SEC,
920 .max_timeout_sec = PXEBS_END_TIMEOUT_SEC,
921};
922
923/****************************************************************************
924 *
925 * Packet construction
926 *
927 */
928
929/**
930 * Create a DHCP packet
931 *
932 * @v dhcppkt DHCP packet structure to fill in
933 * @v netdev Network device
934 * @v msgtype DHCP message type
935 * @v xid Transaction ID (in network-endian order)
936 * @v options Initial options to include (or NULL)
937 * @v options_len Length of initial options
938 * @v data Buffer for DHCP packet
939 * @v max_len Size of DHCP packet buffer
940 * @ret rc Return status code
941 *
942 * Creates a DHCP packet in the specified buffer, and initialise a
943 * DHCP packet structure.
944 */
945int dhcp_create_packet ( struct dhcp_packet *dhcppkt,
946 struct net_device *netdev, uint8_t msgtype,
947 uint32_t xid, const void *options, size_t options_len,
948 void *data, size_t max_len ) {
949 struct dhcphdr *dhcphdr = data;
950 int rc;
951
952 /* Sanity check */
953 if ( max_len < ( sizeof ( *dhcphdr ) + options_len ) )
954 return -ENOSPC;
955
956 /* Initialise DHCP packet content */
957 memset ( dhcphdr, 0, max_len );
958 dhcphdr->xid = xid;
960 dhcphdr->htype = ntohs ( netdev->ll_protocol->ll_proto );
961 dhcphdr->op = dhcp_op[msgtype];
962 dhcphdr->hlen = netdev->ll_protocol->ll_addr_len;
963 memcpy ( dhcphdr->chaddr, netdev->ll_addr,
964 netdev->ll_protocol->ll_addr_len );
965 memcpy ( dhcphdr->options, options, options_len );
966
967 /* If the local link-layer address functions only as a name
968 * (i.e. cannot be used as a destination address), then
969 * request broadcast responses.
970 */
971 if ( netdev->ll_protocol->flags & LL_NAME_ONLY )
973
974 /* If the network device already has an IPv4 address then
975 * unicast responses from the DHCP server may be rejected, so
976 * request broadcast responses.
977 */
978 if ( ipv4_has_any_addr ( netdev ) )
980
981 /* Initialise DHCP packet structure */
982 memset ( dhcppkt, 0, sizeof ( *dhcppkt ) );
983 dhcppkt_init ( dhcppkt, data, max_len );
984
985 /* Set DHCP_MESSAGE_TYPE option */
986 if ( ( rc = dhcppkt_store ( dhcppkt, DHCP_MESSAGE_TYPE,
987 &msgtype, sizeof ( msgtype ) ) ) != 0 )
988 return rc;
989
990 return 0;
991}
992
993/**
994 * Create DHCP request packet
995 *
996 * @v dhcppkt DHCP packet structure to fill in
997 * @v netdev Network device
998 * @v msgtype DHCP message type
999 * @v xid Transaction ID (in network-endian order)
1000 * @v ciaddr Client IP address
1001 * @v data Buffer for DHCP packet
1002 * @v max_len Size of DHCP packet buffer
1003 * @ret rc Return status code
1004 *
1005 * Creates a DHCP request packet in the specified buffer, and
1006 * initialise a DHCP packet structure.
1007 */
1008int dhcp_create_request ( struct dhcp_packet *dhcppkt,
1009 struct net_device *netdev, unsigned int msgtype,
1010 uint32_t xid, struct in_addr ciaddr,
1011 void *data, size_t max_len ) {
1012 struct dhcp_netdev_desc dhcp_desc;
1013 struct dhcp_client_id client_id;
1014 struct dhcp_client_uuid client_uuid;
1015 const struct setting *setting;
1016 uint8_t *dhcp_features;
1017 size_t dhcp_features_len;
1018 size_t ll_addr_len;
1019 void *raw;
1020 ssize_t len;
1021 unsigned int i;
1022 int rc;
1023
1024 /* Create DHCP packet */
1025 if ( ( rc = dhcp_create_packet ( dhcppkt, netdev, msgtype, xid,
1027 sizeof ( dhcp_request_options_data ),
1028 data, max_len ) ) != 0 ) {
1029 DBG ( "DHCP could not create DHCP packet: %s\n",
1030 strerror ( rc ) );
1031 goto err_create_packet;
1032 }
1033
1034 /* Set client IP address */
1035 dhcppkt->dhcphdr->ciaddr = ciaddr;
1036
1037 /* Add options to identify the feature list */
1038 dhcp_features = table_start ( DHCP_FEATURES );
1039 dhcp_features_len = table_num_entries ( DHCP_FEATURES );
1040 if ( ( rc = dhcppkt_store ( dhcppkt, DHCP_EB_ENCAP, dhcp_features,
1041 dhcp_features_len ) ) != 0 ) {
1042 DBG ( "DHCP could not set features list option: %s\n",
1043 strerror ( rc ) );
1044 goto err_store_features;
1045 }
1046
1047 /* Add options to identify the network device */
1048 fetch_raw_setting ( netdev_settings ( netdev ), &busid_setting,
1049 &dhcp_desc, sizeof ( dhcp_desc ) );
1050 if ( ( rc = dhcppkt_store ( dhcppkt, DHCP_EB_BUS_ID, &dhcp_desc,
1051 sizeof ( dhcp_desc ) ) ) != 0 ) {
1052 DBG ( "DHCP could not set bus ID option: %s\n",
1053 strerror ( rc ) );
1054 goto err_store_busid;
1055 }
1056
1057 /* Add DHCP client identifier. Required for Infiniband, and
1058 * doesn't hurt other link layers.
1059 */
1060 client_id.ll_proto = ntohs ( netdev->ll_protocol->ll_proto );
1061 ll_addr_len = netdev->ll_protocol->ll_addr_len;
1062 assert ( ll_addr_len <= sizeof ( client_id.ll_addr ) );
1063 memcpy ( client_id.ll_addr, netdev->ll_addr, ll_addr_len );
1064 if ( ( rc = dhcppkt_store ( dhcppkt, DHCP_CLIENT_ID, &client_id,
1065 ( ll_addr_len + 1 ) ) ) != 0 ) {
1066 DBG ( "DHCP could not set client ID: %s\n",
1067 strerror ( rc ) );
1068 goto err_store_client_id;
1069 }
1070
1071 /* Add client UUID, if we have one. Required for PXE. The
1072 * PXE spec does not specify a byte ordering for UUIDs, but
1073 * RFC4578 suggests that it follows the EFI spec, in which the
1074 * first three fields are little-endian.
1075 */
1076 client_uuid.type = DHCP_CLIENT_UUID_TYPE;
1077 if ( ( len = fetch_uuid_setting ( NULL, &uuid_setting,
1078 &client_uuid.uuid ) ) >= 0 ) {
1079 uuid_mangle ( &client_uuid.uuid );
1080 if ( ( rc = dhcppkt_store ( dhcppkt, DHCP_CLIENT_UUID,
1081 &client_uuid,
1082 sizeof ( client_uuid ) ) ) != 0 ) {
1083 DBG ( "DHCP could not set client UUID: %s\n",
1084 strerror ( rc ) );
1085 goto err_store_client_uuid;
1086 }
1087 }
1088
1089 /* Add request settings, if applicable */
1090 for ( i = 0 ; i < ( sizeof ( dhcp_request_settings ) /
1091 sizeof ( dhcp_request_settings[0] ) ) ; i++ ) {
1094 &raw ) ) >= 0 ) {
1095 rc = dhcppkt_store ( dhcppkt, setting->tag, raw, len );
1096 free ( raw );
1097 if ( rc != 0 ) {
1098 DBG ( "DHCP could not set %s: %s\n",
1099 setting->name, strerror ( rc ) );
1100 goto err_store_raw;
1101 }
1102 }
1103 }
1104
1105 err_store_raw:
1106 err_store_client_uuid:
1107 err_store_client_id:
1108 err_store_busid:
1109 err_store_features:
1110 err_create_packet:
1111 return rc;
1112}
1113
1114/****************************************************************************
1115 *
1116 * Data transfer interface
1117 *
1118 */
1119
1120/**
1121 * Transmit DHCP request
1122 *
1123 * @v dhcp DHCP session
1124 * @ret rc Return status code
1125 */
1126static int dhcp_tx ( struct dhcp_session *dhcp ) {
1127 static struct sockaddr_in peer = {
1128 .sin_family = AF_INET,
1129 };
1130 struct xfer_metadata meta = {
1131 .netdev = dhcp->netdev,
1132 .src = ( struct sockaddr * ) &dhcp->local,
1133 .dest = ( struct sockaddr * ) &peer,
1134 };
1135 struct io_buffer *iobuf;
1136 uint8_t msgtype = dhcp->state->tx_msgtype;
1137 struct dhcp_packet dhcppkt;
1138 int rc;
1139
1140 /* Start retry timer. Do this first so that failures to
1141 * transmit will be retried.
1142 */
1143 start_timer ( &dhcp->timer );
1144
1145 /* Allocate buffer for packet */
1146 iobuf = xfer_alloc_iob ( &dhcp->xfer, DHCP_MIN_LEN );
1147 if ( ! iobuf )
1148 return -ENOMEM;
1149
1150 /* Create basic DHCP packet in temporary buffer */
1151 if ( ( rc = dhcp_create_request ( &dhcppkt, dhcp->netdev, msgtype,
1152 dhcp->xid, dhcp->local.sin_addr,
1153 iobuf->data,
1154 iob_tailroom ( iobuf ) ) ) != 0 ) {
1155 DBGC ( dhcp, "DHCP %p could not construct DHCP request: %s\n",
1156 dhcp, strerror ( rc ) );
1157 goto done;
1158 }
1159
1160 /* (Ab)use the "secs" field to convey metadata about the DHCP
1161 * session state into packet traces. Useful for extracting
1162 * debug information from non-debug builds.
1163 */
1164 dhcppkt.dhcphdr->secs = htons ( ( dhcp->count << 2 ) |
1165 ( dhcp->offer.s_addr ? 0x02 : 0 ) |
1166 ( dhcp->proxy_offer ? 0x01 : 0 ) );
1167
1168 /* Fill in packet based on current state */
1169 if ( ( rc = dhcp->state->tx ( dhcp, &dhcppkt, &peer ) ) != 0 ) {
1170 DBGC ( dhcp, "DHCP %p could not fill DHCP request: %s\n",
1171 dhcp, strerror ( rc ) );
1172 goto done;
1173 }
1174
1175 /* Transmit the packet */
1176 iob_put ( iobuf, dhcppkt_len ( &dhcppkt ) );
1177 if ( ( rc = xfer_deliver ( &dhcp->xfer, iob_disown ( iobuf ),
1178 &meta ) ) != 0 ) {
1179 DBGC ( dhcp, "DHCP %p could not transmit UDP packet: %s\n",
1180 dhcp, strerror ( rc ) );
1181 goto done;
1182 }
1183
1184 done:
1185 free_iob ( iobuf );
1186 return rc;
1187}
1188
1189/**
1190 * Receive new data
1191 *
1192 * @v dhcp DHCP session
1193 * @v iobuf I/O buffer
1194 * @v meta Transfer metadata
1195 * @ret rc Return status code
1196 */
1197static int dhcp_deliver ( struct dhcp_session *dhcp,
1198 struct io_buffer *iobuf,
1199 struct xfer_metadata *meta ) {
1200 struct net_device *netdev = dhcp->netdev;
1201 struct ll_protocol *ll_protocol = netdev->ll_protocol;
1202 struct sockaddr_in *peer;
1203 size_t data_len;
1204 struct dhcp_packet *dhcppkt;
1205 struct dhcphdr *dhcphdr;
1206 uint8_t msgtype = 0;
1207 struct in_addr server_id = { 0 };
1208 struct in_addr pseudo_id;
1209 int rc = 0;
1210
1211 /* Sanity checks */
1212 if ( ! meta->src ) {
1213 DBGC ( dhcp, "DHCP %p received packet without source port\n",
1214 dhcp );
1215 rc = -EINVAL;
1216 goto err_no_src;
1217 }
1218 peer = ( struct sockaddr_in * ) meta->src;
1219
1220 /* Create a DHCP packet containing the I/O buffer contents.
1221 * Whilst we could just use the original buffer in situ, that
1222 * would waste the unused space in the packet buffer, and also
1223 * waste a relatively scarce fully-aligned I/O buffer.
1224 */
1225 data_len = iob_len ( iobuf );
1226 dhcppkt = zalloc ( sizeof ( *dhcppkt ) + data_len );
1227 if ( ! dhcppkt ) {
1228 rc = -ENOMEM;
1229 goto err_alloc_dhcppkt;
1230 }
1231 dhcphdr = ( ( ( void * ) dhcppkt ) + sizeof ( *dhcppkt ) );
1232 memcpy ( dhcphdr, iobuf->data, data_len );
1233 dhcppkt_init ( dhcppkt, dhcphdr, data_len );
1234
1235 /* Identify message type */
1236 dhcppkt_fetch ( dhcppkt, DHCP_MESSAGE_TYPE, &msgtype,
1237 sizeof ( msgtype ) );
1238
1239 /* Identify server ID */
1241 &server_id, sizeof ( server_id ) );
1242
1243 /* Identify server pseudo-ID */
1244 pseudo_id = server_id;
1245 if ( ! pseudo_id.s_addr )
1246 pseudo_id = dhcppkt->dhcphdr->siaddr;
1247 if ( ! pseudo_id.s_addr )
1248 pseudo_id = peer->sin_addr;
1249
1250 /* Check for matching transaction ID */
1251 if ( dhcphdr->xid != dhcp->xid ) {
1252 DBGC ( dhcp, "DHCP %p %s from %s:%d has bad transaction "
1253 "ID\n", dhcp, dhcp_msgtype_name ( msgtype ),
1254 inet_ntoa ( peer->sin_addr ),
1255 ntohs ( peer->sin_port ) );
1256 rc = -EINVAL;
1257 goto err_xid;
1258 };
1259
1260 /* Check for matching client hardware address */
1261 if ( memcmp ( dhcphdr->chaddr, netdev->ll_addr,
1262 ll_protocol->ll_addr_len ) != 0 ) {
1263 DBGC ( dhcp, "DHCP %p %s from %s:%d has bad chaddr %s\n",
1264 dhcp, dhcp_msgtype_name ( msgtype ),
1265 inet_ntoa ( peer->sin_addr ), ntohs ( peer->sin_port ),
1267 rc = -EINVAL;
1268 goto err_chaddr;
1269 }
1270
1271 /* Handle packet based on current state */
1272 dhcp->state->rx ( dhcp, dhcppkt, peer, msgtype, server_id, pseudo_id );
1273
1274 err_chaddr:
1275 err_xid:
1276 dhcppkt_put ( dhcppkt );
1277 err_alloc_dhcppkt:
1278 err_no_src:
1279 free_iob ( iobuf );
1280 return rc;
1281}
1282
1283/** DHCP data transfer interface operations */
1287
1288/** DHCP data transfer interface descriptor */
1291
1292/**
1293 * Handle DHCP retry timer expiry
1294 *
1295 * @v timer DHCP retry timer
1296 * @v fail Failure indicator
1297 */
1298static void dhcp_timer_expired ( struct retry_timer *timer, int fail ) {
1299 struct dhcp_session *dhcp =
1300 container_of ( timer, struct dhcp_session, timer );
1301
1302 /* If we have failed, terminate DHCP */
1303 if ( fail ) {
1304 dhcp_finished ( dhcp, -ETIMEDOUT );
1305 return;
1306 }
1307
1308 /* Increment transmission counter */
1309 dhcp->count++;
1310
1311 /* Handle timer expiry based on current state */
1312 dhcp->state->expired ( dhcp );
1313}
1314
1315/****************************************************************************
1316 *
1317 * Job control interface
1318 *
1319 */
1320
1321/** DHCP job control interface operations */
1324};
1325
1326/** DHCP job control interface descriptor */
1328 INTF_DESC ( struct dhcp_session, job, dhcp_job_op );
1329
1330/****************************************************************************
1331 *
1332 * Instantiators
1333 *
1334 */
1335
1336/**
1337 * DHCP peer address for socket opening
1338 *
1339 * This is a dummy address; the only useful portion is the socket
1340 * family (so that we get a UDP connection). The DHCP client will set
1341 * the IP address and source port explicitly on each transmission.
1342 */
1343static struct sockaddr dhcp_peer = {
1344 .sa_family = AF_INET,
1345};
1346
1347/**
1348 * Start DHCP state machine on a network device
1349 *
1350 * @v job Job control interface
1351 * @v netdev Network device
1352 * @ret rc Return status code
1353 *
1354 * Starts DHCP on the specified network device. If successful, the
1355 * DHCPACK (and ProxyDHCPACK, if applicable) will be registered as
1356 * option sources.
1357 */
1358int start_dhcp ( struct interface *job, struct net_device *netdev ) {
1359 struct dhcp_session *dhcp;
1360 int rc;
1361
1362 /* Allocate and initialise structure */
1363 dhcp = zalloc ( sizeof ( *dhcp ) );
1364 if ( ! dhcp )
1365 return -ENOMEM;
1366 ref_init ( &dhcp->refcnt, dhcp_free );
1367 intf_init ( &dhcp->job, &dhcp_job_desc, &dhcp->refcnt );
1368 intf_init ( &dhcp->xfer, &dhcp_xfer_desc, &dhcp->refcnt );
1369 timer_init ( &dhcp->timer, dhcp_timer_expired, &dhcp->refcnt );
1370 dhcp->netdev = netdev_get ( netdev );
1371 dhcp->local.sin_family = AF_INET;
1372 dhcp->local.sin_port = htons ( BOOTPC_PORT );
1373 dhcp->xid = random();
1374
1375 /* Store DHCP transaction ID for fakedhcp code */
1376 dhcp_last_xid = dhcp->xid;
1377
1378 /* Instantiate child objects and attach to our interfaces */
1379 if ( ( rc = xfer_open_socket ( &dhcp->xfer, SOCK_DGRAM, &dhcp_peer,
1380 ( struct sockaddr * ) &dhcp->local ) ) != 0 )
1381 goto err;
1382
1383 /* Enter DHCPDISCOVER state */
1385
1386 /* Attach parent interface, mortalise self, and return */
1387 intf_plug_plug ( &dhcp->job, job );
1388 ref_put ( &dhcp->refcnt );
1389 return 0;
1390
1391 err:
1392 dhcp_finished ( dhcp, rc );
1393 ref_put ( &dhcp->refcnt );
1394 return rc;
1395}
1396
1397/**
1398 * Retrieve list of PXE boot servers for a given server type
1399 *
1400 * @v dhcp DHCP session
1401 * @v raw DHCP PXE boot server list
1402 * @v raw_len Length of DHCP PXE boot server list
1403 * @v ip IP address list to fill in
1404 *
1405 * The caller must ensure that the IP address list has sufficient
1406 * space.
1407 */
1408static void pxebs_list ( struct dhcp_session *dhcp, void *raw,
1409 size_t raw_len, struct in_addr *ip ) {
1410 struct dhcp_pxe_boot_server *server = raw;
1411 size_t server_len;
1412 unsigned int i;
1413
1414 while ( raw_len ) {
1415 if ( raw_len < sizeof ( *server ) ) {
1416 DBGC ( dhcp, "DHCP %p malformed PXE server list\n",
1417 dhcp );
1418 break;
1419 }
1420 server_len = offsetof ( typeof ( *server ),
1421 ip[ server->num_ip ] );
1422 if ( raw_len < server_len ) {
1423 DBGC ( dhcp, "DHCP %p malformed PXE server list\n",
1424 dhcp );
1425 break;
1426 }
1427 if ( server->type == dhcp->pxe_type ) {
1428 for ( i = 0 ; i < server->num_ip ; i++ )
1429 *(ip++) = server->ip[i];
1430 }
1431 server = ( ( ( void * ) server ) + server_len );
1432 raw_len -= server_len;
1433 }
1434}
1435
1436/**
1437 * Start PXE Boot Server Discovery on a network device
1438 *
1439 * @v job Job control interface
1440 * @v netdev Network device
1441 * @v pxe_type PXE server type
1442 * @ret rc Return status code
1443 *
1444 * Starts PXE Boot Server Discovery on the specified network device.
1445 * If successful, the Boot Server ACK will be registered as an option
1446 * source.
1447 */
1448int start_pxebs ( struct interface *job, struct net_device *netdev,
1449 unsigned int pxe_type ) {
1450 struct setting pxe_discovery_control_setting =
1451 { .tag = DHCP_PXE_DISCOVERY_CONTROL };
1452 struct setting pxe_boot_servers_setting =
1453 { .tag = DHCP_PXE_BOOT_SERVERS };
1454 struct setting pxe_boot_server_mcast_setting =
1455 { .tag = DHCP_PXE_BOOT_SERVER_MCAST };
1456 ssize_t pxebs_list_len;
1457 struct dhcp_session *dhcp;
1458 struct in_addr *ip;
1459 unsigned int pxe_discovery_control;
1460 int rc;
1461
1462 /* Get upper bound for PXE boot server IP address list */
1463 pxebs_list_len = fetch_raw_setting ( NULL, &pxe_boot_servers_setting,
1464 NULL, 0 );
1465 if ( pxebs_list_len < 0 )
1466 pxebs_list_len = 0;
1467
1468 /* Allocate and initialise structure */
1469 dhcp = zalloc ( sizeof ( *dhcp ) + sizeof ( *ip ) /* mcast */ +
1470 sizeof ( *ip ) /* bcast */ + pxebs_list_len +
1471 sizeof ( *ip ) /* terminator */ );
1472 if ( ! dhcp )
1473 return -ENOMEM;
1474 ref_init ( &dhcp->refcnt, dhcp_free );
1475 intf_init ( &dhcp->job, &dhcp_job_desc, &dhcp->refcnt );
1476 intf_init ( &dhcp->xfer, &dhcp_xfer_desc, &dhcp->refcnt );
1477 timer_init ( &dhcp->timer, dhcp_timer_expired, &dhcp->refcnt );
1478 dhcp->netdev = netdev_get ( netdev );
1479 dhcp->local.sin_family = AF_INET;
1481 &dhcp->local.sin_addr );
1482 dhcp->local.sin_port = htons ( BOOTPC_PORT );
1483 dhcp->pxe_type = cpu_to_le16 ( pxe_type );
1484
1485 /* Construct PXE boot server IP address lists */
1486 pxe_discovery_control =
1487 fetch_uintz_setting ( NULL, &pxe_discovery_control_setting );
1488 ip = ( ( ( void * ) dhcp ) + sizeof ( *dhcp ) );
1489 dhcp->pxe_attempt = ip;
1490 if ( ! ( pxe_discovery_control & PXEBS_NO_MULTICAST ) ) {
1491 fetch_ipv4_setting ( NULL, &pxe_boot_server_mcast_setting, ip);
1492 if ( ip->s_addr )
1493 ip++;
1494 }
1495 if ( ! ( pxe_discovery_control & PXEBS_NO_BROADCAST ) )
1496 (ip++)->s_addr = INADDR_BROADCAST;
1497 if ( pxe_discovery_control & PXEBS_NO_UNKNOWN_SERVERS )
1498 dhcp->pxe_accept = ip;
1499 if ( pxebs_list_len ) {
1500 uint8_t buf[pxebs_list_len];
1501
1502 fetch_raw_setting ( NULL, &pxe_boot_servers_setting,
1503 buf, sizeof ( buf ) );
1504 pxebs_list ( dhcp, buf, sizeof ( buf ), ip );
1505 }
1506 if ( ! dhcp->pxe_attempt->s_addr ) {
1507 DBGC ( dhcp, "DHCP %p has no PXE boot servers for type %04x\n",
1508 dhcp, pxe_type );
1509 rc = -EINVAL;
1510 goto err;
1511 }
1512
1513 /* Dump out PXE server lists */
1514 DBGC ( dhcp, "DHCP %p attempting", dhcp );
1515 for ( ip = dhcp->pxe_attempt ; ip->s_addr ; ip++ )
1516 DBGC ( dhcp, " %s", inet_ntoa ( *ip ) );
1517 DBGC ( dhcp, "\n" );
1518 if ( dhcp->pxe_accept ) {
1519 DBGC ( dhcp, "DHCP %p accepting", dhcp );
1520 for ( ip = dhcp->pxe_accept ; ip->s_addr ; ip++ )
1521 DBGC ( dhcp, " %s", inet_ntoa ( *ip ) );
1522 DBGC ( dhcp, "\n" );
1523 }
1524
1525 /* Instantiate child objects and attach to our interfaces */
1526 if ( ( rc = xfer_open_socket ( &dhcp->xfer, SOCK_DGRAM, &dhcp_peer,
1527 ( struct sockaddr * ) &dhcp->local ) ) != 0 )
1528 goto err;
1529
1530 /* Enter PXEBS state */
1532
1533 /* Attach parent interface, mortalise self, and return */
1534 intf_plug_plug ( &dhcp->job, job );
1535 ref_put ( &dhcp->refcnt );
1536 return 0;
1537
1538 err:
1539 dhcp_finished ( dhcp, rc );
1540 ref_put ( &dhcp->refcnt );
1541 return rc;
1542}
1543
1544/** DHCP network device configurator */
1546 .name = "dhcp",
1547 .start = start_dhcp,
1548};
static int options
Definition 3c515.c:286
#define NULL
NULL pointer (VOID *)
Definition Base.h:322
__be32 raw[7]
Definition CIB_PRM.h:0
typeof(acpi_finder=acpi_find)
ACPI table finder.
Definition acpi.c:48
struct arbelprm_rc_send_wqe rc
Definition arbel.h:3
unsigned short uint16_t
Definition stdint.h:11
unsigned int uint32_t
Definition stdint.h:12
unsigned char uint8_t
Definition stdint.h:10
signed long ssize_t
Definition stdint.h:7
signed char int8_t
Definition stdint.h:15
#define DHCP_ARCH_CLIENT_ARCHITECTURE
DHCP client architecture.
Definition dhcparch.h:15
#define DHCP_ARCH_CLIENT_NDI
DHCP client network device interface.
Definition dhcparch.h:18
Assertions.
#define assert(condition)
Assert a condition at run-time.
Definition assert.h:50
static size_t raw_len
Definition base16.h:54
struct bofm_section_header done
Definition bofm_test.c:46
DHCP configuration.
#define DHCP_DISC_START_TIMEOUT_SEC
Definition dhcp.h:23
#define DHCP_REQ_START_TIMEOUT_SEC
Definition dhcp.h:52
#define DHCP_PROXY_START_TIMEOUT_SEC
Definition dhcp.h:60
#define PXEBS_START_TIMEOUT_SEC
Definition dhcp.h:80
#define PXEBS_END_TIMEOUT_SEC
Definition dhcp.h:81
#define DHCP_PROXY_END_TIMEOUT_SEC
Definition dhcp.h:61
#define DHCP_REQ_PROXY_TIMEOUT_SEC
Definition dhcp.h:70
#define DHCP_DISC_PROXY_TIMEOUT_SEC
Definition dhcp.h:40
#define DHCP_DISC_END_TIMEOUT_SEC
Definition dhcp.h:24
#define DHCP_REQ_END_TIMEOUT_SEC
Definition dhcp.h:53
#define PXEBS_MAX_TIMEOUT_SEC
Definition dhcp.h:89
#define DHCP_DISC_MAX_DEFERRALS
Definition dhcp.h:32
Character types.
Device model.
static struct dhcp_session_state dhcp_state_pxebs
PXE Boot Server Discovery state operations.
Definition dhcp.c:198
static struct interface_operation dhcp_job_op[]
DHCP job control interface operations.
Definition dhcp.c:1322
static const char * dhcp_msgtype_name(unsigned int msgtype)
Name a DHCP packet type.
Definition dhcp.c:133
static struct interface_descriptor dhcp_job_desc
DHCP job control interface descriptor.
Definition dhcp.c:1327
static void dhcp_finished(struct dhcp_session *dhcp, int rc)
Mark DHCP session as complete.
Definition dhcp.c:269
uint32_t dhcp_last_xid
Most recent DHCP transaction ID.
Definition dhcp.c:125
static int dhcp_pxebs_tx(struct dhcp_session *dhcp, struct dhcp_packet *dhcppkt, struct sockaddr_in *peer)
Construct transmitted packet for PXE Boot Server Discovery.
Definition dhcp.c:778
static void dhcp_proxy_expired(struct dhcp_session *dhcp)
Handle timer expiry during ProxyDHCP request.
Definition dhcp.c:747
int start_pxebs(struct interface *job, struct net_device *netdev, unsigned int pxe_type)
Start PXE Boot Server Discovery on a network device.
Definition dhcp.c:1448
static struct interface_descriptor dhcp_xfer_desc
DHCP data transfer interface descriptor.
Definition dhcp.c:1289
static struct dhcp_session_state dhcp_state_proxy
ProxyDHCP request state operations.
Definition dhcp.c:197
static void dhcp_defer(struct dhcp_session *dhcp)
Defer DHCP discovery.
Definition dhcp.c:453
static struct dhcp_session_state dhcp_state_discover
DHCP discovery state operations.
Definition dhcp.c:195
static void dhcp_discovery_expired(struct dhcp_session *dhcp)
Handle timer expiry during DHCP discovery.
Definition dhcp.c:473
static void dhcp_free(struct refcnt *refcnt)
Free DHCP session.
Definition dhcp.c:254
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 pseudo_id)
Handle received packet during DHCP discovery.
Definition dhcp.c:357
static int dhcp_pxebs_accept(struct dhcp_session *dhcp, struct in_addr bs)
Check to see if PXE Boot Server address is acceptable.
Definition dhcp.c:809
static void pxebs_list(struct dhcp_session *dhcp, void *raw, size_t raw_len, struct in_addr *ip)
Retrieve list of PXE boot servers for a given server type.
Definition dhcp.c:1408
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 pseudo_id)
Handle received packet during ProxyDHCP request.
Definition dhcp.c:699
static const struct setting * dhcp_request_settings[]
Settings copied in to all DHCP requests.
Definition dhcp.c:105
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 pseudo_id)
Handle received packet during PXE Boot Server Discovery.
Definition dhcp.c:838
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 pseudo_id)
Handle received packet during DHCP request.
Definition dhcp.c:547
static uint8_t dhcp_request_options_data[]
Raw option data for options common to all DHCP requests.
Definition dhcp.c:82
static void dhcp_timer_expired(struct retry_timer *timer, int fail)
Handle DHCP retry timer expiry.
Definition dhcp.c:1298
static struct dhcp_session_state dhcp_state_request
DHCP request state operations.
Definition dhcp.c:196
static struct sockaddr dhcp_peer
DHCP peer address for socket opening.
Definition dhcp.c:1343
static void dhcp_request_expired(struct dhcp_session *dhcp)
Handle timer expiry during DHCP discovery.
Definition dhcp.c:644
static const uint8_t dhcp_op[]
DHCP operation types.
Definition dhcp.c:70
static int dhcp_deliver(struct dhcp_session *dhcp, struct io_buffer *iobuf, struct xfer_metadata *meta)
Receive new data.
Definition dhcp.c:1197
static int dhcp_request_tx(struct dhcp_session *dhcp, struct dhcp_packet *dhcppkt, struct sockaddr_in *peer)
Construct transmitted packet for DHCP request.
Definition dhcp.c:509
static int dhcp_has_pxeopts(struct dhcp_packet *dhcppkt)
Check if DHCP packet contains PXE options.
Definition dhcp.c:307
static void dhcp_pxebs_expired(struct dhcp_session *dhcp)
Handle timer expiry during PXE Boot Server Discovery.
Definition dhcp.c:891
int start_dhcp(struct interface *job, struct net_device *netdev)
Start DHCP state machine on a network device.
Definition dhcp.c:1358
int dhcp_create_packet(struct dhcp_packet *dhcppkt, struct net_device *netdev, uint8_t msgtype, uint32_t xid, const void *options, size_t options_len, void *data, size_t max_len)
Create a DHCP packet.
Definition dhcp.c:945
int dhcp_create_request(struct dhcp_packet *dhcppkt, struct net_device *netdev, unsigned int msgtype, uint32_t xid, struct in_addr ciaddr, void *data, size_t max_len)
Create DHCP request packet.
Definition dhcp.c:1008
static int dhcp_tx(struct dhcp_session *dhcp)
Transmit DHCP request.
Definition dhcp.c:1126
static void dhcp_set_state(struct dhcp_session *dhcp, struct dhcp_session_state *state)
Transition to new DHCP session state.
Definition dhcp.c:285
static int dhcp_proxy_tx(struct dhcp_session *dhcp, struct dhcp_packet *dhcppkt, struct sockaddr_in *peer)
Construct transmitted packet for ProxyDHCP request.
Definition dhcp.c:668
static struct interface_operation dhcp_xfer_operations[]
DHCP data transfer interface operations.
Definition dhcp.c:1284
static int dhcp_discovery_tx(struct dhcp_session *dhcp, struct dhcp_packet *dhcppkt __unused, struct sockaddr_in *peer)
Construct transmitted packet for DHCP discovery.
Definition dhcp.c:334
DHCP options.
void dhcppkt_init(struct dhcp_packet *dhcppkt, struct dhcphdr *data, size_t len)
Initialise DHCP packet.
Definition dhcppkt.c:301
int dhcppkt_store(struct dhcp_packet *dhcppkt, unsigned int tag, const void *data, size_t len)
Store value of DHCP packet setting.
Definition dhcppkt.c:165
int dhcppkt_fetch(struct dhcp_packet *dhcppkt, unsigned int tag, void *data, size_t len)
Fetch value of DHCP packet setting.
Definition dhcppkt.c:196
DHCP packets.
static struct dhcp_packet * dhcppkt_get(struct dhcp_packet *dhcppkt)
Increment reference count on DHCP packet.
Definition dhcppkt.h:39
static void dhcppkt_put(struct dhcp_packet *dhcppkt)
Decrement reference count on DHCP packet.
Definition dhcppkt.h:50
static size_t dhcppkt_len(struct dhcp_packet *dhcppkt)
Get used length of DHCP packet.
Definition dhcppkt.h:60
ring len
Length.
Definition dwmac.h:226
const struct setting ip_setting
uint8_t data[48]
Additional event data.
Definition ena.h:11
uint8_t meta
Metadata flags.
Definition ena.h:3
Error codes.
uint8_t state
State.
Definition eth_slow.h:36
static struct net_device * netdev
Definition gdbudp.c:53
#define AF_INET
IPv4 Internet addresses.
Definition socket.h:64
#define __unused
Declare a variable or data structure as unused.
Definition compiler.h:573
#define SOCK_DGRAM
Definition socket.h:30
#define DBGC(...)
Definition compiler.h:505
#define DBG(...)
Print a debugging message.
Definition compiler.h:498
#define DHCP_CLIENT_ARCHITECTURE
Client system architecture.
Definition dhcp.h:271
#define DHCPREQUEST
Definition dhcp.h:200
#define DHCP_NTP_SERVERS
NTP servers.
Definition dhcp.h:90
#define DHCP_STATIC_ROUTES
Classless static routes.
Definition dhcp.h:349
#define DHCP_ROOT_PATH
Root path.
Definition dhcp.h:84
#define DHCP_DOMAIN_NAME
Domain name.
Definition dhcp.h:81
#define DHCP_REQUESTED_ADDRESS
Requested IP address.
Definition dhcp.h:177
#define DHCP_CLIENT_UUID
UUID client identifier.
Definition dhcp.h:333
#define DHCP_CLIENT_UUID_TYPE
Definition dhcp.h:343
#define DHCPRELEASE
Definition dhcp.h:204
#define DHCP_VENDOR_PXECLIENT(arch, ndi)
Vendor class identifier for PXE clients.
Definition dhcp.h:220
#define DHCP_MAX_MESSAGE_SIZE
Maximum DHCP message size.
Definition dhcp.h:214
#define DHCP_EB_PRIORITY
Priority of this options block.
Definition dhcp.h:366
#define DHCPNAK
Definition dhcp.h:203
#define DHCPACK
Definition dhcp.h:202
#define DHCP_EB_ENCAP
Etherboot-specific encapsulated options.
Definition dhcp.h:357
#define DHCP_SUBNET_MASK
Subnet mask.
Definition dhcp.h:66
#define DHCP_PXE_BOOT_SERVERS
PXE boot servers.
Definition dhcp.h:114
#define DHCP_PXE_BOOT_MENU_ITEM
PXE boot menu item.
Definition dhcp.h:159
#define DHCP_CLIENT_ID
Client identifier.
Definition dhcp.h:243
#define DHCP_VENDOR_ENCAP
Vendor encapsulated options.
Definition dhcp.h:93
#define DHCP_MTU
Maximum transmission unit.
Definition dhcp.h:87
#define DHCP_VENDOR_CLASS_ID
Vendor class identifier.
Definition dhcp.h:217
#define DHCP_ISCSI_INITIATOR_IQN
iSCSI initiator IQN
Definition dhcp.h:539
#define DHCP_PXE_DISCOVERY_CONTROL
PXE boot server discovery control.
Definition dhcp.h:96
#define DHCPDISCOVER
Definition dhcp.h:198
#define DHCP_EB_NO_PXEDHCP
Skip PXE DHCP protocol extensions such as ProxyDHCP.
Definition dhcp.h:433
#define DHCP_PARAMETER_REQUEST_LIST
Parameter request list.
Definition dhcp.h:211
#define DHCP_DNS_SERVERS
DNS servers.
Definition dhcp.h:72
#define DHCP_CLIENT_NDI
Client network device interface.
Definition dhcp.h:330
#define DHCPOFFER
Definition dhcp.h:199
#define DHCP_MESSAGE_TYPE
DHCP message type.
Definition dhcp.h:196
#define DHCPINFORM
Definition dhcp.h:205
#define DHCP_END
End of options.
Definition dhcp.h:549
#define DHCP_USER_CLASS_ID
User class identifier.
Definition dhcp.h:268
#define DHCP_PXE_BOOT_MENU
PXE boot menu.
Definition dhcp.h:127
#define DHCP_DOMAIN_SEARCH
DNS domain search list.
Definition dhcp.h:346
#define DHCP_EB_BUS_ID
Network device descriptor.
Definition dhcp.h:446
#define DHCP_SERVER_IDENTIFIER
DHCP server identifier.
Definition dhcp.h:208
#define DHCPNONE
Definition dhcp.h:197
#define DHCP_BOOTFILE_NAME
Bootfile name.
Definition dhcp.h:265
#define DHCP_HOST_NAME
Host name.
Definition dhcp.h:78
#define DHCPDECLINE
Definition dhcp.h:201
#define DHCP_PXE_BOOT_SERVER_MCAST
PXE boot server multicast address.
Definition dhcp.h:111
#define DHCP_ROUTERS
Routers.
Definition dhcp.h:69
#define DHCP_TFTP_SERVER_NAME
TFTP server name.
Definition dhcp.h:258
#define DHCP_LOG_SERVERS
Syslog servers.
Definition dhcp.h:75
@ PXEBS_NO_UNKNOWN_SERVERS
Accept only servers in DHCP_PXE_BOOT_SERVERS list.
Definition dhcp.h:105
@ PXEBS_NO_MULTICAST
Inhibit multicast discovery.
Definition dhcp.h:103
@ PXEBS_NO_BROADCAST
Inhibit broadcast discovery.
Definition dhcp.h:101
#define FILE_LICENCE(_licence)
Declare a particular licence as applying to a file.
Definition compiler.h:896
#define ENOSPC
No space left on device.
Definition errno.h:550
#define EINVAL
Invalid argument.
Definition errno.h:429
#define ETIMEDOUT
Connection timed out.
Definition errno.h:670
#define ENOMEM
Not enough space.
Definition errno.h:535
#define FILE_SECBOOT(_status)
Declare a file's UEFI Secure Boot permission status.
Definition compiler.h:926
#define SETTING_MISC
Miscellaneous settings.
Definition settings.h:81
#define ETH_MAX_MTU
Definition if_ether.h:15
#define INADDR_BROADCAST
Definition in.h:22
#define le16_to_cpu(value)
Definition byteswap.h:113
#define htonl(value)
Definition byteswap.h:134
#define htons(value)
Definition byteswap.h:136
#define ntohs(value)
Definition byteswap.h:137
#define cpu_to_le16(value)
Definition byteswap.h:107
Dynamic Host Configuration Protocol.
#define PXE_PORT
PXE server port.
Definition dhcp.h:33
#define PXEBS_SETTINGS_NAME
Setting block name used for BootServerDHCP responses.
Definition dhcp.h:717
#define DHCP_OPTION(...)
Construct a DHCP option from a list of bytes.
Definition dhcp.h:554
#define BOOTP_REQUEST
Opcode for a request from client to server.
Definition dhcp.h:688
#define BOOTPS_PORT
BOOTP/DHCP server port.
Definition dhcp.h:27
#define BOOTPC_PORT
BOOTP/DHCP client port.
Definition dhcp.h:30
#define DHCP_STRING(...)
Construct a DHCP option from a list of characters.
Definition dhcp.h:557
#define PROXYDHCP_SETTINGS_NAME
Settings block name used for ProxyDHCP responses.
Definition dhcp.h:714
#define DHCP_WORD(value)
Construct a word-valued DHCP option.
Definition dhcp.h:563
#define DHCP_BYTE(value)
Construct a byte-valued DHCP option.
Definition dhcp.h:560
#define BOOTP_FL_BROADCAST
BOOTP reply must be broadcast.
Definition dhcp.h:698
#define BOOTP_REPLY
Opcode for a reply from server to client.
Definition dhcp.h:691
#define DHCP_MAGIC_COOKIE
DHCP magic cookie.
Definition dhcp.h:701
#define DHCP_SETTINGS_NAME
Settings block name used for DHCP responses.
Definition dhcp.h:711
#define DHCP_MIN_LEN
DHCP minimum packet length.
Definition dhcp.h:708
DHCP client architecture definitions.
Configuration settings.
#define __setting(setting_order, name)
Declare a configuration setting.
Definition settings.h:57
Transport-network layer interface.
iPXE timers
#define TICKS_PER_SEC
Number of ticks per second.
Definition timer.h:16
String functions.
void * memcpy(void *dest, const void *src, size_t len) __nonnull
void * memset(void *dest, int character, size_t len) __nonnull
void intf_close(struct interface *intf, int rc)
Close an object interface.
Definition interface.c:250
void intf_plug_plug(struct interface *a, struct interface *b)
Plug two object interfaces together.
Definition interface.c:108
void intf_shutdown(struct interface *intf, int rc)
Shut down an object interface.
Definition interface.c:279
#define INTF_DESC(object_type, intf, operations)
Define an object interface descriptor.
Definition interface.h:81
static void intf_init(struct interface *intf, struct interface_descriptor *desc, struct refcnt *refcnt)
Initialise an object interface.
Definition interface.h:204
#define INTF_OP(op_type, object_type, op_func)
Define an object interface operation.
Definition interface.h:33
void free_iob(struct io_buffer *iobuf)
Free I/O buffer.
Definition iobuf.c:153
I/O buffers.
#define iob_put(iobuf, len)
Definition iobuf.h:125
#define iob_disown(iobuf)
Disown an I/O buffer.
Definition iobuf.h:217
static size_t iob_len(struct io_buffer *iobuf)
Calculate length of data in an I/O buffer.
Definition iobuf.h:160
static size_t iob_tailroom(struct io_buffer *iobuf)
Calculate available space at end of an I/O buffer.
Definition iobuf.h:180
IP protocol.
int ipv4_has_any_addr(struct net_device *netdev)
Check if network device has any IPv4 address.
Definition ipv4.c:589
char * inet_ntoa(struct in_addr in)
Convert IPv4 address to dotted-quad notation.
Definition ipv4.c:814
Feature list.
#define DHCP_FEATURES
DHCP feature table.
Definition features.h:63
Job control interfaces.
void * zalloc(size_t size)
Allocate cleared memory.
Definition malloc.c:662
struct mschapv2_challenge peer
Peer challenge.
Definition mschapv2.h:1
Network device management.
static int netdev_link_blocked(struct net_device *netdev)
Check link block state of network device.
Definition netdevice.h:651
static struct net_device * netdev_get(struct net_device *netdev)
Get reference to network device.
Definition netdevice.h:565
#define LL_NAME_ONLY
Local link-layer address functions only as a name.
Definition netdevice.h:211
static void netdev_put(struct net_device *netdev)
Drop reference to network device.
Definition netdevice.h:576
#define __net_device_configurator
Declare a network device configurator.
Definition netdevice.h:337
static struct settings * netdev_settings(struct net_device *netdev)
Get per-netdevice configuration settings block.
Definition netdevice.h:587
int xfer_open_socket(struct interface *intf, int semantics, struct sockaddr *peer, struct sockaddr *local)
Open socket.
Definition open.c:143
Data transfer interface opening.
IP4_t ip
Destination IP address.
Definition pxe_api.h:1
long int random(void)
Generate a pseudo-random number between 0 and 2147483647L or 2147483562?
Definition random.c:32
static void(* free)(struct refcnt *refcnt))
Definition refcnt.h:55
#define ref_put(refcnt)
Drop reference to object.
Definition refcnt.h:107
#define ref_init(refcnt, free)
Initialise a reference counter.
Definition refcnt.h:65
void start_timer(struct retry_timer *timer)
Start timer.
Definition retry.c:94
void start_timer_fixed(struct retry_timer *timer, unsigned long timeout)
Start timer with a specified timeout.
Definition retry.c:65
void stop_timer(struct retry_timer *timer)
Stop timer.
Definition retry.c:118
Retry timers.
static void start_timer_nodelay(struct retry_timer *timer)
Start timer with no delay.
Definition retry.h:100
int register_settings(struct settings *settings, struct settings *parent, const char *name)
Register settings block.
Definition settings.c:476
int fetch_raw_setting_copy(struct settings *settings, const struct setting *setting, void **data)
Fetch value of setting.
Definition settings.c:822
int fetch_raw_setting(struct settings *settings, const struct setting *setting, void *data, size_t len)
Fetch value of setting.
Definition settings.c:804
unsigned long fetch_uintz_setting(struct settings *settings, const struct setting *setting)
Fetch value of unsigned integer setting, or zero.
Definition settings.c:1069
void unregister_settings(struct settings *settings)
Unregister settings block.
Definition settings.c:515
int fetch_ipv4_setting(struct settings *settings, const struct setting *setting, struct in_addr *inp)
Fetch value of IPv4 address setting.
Definition settings.c:913
struct settings * find_settings(const char *name)
Find settings block.
Definition settings.c:407
int fetch_uuid_setting(struct settings *settings, const struct setting *setting, union uuid *uuid)
Fetch value of UUID setting.
Definition settings.c:1085
#define offsetof(type, field)
Get offset of a field within a structure.
Definition stddef.h:25
#define container_of(ptr, type, field)
Get containing structure.
Definition stddef.h:36
uint16_t priority
Priotity.
Definition stp.h:1
char * strerror(int errno)
Retrieve string representation of error number.
Definition strerror.c:79
int strncmp(const char *first, const char *second, size_t max)
Compare strings.
Definition string.c:187
int memcmp(const void *first, const void *second, size_t len)
Compare memory regions.
Definition string.c:115
Client identifier.
Definition dhcp.h:246
uint8_t ll_addr[MAX_LL_ADDR_LEN]
Link-layer address.
Definition dhcp.h:250
uint8_t ll_proto
Link-layer protocol.
Definition dhcp.h:248
UUID client identifier.
Definition dhcp.h:336
union uuid uuid
UUID.
Definition dhcp.h:340
uint8_t type
Identifier type.
Definition dhcp.h:338
Network device descriptor.
Definition dhcp.h:449
A DHCP packet.
Definition dhcppkt.h:21
struct settings settings
Settings interface.
Definition dhcppkt.h:29
struct dhcphdr * dhcphdr
The DHCP packet contents.
Definition dhcppkt.h:25
PXE boot menu item.
Definition dhcp.h:162
uint16_t type
"Type"
Definition dhcp.h:168
PXE boot server.
Definition dhcp.h:117
uint8_t num_ip
Number of IPv4 addresses.
Definition dhcp.h:121
struct in_addr ip[0]
IPv4 addresses.
Definition dhcp.h:123
uint16_t type
"Type"
Definition dhcp.h:119
DHCP session state operations.
Definition dhcp.c:157
uint8_t min_timeout_sec
Timeout parameters.
Definition dhcp.c:191
uint8_t tx_msgtype
Transmitted message type.
Definition dhcp.c:189
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 received packet.
Definition dhcp.c:179
void(* expired)(struct dhcp_session *dhcp)
Handle timer expiry.
Definition dhcp.c:187
const char * name
State name.
Definition dhcp.c:159
uint8_t max_timeout_sec
Definition dhcp.c:192
int(* tx)(struct dhcp_session *dhcp, struct dhcp_packet *dhcppkt, struct sockaddr_in *peer)
Construct transmitted packet.
Definition dhcp.c:167
A DHCP session.
Definition dhcp.c:201
struct in_addr offer
Offered IP address.
Definition dhcp.c:219
int proxy_priority
ProxyDHCP offer priority.
Definition dhcp.c:232
struct dhcp_session_state * state
State of the session.
Definition dhcp.c:214
struct in_addr proxy_server
ProxyDHCP server.
Definition dhcp.c:228
struct interface xfer
Data transfer interface.
Definition dhcp.c:207
int no_pxedhcp
ProxyDHCP protocol extensions should be ignored.
Definition dhcp.c:226
uint16_t pxe_type
PXE Boot Server type.
Definition dhcp.c:235
unsigned long start
Start time of the current state (in ticks)
Definition dhcp.c:246
uint32_t xid
Transaction ID (in network-endian order)
Definition dhcp.c:216
int priority
DHCP offer priority.
Definition dhcp.c:223
struct sockaddr_in local
Local socket address.
Definition dhcp.c:212
struct refcnt refcnt
Reference counter.
Definition dhcp.c:203
struct retry_timer timer
Retransmission timer.
Definition dhcp.c:242
struct in_addr * pxe_accept
List of PXE Boot Servers to accept.
Definition dhcp.c:239
struct dhcp_packet * proxy_offer
ProxyDHCP offer.
Definition dhcp.c:230
struct in_addr * pxe_attempt
List of PXE Boot Servers to attempt.
Definition dhcp.c:237
struct net_device * netdev
Network device being configured.
Definition dhcp.c:210
unsigned int count
Transmission counter.
Definition dhcp.c:244
struct in_addr server
DHCP server.
Definition dhcp.c:221
struct interface job
Job control interface.
Definition dhcp.c:205
A DHCP header.
Definition dhcp.h:616
uint32_t xid
Transaction ID.
Definition dhcp.h:634
uint32_t magic
DHCP magic cookie.
Definition dhcp.h:677
uint8_t op
Operation.
Definition dhcp.h:621
uint8_t options[0]
DHCP options.
Definition dhcp.h:684
uint8_t chaddr[16]
Client hardware address.
Definition dhcp.h:662
struct in_addr yiaddr
"Your" IP address
Definition dhcp.h:649
uint16_t secs
Seconds since start of acquisition.
Definition dhcp.h:636
uint8_t htype
Hardware address type.
Definition dhcp.h:628
struct in_addr ciaddr
"Client" IP address
Definition dhcp.h:644
struct in_addr siaddr
"Server" IP address
Definition dhcp.h:655
uint16_t flags
Flags.
Definition dhcp.h:638
uint8_t hlen
Hardware address length.
Definition dhcp.h:630
IP address structure.
Definition in.h:42
uint32_t s_addr
Definition in.h:43
An object interface descriptor.
Definition interface.h:56
An object interface operation.
Definition interface.h:18
An object interface.
Definition interface.h:125
A persistent I/O buffer.
Definition iobuf.h:38
void * data
Start of data.
Definition iobuf.h:53
A link-layer protocol.
Definition netdevice.h:115
const char *(* ntoa)(const void *ll_addr)
Transcribe link-layer address.
Definition netdevice.h:164
uint8_t ll_addr_len
Link-layer address length.
Definition netdevice.h:199
A network device configurator.
Definition netdevice.h:314
A network device.
Definition netdevice.h:353
A reference counter.
Definition refcnt.h:27
A retry timer.
Definition retry.h:22
A setting.
Definition settings.h:24
const char * name
Name.
Definition settings.h:29
uint64_t tag
Setting tag, if applicable.
Definition settings.h:44
A settings block.
Definition settings.h:133
struct settings * parent
Parent settings block.
Definition settings.h:139
IPv4 socket address.
Definition in.h:85
uint16_t sin_port
TCP/IP port (part of struct sockaddr_tcpip)
Definition in.h:94
struct in_addr sin_addr
IPv4 address.
Definition in.h:101
sa_family_t sin_family
Socket address family (part of struct sockaddr)
Definition in.h:90
Generalized socket address structure.
Definition socket.h:97
A timer.
Definition timer.h:29
Data transfer metadata.
Definition xfer.h:23
#define table_num_entries(table)
Get number of entries in linker table.
Definition tables.h:336
#define table_start(table)
Get start of linker table.
Definition tables.h:283
unsigned long currticks(void)
Get current system time in ticks.
Definition timer.c:43
uint32_t data_len
Microcode data size (or 0 to indicate 2000 bytes)
Definition ucode.h:15
Universally unique IDs.
static void uuid_mangle(union uuid *uuid)
Change UUID endianness.
Definition uuid.h:44
int xfer_deliver(struct interface *intf, struct io_buffer *iobuf, struct xfer_metadata *meta)
Deliver datagram.
Definition xfer.c:195
struct io_buffer * xfer_alloc_iob(struct interface *intf, size_t len)
Allocate I/O buffer.
Definition xfer.c:159
Data transfer interfaces.