@@ -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 ;
0 commit comments