|
@@ -231,9 +231,9 @@ struct dhcp_session {
|
231
|
231
|
int no_pxedhcp;
|
232
|
232
|
/** ProxyDHCP server */
|
233
|
233
|
struct in_addr proxy_server;
|
234
|
|
- /** ProxyDHCP port */
|
235
|
|
- uint16_t proxy_port;
|
236
|
|
- /** ProxyDHCP server priority */
|
|
234
|
+ /** ProxyDHCP offer */
|
|
235
|
+ struct dhcp_packet *proxy_offer;
|
|
236
|
+ /** ProxyDHCP offer priority */
|
237
|
237
|
int proxy_priority;
|
238
|
238
|
|
239
|
239
|
/** PXE Boot Server type */
|
|
@@ -259,6 +259,7 @@ static void dhcp_free ( struct refcnt *refcnt ) {
|
259
|
259
|
container_of ( refcnt, struct dhcp_session, refcnt );
|
260
|
260
|
|
261
|
261
|
netdev_put ( dhcp->netdev );
|
|
262
|
+ dhcppkt_put ( dhcp->proxy_offer );
|
262
|
263
|
free ( dhcp );
|
263
|
264
|
}
|
264
|
265
|
|
|
@@ -297,6 +298,28 @@ static void dhcp_set_state ( struct dhcp_session *dhcp,
|
297
|
298
|
start_timer_nodelay ( &dhcp->timer );
|
298
|
299
|
}
|
299
|
300
|
|
|
301
|
+/**
|
|
302
|
+ * Check if DHCP packet contains PXE options
|
|
303
|
+ *
|
|
304
|
+ * @v dhcppkt DHCP packet
|
|
305
|
+ * @ret has_pxeopts DHCP packet contains PXE options
|
|
306
|
+ *
|
|
307
|
+ * It is assumed that the packet is already known to contain option 60
|
|
308
|
+ * set to "PXEClient".
|
|
309
|
+ */
|
|
310
|
+static int dhcp_has_pxeopts ( struct dhcp_packet *dhcppkt ) {
|
|
311
|
+
|
|
312
|
+ /* Check for a boot filename */
|
|
313
|
+ if ( dhcppkt_fetch ( dhcppkt, DHCP_BOOTFILE_NAME, NULL, 0 ) > 0 )
|
|
314
|
+ return 1;
|
|
315
|
+
|
|
316
|
+ /* Check for a PXE boot menu */
|
|
317
|
+ if ( dhcppkt_fetch ( dhcppkt, DHCP_PXE_BOOT_MENU, NULL, 0 ) > 0 )
|
|
318
|
+ return 1;
|
|
319
|
+
|
|
320
|
+ return 0;
|
|
321
|
+}
|
|
322
|
+
|
300
|
323
|
/****************************************************************************
|
301
|
324
|
*
|
302
|
325
|
* DHCP state machine
|
|
@@ -340,8 +363,6 @@ static void dhcp_discovery_rx ( struct dhcp_session *dhcp,
|
340
|
363
|
char vci[9]; /* "PXEClient" */
|
341
|
364
|
int vci_len;
|
342
|
365
|
int has_pxeclient;
|
343
|
|
- int pxeopts_len;
|
344
|
|
- int has_pxeopts;
|
345
|
366
|
int8_t priority = 0;
|
346
|
367
|
uint8_t no_pxedhcp = 0;
|
347
|
368
|
unsigned long elapsed;
|
|
@@ -362,12 +383,10 @@ static void dhcp_discovery_rx ( struct dhcp_session *dhcp,
|
362
|
383
|
vci, sizeof ( vci ) );
|
363
|
384
|
has_pxeclient = ( ( vci_len >= ( int ) sizeof ( vci ) ) &&
|
364
|
385
|
( strncmp ( "PXEClient", vci, sizeof (vci) ) == 0 ));
|
365
|
|
-
|
366
|
|
- /* Identify presence of PXE-specific options */
|
367
|
|
- pxeopts_len = dhcppkt_fetch ( dhcppkt, DHCP_PXE_BOOT_MENU, NULL, 0 );
|
368
|
|
- has_pxeopts = ( pxeopts_len >= 0 );
|
369
|
|
- if ( has_pxeclient )
|
370
|
|
- DBGC ( dhcp, "%s", ( has_pxeopts ? " pxe" : " proxy" ) );
|
|
386
|
+ if ( has_pxeclient ) {
|
|
387
|
+ DBGC ( dhcp, "%s",
|
|
388
|
+ ( dhcp_has_pxeopts ( dhcppkt ) ? " pxe" : " proxy" ) );
|
|
389
|
+ }
|
371
|
390
|
|
372
|
391
|
/* Identify priority */
|
373
|
392
|
dhcppkt_fetch ( dhcppkt, DHCP_EB_PRIORITY, &priority,
|
|
@@ -393,17 +412,11 @@ static void dhcp_discovery_rx ( struct dhcp_session *dhcp,
|
393
|
412
|
}
|
394
|
413
|
|
395
|
414
|
/* Select as ProxyDHCP offer, if applicable */
|
396
|
|
- if ( has_pxeclient && ( msgtype == DHCPOFFER ) &&
|
|
415
|
+ if ( server_id.s_addr && has_pxeclient &&
|
397
|
416
|
( priority >= dhcp->proxy_priority ) ) {
|
398
|
|
- /* If the offer already includes the PXE options, then
|
399
|
|
- * assume that we can send the ProxyDHCPREQUEST to
|
400
|
|
- * port 67 (since the DHCPDISCOVER that triggered this
|
401
|
|
- * ProxyDHCPOFFER was sent to port 67). Otherwise,
|
402
|
|
- * send the ProxyDHCPREQUEST to port 4011.
|
403
|
|
- */
|
|
417
|
+ dhcppkt_put ( dhcp->proxy_offer );
|
404
|
418
|
dhcp->proxy_server = server_id;
|
405
|
|
- dhcp->proxy_port = ( has_pxeopts ? htons ( BOOTPS_PORT )
|
406
|
|
- : htons ( PXE_PORT ) );
|
|
419
|
+ dhcp->proxy_offer = dhcppkt_get ( dhcppkt );
|
407
|
420
|
dhcp->proxy_priority = priority;
|
408
|
421
|
}
|
409
|
422
|
|
|
@@ -421,7 +434,7 @@ static void dhcp_discovery_rx ( struct dhcp_session *dhcp,
|
421
|
434
|
|
422
|
435
|
/* If we can't yet transition to DHCPREQUEST, do nothing */
|
423
|
436
|
elapsed = ( currticks() - dhcp->start );
|
424
|
|
- if ( ! ( dhcp->no_pxedhcp || dhcp->proxy_server.s_addr ||
|
|
437
|
+ if ( ! ( dhcp->no_pxedhcp || dhcp->proxy_offer ||
|
425
|
438
|
( elapsed > PROXYDHCP_MAX_TIMEOUT ) ) )
|
426
|
439
|
return;
|
427
|
440
|
|
|
@@ -507,6 +520,7 @@ static void dhcp_request_rx ( struct dhcp_session *dhcp,
|
507
|
520
|
struct in_addr server_id ) {
|
508
|
521
|
struct in_addr ip;
|
509
|
522
|
struct settings *parent;
|
|
523
|
+ struct settings *settings;
|
510
|
524
|
int rc;
|
511
|
525
|
|
512
|
526
|
DBGC ( dhcp, "DHCP %p %s from %s:%d", dhcp,
|
|
@@ -536,21 +550,36 @@ static void dhcp_request_rx ( struct dhcp_session *dhcp,
|
536
|
550
|
|
537
|
551
|
/* Register settings */
|
538
|
552
|
parent = netdev_settings ( dhcp->netdev );
|
539
|
|
- if ( ( rc = register_settings ( &dhcppkt->settings, parent ) ) != 0 ){
|
|
553
|
+ settings = &dhcppkt->settings;
|
|
554
|
+ if ( ( rc = register_settings ( settings, parent ) ) != 0 ) {
|
540
|
555
|
DBGC ( dhcp, "DHCP %p could not register settings: %s\n",
|
541
|
556
|
dhcp, strerror ( rc ) );
|
542
|
557
|
dhcp_finished ( dhcp, rc );
|
543
|
558
|
return;
|
544
|
559
|
}
|
545
|
560
|
|
546
|
|
- /* Start ProxyDHCPREQUEST if applicable */
|
547
|
|
- if ( dhcp->proxy_server.s_addr /* Have ProxyDHCP server */ &&
|
548
|
|
- ( ! dhcp->no_pxedhcp ) /* ProxyDHCP not disabled */ &&
|
549
|
|
- ( /* ProxyDHCP server is not just the DHCP server itself */
|
550
|
|
- ( dhcp->proxy_server.s_addr != dhcp->server.s_addr ) ||
|
551
|
|
- ( dhcp->proxy_port != htons ( BOOTPS_PORT ) ) ) ) {
|
552
|
|
- dhcp_set_state ( dhcp, &dhcp_state_proxy );
|
553
|
|
- return;
|
|
561
|
+ /* Perform ProxyDHCP if applicable */
|
|
562
|
+ if ( dhcp->proxy_offer /* Have ProxyDHCP offer */ &&
|
|
563
|
+ ( ! dhcp->no_pxedhcp ) /* ProxyDHCP not disabled */ ) {
|
|
564
|
+ if ( dhcp_has_pxeopts ( dhcp->proxy_offer ) ) {
|
|
565
|
+ /* PXE options already present; register settings
|
|
566
|
+ * without performing a ProxyDHCPREQUEST
|
|
567
|
+ */
|
|
568
|
+ settings = &dhcp->proxy_offer->settings;
|
|
569
|
+ settings->name = PROXYDHCP_SETTINGS_NAME;
|
|
570
|
+ if ( ( rc = register_settings ( settings,
|
|
571
|
+ NULL ) ) != 0 ) {
|
|
572
|
+ DBGC ( dhcp, "DHCP %p could not register "
|
|
573
|
+ "proxy settings: %s\n",
|
|
574
|
+ dhcp, strerror ( rc ) );
|
|
575
|
+ dhcp_finished ( dhcp, rc );
|
|
576
|
+ return;
|
|
577
|
+ }
|
|
578
|
+ } else {
|
|
579
|
+ /* PXE options not present; use a ProxyDHCPREQUEST */
|
|
580
|
+ dhcp_set_state ( dhcp, &dhcp_state_proxy );
|
|
581
|
+ return;
|
|
582
|
+ }
|
554
|
583
|
}
|
555
|
584
|
|
556
|
585
|
/* Terminate DHCP */
|
|
@@ -590,8 +619,8 @@ static int dhcp_proxy_tx ( struct dhcp_session *dhcp,
|
590
|
619
|
struct sockaddr_in *peer ) {
|
591
|
620
|
int rc;
|
592
|
621
|
|
593
|
|
- DBGC ( dhcp, "DHCP %p ProxyDHCP REQUEST to %s:%d\n", dhcp,
|
594
|
|
- inet_ntoa ( dhcp->proxy_server ), ntohs ( dhcp->proxy_port ) );
|
|
622
|
+ DBGC ( dhcp, "DHCP %p ProxyDHCP REQUEST to %s\n", dhcp,
|
|
623
|
+ inet_ntoa ( dhcp->proxy_server ) );
|
595
|
624
|
|
596
|
625
|
/* Set server ID */
|
597
|
626
|
if ( ( rc = dhcppkt_store ( dhcppkt, DHCP_SERVER_IDENTIFIER,
|
|
@@ -601,7 +630,7 @@ static int dhcp_proxy_tx ( struct dhcp_session *dhcp,
|
601
|
630
|
|
602
|
631
|
/* Set server address */
|
603
|
632
|
peer->sin_addr = dhcp->proxy_server;
|
604
|
|
- peer->sin_port = dhcp->proxy_port;
|
|
633
|
+ peer->sin_port = htons ( PXE_PORT );
|
605
|
634
|
|
606
|
635
|
return 0;
|
607
|
636
|
}
|
|
@@ -619,6 +648,7 @@ static void dhcp_proxy_rx ( struct dhcp_session *dhcp,
|
619
|
648
|
struct dhcp_packet *dhcppkt,
|
620
|
649
|
struct sockaddr_in *peer, uint8_t msgtype,
|
621
|
650
|
struct in_addr server_id ) {
|
|
651
|
+ struct settings *settings = &dhcppkt->settings;
|
622
|
652
|
int rc;
|
623
|
653
|
|
624
|
654
|
DBGC ( dhcp, "DHCP %p %s from %s:%d", dhcp,
|
|
@@ -629,7 +659,7 @@ static void dhcp_proxy_rx ( struct dhcp_session *dhcp,
|
629
|
659
|
DBGC ( dhcp, "\n" );
|
630
|
660
|
|
631
|
661
|
/* Filter out unacceptable responses */
|
632
|
|
- if ( peer->sin_port != dhcp->proxy_port )
|
|
662
|
+ if ( peer->sin_port != ntohs ( PXE_PORT ) )
|
633
|
663
|
return;
|
634
|
664
|
if ( ( msgtype != DHCPOFFER ) && ( msgtype != DHCPACK ) )
|
635
|
665
|
return;
|
|
@@ -638,9 +668,9 @@ static void dhcp_proxy_rx ( struct dhcp_session *dhcp,
|
638
|
668
|
return;
|
639
|
669
|
|
640
|
670
|
/* Register settings */
|
641
|
|
- dhcppkt->settings.name = PROXYDHCP_SETTINGS_NAME;
|
642
|
|
- if ( ( rc = register_settings ( &dhcppkt->settings, NULL ) ) != 0 ) {
|
643
|
|
- DBGC ( dhcp, "DHCP %p could not register settings: %s\n",
|
|
671
|
+ settings->name = PROXYDHCP_SETTINGS_NAME;
|
|
672
|
+ if ( ( rc = register_settings ( settings, NULL ) ) != 0 ) {
|
|
673
|
+ DBGC ( dhcp, "DHCP %p could not register proxy settings: %s\n",
|
644
|
674
|
dhcp, strerror ( rc ) );
|
645
|
675
|
dhcp_finished ( dhcp, rc );
|
646
|
676
|
return;
|