|
@@ -287,6 +287,8 @@ enum dhcp_session_state {
|
287
|
287
|
DHCP_STATE_REQUEST,
|
288
|
288
|
/** Sending ProxyDHCPREQUESTs, waiting for ProxyDHCPACK */
|
289
|
289
|
DHCP_STATE_PROXYREQUEST,
|
|
290
|
+ /** Sending BootServerDHCPREQUESTs, waiting for BootServerDHCPACK */
|
|
291
|
+ DHCP_STATE_BSREQUEST,
|
290
|
292
|
};
|
291
|
293
|
|
292
|
294
|
/**
|
|
@@ -300,6 +302,7 @@ static inline const char * dhcp_state_name ( enum dhcp_session_state state ) {
|
300
|
302
|
case DHCP_STATE_DISCOVER: return "DHCPDISCOVER";
|
301
|
303
|
case DHCP_STATE_REQUEST: return "DHCPREQUEST";
|
302
|
304
|
case DHCP_STATE_PROXYREQUEST: return "ProxyDHCPREQUEST";
|
|
305
|
+ case DHCP_STATE_BSREQUEST: return "BootServerREQUEST";
|
303
|
306
|
default: return "<invalid>";
|
304
|
307
|
}
|
305
|
308
|
}
|
|
@@ -326,6 +329,12 @@ struct dhcp_session {
|
326
|
329
|
struct dhcp_settings *dhcpoffer;
|
327
|
330
|
/** ProxyDHCPOFFER obtained during DHCPDISCOVER */
|
328
|
331
|
struct dhcp_settings *proxydhcpoffer;
|
|
332
|
+ /** DHCPACK obtained during DHCPREQUEST */
|
|
333
|
+ struct dhcp_settings *dhcpack;
|
|
334
|
+ /** ProxyDHCPACK obtained during ProxyDHCPREQUEST */
|
|
335
|
+ struct dhcp_settings *proxydhcpack;
|
|
336
|
+ /** BootServerDHCPACK obtained during BootServerDHCPREQUEST */
|
|
337
|
+ struct dhcp_settings *bsdhcpack;
|
329
|
338
|
/** Retransmission timer */
|
330
|
339
|
struct retry_timer timer;
|
331
|
340
|
/** Start time of the current state (in ticks) */
|
|
@@ -344,6 +353,9 @@ static void dhcp_free ( struct refcnt *refcnt ) {
|
344
|
353
|
netdev_put ( dhcp->netdev );
|
345
|
354
|
dhcpset_put ( dhcp->dhcpoffer );
|
346
|
355
|
dhcpset_put ( dhcp->proxydhcpoffer );
|
|
356
|
+ dhcpset_put ( dhcp->dhcpack );
|
|
357
|
+ dhcpset_put ( dhcp->proxydhcpack );
|
|
358
|
+ dhcpset_put ( dhcp->bsdhcpack );
|
347
|
359
|
free ( dhcp );
|
348
|
360
|
}
|
349
|
361
|
|
|
@@ -555,6 +567,10 @@ static int dhcp_tx ( struct dhcp_session *dhcp ) {
|
555
|
567
|
.sin_family = AF_INET,
|
556
|
568
|
.sin_port = htons ( PROXYDHCP_PORT ),
|
557
|
569
|
};
|
|
570
|
+ static struct sockaddr_in client = {
|
|
571
|
+ .sin_family = AF_INET,
|
|
572
|
+ .sin_port = htons ( BOOTPC_PORT ),
|
|
573
|
+ };
|
558
|
574
|
struct xfer_metadata meta = {
|
559
|
575
|
.netdev = dhcp->netdev,
|
560
|
576
|
};
|
|
@@ -584,6 +600,7 @@ static int dhcp_tx ( struct dhcp_session *dhcp ) {
|
584
|
600
|
DBGC ( dhcp, "DHCP %p transmitting ProxyDHCPREQUEST\n", dhcp );
|
585
|
601
|
assert ( dhcp->dhcpoffer );
|
586
|
602
|
assert ( dhcp->proxydhcpoffer );
|
|
603
|
+ assert ( dhcp->dhcpack );
|
587
|
604
|
offer = &dhcp->proxydhcpoffer->dhcppkt;
|
588
|
605
|
ciaddr = dhcp->dhcpoffer->dhcppkt.dhcphdr->yiaddr;
|
589
|
606
|
check_len = dhcppkt_fetch ( offer, DHCP_SERVER_IDENTIFIER,
|
|
@@ -594,6 +611,24 @@ static int dhcp_tx ( struct dhcp_session *dhcp ) {
|
594
|
611
|
assert ( proxydhcp_server.sin_addr.s_addr != 0 );
|
595
|
612
|
assert ( check_len == sizeof ( proxydhcp_server.sin_addr ) );
|
596
|
613
|
break;
|
|
614
|
+ case DHCP_STATE_BSREQUEST:
|
|
615
|
+ DBGC ( dhcp, "DHCP %p transmitting BootServerREQUEST\n",
|
|
616
|
+ dhcp );
|
|
617
|
+ assert ( dhcp->dhcpoffer );
|
|
618
|
+ assert ( dhcp->proxydhcpoffer );
|
|
619
|
+ assert ( dhcp->dhcpack );
|
|
620
|
+ assert ( dhcp->proxydhcpack );
|
|
621
|
+ offer = &dhcp->proxydhcpoffer->dhcppkt;
|
|
622
|
+ ciaddr = dhcp->dhcpoffer->dhcppkt.dhcphdr->yiaddr;
|
|
623
|
+ check_len = dhcppkt_fetch ( &dhcp->proxydhcpack->dhcppkt,
|
|
624
|
+ DHCP_PXE_BOOT_SERVER_MCAST,
|
|
625
|
+ &proxydhcp_server.sin_addr,
|
|
626
|
+ sizeof(proxydhcp_server.sin_addr));
|
|
627
|
+ meta.dest = ( struct sockaddr * ) &proxydhcp_server;
|
|
628
|
+ assert ( ciaddr.s_addr != 0 );
|
|
629
|
+ assert ( proxydhcp_server.sin_addr.s_addr != 0 );
|
|
630
|
+ assert ( check_len == sizeof ( proxydhcp_server.sin_addr ) );
|
|
631
|
+ break;
|
597
|
632
|
default:
|
598
|
633
|
assert ( 0 );
|
599
|
634
|
break;
|
|
@@ -613,6 +648,12 @@ static int dhcp_tx ( struct dhcp_session *dhcp ) {
|
613
|
648
|
goto done;
|
614
|
649
|
}
|
615
|
650
|
|
|
651
|
+ /* Explicitly specify source address, if available. */
|
|
652
|
+ if ( ciaddr.s_addr ) {
|
|
653
|
+ client.sin_addr = ciaddr;
|
|
654
|
+ meta.src = ( struct sockaddr * ) &client;
|
|
655
|
+ }
|
|
656
|
+
|
616
|
657
|
/* Transmit the packet */
|
617
|
658
|
iob_put ( iobuf, dhcppkt.len );
|
618
|
659
|
rc = xfer_deliver_iob_meta ( &dhcp->xfer, iobuf, &meta );
|
|
@@ -650,6 +691,7 @@ static void dhcp_set_state ( struct dhcp_session *dhcp,
|
650
|
691
|
* @v dhcp DHCP session
|
651
|
692
|
*/
|
652
|
693
|
static void dhcp_next_state ( struct dhcp_session *dhcp ) {
|
|
694
|
+ struct in_addr bs_mcast = { 0 };
|
653
|
695
|
|
654
|
696
|
switch ( dhcp->state ) {
|
655
|
697
|
case DHCP_STATE_DISCOVER:
|
|
@@ -662,6 +704,17 @@ static void dhcp_next_state ( struct dhcp_session *dhcp ) {
|
662
|
704
|
}
|
663
|
705
|
/* Fall through */
|
664
|
706
|
case DHCP_STATE_PROXYREQUEST:
|
|
707
|
+ if ( dhcp->proxydhcpack ) {
|
|
708
|
+ dhcppkt_fetch ( &dhcp->proxydhcpack->dhcppkt,
|
|
709
|
+ DHCP_PXE_BOOT_SERVER_MCAST,
|
|
710
|
+ &bs_mcast, sizeof ( bs_mcast ) );
|
|
711
|
+ if ( bs_mcast.s_addr ) {
|
|
712
|
+ dhcp_set_state ( dhcp, DHCP_STATE_BSREQUEST );
|
|
713
|
+ break;
|
|
714
|
+ }
|
|
715
|
+ }
|
|
716
|
+ /* Fall through */
|
|
717
|
+ case DHCP_STATE_BSREQUEST:
|
665
|
718
|
dhcp_finished ( dhcp, 0 );
|
666
|
719
|
break;
|
667
|
720
|
default:
|
|
@@ -845,9 +898,13 @@ static void dhcp_rx_dhcpack ( struct dhcp_session *dhcp,
|
845
|
898
|
return;
|
846
|
899
|
}
|
847
|
900
|
|
|
901
|
+ /* Record DHCPACK */
|
|
902
|
+ assert ( dhcp->dhcpack == NULL );
|
|
903
|
+ dhcp->dhcpack = dhcpset_get ( dhcpack );
|
|
904
|
+
|
848
|
905
|
/* Register settings */
|
849
|
906
|
parent = netdev_settings ( dhcp->netdev );
|
850
|
|
- if ( ( rc = dhcp_store_dhcpack ( dhcp, dhcpack, parent ) ) !=0 )
|
|
907
|
+ if ( ( rc = dhcp_store_dhcpack ( dhcp, dhcpack, parent ) ) != 0 )
|
851
|
908
|
return;
|
852
|
909
|
|
853
|
910
|
/* Transition to next state */
|
|
@@ -885,6 +942,10 @@ static void dhcp_rx_proxydhcpack ( struct dhcp_session *dhcp,
|
885
|
942
|
/* Rename settings */
|
886
|
943
|
proxydhcpack->settings.name = PROXYDHCP_SETTINGS_NAME;
|
887
|
944
|
|
|
945
|
+ /* Record ProxyDHCPACK */
|
|
946
|
+ assert ( dhcp->proxydhcpack == NULL );
|
|
947
|
+ dhcp->proxydhcpack = dhcpset_get ( proxydhcpack );
|
|
948
|
+
|
888
|
949
|
/* Register settings */
|
889
|
950
|
if ( ( rc = dhcp_store_dhcpack ( dhcp, proxydhcpack, NULL ) ) != 0 )
|
890
|
951
|
return;
|
|
@@ -893,6 +954,31 @@ static void dhcp_rx_proxydhcpack ( struct dhcp_session *dhcp,
|
893
|
954
|
dhcp_next_state ( dhcp );
|
894
|
955
|
}
|
895
|
956
|
|
|
957
|
+/**
|
|
958
|
+ * Handle received BootServerDHCPACK
|
|
959
|
+ *
|
|
960
|
+ * @v dhcp DHCP session
|
|
961
|
+ * @v bsdhcpack Received BootServerDHCPACK
|
|
962
|
+ */
|
|
963
|
+static void dhcp_rx_bsdhcpack ( struct dhcp_session *dhcp,
|
|
964
|
+ struct dhcp_settings *bsdhcpack ) {
|
|
965
|
+ int rc;
|
|
966
|
+
|
|
967
|
+ /* Rename settings */
|
|
968
|
+ bsdhcpack->settings.name = BSDHCP_SETTINGS_NAME;
|
|
969
|
+
|
|
970
|
+ /* Record ProxyDHCPACK */
|
|
971
|
+ assert ( dhcp->bsdhcpack == NULL );
|
|
972
|
+ dhcp->bsdhcpack = dhcpset_get ( bsdhcpack );
|
|
973
|
+
|
|
974
|
+ /* Register settings */
|
|
975
|
+ if ( ( rc = dhcp_store_dhcpack ( dhcp, bsdhcpack, NULL ) ) != 0 )
|
|
976
|
+ return;
|
|
977
|
+
|
|
978
|
+ /* Transition to next state */
|
|
979
|
+ dhcp_next_state ( dhcp );
|
|
980
|
+}
|
|
981
|
+
|
896
|
982
|
/**
|
897
|
983
|
* Receive new data
|
898
|
984
|
*
|
|
@@ -969,6 +1055,11 @@ static int dhcp_deliver_iob ( struct xfer_interface *xfer,
|
969
|
1055
|
( src_port == htons ( PROXYDHCP_PORT ) ) )
|
970
|
1056
|
dhcp_rx_proxydhcpack ( dhcp, dhcpset );
|
971
|
1057
|
break;
|
|
1058
|
+ case DHCP_STATE_BSREQUEST:
|
|
1059
|
+ if ( ( msgtype == DHCPACK ) &&
|
|
1060
|
+ ( src_port == htons ( PROXYDHCP_PORT ) ) )
|
|
1061
|
+ dhcp_rx_bsdhcpack ( dhcp, dhcpset );
|
|
1062
|
+ break;
|
972
|
1063
|
default:
|
973
|
1064
|
assert ( 0 );
|
974
|
1065
|
break;
|