]> git.ipfire.org Git - thirdparty/ipxe.git/commitdiff
[dhcp] Allow pseudo-DHCP servers to use pseudo-identifiers
authorMichael Brown <mcb30@ipxe.org>
Tue, 18 Aug 2015 14:43:06 +0000 (15:43 +0100)
committerMichael Brown <mcb30@ipxe.org>
Tue, 18 Aug 2015 14:43:06 +0000 (15:43 +0100)
Some ProxyDHCP servers and PXE boot servers do not specify a DHCP
server identifier via option 54.  We currently work around this in a
variety of ad-hoc ways:

 - if a ProxyDHCPACK has no server identifier then we treat it as
   having the correct server identifier,

 - if a boot server ACK has no server identifier then we use the
   packet's source IP address as the server identifier.

Introduce the concept of a DHCP server pseudo-identifier, defined as
being:

 - the server identifier (option 54), or

 - if there is no server identifier, then the next-server address
   (siaddr),

 - if there is no server identifier or next-server address, then the
   DHCP packet's source IP address.

Use the pseudo-identifier in place of the server identifier when
handling ProxyDHCP and PXE boot server responses.

Originally-fixed-by: Wissam Shoukair <wissams@mellanox.com>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
src/net/udp/dhcp.c

index 61bef998575f526461f01f8f13bc5b929048e214..7d5237bc04391db1a8339d96525d17b9e80b58ba 100644 (file)
@@ -154,22 +154,23 @@ struct dhcp_session_state {
         * @v dhcppkt           DHCP packet
         * @v peer              Destination address
         */
-       int ( * tx ) ( struct dhcp_session *dhcp,
-                      struct dhcp_packet *dhcppkt,
+       int ( * tx ) ( struct dhcp_session *dhcp, struct dhcp_packet *dhcppkt,
                       struct sockaddr_in *peer );
-       /** Handle received packet
+       /**
+        * Handle received packet
         *
         * @v dhcp              DHCP session
         * @v dhcppkt           DHCP packet
         * @v peer              DHCP server address
         * @v msgtype           DHCP message type
         * @v server_id         DHCP server ID
+        * @v pseudo_id         DHCP server pseudo-ID
         */
-       void ( * rx ) ( struct dhcp_session *dhcp,
-                       struct dhcp_packet *dhcppkt,
-                       struct sockaddr_in *peer,
-                       uint8_t msgtype, struct in_addr server_id );
-       /** Handle timer expiry
+       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 timer expiry
         *
         * @v dhcp              DHCP session
         */
@@ -340,11 +341,13 @@ static int dhcp_discovery_tx ( struct dhcp_session *dhcp,
  * @v peer             DHCP server address
  * @v msgtype          DHCP message type
  * @v server_id                DHCP server ID
+ * @v pseudo_id                DHCP server pseudo-ID
  */
 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 server_id,
+                               struct in_addr pseudo_id ) {
        struct in_addr ip;
        char vci[9]; /* "PXEClient" */
        int vci_len;
@@ -356,8 +359,11 @@ static void dhcp_discovery_rx ( struct dhcp_session *dhcp,
        DBGC ( dhcp, "DHCP %p %s from %s:%d", dhcp,
               dhcp_msgtype_name ( msgtype ), inet_ntoa ( peer->sin_addr ),
               ntohs ( peer->sin_port ) );
-       if ( server_id.s_addr != peer->sin_addr.s_addr )
-               DBGC ( dhcp, " (%s)", inet_ntoa ( server_id ) );
+       if ( ( server_id.s_addr != peer->sin_addr.s_addr ) ||
+            ( pseudo_id.s_addr != peer->sin_addr.s_addr ) ) {
+               DBGC ( dhcp, " (%s/", inet_ntoa ( server_id ) );
+               DBGC ( dhcp, "%s)", inet_ntoa ( pseudo_id ) );
+       }
 
        /* Identify offered IP address */
        ip = dhcppkt->dhcphdr->yiaddr;
@@ -398,10 +404,10 @@ static void dhcp_discovery_rx ( struct dhcp_session *dhcp,
        }
 
        /* Select as ProxyDHCP offer, if applicable */
-       if ( server_id.s_addr && has_pxeclient &&
+       if ( pseudo_id.s_addr && has_pxeclient &&
             ( priority >= dhcp->proxy_priority ) ) {
                dhcppkt_put ( dhcp->proxy_offer );
-               dhcp->proxy_server = server_id;
+               dhcp->proxy_server = pseudo_id;
                dhcp->proxy_offer = dhcppkt_get ( dhcppkt );
                dhcp->proxy_priority = priority;
        }
@@ -510,11 +516,13 @@ static int dhcp_request_tx ( struct dhcp_session *dhcp,
  * @v peer             DHCP server address
  * @v msgtype          DHCP message type
  * @v server_id                DHCP server ID
+ * @v pseudo_id                DHCP server pseudo-ID
  */
 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 server_id,
+                             struct in_addr pseudo_id ) {
        struct in_addr ip;
        struct settings *parent;
        struct settings *settings;
@@ -523,8 +531,11 @@ static void dhcp_request_rx ( struct dhcp_session *dhcp,
        DBGC ( dhcp, "DHCP %p %s from %s:%d", dhcp,
               dhcp_msgtype_name ( msgtype ), inet_ntoa ( peer->sin_addr ),
               ntohs ( peer->sin_port ) );
-       if ( server_id.s_addr != peer->sin_addr.s_addr )
-               DBGC ( dhcp, " (%s)", inet_ntoa ( server_id ) );
+       if ( ( server_id.s_addr != peer->sin_addr.s_addr ) ||
+            ( pseudo_id.s_addr != peer->sin_addr.s_addr ) ) {
+               DBGC ( dhcp, " (%s/", inet_ntoa ( server_id ) );
+               DBGC ( dhcp, "%s)", inet_ntoa ( pseudo_id ) );
+       }
 
        /* Identify leased IP address */
        ip = dhcppkt->dhcphdr->yiaddr;
@@ -641,19 +652,24 @@ static int dhcp_proxy_tx ( struct dhcp_session *dhcp,
  * @v peer             DHCP server address
  * @v msgtype          DHCP message type
  * @v server_id                DHCP server ID
+ * @v pseudo_id                DHCP server pseudo-ID
  */
 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 server_id,
+                           struct in_addr pseudo_id ) {
        struct settings *settings = &dhcppkt->settings;
        int rc;
 
        DBGC ( dhcp, "DHCP %p %s from %s:%d", dhcp,
               dhcp_msgtype_name ( msgtype ), inet_ntoa ( peer->sin_addr ),
               ntohs ( peer->sin_port ) );
-       if ( server_id.s_addr != peer->sin_addr.s_addr )
-               DBGC ( dhcp, " (%s)", inet_ntoa ( server_id ) );
+       if ( ( server_id.s_addr != peer->sin_addr.s_addr ) ||
+            ( pseudo_id.s_addr != peer->sin_addr.s_addr ) ) {
+               DBGC ( dhcp, " (%s/", inet_ntoa ( server_id ) );
+               DBGC ( dhcp, "%s)", inet_ntoa ( pseudo_id ) );
+       }
        DBGC ( dhcp, "\n" );
 
        /* Filter out unacceptable responses */
@@ -661,8 +677,7 @@ static void dhcp_proxy_rx ( struct dhcp_session *dhcp,
                return;
        if ( ( msgtype != DHCPOFFER ) && ( msgtype != DHCPACK ) )
                return;
-       if ( server_id.s_addr /* Linux PXE server omits server ID */ &&
-            ( server_id.s_addr != dhcp->proxy_server.s_addr ) )
+       if ( ( pseudo_id.s_addr != dhcp->proxy_server.s_addr ) )
                return;
 
        /* Register settings */
@@ -772,19 +787,24 @@ static int dhcp_pxebs_accept ( struct dhcp_session *dhcp,
  * @v peer             DHCP server address
  * @v msgtype          DHCP message type
  * @v server_id                DHCP server ID
+ * @v pseudo_id                DHCP server pseudo-ID
  */
 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 server_id,
+                           struct in_addr pseudo_id ) {
        struct dhcp_pxe_boot_menu_item menu_item = { 0, 0 };
        int rc;
 
        DBGC ( dhcp, "DHCP %p %s from %s:%d", dhcp,
               dhcp_msgtype_name ( msgtype ), inet_ntoa ( peer->sin_addr ),
               ntohs ( peer->sin_port ) );
-       if ( server_id.s_addr != peer->sin_addr.s_addr )
-               DBGC ( dhcp, " (%s)", inet_ntoa ( server_id ) );
+       if ( ( server_id.s_addr != peer->sin_addr.s_addr ) ||
+            ( pseudo_id.s_addr != peer->sin_addr.s_addr ) ) {
+               DBGC ( dhcp, " (%s/", inet_ntoa ( server_id ) );
+               DBGC ( dhcp, "%s)", inet_ntoa ( pseudo_id ) );
+       }
 
        /* Identify boot menu item */
        dhcppkt_fetch ( dhcppkt, DHCP_PXE_BOOT_MENU_ITEM,
@@ -801,8 +821,7 @@ static void dhcp_pxebs_rx ( struct dhcp_session *dhcp,
                return;
        if ( menu_item.type != dhcp->pxe_type )
                return;
-       if ( ! dhcp_pxebs_accept ( dhcp, ( server_id.s_addr ?
-                                          server_id : peer->sin_addr ) ) )
+       if ( ! dhcp_pxebs_accept ( dhcp, pseudo_id ) )
                return;
 
        /* Register settings */
@@ -1134,6 +1153,7 @@ static int dhcp_deliver ( struct dhcp_session *dhcp,
        struct dhcphdr *dhcphdr;
        uint8_t msgtype = 0;
        struct in_addr server_id = { 0 };
+       struct in_addr pseudo_id;
        int rc = 0;
 
        /* Sanity checks */
@@ -1168,6 +1188,13 @@ static int dhcp_deliver ( struct dhcp_session *dhcp,
        dhcppkt_fetch ( dhcppkt, DHCP_SERVER_IDENTIFIER,
                        &server_id, sizeof ( server_id ) );
 
+       /* Identify server pseudo-ID */
+       pseudo_id = server_id;
+       if ( ! pseudo_id.s_addr )
+               pseudo_id = dhcppkt->dhcphdr->siaddr;
+       if ( ! pseudo_id.s_addr )
+               pseudo_id = peer->sin_addr;
+
        /* Check for matching transaction ID */
        if ( dhcphdr->xid != dhcp->xid ) {
                DBGC ( dhcp, "DHCP %p %s from %s:%d has bad transaction "
@@ -1190,7 +1217,7 @@ static int dhcp_deliver ( struct dhcp_session *dhcp,
        }
 
        /* Handle packet based on current state */
-       dhcp->state->rx ( dhcp, dhcppkt, peer, msgtype, server_id );
+       dhcp->state->rx ( dhcp, dhcppkt, peer, msgtype, server_id, pseudo_id );
 
  err_chaddr:
  err_xid: