From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from list by lists.gnu.org with archive (Exim 4.71) id 1gtc9z-0002vz-GX for mharc-grub-devel@gnu.org; Tue, 12 Feb 2019 12:47:55 -0500 Received: from eggs.gnu.org ([209.51.188.92]:53962) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gtc9x-0002tS-1a for grub-devel@gnu.org; Tue, 12 Feb 2019 12:47:54 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1gtc9q-0003Hx-Pf for grub-devel@gnu.org; Tue, 12 Feb 2019 12:47:50 -0500 Received: from usa-sjc-mx-foss1.foss.arm.com ([217.140.101.70]:37686 helo=foss.arm.com) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gtc9h-0002uK-DG for grub-devel@gnu.org; Tue, 12 Feb 2019 12:47:38 -0500 Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.72.51.249]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 2F94B15BF; Tue, 12 Feb 2019 09:47:19 -0800 (PST) Received: from donnerap.arm.com (donnerap.cambridge.arm.com [10.1.197.44]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id CD7F23F675; Tue, 12 Feb 2019 09:47:17 -0800 (PST) From: Andre Przywara To: Daniel Kiper Cc: Vladimir Serbinenko , Andrei Borzenkov , Daniel Kiper , Mark Rutland , grub-devel@gnu.org Subject: [PATCH v2 7/9] net: dhcp: allow receiving DHCP OFFER and ACK packets Date: Tue, 12 Feb 2019 17:46:58 +0000 Message-Id: <20190212174700.184741-8-andre.przywara@arm.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20190212174700.184741-1-andre.przywara@arm.com> References: <20190212174700.184741-1-andre.przywara@arm.com> X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 217.140.101.70 X-BeenThere: grub-devel@gnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: The development of GNU GRUB List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 12 Feb 2019 17:47:54 -0000 From: Andrei Borzenkov In respone to a BOOTREQUEST packet a BOOTP server would answer with a BOOTREPLY packet, which ends the conversation for good. DHCP uses a 4-way handshake, where the initial server respone is an OFFER, which has to be answered with REQUEST by the client again, only to be completed by an ACKNOWLEDGE packet from the server. Teach the grub_net_process_dhcp() function to deal with OFFER packets, and treat ACK packets the same es BOOTREPLY packets. Signed-off-by: Andre Przywara --- grub-core/net/bootp.c | 76 +++++++++++++++++++++++++++++++++++-------- include/grub/net.h | 5 +++ 2 files changed, 67 insertions(+), 14 deletions(-) diff --git a/grub-core/net/bootp.c b/grub-core/net/bootp.c index 0c6756ea0..f02e73003 100644 --- a/grub-core/net/bootp.c +++ b/grub-core/net/bootp.c @@ -30,6 +30,21 @@ enum GRUB_DHCP_OPT_OVERLOAD_FILE = 1, GRUB_DHCP_OPT_OVERLOAD_SNAME = 2, }; +enum +{ + GRUB_DHCP_MESSAGE_UNKNOWN, + GRUB_DHCP_MESSAGE_DISCOVER, + GRUB_DHCP_MESSAGE_OFFER, + GRUB_DHCP_MESSAGE_REQUEST, + GRUB_DHCP_MESSAGE_DECLINE, + GRUB_DHCP_MESSAGE_ACK, + GRUB_DHCP_MESSAGE_NAK, + GRUB_DHCP_MESSAGE_RELEASE, + GRUB_DHCP_MESSAGE_INFORM, +}; + +/* Max timeout when waiting for BOOTP/DHCP reply */ +#define GRUB_DHCP_MAX_PACKET_TIMEOUT 32 #define GRUB_BOOTP_MAX_OPTIONS_SIZE 64 @@ -444,25 +459,58 @@ grub_net_process_dhcp (struct grub_net_buff *nb, struct grub_net_card *card = iface->card; const struct grub_net_bootp_packet *bp = (const struct grub_net_bootp_packet *) nb->data; grub_size_t size = nb->tail - nb->data; + const grub_uint8_t *opt; + grub_uint8_t opt_len, type; + grub_uint32_t srv_id = 0; - name = grub_xasprintf ("%s:dhcp", card->name); - if (!name) - { - grub_print_error (); - return; - } - grub_net_configure_by_dhcp_ack (name, card, 0, bp, size, 0, 0, 0); - grub_free (name); - if (grub_errno) - grub_print_error (); + opt = find_dhcp_option (bp, size, GRUB_NET_DHCP_MESSAGE_TYPE, &opt_len); + if (opt && opt_len == 1) + type = *opt; else + type = GRUB_DHCP_MESSAGE_UNKNOWN; + + opt = find_dhcp_option (bp, size, GRUB_NET_DHCP_SERVER_IDENTIFIER, &opt_len); + if (opt && opt_len == sizeof (srv_id)) + srv_id = grub_get_unaligned32 (opt); + + /* + * If we received BOOTP reply or DHCPACK, proceed with configuration. + * Otherwise store offered address and server id for later processing + * of DHCPACK. + * xid and srv_id are stored in network order so do not need conversion. + */ + if ((!iface->srv_id && type == GRUB_DHCP_MESSAGE_UNKNOWN) + || (iface->srv_id && type == GRUB_DHCP_MESSAGE_ACK + && bp->ident == iface->xid + && srv_id == iface->srv_id)) { - if (grub_memcmp (iface->name, card->name, grub_strlen (card->name)) == 0 - && grub_memcmp (iface->name + grub_strlen (card->name), - ":dhcp_tmp", sizeof (":dhcp_tmp") - 1) == 0) + name = grub_xasprintf ("%s:dhcp", card->name); + if (!name) { - grub_net_network_level_interface_unregister (iface); + grub_print_error (); + return; } + grub_net_configure_by_dhcp_ack (name, card, 0, bp, size, 0, 0, 0); + grub_free (name); + if (grub_errno) + grub_print_error (); + else + grub_net_network_level_interface_unregister (iface); + } + else if (!iface->srv_id && type == GRUB_DHCP_MESSAGE_OFFER && srv_id) + { + iface->srv_id = srv_id; + iface->my_ip = bp->your_ip; + /* Reset retransmission timer */ + iface->dhcp_tmo = iface->dhcp_tmo_left = 1; + } + else if (iface->srv_id && type == GRUB_DHCP_MESSAGE_NAK + && bp->ident == iface->xid + && srv_id == iface->srv_id) + { + iface->xid = iface->srv_id = iface->my_ip = 0; + /* Reset retransmission timer */ + iface->dhcp_tmo = iface->dhcp_tmo_left = 1; } } diff --git a/include/grub/net.h b/include/grub/net.h index f7b546446..68a9f1311 100644 --- a/include/grub/net.h +++ b/include/grub/net.h @@ -292,6 +292,9 @@ struct grub_net_network_level_interface struct grub_net_bootp_packet *dhcp_ack; grub_size_t dhcp_acklen; grub_uint16_t vlantag; + grub_uint32_t xid; /* DHCPv4 transaction id */ + grub_uint32_t srv_id; /* DHCPv4 server_identifier */ + grub_uint32_t my_ip; /* DHCPv4 offered IP address */ unsigned dhcp_tmo_left; /* DHCPv4 running retransmission timeout */ unsigned dhcp_tmo; /* DHCPv4 current retransmission timeout */ void *data; @@ -460,6 +463,8 @@ enum GRUB_NET_BOOTP_ROOT_PATH = 0x11, GRUB_NET_BOOTP_EXTENSIONS_PATH = 0x12, GRUB_NET_DHCP_OVERLOAD = 52, + GRUB_NET_DHCP_MESSAGE_TYPE = 53, + GRUB_NET_DHCP_SERVER_IDENTIFIER = 54, GRUB_NET_DHCP_TFTP_SERVER_NAME = 66, GRUB_NET_DHCP_BOOTFILE_NAME = 67, GRUB_NET_BOOTP_END = 0xff -- 2.17.1