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