Hi, On Fri, 7 Apr 2023 at 18:56, <seanedm...@linux.microsoft.com> wrote: > > From: Sean Edmond <seanedm...@microsoft.com> > > Adds DHCPv6 protocol to u-boot. > > Allows for address assignement with DHCPv6 4-message exchange > (SOLICIT->ADVERTISE->REQUEST->REPLY). Includes DHCPv6 options > required by RFC 8415. Also adds DHCPv6 options required > for PXE boot. > > Possible enhancements: > - Duplicate address detection on DHCPv6 assigned address > - IPv6 address assignement through SLAAC > - Sending/parsing other DHCPv6 options (NTP, DNS, etc...) > > Signed-off-by: Sean Edmond <seanedm...@microsoft.com> > --- > include/net.h | 8 +- > net/Makefile | 1 + > net/dhcpv6.c | 735 ++++++++++++++++++++++++++++++++++++++++++++++++++ > net/dhcpv6.h | 212 +++++++++++++++ > net/net.c | 12 + > 5 files changed, 966 insertions(+), 2 deletions(-) > create mode 100644 net/dhcpv6.c > create mode 100644 net/dhcpv6.h
This looks good to me. I just have a few nits below. With those fixed: Reviewed-by: Simon Glass <s...@chromium.org> > > diff --git a/include/net.h b/include/net.h > index 399af5e064..cac818e292 100644 > --- a/include/net.h > +++ b/include/net.h > @@ -484,6 +484,10 @@ extern char net_hostname[32]; /* Our > hostname */ > #ifdef CONFIG_NET > extern char net_root_path[CONFIG_BOOTP_MAX_ROOT_PATH_LEN]; /* Our root > path */ > #endif > +#if defined(CONFIG_DHCP6_PXE_DHCP_OPTION) You can drop this #ifdef as any reference to a non-existent var will give a build error. > +/* Indicates whether the pxe path prefix / config file was specified in dhcp > option */ > +extern char *pxelinux_configfile; > +#endif > /** END OF BOOTP EXTENTIONS **/ > extern u8 net_ethaddr[ARP_HLEN]; /* Our ethernet > address */ > extern u8 net_server_ethaddr[ARP_HLEN]; /* Boot server enet > address */ > @@ -504,8 +508,8 @@ extern ushort net_native_vlan; /* > Our Native VLAN */ > extern int net_restart_wrap; /* Tried all network devices > */ > > enum proto_t { > - BOOTP, RARP, ARP, TFTPGET, DHCP, PING, PING6, DNS, NFS, CDP, NETCONS, > - SNTP, TFTPSRV, TFTPPUT, LINKLOCAL, FASTBOOT, WOL, UDP, NCSI, WGET > + BOOTP, RARP, ARP, TFTPGET, DHCP, DHCP6, PING, PING6, DNS, NFS, CDP, > + NETCONS, SNTP, TFTPSRV, TFTPPUT, LINKLOCAL, FASTBOOT, WOL, UDP, NCSI, > WGET > }; > > extern char net_boot_file_name[1024];/* Boot File name */ > diff --git a/net/Makefile b/net/Makefile > index bea000b206..5968110170 100644 > --- a/net/Makefile > +++ b/net/Makefile > @@ -22,6 +22,7 @@ obj-$(CONFIG_IPV6) += net6.o > obj-$(CONFIG_CMD_NFS) += nfs.o > obj-$(CONFIG_CMD_PING) += ping.o > obj-$(CONFIG_CMD_PING6) += ping6.o > +obj-$(CONFIG_CMD_DHCP6) += dhcpv6.o > obj-$(CONFIG_CMD_PCAP) += pcap.o > obj-$(CONFIG_CMD_RARP) += rarp.o > obj-$(CONFIG_CMD_SNTP) += sntp.o > diff --git a/net/dhcpv6.c b/net/dhcpv6.c > new file mode 100644 > index 0000000000..9204909c1f > --- /dev/null > +++ b/net/dhcpv6.c > @@ -0,0 +1,735 @@ > +// SPDX-License-Identifier: GPL-2.0+ > +/* > + * Copyright (C) Microsoft Corporation > + * Author: Sean Edmond <seanedm...@microsoft.com> > + * > + */ > + > +/* Simple DHCP6 network layer implementation. */ > + > +#include <common.h> > +#include <bootstage.h> > +#include <command.h> > +#include <env.h> > +#include <efi_loader.h> > +#include <log.h> > +#include <net.h> > +#include <rand.h> > +#include <uuid.h> > +#include <linux/delay.h> > +#include <net/tftp.h> > +#include "dhcpv6.h" > +#include <net6.h> > +#include <malloc.h> > +#include "net_rand.h" Please fix header order: https://u-boot.readthedocs.io/en/latest/develop/codingstyle.html#include-files > + > +#define PORT_DHCP6_S 547 /* DHCP6 server UDP port */ > +#define PORT_DHCP6_C 546 /* DHCP6 client UDP port */ > + > +/* default timeout parameters (in ms) */ > +#define SOL_MAX_DELAY_MS 1000 > +#define SOL_TIMEOUT_MS 1000 > +#define SOL_MAX_RT_MS 3600000 > +#define REQ_TIMEOUT_MS 1000 > +#define REQ_MAX_RT_MS 30000 > +#define REQ_MAX_RC 10 > +#define MAX_WAIT_TIME_MS 60000 > + > +/* global variable to track any updates from DHCP6 server */ > +int updated_sol_max_rt_ms = SOL_MAX_RT_MS; > + > +static void dhcp6_timeout_handler(void); > +static void dhcp6_state_machine(bool timeout, uchar *rx_pkt, unsigned int > len); > +static void dhcp6_parse_options(uchar *rx_pkt, unsigned int len); Rather than forward decls can you reorder the functions? > + > +struct dhcp6_sm_params sm_params; > + > +/* > + * Handle DHCP received packets (set as UDP handler) > + */ Please check single-line comment style > +static void dhcp6_handler(uchar *pkt, unsigned int dest, struct in_addr sip, > + unsigned int src, unsigned int len) > +{ > + /* return if ports don't match DHCPv6 ports */ > + if (dest != PORT_DHCP6_C || src != PORT_DHCP6_S) > + return; > + > + dhcp6_state_machine(false, pkt, len); > +} > + [..] > + case DHCP6_OPTION_OPT_BOOTFILE_URL: > + debug("DHCP6_OPTION_OPT_BOOTFILE_URL FOUND\n"); > + copy_filename(net_boot_file_name, option_ptr, > option_len + 1); > + debug("net_boot_file_name: %s\n", net_boot_file_name); > + > + /* copy server_ip6 (required for PXE) */ > + s = strchr(net_boot_file_name, '['); > + e = strchr(net_boot_file_name, ']'); > + if (s && e && e > s) > + string_to_ip6(s + 1, e - s - 1, > &net_server_ip6); > + break; > +#if IS_ENABLED(CONFIG_DHCP6_PXE_DHCP_OPTION) > + case DHCP6_OPTION_OPT_BOOTFILE_PARAM: Can you do something like this to avoid the #ifdef ? case DHCP6_OPTION_OPT_BOOTFILE_PARAM: if (IS_ENABLED(CONFIG_DHCP6_PXE_DHCP_OPTION) { ... } You could even add a 'fallthough' if you move it to last position in the switch(). > + debug("DHCP6_OPTION_OPT_BOOTFILE_PARAM FOUND\n"); > + > + if (pxelinux_configfile) > + free(pxelinux_configfile); > + > + pxelinux_configfile = (char *)malloc((option_len + 1) > * sizeof(char)); > + if (pxelinux_configfile) { > + memcpy(pxelinux_configfile, option_ptr, > option_len); > + pxelinux_configfile[option_len] = '\0'; Does strlcpy() with option_len + 1 work here? > + } If malloc() fails it needs to be reported. > + > + debug("PXE CONFIG FILE %s\n", pxelinux_configfile); > + break; > +#endif > + case DHCP6_OPTION_PREFERENCE: > + debug("DHCP6_OPTION_PREFERENCE FOUND\n"); > + sm_params.rx_status.preference = *option_ptr; > + break; > + default: > + debug("Unknown Option ID: %d, skipping parsing\n", > + ntohs(option_hdr->option_id)); > + break; > + } > + /* Increment to next option header */ > + option_hdr = (struct dhcp6_option_hdr *)(((uchar > *)option_hdr) + > + sizeof(struct dhcp6_option_hdr) + option_len); > + } > +} > + [..] > +/* > + * Timeout for DHCP6 SOLICIT/REQUEST. Fix single-line comment format (globally) > + */ > +static void dhcp6_timeout_handler(void) > +{ > + /* call state machine with the timeout flag */ > + dhcp6_state_machine(true, NULL, 0); > +} > + > +/* > + * Start or restart DHCP6 > + */ > +void dhcp6_start(void) > +{ > + memset(&sm_params, 0, sizeof(struct dhcp6_sm_params)); > + > + /* seed the RNG with MAC address */ > + srand_mac(); > + > + sm_params.curr_state = DHCP6_INIT; > + dhcp6_state_machine(false, NULL, 0); > +} > diff --git a/net/dhcpv6.h b/net/dhcpv6.h > new file mode 100644 > index 0000000000..6a0158127a > --- /dev/null > +++ b/net/dhcpv6.h > @@ -0,0 +1,212 @@ > +/* SPDX-License-Identifier: GPL-2.0+ */ > +/* > + * Copyright (C) Microsoft Corporation > + * Author: Sean Edmond <seanedm...@microsoft.com> > + * > + */ > + > +#ifndef __DHCP6_H__ > +#define __DHCP6_H__ > + > +#include <net6.h> Is this needed? If so it might be better to split out the bits you need into a net6_defs.h or something like that. > +#include <net.h> Please don't include net.h as it brings in heaps of stuff. > + > +/* Message types */ > +#define DHCP6_MSG_SOLICIT 1 > +#define DHCP6_MSG_ADVERTISE 2 > +#define DHCP6_MSG_REQUEST 3 > +#define DHCP6_MSG_REPLY 7 [..] > + > +/* Send a DHCPv6 request */ Can you add a bit more detail here, e.g. mention the state machine and what happens next? > +void dhcp6_start(void); > + > +#endif /* __DHCP6_H__ */ > diff --git a/net/net.c b/net/net.c > index c9a749f6cc..73d5b2bc80 100644 > --- a/net/net.c > +++ b/net/net.c > @@ -122,6 +122,9 @@ > #endif > #include <net/tcp.h> > #include <net/wget.h> > +#if defined(CONFIG_CMD_DHCP6) > +#include "dhcpv6.h" No need to exclude the header so you can drop the #ifdef > +#endif > > /** BOOTP EXTENTIONS **/ > > @@ -135,6 +138,10 @@ struct in_addr net_dns_server; > /* Our 2nd DNS IP address */ > struct in_addr net_dns_server2; > #endif > +#if defined(CONFIG_DHCP6_PXE_DHCP_OPTION) > +/* Indicates whether the pxe path prefix / config file was specified in dhcp > option */ > +char *pxelinux_configfile; > +#endif > > /** END OF BOOTP EXTENTIONS **/ > > @@ -510,6 +517,11 @@ restart: > dhcp_request(); /* Basically same as BOOTP */ > break; > #endif > +#if defined(CONFIG_CMD_DHCP6) > + case DHCP6: Can we use the if (IS_ENABLED()) thing again here to drop this #ifdef? > + dhcp6_start(); > + break; > +#endif > #if defined(CONFIG_CMD_BOOTP) > case BOOTP: > bootp_reset(); > -- > 2.40.0 > Regards, Simon