[PATCH] Fix neighbor discovery ethernet address saving

2024-04-29 Thread seanedmond
From: Sean Edmond 

When a successful neighbor advertisement is received, the ethernet
address should be saved for later use to avoid having to redo the
neighbor discovery process.

For example, with TFTP the address should get saved into
"net_server_ethaddr".  This is being done correctly with ARP for IPv4,
but not for neighbor discovery with IPv6.

Signed-off-by: Sean Edmond 
---
 net/ndisc.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/net/ndisc.c b/net/ndisc.c
index d1cec0601c8..505515f2d95 100644
--- a/net/ndisc.c
+++ b/net/ndisc.c
@@ -461,8 +461,8 @@ int ndisc_receive(struct ethernet_hdr *et, struct ip6_hdr 
*ip6, int len)
ndisc_extract_enetaddr(ndisc, neigh_eth_addr);
 
/* save address for later use */
-   if (!net_nd_packet_mac)
-   net_nd_packet_mac = neigh_eth_addr;
+   if (net_nd_packet_mac)
+   memcpy(net_nd_packet_mac, neigh_eth_addr, 6);
 
/* modify header, and transmit it */
memcpy(((struct ethernet_hdr 
*)net_nd_tx_packet)->et_dest,
-- 
2.42.0



[PATCH v5 3/3] net: bootp: add config option BOOTP_RANDOM_XID

2023-11-17 Thread seanedmond
From: Sean Edmond 

The new config option BOOTP_RANDOM_XID will randomize the transaction ID
for each new BOOT/DHCPv4 exchange.

Signed-off-by: Sean Edmond 
---

changes in v5:
- fix depends for BOOTP_RANDOM_XID:
  "depends on CMD_BOOTP && (LIB_RAND || LIB_HW_RAND)"

changes in v3:
- Add depends for BOOTP_RANDOM_XID

 cmd/Kconfig |  7 +++
 net/bootp.c | 31 +--
 2 files changed, 24 insertions(+), 14 deletions(-)

diff --git a/cmd/Kconfig b/cmd/Kconfig
index 93bf752035c..baab359c55b 100644
--- a/cmd/Kconfig
+++ b/cmd/Kconfig
@@ -1853,6 +1853,13 @@ config BOOTP_VCI_STRING
default "U-Boot.arm" if ARM
default "U-Boot"
 
+config BOOTP_RANDOM_XID
+   bool "Send random transaction ID to BOOTP/DHCP server"
+   depends on CMD_BOOTP && (LIB_RAND || LIB_HW_RAND)
+   help
+ Selecting this will allow for a random transaction ID to get
+ selected for each BOOTP/DHCPv4 exchange.
+
 if CMD_DHCP6
 
 config DHCP6_PXE_CLIENTARCH
diff --git a/net/bootp.c b/net/bootp.c
index 89425717328..49cd9064436 100644
--- a/net/bootp.c
+++ b/net/bootp.c
@@ -837,22 +837,25 @@ void bootp_request(void)
 
/* Only generate a new transaction ID for each new BOOTP request */
if (bootp_try == 1) {
-   /*
-*  Bootp ID is the lower 4 bytes of our ethernet address
-*  plus the current time in ms.
-*/
-   bootp_id = ((u32)net_ethaddr[2] << 24)
-   | ((u32)net_ethaddr[3] << 16)
-   | ((u32)net_ethaddr[4] << 8)
-   | (u32)net_ethaddr[5];
-   bootp_id += get_timer(0);
-   bootp_id = htonl(bootp_id);
-   bootp_add_id(bootp_id);
-   net_copy_u32(>bp_id, _id);
-   } else {
-   net_copy_u32(>bp_id, _id);
+   if (IS_ENABLED(CONFIG_BOOTP_RANDOM_XID)) {
+   srand(get_ticks() + rand());
+   bootp_id = rand();
+   } else {
+   /*
+*  Bootp ID is the lower 4 bytes of our ethernet 
address
+*  plus the current time in ms.
+*/
+   bootp_id = ((u32)net_ethaddr[2] << 24)
+   | ((u32)net_ethaddr[3] << 16)
+   | ((u32)net_ethaddr[4] << 8)
+   | (u32)net_ethaddr[5];
+   bootp_id += get_timer(0);
+   bootp_id = htonl(bootp_id);
+   }
}
 
+   bootp_add_id(bootp_id);
+   net_copy_u32(>bp_id, _id);
/*
 * Calculate proper packet lengths taking into account the
 * variable size of the options field
-- 
2.42.0



[PATCH v5 1/3] net: Additional fixes for dhcp option 209

2023-11-17 Thread seanedmond
From: Sean Edmond 

Addresses feedback from latest review:
- Enable option 209 by default
- Set pxelinux_configfile to NULL to avoid potential double free
- change hardcoced 209 to a define

Signed-off-by: Sean Edmond 
---

changes in v4:
- rebase master and resolve conflicts
- change commit description for this patch (this is now
  an enhancement patch)
- default y for BOOTP_PXE_DHCP_OPTION (feedback from review)

changes in v3:
- add define for option 209 and rfc5071 reference

 cmd/Kconfig | 1 +
 cmd/pxe.c   | 2 ++
 net/bootp.c | 4 ++--
 net/bootp.h | 2 ++
 4 files changed, 7 insertions(+), 2 deletions(-)

diff --git a/cmd/Kconfig b/cmd/Kconfig
index df6d71c103f..ae846b204dc 100644
--- a/cmd/Kconfig
+++ b/cmd/Kconfig
@@ -1842,6 +1842,7 @@ config BOOTP_PXE_CLIENTARCH
 
 config BOOTP_PXE_DHCP_OPTION
bool "Request & store 'pxe_configfile' from BOOTP/DHCP server"
+   default y
depends on BOOTP_PXE
 
 config BOOTP_VCI_STRING
diff --git a/cmd/pxe.c b/cmd/pxe.c
index 21134eb7a30..9404f445187 100644
--- a/cmd/pxe.c
+++ b/cmd/pxe.c
@@ -65,6 +65,8 @@ static int pxe_dhcp_option_path(struct pxe_context *ctx, 
unsigned long pxefile_a
int ret = get_pxe_file(ctx, pxelinux_configfile, pxefile_addr_r);
 
free(pxelinux_configfile);
+   /* set to NULL to avoid double-free if DHCP is tried again */
+   pxelinux_configfile = NULL;
 
return ret;
 }
diff --git a/net/bootp.c b/net/bootp.c
index 68002909634..24547cf7bfd 100644
--- a/net/bootp.c
+++ b/net/bootp.c
@@ -603,7 +603,7 @@ static int dhcp_extended(u8 *e, int message_type, struct 
in_addr server_ip,
*cnt += 1;
 #endif
if (IS_ENABLED(CONFIG_BOOTP_PXE_DHCP_OPTION)) {
-   *e++ = 209; /* PXELINUX Config File */
+   *e++ = DHCP_OPTION_PXE_CONFIG_FILE; /* PXELINUX Config File 
*/
*cnt += 1;
}
/* no options, so back up to avoid sending an empty request list */
@@ -914,7 +914,7 @@ static void dhcp_process_options(uchar *popt, uchar *end)
net_boot_file_name[size] = 0;
}
break;
-   case 209:   /* PXELINUX Config File */
+   case DHCP_OPTION_PXE_CONFIG_FILE:   /* PXELINUX Config File 
*/
if (IS_ENABLED(CONFIG_BOOTP_PXE_DHCP_OPTION)) {
/* In case it has already been allocated when 
get DHCP Offer packet,
 * free first to avoid memory leak.
diff --git a/net/bootp.h b/net/bootp.h
index 4e32b19d424..24b32c73f62 100644
--- a/net/bootp.h
+++ b/net/bootp.h
@@ -91,6 +91,8 @@ typedef enum { INIT,
 #define DHCP_NAK  6
 #define DHCP_RELEASE  7
 
+#define DHCP_OPTION_PXE_CONFIG_FILE209 /* "ConfigFile" option 
according to rfc5071 */
+
 /**/
 
 #endif /* __BOOTP_H__ */
-- 
2.42.0



[PATCH v5 2/3] net: bootp: BOOTP/DHCPv4 retransmission improvements

2023-11-17 Thread seanedmond
From: Sean Edmond 

This patch introduces 3 improvements to align with RFC 951:
- retransmission backoff interval maximum is configurable
- initial retranmission backoff interval is configurable
- transaction ID is kept the same for each BOOTP/DHCPv4 request

In applications where thousands of nodes are serviced by a single DHCP
server, maximizing the retransmission backoff interval at 2 seconds (the
current u-boot default) exerts high pressure on the DHCP server and
network layer.

RFC 951 “7.2. Client Retransmission Strategy” states that the
retransmission backoff interval should be limited to 60 seconds.  This
patch allows the interval to be configurable using the environment
variable "bootpretransmitperiodmax"

The initial retranmission backoff period defaults to 250ms, which is
also too small for these scenarios with many clients.  This patch makes
the initial retransmission interval to be configurable using the
environment variable "bootpretransmitperiodinit".

Also, on a retransmission it is not expected for the transaction ID to
change (only the 'secs' field should be updated). Let's save the
transaction ID and use the same transaction ID for each BOOTP/DHCPv4
exchange.

Signed-off-by: Sean Edmond 
---

changes in v4:
- Add "select LIB_RAND" for "config CMD_BOOTP" (retransmission
  improvements require rand())

changes in v3:
- Set RETRANSMIT_PERIOD_MAX_MS=6
- Add randomization factor to retransmission timeout

changes in v2:
- use env_get_ulong() to get environment variables

 cmd/Kconfig |  2 +-
 net/bootp.c | 71 +
 2 files changed, 56 insertions(+), 17 deletions(-)

diff --git a/cmd/Kconfig b/cmd/Kconfig
index ae846b204dc..93bf752035c 100644
--- a/cmd/Kconfig
+++ b/cmd/Kconfig
@@ -1717,6 +1717,7 @@ if CMD_NET
 config CMD_BOOTP
bool "bootp"
default y
+   select LIB_RAND
help
  bootp - boot image via network using BOOTP/TFTP protocol
 
@@ -1725,7 +1726,6 @@ config CMD_DHCP
depends on CMD_BOOTP
help
  Boot image via network using DHCP/TFTP protocol
-
 config CMD_DHCP6
bool "dhcp6"
depends on IPV6
diff --git a/net/bootp.c b/net/bootp.c
index 24547cf7bfd..89425717328 100644
--- a/net/bootp.c
+++ b/net/bootp.c
@@ -42,6 +42,22 @@
  */
 #define TIMEOUT_MS ((3 + (CONFIG_NET_RETRY_COUNT * 5)) * 1000)
 
+/*
+ * According to rfc951 : 7.2. Client Retransmission Strategy
+ * "After the 'average' backoff reaches about 60 seconds, it should be
+ * increased no further, but still randomized."
+ *
+ * U-Boot has saturated this backoff at 2 seconds for a long time.
+ * To modify, set the environment variable "bootpretransmitperiodmax"
+ */
+#define RETRANSMIT_PERIOD_MAX_MS   6
+
+/* Retransmission timeout for the initial packet (in milliseconds).
+ * This timeout will double on each retry.  To modify, set the
+ * environment variable bootpretransmitperiodinit.
+ */
+#define RETRANSMIT_PERIOD_INIT_MS  250
+
 #ifndef CFG_DHCP_MIN_EXT_LEN   /* minimal length of extension list */
 #define CFG_DHCP_MIN_EXT_LEN 64
 #endif
@@ -53,6 +69,7 @@
 u32bootp_ids[CFG_BOOTP_ID_CACHE_SIZE];
 unsigned int   bootp_num_ids;
 intbootp_try;
+u32bootp_id;
 ulong  bootp_start;
 ulong  bootp_timeout;
 char net_nis_domain[32] = {0,}; /* Our NIS domain */
@@ -60,6 +77,7 @@ char net_hostname[32] = {0,}; /* Our hostname */
 char net_root_path[CONFIG_BOOTP_MAX_ROOT_PATH_LEN] = {0,}; /* Our bootpath */
 
 static ulong time_taken_max;
+static u32   retransmit_period_max_ms;
 
 #if defined(CONFIG_CMD_DHCP)
 static dhcp_state_t dhcp_state = INIT;
@@ -396,6 +414,7 @@ static void bootp_handler(uchar *pkt, unsigned dest, struct 
in_addr sip,
 static void bootp_timeout_handler(void)
 {
ulong time_taken = get_timer(bootp_start);
+   int rand_minus_plus_100;
 
if (time_taken >= time_taken_max) {
 #ifdef CONFIG_BOOTP_MAY_FAIL
@@ -414,8 +433,17 @@ static void bootp_timeout_handler(void)
}
} else {
bootp_timeout *= 2;
-   if (bootp_timeout > 2000)
-   bootp_timeout = 2000;
+   if (bootp_timeout > retransmit_period_max_ms)
+   bootp_timeout = retransmit_period_max_ms;
+
+   /* Randomize by adding bootp_timeout*RAND, where RAND
+* is a randomization factor between -0.1..+0.1
+*/
+   srand(get_ticks() + rand());
+   rand_minus_plus_100 = ((rand() % 200) - 100);
+   bootp_timeout = bootp_timeout +
+   (((int)bootp_timeout * rand_minus_plus_100) / 
1000);
+
net_set_timeout_handler(bootp_timeout, bootp_timeout_handler);
bootp_request();
}
@@ -711,10 +739,14 @@ static int bootp_extended(u8 *e)
 
 void bootp_reset(void)
 {
+   char *ep;  /* Environment pointer */
+
bootp_num_ids = 

[PATCH v5 0/3] BOOTP/DHCPv4 enhancements

2023-11-17 Thread seanedmond
From: Sean Edmond 

In our datacenter application, a single DHCP server is servicing 36000+ clients.
Improvements are required to the DHCPv4 retransmission behavior to align with
RFC and ensure less pressure is exerted on the server:
- retransmission backoff interval maximum is configurable 
  (environment variable bootpretransmitperiodmax)
- initial retransmission backoff interval is configurable 
  (environment variable bootpretransmitperiodinit)
- transaction ID is kept the same for each BOOTP/DHCPv4 request 
  (not recreated on each retry)

For our application we'll use:
- bootpretransmitperiodmax=16000
- bootpretransmitperiodinit=2000

A new configuration BOOTP_RANDOM_XID has been added to enable a randomized
BOOTP/DHCPv4 transaction ID.

Enhance DHCPv4 sending/parsing option 209 (PXE config file).  A previous
patch was accepted.  A new patch fixes a possible double free() and
addresses latest review comments.

changes in v5:
- fix depends for BOOTP_RANDOM_XID:
  "depends on CMD_BOOTP && (LIB_RAND || LIB_HW_RAND)"
- add change log to individual patches

changes in v4:
- rebase master and resolve conflicts
- change commit description for DHCP option 209 patch (this is now
  an enhancement patch)
- default y for BOOTP_PXE_DHCP_OPTION (feedback from review)
- Add "select LIB_RAND" for "config CMD_BOOTP" (retransmission
  improvements require rand())

changes in v3:
- add define for option 209 and rfc5071 reference
- Set RETRANSMIT_PERIOD_MAX_MS=6
- Add randomization factor to retransmission timeout
- Add depends for BOOTP_RANDOM_XID

changes in v2:
- use env_get_ulong() to get environment variables

Sean Edmond (3):
  net: Additional fixes for dhcp option 209
  net: bootp: BOOTP/DHCPv4 retransmission improvements
  net: bootp: add config option BOOTP_RANDOM_XID

 cmd/Kconfig | 10 ++-
 cmd/pxe.c   |  2 ++
 net/bootp.c | 76 +
 net/bootp.h |  2 ++
 4 files changed, 72 insertions(+), 18 deletions(-)

-- 
2.42.0



[PATCH v4 2/3] net: bootp: BOOTP/DHCPv4 retransmission improvements

2023-11-17 Thread seanedmond
From: Sean Edmond 

This patch introduces 3 improvements to align with RFC 951:
- retransmission backoff interval maximum is configurable
- initial retranmission backoff interval is configurable
- transaction ID is kept the same for each BOOTP/DHCPv4 request

In applications where thousands of nodes are serviced by a single DHCP
server, maximizing the retransmission backoff interval at 2 seconds (the
current u-boot default) exerts high pressure on the DHCP server and
network layer.

RFC 951 “7.2. Client Retransmission Strategy” states that the
retransmission backoff interval should be limited to 60 seconds.  This
patch allows the interval to be configurable using the environment
variable "bootpretransmitperiodmax"

The initial retranmission backoff period defaults to 250ms, which is
also too small for these scenarios with many clients.  This patch makes
the initial retransmission interval to be configurable using the
environment variable "bootpretransmitperiodinit".

Also, on a retransmission it is not expected for the transaction ID to
change (only the 'secs' field should be updated). Let's save the
transaction ID and use the same transaction ID for each BOOTP/DHCPv4
exchange.

Signed-off-by: Sean Edmond 
---
 cmd/Kconfig |  2 +-
 net/bootp.c | 71 +
 2 files changed, 56 insertions(+), 17 deletions(-)

diff --git a/cmd/Kconfig b/cmd/Kconfig
index ae846b204dc..93bf752035c 100644
--- a/cmd/Kconfig
+++ b/cmd/Kconfig
@@ -1717,6 +1717,7 @@ if CMD_NET
 config CMD_BOOTP
bool "bootp"
default y
+   select LIB_RAND
help
  bootp - boot image via network using BOOTP/TFTP protocol
 
@@ -1725,7 +1726,6 @@ config CMD_DHCP
depends on CMD_BOOTP
help
  Boot image via network using DHCP/TFTP protocol
-
 config CMD_DHCP6
bool "dhcp6"
depends on IPV6
diff --git a/net/bootp.c b/net/bootp.c
index 24547cf7bfd..89425717328 100644
--- a/net/bootp.c
+++ b/net/bootp.c
@@ -42,6 +42,22 @@
  */
 #define TIMEOUT_MS ((3 + (CONFIG_NET_RETRY_COUNT * 5)) * 1000)
 
+/*
+ * According to rfc951 : 7.2. Client Retransmission Strategy
+ * "After the 'average' backoff reaches about 60 seconds, it should be
+ * increased no further, but still randomized."
+ *
+ * U-Boot has saturated this backoff at 2 seconds for a long time.
+ * To modify, set the environment variable "bootpretransmitperiodmax"
+ */
+#define RETRANSMIT_PERIOD_MAX_MS   6
+
+/* Retransmission timeout for the initial packet (in milliseconds).
+ * This timeout will double on each retry.  To modify, set the
+ * environment variable bootpretransmitperiodinit.
+ */
+#define RETRANSMIT_PERIOD_INIT_MS  250
+
 #ifndef CFG_DHCP_MIN_EXT_LEN   /* minimal length of extension list */
 #define CFG_DHCP_MIN_EXT_LEN 64
 #endif
@@ -53,6 +69,7 @@
 u32bootp_ids[CFG_BOOTP_ID_CACHE_SIZE];
 unsigned int   bootp_num_ids;
 intbootp_try;
+u32bootp_id;
 ulong  bootp_start;
 ulong  bootp_timeout;
 char net_nis_domain[32] = {0,}; /* Our NIS domain */
@@ -60,6 +77,7 @@ char net_hostname[32] = {0,}; /* Our hostname */
 char net_root_path[CONFIG_BOOTP_MAX_ROOT_PATH_LEN] = {0,}; /* Our bootpath */
 
 static ulong time_taken_max;
+static u32   retransmit_period_max_ms;
 
 #if defined(CONFIG_CMD_DHCP)
 static dhcp_state_t dhcp_state = INIT;
@@ -396,6 +414,7 @@ static void bootp_handler(uchar *pkt, unsigned dest, struct 
in_addr sip,
 static void bootp_timeout_handler(void)
 {
ulong time_taken = get_timer(bootp_start);
+   int rand_minus_plus_100;
 
if (time_taken >= time_taken_max) {
 #ifdef CONFIG_BOOTP_MAY_FAIL
@@ -414,8 +433,17 @@ static void bootp_timeout_handler(void)
}
} else {
bootp_timeout *= 2;
-   if (bootp_timeout > 2000)
-   bootp_timeout = 2000;
+   if (bootp_timeout > retransmit_period_max_ms)
+   bootp_timeout = retransmit_period_max_ms;
+
+   /* Randomize by adding bootp_timeout*RAND, where RAND
+* is a randomization factor between -0.1..+0.1
+*/
+   srand(get_ticks() + rand());
+   rand_minus_plus_100 = ((rand() % 200) - 100);
+   bootp_timeout = bootp_timeout +
+   (((int)bootp_timeout * rand_minus_plus_100) / 
1000);
+
net_set_timeout_handler(bootp_timeout, bootp_timeout_handler);
bootp_request();
}
@@ -711,10 +739,14 @@ static int bootp_extended(u8 *e)
 
 void bootp_reset(void)
 {
+   char *ep;  /* Environment pointer */
+
bootp_num_ids = 0;
bootp_try = 0;
bootp_start = get_timer(0);
-   bootp_timeout = 250;
+
+   bootp_timeout = env_get_ulong("bootpretransmitperiodinit", 10, 
RETRANSMIT_PERIOD_INIT_MS);
+
 }
 
 void bootp_request(void)
@@ -726,7 +758,6 @@ void bootp_request(void)
 #ifdef 

[PATCH v4 1/3] net: Additional fixes for dhcp option 209

2023-11-17 Thread seanedmond
From: Sean Edmond 

Addresses feedback from latest review:
- Enable option 209 by default
- Set pxelinux_configfile to NULL to avoid potential double free
- change hardcoced 209 to a define

Signed-off-by: Sean Edmond 
---
 cmd/Kconfig | 1 +
 cmd/pxe.c   | 2 ++
 net/bootp.c | 4 ++--
 net/bootp.h | 2 ++
 4 files changed, 7 insertions(+), 2 deletions(-)

diff --git a/cmd/Kconfig b/cmd/Kconfig
index df6d71c103f..ae846b204dc 100644
--- a/cmd/Kconfig
+++ b/cmd/Kconfig
@@ -1842,6 +1842,7 @@ config BOOTP_PXE_CLIENTARCH
 
 config BOOTP_PXE_DHCP_OPTION
bool "Request & store 'pxe_configfile' from BOOTP/DHCP server"
+   default y
depends on BOOTP_PXE
 
 config BOOTP_VCI_STRING
diff --git a/cmd/pxe.c b/cmd/pxe.c
index 21134eb7a30..9404f445187 100644
--- a/cmd/pxe.c
+++ b/cmd/pxe.c
@@ -65,6 +65,8 @@ static int pxe_dhcp_option_path(struct pxe_context *ctx, 
unsigned long pxefile_a
int ret = get_pxe_file(ctx, pxelinux_configfile, pxefile_addr_r);
 
free(pxelinux_configfile);
+   /* set to NULL to avoid double-free if DHCP is tried again */
+   pxelinux_configfile = NULL;
 
return ret;
 }
diff --git a/net/bootp.c b/net/bootp.c
index 68002909634..24547cf7bfd 100644
--- a/net/bootp.c
+++ b/net/bootp.c
@@ -603,7 +603,7 @@ static int dhcp_extended(u8 *e, int message_type, struct 
in_addr server_ip,
*cnt += 1;
 #endif
if (IS_ENABLED(CONFIG_BOOTP_PXE_DHCP_OPTION)) {
-   *e++ = 209; /* PXELINUX Config File */
+   *e++ = DHCP_OPTION_PXE_CONFIG_FILE; /* PXELINUX Config File 
*/
*cnt += 1;
}
/* no options, so back up to avoid sending an empty request list */
@@ -914,7 +914,7 @@ static void dhcp_process_options(uchar *popt, uchar *end)
net_boot_file_name[size] = 0;
}
break;
-   case 209:   /* PXELINUX Config File */
+   case DHCP_OPTION_PXE_CONFIG_FILE:   /* PXELINUX Config File 
*/
if (IS_ENABLED(CONFIG_BOOTP_PXE_DHCP_OPTION)) {
/* In case it has already been allocated when 
get DHCP Offer packet,
 * free first to avoid memory leak.
diff --git a/net/bootp.h b/net/bootp.h
index 4e32b19d424..24b32c73f62 100644
--- a/net/bootp.h
+++ b/net/bootp.h
@@ -91,6 +91,8 @@ typedef enum { INIT,
 #define DHCP_NAK  6
 #define DHCP_RELEASE  7
 
+#define DHCP_OPTION_PXE_CONFIG_FILE209 /* "ConfigFile" option 
according to rfc5071 */
+
 /**/
 
 #endif /* __BOOTP_H__ */
-- 
2.42.0



[PATCH v4 0/3] [PATCH v4 0/3] [PATCH v3 0/3] BOOTP/DHCPv4 enhancements

2023-11-17 Thread seanedmond
From: Sean Edmond 

In our datacenter application, a single DHCP server is servicing 36000+ clients.
Improvements are required to the DHCPv4 retransmission behavior to align with
RFC and ensure less pressure is exerted on the server:
- retransmission backoff interval maximum is configurable 
  (environment variable bootpretransmitperiodmax)
- initial retransmission backoff interval is configurable 
  (environment variable bootpretransmitperiodinit)
- transaction ID is kept the same for each BOOTP/DHCPv4 request 
  (not recreated on each retry)

For our application we'll use:
- bootpretransmitperiodmax=16000
- bootpretransmitperiodinit=2000

A new configuration BOOTP_RANDOM_XID has been added to enable a randomized
BOOTP/DHCPv4 transaction ID.

Enhance DHCPv4 sending/parsing option 209 (PXE config file).  A previous
patch was accepted.  A new patch fixes a possible double free() and
addresses latest review comments.

changes in v4:
- rebase master and resolve conflicts
- change commit description for DHCP option 209 patch (this is now
  an enhancement patch)
- default y for BOOTP_PXE_DHCP_OPTION (feedback from review)
- Add "select LIB_RAND" for "config CMD_BOOTP" (retransmission
  improvements require rand())

changes in v3:
- add define for option 209 and rfc5071 reference
- Set RETRANSMIT_PERIOD_MAX_MS=6
- Add randomization factor to retransmission timeout
- Add depends for BOOTP_RANDOM_XID

changes in v2:
- use env_get_ulong() to get environment variables

Sean Edmond (3):
  net: Additional fixes for dhcp option 209
  net: bootp: BOOTP/DHCPv4 retransmission improvements
  net: bootp: add config option BOOTP_RANDOM_XID

 cmd/Kconfig | 10 ++-
 cmd/pxe.c   |  2 ++
 net/bootp.c | 76 +
 net/bootp.h |  2 ++
 4 files changed, 72 insertions(+), 18 deletions(-)

-- 
2.42.0



[PATCH v4 3/3] net: bootp: add config option BOOTP_RANDOM_XID

2023-11-17 Thread seanedmond
From: Sean Edmond 

The new config option BOOTP_RANDOM_XID will randomize the transaction ID
for each new BOOT/DHCPv4 exchange.

Signed-off-by: Sean Edmond 
---
 cmd/Kconfig |  7 +++
 net/bootp.c | 31 +--
 2 files changed, 24 insertions(+), 14 deletions(-)

diff --git a/cmd/Kconfig b/cmd/Kconfig
index 93bf752035c..244237e6d60 100644
--- a/cmd/Kconfig
+++ b/cmd/Kconfig
@@ -1853,6 +1853,13 @@ config BOOTP_VCI_STRING
default "U-Boot.arm" if ARM
default "U-Boot"
 
+config BOOTP_RANDOM_XID
+   bool "Send random transaction ID to BOOTP/DHCP server"
+   depends on CMD_BOOTP && (LIB_RAND || EXYNOS_ACE_SHA || RNG_NPCM)
+   help
+ Selecting this will allow for a random transaction ID to get
+ selected for each BOOTP/DHCPv4 exchange.
+
 if CMD_DHCP6
 
 config DHCP6_PXE_CLIENTARCH
diff --git a/net/bootp.c b/net/bootp.c
index 89425717328..49cd9064436 100644
--- a/net/bootp.c
+++ b/net/bootp.c
@@ -837,22 +837,25 @@ void bootp_request(void)
 
/* Only generate a new transaction ID for each new BOOTP request */
if (bootp_try == 1) {
-   /*
-*  Bootp ID is the lower 4 bytes of our ethernet address
-*  plus the current time in ms.
-*/
-   bootp_id = ((u32)net_ethaddr[2] << 24)
-   | ((u32)net_ethaddr[3] << 16)
-   | ((u32)net_ethaddr[4] << 8)
-   | (u32)net_ethaddr[5];
-   bootp_id += get_timer(0);
-   bootp_id = htonl(bootp_id);
-   bootp_add_id(bootp_id);
-   net_copy_u32(>bp_id, _id);
-   } else {
-   net_copy_u32(>bp_id, _id);
+   if (IS_ENABLED(CONFIG_BOOTP_RANDOM_XID)) {
+   srand(get_ticks() + rand());
+   bootp_id = rand();
+   } else {
+   /*
+*  Bootp ID is the lower 4 bytes of our ethernet 
address
+*  plus the current time in ms.
+*/
+   bootp_id = ((u32)net_ethaddr[2] << 24)
+   | ((u32)net_ethaddr[3] << 16)
+   | ((u32)net_ethaddr[4] << 8)
+   | (u32)net_ethaddr[5];
+   bootp_id += get_timer(0);
+   bootp_id = htonl(bootp_id);
+   }
}
 
+   bootp_add_id(bootp_id);
+   net_copy_u32(>bp_id, _id);
/*
 * Calculate proper packet lengths taking into account the
 * variable size of the options field
-- 
2.42.0



[PATCH v5 5/5] fdt: Fix compile error for !OFNODE_MULTI_TREE

2023-11-16 Thread seanedmond
From: Sean Edmond 

Required to fix the following compile error when building sandbox:
/tmp/cci9ibby.ltrans21.ltrans.o: In function `do_cedit_load':
:(.text+0x601d): undefined reference to `oftree_dispose'

Signed-off-by: Sean Edmond 
---
 drivers/core/ofnode.c | 12 ++--
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/drivers/core/ofnode.c b/drivers/core/ofnode.c
index 6ce468d9cac..ec25466a5e7 100644
--- a/drivers/core/ofnode.c
+++ b/drivers/core/ofnode.c
@@ -135,12 +135,6 @@ int oftree_new(oftree *treep)
return 0;
 }
 
-void oftree_dispose(oftree tree)
-{
-   if (of_live_active())
-   of_live_free(tree.np);
-}
-
 void *ofnode_lookup_fdt(ofnode node)
 {
if (gd->flags & GD_FLG_RELOC) {
@@ -243,6 +237,12 @@ int oftree_new(oftree *treep)
 
 #endif /* OFNODE_MULTI_TREE */
 
+void oftree_dispose(oftree tree)
+{
+   if (of_live_active())
+   of_live_free(tree.np);
+}
+
 int oftree_to_fdt(oftree tree, struct abuf *buf)
 {
int ret;
-- 
2.42.0



[PATCH v5 3/5] cmd: kaslrseed: Use common API to fixup FDT

2023-11-16 Thread seanedmond
From: Sean Edmond 

Use the newly introduced common API fdt_fixup_kaslr_seed() in the
kaslrseed command.

Signed-off-by: Sean Edmond 
---
 cmd/kaslrseed.c | 22 --
 1 file changed, 8 insertions(+), 14 deletions(-)

diff --git a/cmd/kaslrseed.c b/cmd/kaslrseed.c
index 9acb8e16386..23ed7c066aa 100644
--- a/cmd/kaslrseed.c
+++ b/cmd/kaslrseed.c
@@ -19,7 +19,7 @@ static int do_kaslr_seed(struct cmd_tbl *cmdtp, int flag, int 
argc, char *const
size_t n = 0x8;
struct udevice *dev;
u64 *buf;
-   int nodeoffset;
+   ofnode root;
int ret = CMD_RET_SUCCESS;
 
if (uclass_get_device(UCLASS_RNG, 0, ) || !dev) {
@@ -45,21 +45,15 @@ static int do_kaslr_seed(struct cmd_tbl *cmdtp, int flag, 
int argc, char *const
return CMD_RET_FAILURE;
}
 
-   ret = fdt_check_header(working_fdt);
-   if (ret < 0) {
-   printf("fdt_chosen: %s\n", fdt_strerror(ret));
-   return CMD_RET_FAILURE;
-   }
-
-   nodeoffset = fdt_find_or_add_subnode(working_fdt, 0, "chosen");
-   if (nodeoffset < 0) {
-   printf("Reading chosen node failed\n");
-   return CMD_RET_FAILURE;
+   ret = root_ofnode_from_fdt(working_fdt, );
+   if (ret) {
+   printf("ERROR: Unable to get root ofnode\n");
+   goto CMD_RET_FAILURE;
}
 
-   ret = fdt_setprop(working_fdt, nodeoffset, "kaslr-seed", buf, 
sizeof(buf));
-   if (ret < 0) {
-   printf("Unable to set kaslr-seed on chosen node: %s\n", 
fdt_strerror(ret));
+   ret = fdt_fixup_kaslr_seed(root, (u8 *)buf, sizeof(buf));
+   if (ret) {
+   printf("ERROR: failed to add kaslr-seed to fdt\n");
return CMD_RET_FAILURE;
}
 
-- 
2.42.0



[PATCH v5 4/5] dm: core: Modify default for OFNODE_MULTI_TREE

2023-11-16 Thread seanedmond
From: Sean Edmond 

There is a preference to use the "ofnode" API for FDT fixups
moving forward.  The FDT fixup will usually be for the kernel FDT.  To
fixup the kernel FDT with the ofnode API, it's required to set the
OFNODE_MULTI_TREE option.

To ensure existing users of kaslr fdt fixup are not impacted, Let's modify
the default value for OFNODE_MULTI_TREE to ensure it's always set.
This will cause a 1007 byte increase in the code size.

Signed-off-by: Sean Edmond 
---
 drivers/core/Kconfig | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/core/Kconfig b/drivers/core/Kconfig
index 737d4590d5b..c01a8dc7e0a 100644
--- a/drivers/core/Kconfig
+++ b/drivers/core/Kconfig
@@ -423,7 +423,8 @@ config DM_DEV_READ_INLINE
 
 config OFNODE_MULTI_TREE
bool "Allow the ofnode interface to access any tree"
-   default y if EVENT && !DM_DEV_READ_INLINE && !DM_INLINE_OFNODE
+   depends on OF_CONTROL
+   default y
help
  Normally U-Boot makes use of its control FDT, the one used to bind
  devices and provide options. In some cases, U-Boot must also process
-- 
2.42.0



[PATCH v5 0/5] Populate kaslr seed with RNG

2023-11-16 Thread seanedmond
From: Sean Edmond 

This patch series creates a common API (fdt_fixup_kaslr_seed()) for 
populating the kaslr seed in the DTB.  Existing users (kaslrseed,
and ARMv8 sec firmware) have been updated to use this common API.

New functionality has been introduced to populate the kaslr using
the RNG.  This can be enabled with CONFIG_RNG_TPM_SEED.  

changes in v5:
- Always enable OFNODE_MULTI_TREE
- include dm/ofnode-decl.h instead of dm/ofnode.h
- cast buffer to (u8 *) in kaslrseed.c

changes in v4:
- Fix compile issue when CONFIG_OF_CONTROL not set

changes in v3:
- Populate with RNG device instead of TPM device (this is a more generic 
solution)
- Use event spy to do the FDT fixup
- fix compile error for sandbox for !OFNODE_MULTI_TREE

changes in v2:
- fdt_fixup_kaslr_seed() uses the ofnode API
- Add root_ofnode_from_fdt() to get the root node from an FDT and
  perform error checking on the oftree
- add comments to exported functions
- Add error checking in image_setup_libfdt() for return from
  fdt_tpm_kaslr_seed()
- uclass_get_device() -> uclass_first_device_err()
- Change default config for OFNODE_MULTI_TREE (y if !OF_LIVE)

Dhananjay Phadke (2):
  fdt: common API to populate kaslr seed
  fdt: kaslr seed from RNG device

Sean Edmond (3):
  cmd: kaslrseed: Use common API to fixup FDT
  dm: core: Modify default for OFNODE_MULTI_TREE
  fdt: Fix compile error for !OFNODE_MULTI_TREE

 arch/arm/cpu/armv8/sec_firmware.c | 39 --
 boot/fdt_support.c| 55 +++
 cmd/kaslrseed.c   | 22 +
 drivers/core/Kconfig  |  3 +-
 drivers/core/ofnode.c | 29 
 include/dm/ofnode.h   | 12 +++
 include/fdt_support.h |  9 +
 lib/Kconfig   |  7 
 8 files changed, 130 insertions(+), 46 deletions(-)

-- 
2.42.0



[PATCH v5 1/5] fdt: common API to populate kaslr seed

2023-11-16 Thread seanedmond
From: Dhananjay Phadke 

fdt_fixup_kaslr_seed() will update given ofnode with random seed value.
Source for random seed can be TPM or RNG driver in u-boot or sec
firmware (ARM).

Signed-off-by: Dhananjay Phadke 
Signed-off-by: Sean Edmond 
---
 arch/arm/cpu/armv8/sec_firmware.c | 39 +++
 boot/fdt_support.c| 19 +++
 drivers/core/ofnode.c | 17 ++
 include/dm/ofnode.h   | 12 ++
 include/fdt_support.h |  9 +++
 5 files changed, 71 insertions(+), 25 deletions(-)

diff --git a/arch/arm/cpu/armv8/sec_firmware.c 
b/arch/arm/cpu/armv8/sec_firmware.c
index c0e8726346f..5f04cd8aecd 100644
--- a/arch/arm/cpu/armv8/sec_firmware.c
+++ b/arch/arm/cpu/armv8/sec_firmware.c
@@ -411,46 +411,35 @@ int sec_firmware_init(const void *sec_firmware_img,
 /*
  * fdt_fix_kaslr - Add kalsr-seed node in Device tree
  * @fdt:   Device tree
- * @eret:  0 in case of error, 1 for success
+ * @eret:  0 for success
  */
 int fdt_fixup_kaslr(void *fdt)
 {
-   int nodeoffset;
-   int err, ret = 0;
-   u8 rand[8];
+   int ret = 0;
 
 #if defined(CONFIG_ARMV8_SEC_FIRMWARE_SUPPORT)
+   u8 rand[8];
+   ofnode root;
+
/* Check if random seed generation is  supported */
if (sec_firmware_support_hwrng() == false) {
printf("WARNING: SEC firmware not running, no kaslr-seed\n");
-   return 0;
+   return -EOPNOTSUPP;
}
 
-   err = sec_firmware_get_random(rand, 8);
-   if (err < 0) {
+   ret = sec_firmware_get_random(rand, 8);
+   if (ret < 0) {
printf("WARNING: No random number to set kaslr-seed\n");
-   return 0;
+   return ret;
}
 
-   err = fdt_check_header(fdt);
-   if (err < 0) {
-   printf("fdt_chosen: %s\n", fdt_strerror(err));
-   return 0;
+   ret = root_ofnode_from_fdt(fdt, );
+   if (ret < 0) {
+   printf("WARNING: Unable to get root ofnode\n");
+   return ret;
}
 
-   /* find or create "/chosen" node. */
-   nodeoffset = fdt_find_or_add_subnode(fdt, 0, "chosen");
-   if (nodeoffset < 0)
-   return 0;
-
-   err = fdt_setprop(fdt, nodeoffset, "kaslr-seed", rand,
- sizeof(rand));
-   if (err < 0) {
-   printf("WARNING: can't set kaslr-seed %s.\n",
-  fdt_strerror(err));
-   return 0;
-   }
-   ret = 1;
+   ret = fdt_fixup_kaslr_seed(root, rand, sizeof(rand));
 #endif
 
return ret;
diff --git a/boot/fdt_support.c b/boot/fdt_support.c
index b15d07765fe..49d14a949be 100644
--- a/boot/fdt_support.c
+++ b/boot/fdt_support.c
@@ -631,6 +631,25 @@ void fdt_fixup_ethernet(void *fdt)
}
 }
 
+int fdt_fixup_kaslr_seed(ofnode node, const u8 *seed, int len)
+{
+   ofnode chosen;
+   int ret;
+
+   /* find or create "/chosen" node. */
+   ret = ofnode_add_subnode(node, "chosen", );
+   if (ret && ret != -EEXIST)
+   return -ENOENT;
+
+   ret = ofnode_write_prop(chosen, "kaslr-seed", seed, len, true);
+   if (ret) {
+   printf("WARNING: can't set kaslr-seed\n");
+   return ret;
+   }
+
+   return 0;
+}
+
 int fdt_record_loadable(void *blob, u32 index, const char *name,
uintptr_t load_addr, u32 size, uintptr_t entry_point,
const char *type, const char *os, const char *arch)
diff --git a/drivers/core/ofnode.c b/drivers/core/ofnode.c
index f72ea416cf1..6ce468d9cac 100644
--- a/drivers/core/ofnode.c
+++ b/drivers/core/ofnode.c
@@ -966,6 +966,23 @@ ofnode oftree_path(oftree tree, const char *path)
}
 }
 
+int root_ofnode_from_fdt(void *fdt, ofnode *root_node)
+{
+   oftree tree;
+   /* If OFNODE_MULTI_TREE is not set, and if fdt is not the control FDT,
+*  oftree_from_fdt() will return NULL
+*/
+   tree = oftree_from_fdt(fdt);
+
+   if (!oftree_valid(tree)) {
+   printf("Cannot create oftree\n");
+   return -EINVAL;
+   }
+   *root_node = oftree_root(tree);
+
+   return 0;
+}
+
 const void *ofnode_read_chosen_prop(const char *propname, int *sizep)
 {
ofnode chosen_node;
diff --git a/include/dm/ofnode.h b/include/dm/ofnode.h
index 5795115c490..3e0bbd0c33e 100644
--- a/include/dm/ofnode.h
+++ b/include/dm/ofnode.h
@@ -936,6 +936,18 @@ ofnode oftree_path(oftree tree, const char *path);
  */
 ofnode oftree_root(oftree tree);
 
+/**
+ * root_ofnode_from_fdt() - Gets the root ofnode given an FDT blob.
+ *  Note, this will fail if OFNODE_MULTI_TREE
+ *  is not set.
+ *
+ * @fdt: Device tree to use
+ * @root_node : Root ofnode
+ *
+ * Return: 0 if OK, -ve on error
+ */
+int root_ofnode_from_fdt(void *fdt, ofnode 

[PATCH v5 2/5] fdt: kaslr seed from RNG device

2023-11-16 Thread seanedmond
From: Dhananjay Phadke 

Add support for KASLR seed from the RNG device. Invokes dm_rng_read()
API to read 8-bytes of random bytes.  Performs the FDT fixup using event
spy.  To enable use CONFIG_KASLR_RNG_SEED

Signed-off-by: Dhananjay Phadke 
Signed-off-by: Drew Kluemke 
Signed-off-by: Sean Edmond 
---
 boot/fdt_support.c | 36 
 lib/Kconfig|  7 +++
 2 files changed, 43 insertions(+)

diff --git a/boot/fdt_support.c b/boot/fdt_support.c
index 49d14a949be..12defcf645c 100644
--- a/boot/fdt_support.c
+++ b/boot/fdt_support.c
@@ -12,7 +12,10 @@
 #include 
 #include 
 #include 
+#include 
 #include 
+#include 
+#include 
 #include 
 #include 
 #include 
@@ -650,6 +653,39 @@ int fdt_fixup_kaslr_seed(ofnode node, const u8 *seed, int 
len)
return 0;
 }
 
+int fdt_rng_kaslr_seed(void *ctx, struct event *event)
+{
+   u8 rand[8] = {0};
+   struct udevice *dev;
+   int ret;
+   oftree tree = event->data.ft_fixup.tree;
+   ofnode root_node = oftree_root(tree);
+
+   ret = uclass_first_device_err(UCLASS_RNG, );
+   if (ret) {
+   printf("ERROR: Failed to find RNG device\n");
+   return ret;
+   }
+
+   ret = dm_rng_read(dev, rand, sizeof(rand));
+   if (ret) {
+   printf("ERROR: RNG read failed, ret=%d\n", ret);
+   return ret;
+   }
+
+   ret = fdt_fixup_kaslr_seed(root_node, rand, sizeof(rand));
+   if (ret) {
+   printf("ERROR: failed to add kaslr-seed to fdt\n");
+   return ret;
+   }
+
+   return 0;
+}
+
+#if defined(CONFIG_KASLR_RNG_SEED)
+EVENT_SPY(EVT_FT_FIXUP, fdt_rng_kaslr_seed);
+#endif
+
 int fdt_record_loadable(void *blob, u32 index, const char *name,
uintptr_t load_addr, u32 size, uintptr_t entry_point,
const char *type, const char *os, const char *arch)
diff --git a/lib/Kconfig b/lib/Kconfig
index 19649517a39..4f5dfc00d6f 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -477,6 +477,13 @@ config VPL_TPM
  for the low-level TPM interface, but only one TPM is supported at
  a time by the TPM library.
 
+config KASLR_RNG_SEED
+   bool "Use RNG driver for KASLR random seed"
+   depends on DM_RNG
+   help
+ This enables support for using the RNG driver as entropy source for
+ KASLR seed populated in kernel's device tree.
+
 endmenu
 
 menu "Android Verified Boot"
-- 
2.42.0



[PATCH v3 0/3] BOOTP/DHCPv4 enhancements

2023-11-03 Thread seanedmond
From: Sean Edmond 

In our datacenter application, a single DHCP server is servicing 36000+ clients.
Improvements are required to the DHCPv4 retransmission behavior to align with
RFC and ensure less pressure is exerted on the server:
- retransmission backoff interval maximum is configurable 
  (environment variable bootpretransmitperiodmax)
- initial retransmission backoff interval is configurable 
  (environment variable bootpretransmitperiodinit)
- transaction ID is kept the same for each BOOTP/DHCPv4 request 
  (not recreated on each retry)

For our application we'll use:
- bootpretransmitperiodmax=16000
- bootpretransmitperiodinit=2000

A new configuration BOOTP_RANDOM_XID has been added to enable a randomized
BOOTP/DHCPv4 transaction ID.

Add functionality for DHCPv4 sending/parsing option 209 (PXE config file).
Enabled with Kconfig BOOTP_PXE_DHCP_OPTION.  Note, this patch was
submitted previously but this latest version has been enhanced to
avoid a possible double free().

changes in v3:
- add define for option 209 and rfc5071 reference
- Set RETRANSMIT_PERIOD_MAX_MS=6
- Add randomization factor to retransmission timeout
- Add depends for BOOTP_RANDOM_XID

changes in v2:
- use env_get_ulong() to get environment variables

Sean Edmond (3):
  net: Get pxe config file from dhcp option 209
  net: bootp: BOOTP/DHCPv4 retransmission improvements
  net: bootp: add config option BOOTP_RANDOM_XID

Sean Edmond (3):
  net: Get pxe config file from dhcp option 209
  net: bootp: BOOTP/DHCPv4 retransmission improvements
  net: bootp: add config option BOOTP_RANDOM_XID

 cmd/Kconfig | 11 +++
 cmd/pxe.c   | 10 ++
 net/bootp.c | 93 -
 net/bootp.h |  2 ++
 4 files changed, 101 insertions(+), 15 deletions(-)

-- 
2.42.0



[PATCH v3 1/3] net: Get pxe config file from dhcp option 209

2023-11-03 Thread seanedmond
From: Sean Edmond 

Allow dhcp server pass pxe config file full path by using option 209
as specified in RFC5071.

Signed-off-by: Sean Edmond 
---
 cmd/Kconfig |  4 
 cmd/pxe.c   | 10 ++
 net/bootp.c | 21 +
 net/bootp.h |  2 ++
 4 files changed, 37 insertions(+)

diff --git a/cmd/Kconfig b/cmd/Kconfig
index fd16c3a48e5..df6d71c103f 100644
--- a/cmd/Kconfig
+++ b/cmd/Kconfig
@@ -1840,6 +1840,10 @@ config BOOTP_PXE_CLIENTARCH
default 0x15 if ARM
default 0x0 if X86
 
+config BOOTP_PXE_DHCP_OPTION
+   bool "Request & store 'pxe_configfile' from BOOTP/DHCP server"
+   depends on BOOTP_PXE
+
 config BOOTP_VCI_STRING
string
depends on CMD_BOOTP
diff --git a/cmd/pxe.c b/cmd/pxe.c
index 704589702f2..9404f445187 100644
--- a/cmd/pxe.c
+++ b/cmd/pxe.c
@@ -65,6 +65,8 @@ static int pxe_dhcp_option_path(struct pxe_context *ctx, 
unsigned long pxefile_a
int ret = get_pxe_file(ctx, pxelinux_configfile, pxefile_addr_r);
 
free(pxelinux_configfile);
+   /* set to NULL to avoid double-free if DHCP is tried again */
+   pxelinux_configfile = NULL;
 
return ret;
 }
@@ -141,6 +143,14 @@ int pxe_get(ulong pxefile_addr_r, char **bootdirp, ulong 
*sizep, bool use_ipv6)
  env_get("bootfile"), use_ipv6))
return -ENOMEM;
 
+   if (IS_ENABLED(CONFIG_BOOTP_PXE_DHCP_OPTION) &&
+   pxelinux_configfile && !use_ipv6) {
+   if (pxe_dhcp_option_path(, pxefile_addr_r) > 0)
+   goto done;
+
+   goto error_exit;
+   }
+
if (IS_ENABLED(CONFIG_DHCP6_PXE_DHCP_OPTION) &&
pxelinux_configfile && use_ipv6) {
if (pxe_dhcp_option_path(, pxefile_addr_r) > 0)
diff --git a/net/bootp.c b/net/bootp.c
index 7b0f45e18a9..24547cf7bfd 100644
--- a/net/bootp.c
+++ b/net/bootp.c
@@ -26,6 +26,7 @@
 #ifdef CONFIG_BOOTP_RANDOM_DELAY
 #include "net_rand.h"
 #endif
+#include 
 
 #define BOOTP_VENDOR_MAGIC 0x63825363  /* RFC1048 Magic Cookie */
 
@@ -601,6 +602,10 @@ static int dhcp_extended(u8 *e, int message_type, struct 
in_addr server_ip,
*e++  = 42;
*cnt += 1;
 #endif
+   if (IS_ENABLED(CONFIG_BOOTP_PXE_DHCP_OPTION)) {
+   *e++ = DHCP_OPTION_PXE_CONFIG_FILE; /* PXELINUX Config File 
*/
+   *cnt += 1;
+   }
/* no options, so back up to avoid sending an empty request list */
if (*cnt == 0)
e -= 2;
@@ -909,6 +914,22 @@ static void dhcp_process_options(uchar *popt, uchar *end)
net_boot_file_name[size] = 0;
}
break;
+   case DHCP_OPTION_PXE_CONFIG_FILE:   /* PXELINUX Config File 
*/
+   if (IS_ENABLED(CONFIG_BOOTP_PXE_DHCP_OPTION)) {
+   /* In case it has already been allocated when 
get DHCP Offer packet,
+* free first to avoid memory leak.
+*/
+   if (pxelinux_configfile)
+   free(pxelinux_configfile);
+
+   pxelinux_configfile = (char *)malloc((oplen + 
1) * sizeof(char));
+
+   if (pxelinux_configfile)
+   strlcpy(pxelinux_configfile, popt + 2, 
oplen + 1);
+   else
+   printf("Error: Failed to allocate 
pxelinux_configfile\n");
+   }
+   break;
default:
 #if defined(CONFIG_BOOTP_VENDOREX)
if (dhcp_vendorex_proc(popt))
diff --git a/net/bootp.h b/net/bootp.h
index 4e32b19d424..24b32c73f62 100644
--- a/net/bootp.h
+++ b/net/bootp.h
@@ -91,6 +91,8 @@ typedef enum { INIT,
 #define DHCP_NAK  6
 #define DHCP_RELEASE  7
 
+#define DHCP_OPTION_PXE_CONFIG_FILE209 /* "ConfigFile" option 
according to rfc5071 */
+
 /**/
 
 #endif /* __BOOTP_H__ */
-- 
2.42.0



[PATCH v3 2/3] net: bootp: BOOTP/DHCPv4 retransmission improvements

2023-11-03 Thread seanedmond
From: Sean Edmond 

This patch introduces 3 improvements to align with RFC 951:
- retransmission backoff interval maximum is configurable
- initial retranmission backoff interval is configurable
- transaction ID is kept the same for each BOOTP/DHCPv4 request

In applications where thousands of nodes are serviced by a single DHCP
server, maximizing the retransmission backoff interval at 2 seconds (the
current u-boot default) exerts high pressure on the DHCP server and
network layer.

RFC 951 “7.2. Client Retransmission Strategy” states that the
retransmission backoff interval should be limited to 60 seconds.  This
patch allows the interval to be configurable using the environment
variable "bootpretransmitperiodmax"

The initial retranmission backoff period defaults to 250ms, which is
also too small for these scenarios with many clients.  This patch makes
the initial retransmission interval to be configurable using the
environment variable "bootpretransmitperiodinit".

Also, on a retransmission it is not expected for the transaction ID to
change (only the 'secs' field should be updated). Let's save the
transaction ID and use the same transaction ID for each BOOTP/DHCPv4
exchange.

Signed-off-by: Sean Edmond 
---
 net/bootp.c | 71 +
 1 file changed, 55 insertions(+), 16 deletions(-)

diff --git a/net/bootp.c b/net/bootp.c
index 24547cf7bfd..9e4f37239da 100644
--- a/net/bootp.c
+++ b/net/bootp.c
@@ -42,6 +42,22 @@
  */
 #define TIMEOUT_MS ((3 + (CONFIG_NET_RETRY_COUNT * 5)) * 1000)
 
+/*
+ * According to rfc951 : 7.2. Client Retransmission Strategy
+ * "After the 'average' backoff reaches about 60 seconds, it should be
+ * increased no further, but still randomized."
+ *
+ * U-Boot has saturated this backoff at 2 seconds for a long time.
+ * To modify, set the environment variable "bootpretransmitperiodmax"
+ */
+#define RETRANSMIT_PERIOD_MAX_MS   6
+
+/* Retransmission timeout for the initial packet (in milliseconds).
+ * This timeout will double on each retry.  To modify, set the
+ * environment variable bootpretransmitperiodinit.
+ */
+#define RETRANSMIT_PERIOD_INIT_MS  250
+
 #ifndef CFG_DHCP_MIN_EXT_LEN   /* minimal length of extension list */
 #define CFG_DHCP_MIN_EXT_LEN 64
 #endif
@@ -53,6 +69,7 @@
 u32bootp_ids[CFG_BOOTP_ID_CACHE_SIZE];
 unsigned int   bootp_num_ids;
 intbootp_try;
+u32bootp_id;
 ulong  bootp_start;
 ulong  bootp_timeout;
 char net_nis_domain[32] = {0,}; /* Our NIS domain */
@@ -60,6 +77,7 @@ char net_hostname[32] = {0,}; /* Our hostname */
 char net_root_path[CONFIG_BOOTP_MAX_ROOT_PATH_LEN] = {0,}; /* Our bootpath */
 
 static ulong time_taken_max;
+static u32   retransmit_period_max_ms;
 
 #if defined(CONFIG_CMD_DHCP)
 static dhcp_state_t dhcp_state = INIT;
@@ -396,6 +414,7 @@ static void bootp_handler(uchar *pkt, unsigned dest, struct 
in_addr sip,
 static void bootp_timeout_handler(void)
 {
ulong time_taken = get_timer(bootp_start);
+   int rand_minus_plus_100;
 
if (time_taken >= time_taken_max) {
 #ifdef CONFIG_BOOTP_MAY_FAIL
@@ -414,8 +433,17 @@ static void bootp_timeout_handler(void)
}
} else {
bootp_timeout *= 2;
-   if (bootp_timeout > 2000)
-   bootp_timeout = 2000;
+   if (bootp_timeout > retransmit_period_max_ms)
+   bootp_timeout = retransmit_period_max_ms;
+
+   /* Randomize by adding bootp_timeout*RAND, where RAND
+* is a randomization factor between -0.1..+0.1
+*/
+   srand(get_ticks() + rand());
+   rand_minus_plus_100 = ((rand() % 200) - 100);
+   bootp_timeout = bootp_timeout +
+   ((bootp_timeout * rand_minus_plus_100) / 1000);
+
net_set_timeout_handler(bootp_timeout, bootp_timeout_handler);
bootp_request();
}
@@ -711,10 +739,14 @@ static int bootp_extended(u8 *e)
 
 void bootp_reset(void)
 {
+   char *ep;  /* Environment pointer */
+
bootp_num_ids = 0;
bootp_try = 0;
bootp_start = get_timer(0);
-   bootp_timeout = 250;
+
+   bootp_timeout = env_get_ulong("bootpretransmitperiodinit", 10, 
RETRANSMIT_PERIOD_INIT_MS);
+
 }
 
 void bootp_request(void)
@@ -726,7 +758,6 @@ void bootp_request(void)
 #ifdef CONFIG_BOOTP_RANDOM_DELAY
ulong rand_ms;
 #endif
-   u32 bootp_id;
struct in_addr zero_ip;
struct in_addr bcast_ip;
char *ep;  /* Environment pointer */
@@ -742,6 +773,9 @@ void bootp_request(void)
else
time_taken_max = TIMEOUT_MS;
 
+   retransmit_period_max_ms = env_get_ulong("bootpretransmitperiodmax", 10,
+RETRANSMIT_PERIOD_MAX_MS);
+
 #ifdef CONFIG_BOOTP_RANDOM_DELAY   /* Random BOOTP delay */
if 

[PATCH v3 3/3] net: bootp: add config option BOOTP_RANDOM_XID

2023-11-03 Thread seanedmond
From: Sean Edmond 

The new config option BOOTP_RANDOM_XID will randomize the transaction ID
for each new BOOT/DHCPv4 exchange.

Signed-off-by: Sean Edmond 
---
 cmd/Kconfig |  7 +++
 net/bootp.c | 31 +--
 2 files changed, 24 insertions(+), 14 deletions(-)

diff --git a/cmd/Kconfig b/cmd/Kconfig
index df6d71c103f..ba3c7a34806 100644
--- a/cmd/Kconfig
+++ b/cmd/Kconfig
@@ -1852,6 +1852,13 @@ config BOOTP_VCI_STRING
default "U-Boot.arm" if ARM
default "U-Boot"
 
+config BOOTP_RANDOM_XID
+   bool "Send random transaction ID to BOOTP/DHCP server"
+   depends on CMD_BOOTP && (LIB_RAND || EXYNOS_ACE_SHA || RNG_NPCM)
+   help
+ Selecting this will allow for a random transaction ID to get
+ selected for each BOOTP/DHCPv4 exchange.
+
 if CMD_DHCP6
 
 config DHCP6_PXE_CLIENTARCH
diff --git a/net/bootp.c b/net/bootp.c
index 9e4f37239da..a8cddcb32e0 100644
--- a/net/bootp.c
+++ b/net/bootp.c
@@ -837,22 +837,25 @@ void bootp_request(void)
 
/* Only generate a new transaction ID for each new BOOTP request */
if (bootp_try == 1) {
-   /*
-*  Bootp ID is the lower 4 bytes of our ethernet address
-*  plus the current time in ms.
-*/
-   bootp_id = ((u32)net_ethaddr[2] << 24)
-   | ((u32)net_ethaddr[3] << 16)
-   | ((u32)net_ethaddr[4] << 8)
-   | (u32)net_ethaddr[5];
-   bootp_id += get_timer(0);
-   bootp_id = htonl(bootp_id);
-   bootp_add_id(bootp_id);
-   net_copy_u32(>bp_id, _id);
-   } else {
-   net_copy_u32(>bp_id, _id);
+   if (IS_ENABLED(CONFIG_BOOTP_RANDOM_XID)) {
+   srand(get_ticks() + rand());
+   bootp_id = rand();
+   } else {
+   /*
+*  Bootp ID is the lower 4 bytes of our ethernet 
address
+*  plus the current time in ms.
+*/
+   bootp_id = ((u32)net_ethaddr[2] << 24)
+   | ((u32)net_ethaddr[3] << 16)
+   | ((u32)net_ethaddr[4] << 8)
+   | (u32)net_ethaddr[5];
+   bootp_id += get_timer(0);
+   bootp_id = htonl(bootp_id);
+   }
}
 
+   bootp_add_id(bootp_id);
+   net_copy_u32(>bp_id, _id);
/*
 * Calculate proper packet lengths taking into account the
 * variable size of the options field
-- 
2.42.0



[PATCH v4 4/5] dm: core: Modify default for OFNODE_MULTI_TREE

2023-11-03 Thread seanedmond
From: Sean Edmond 

There is a preference to use the "ofnode" API for FDT fixups
moving forward.  The FDT fixup will usually be for the kernel FDT.  To
fixup the kernel FDT with the ofnode API, it's required to set the
OFNODE_MULTI_TREE option.

To ensure existing users of kaslr fdt fixup are not impacted, Let's modify
the default value for OFNODE_MULTI_TREE to ensure it's always set if
!OF_LIVE.  This will cause a 1007 byte increase in the code size.

Signed-off-by: Sean Edmond 
---
 drivers/core/Kconfig | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/core/Kconfig b/drivers/core/Kconfig
index fe5c41d57ec..f8f4d429eba 100644
--- a/drivers/core/Kconfig
+++ b/drivers/core/Kconfig
@@ -424,7 +424,8 @@ config DM_DEV_READ_INLINE
 
 config OFNODE_MULTI_TREE
bool "Allow the ofnode interface to access any tree"
-   default y if EVENT && !DM_DEV_READ_INLINE && !DM_INLINE_OFNODE
+   depends on OF_CONTROL
+   default y if !OF_LIVE
help
  Normally U-Boot makes use of its control FDT, the one used to bind
  devices and provide options. In some cases, U-Boot must also process
-- 
2.42.0



[PATCH v4 2/5] fdt: kaslr seed from RNG device

2023-11-03 Thread seanedmond
From: Dhananjay Phadke 

Add support for KASLR seed from the RNG device. Invokes dm_rng_read()
API to read 8-bytes of random bytes.  Performs the FDT fixup using event
spy.  To enable use CONFIG_KASLR_RNG_SEED

Signed-off-by: Dhananjay Phadke 
Signed-off-by: Drew Kluemke 
Signed-off-by: Sean Edmond 
---
 boot/fdt_support.c | 36 
 lib/Kconfig|  7 +++
 2 files changed, 43 insertions(+)

diff --git a/boot/fdt_support.c b/boot/fdt_support.c
index 52be4375b46..09ce5828659 100644
--- a/boot/fdt_support.c
+++ b/boot/fdt_support.c
@@ -12,7 +12,10 @@
 #include 
 #include 
 #include 
+#include 
 #include 
+#include 
+#include 
 #include 
 #include 
 #include 
@@ -650,6 +653,39 @@ int fdt_fixup_kaslr_seed(ofnode node, const u8 *seed, int 
len)
return 0;
 }
 
+int fdt_rng_kaslr_seed(void *ctx, struct event *event)
+{
+   u8 rand[8] = {0};
+   struct udevice *dev;
+   int ret;
+   oftree tree = event->data.ft_fixup.tree;
+   ofnode root_node = oftree_root(tree);
+
+   ret = uclass_first_device_err(UCLASS_RNG, );
+   if (ret) {
+   printf("ERROR: Failed to find RNG device\n");
+   return ret;
+   }
+
+   ret = dm_rng_read(dev, rand, sizeof(rand));
+   if (ret) {
+   printf("ERROR: RNG read failed, ret=%d\n", ret);
+   return ret;
+   }
+
+   ret = fdt_fixup_kaslr_seed(root_node, rand, sizeof(rand));
+   if (ret) {
+   printf("ERROR: failed to add kaslr-seed to fdt\n");
+   return ret;
+   }
+
+   return 0;
+}
+
+#if defined(CONFIG_KASLR_RNG_SEED)
+EVENT_SPY(EVT_FT_FIXUP, fdt_rng_kaslr_seed);
+#endif
+
 int fdt_record_loadable(void *blob, u32 index, const char *name,
uintptr_t load_addr, u32 size, uintptr_t entry_point,
const char *type, const char *os, const char *arch)
diff --git a/lib/Kconfig b/lib/Kconfig
index 19649517a39..4f5dfc00d6f 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -477,6 +477,13 @@ config VPL_TPM
  for the low-level TPM interface, but only one TPM is supported at
  a time by the TPM library.
 
+config KASLR_RNG_SEED
+   bool "Use RNG driver for KASLR random seed"
+   depends on DM_RNG
+   help
+ This enables support for using the RNG driver as entropy source for
+ KASLR seed populated in kernel's device tree.
+
 endmenu
 
 menu "Android Verified Boot"
-- 
2.42.0



[PATCH v4 3/5] cmd: kaslrseed: Use common API to fixup FDT

2023-11-03 Thread seanedmond
From: Sean Edmond 

Use the newly introduced common API fdt_fixup_kaslr_seed() in the
kaslrseed command.

Signed-off-by: Sean Edmond 
---
 cmd/kaslrseed.c | 22 --
 1 file changed, 8 insertions(+), 14 deletions(-)

diff --git a/cmd/kaslrseed.c b/cmd/kaslrseed.c
index 9acb8e16386..6f423702e7c 100644
--- a/cmd/kaslrseed.c
+++ b/cmd/kaslrseed.c
@@ -19,7 +19,7 @@ static int do_kaslr_seed(struct cmd_tbl *cmdtp, int flag, int 
argc, char *const
size_t n = 0x8;
struct udevice *dev;
u64 *buf;
-   int nodeoffset;
+   ofnode root;
int ret = CMD_RET_SUCCESS;
 
if (uclass_get_device(UCLASS_RNG, 0, ) || !dev) {
@@ -45,21 +45,15 @@ static int do_kaslr_seed(struct cmd_tbl *cmdtp, int flag, 
int argc, char *const
return CMD_RET_FAILURE;
}
 
-   ret = fdt_check_header(working_fdt);
-   if (ret < 0) {
-   printf("fdt_chosen: %s\n", fdt_strerror(ret));
-   return CMD_RET_FAILURE;
-   }
-
-   nodeoffset = fdt_find_or_add_subnode(working_fdt, 0, "chosen");
-   if (nodeoffset < 0) {
-   printf("Reading chosen node failed\n");
-   return CMD_RET_FAILURE;
+   ret = root_ofnode_from_fdt(working_fdt, );
+   if (ret) {
+   printf("ERROR: Unable to get root ofnode\n");
+   goto CMD_RET_FAILURE;
}
 
-   ret = fdt_setprop(working_fdt, nodeoffset, "kaslr-seed", buf, 
sizeof(buf));
-   if (ret < 0) {
-   printf("Unable to set kaslr-seed on chosen node: %s\n", 
fdt_strerror(ret));
+   ret = fdt_fixup_kaslr_seed(root, buf, sizeof(buf));
+   if (ret) {
+   printf("ERROR: failed to add kaslr-seed to fdt\n");
return CMD_RET_FAILURE;
}
 
-- 
2.42.0



[PATCH v4 5/5] fdt: Fix compile error for !OFNODE_MULTI_TREE

2023-11-03 Thread seanedmond
From: Sean Edmond 

Required to fix the following compile error when building sandbox:
/tmp/cci9ibby.ltrans21.ltrans.o: In function `do_cedit_load':
:(.text+0x601d): undefined reference to `oftree_dispose'

Signed-off-by: Sean Edmond 
---
 drivers/core/ofnode.c | 12 ++--
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/drivers/core/ofnode.c b/drivers/core/ofnode.c
index 55291f0202b..c3d326831fc 100644
--- a/drivers/core/ofnode.c
+++ b/drivers/core/ofnode.c
@@ -135,12 +135,6 @@ int oftree_new(oftree *treep)
return 0;
 }
 
-void oftree_dispose(oftree tree)
-{
-   if (of_live_active())
-   of_live_free(tree.np);
-}
-
 void *ofnode_lookup_fdt(ofnode node)
 {
if (gd->flags & GD_FLG_RELOC) {
@@ -243,6 +237,12 @@ int oftree_new(oftree *treep)
 
 #endif /* OFNODE_MULTI_TREE */
 
+void oftree_dispose(oftree tree)
+{
+   if (of_live_active())
+   of_live_free(tree.np);
+}
+
 int oftree_to_fdt(oftree tree, struct abuf *buf)
 {
int ret;
-- 
2.42.0



[PATCH v4 1/5] fdt: common API to populate kaslr seed

2023-11-03 Thread seanedmond
From: Dhananjay Phadke 

fdt_fixup_kaslr_seed() will update given ofnode with random seed value.
Source for random seed can be TPM or RNG driver in u-boot or sec
firmware (ARM).

Signed-off-by: Dhananjay Phadke 
Signed-off-by: Sean Edmond 
---
 arch/arm/cpu/armv8/sec_firmware.c | 39 +++
 boot/fdt_support.c| 19 +++
 drivers/core/ofnode.c | 17 ++
 include/dm/ofnode.h   | 12 ++
 include/fdt_support.h |  9 +++
 5 files changed, 71 insertions(+), 25 deletions(-)

diff --git a/arch/arm/cpu/armv8/sec_firmware.c 
b/arch/arm/cpu/armv8/sec_firmware.c
index c0e8726346f..5f04cd8aecd 100644
--- a/arch/arm/cpu/armv8/sec_firmware.c
+++ b/arch/arm/cpu/armv8/sec_firmware.c
@@ -411,46 +411,35 @@ int sec_firmware_init(const void *sec_firmware_img,
 /*
  * fdt_fix_kaslr - Add kalsr-seed node in Device tree
  * @fdt:   Device tree
- * @eret:  0 in case of error, 1 for success
+ * @eret:  0 for success
  */
 int fdt_fixup_kaslr(void *fdt)
 {
-   int nodeoffset;
-   int err, ret = 0;
-   u8 rand[8];
+   int ret = 0;
 
 #if defined(CONFIG_ARMV8_SEC_FIRMWARE_SUPPORT)
+   u8 rand[8];
+   ofnode root;
+
/* Check if random seed generation is  supported */
if (sec_firmware_support_hwrng() == false) {
printf("WARNING: SEC firmware not running, no kaslr-seed\n");
-   return 0;
+   return -EOPNOTSUPP;
}
 
-   err = sec_firmware_get_random(rand, 8);
-   if (err < 0) {
+   ret = sec_firmware_get_random(rand, 8);
+   if (ret < 0) {
printf("WARNING: No random number to set kaslr-seed\n");
-   return 0;
+   return ret;
}
 
-   err = fdt_check_header(fdt);
-   if (err < 0) {
-   printf("fdt_chosen: %s\n", fdt_strerror(err));
-   return 0;
+   ret = root_ofnode_from_fdt(fdt, );
+   if (ret < 0) {
+   printf("WARNING: Unable to get root ofnode\n");
+   return ret;
}
 
-   /* find or create "/chosen" node. */
-   nodeoffset = fdt_find_or_add_subnode(fdt, 0, "chosen");
-   if (nodeoffset < 0)
-   return 0;
-
-   err = fdt_setprop(fdt, nodeoffset, "kaslr-seed", rand,
- sizeof(rand));
-   if (err < 0) {
-   printf("WARNING: can't set kaslr-seed %s.\n",
-  fdt_strerror(err));
-   return 0;
-   }
-   ret = 1;
+   ret = fdt_fixup_kaslr_seed(root, rand, sizeof(rand));
 #endif
 
return ret;
diff --git a/boot/fdt_support.c b/boot/fdt_support.c
index 5e49078f8c3..52be4375b46 100644
--- a/boot/fdt_support.c
+++ b/boot/fdt_support.c
@@ -631,6 +631,25 @@ void fdt_fixup_ethernet(void *fdt)
}
 }
 
+int fdt_fixup_kaslr_seed(ofnode node, const u8 *seed, int len)
+{
+   ofnode chosen;
+   int ret;
+
+   /* find or create "/chosen" node. */
+   ret = ofnode_add_subnode(node, "chosen", );
+   if (ret && ret != -EEXIST)
+   return -ENOENT;
+
+   ret = ofnode_write_prop(chosen, "kaslr-seed", seed, len, true);
+   if (ret) {
+   printf("WARNING: can't set kaslr-seed\n");
+   return ret;
+   }
+
+   return 0;
+}
+
 int fdt_record_loadable(void *blob, u32 index, const char *name,
uintptr_t load_addr, u32 size, uintptr_t entry_point,
const char *type, const char *os, const char *arch)
diff --git a/drivers/core/ofnode.c b/drivers/core/ofnode.c
index 29a42945102..55291f0202b 100644
--- a/drivers/core/ofnode.c
+++ b/drivers/core/ofnode.c
@@ -966,6 +966,23 @@ ofnode oftree_path(oftree tree, const char *path)
}
 }
 
+int root_ofnode_from_fdt(void *fdt, ofnode *root_node)
+{
+   oftree tree;
+   /* If OFNODE_MULTI_TREE is not set, and if fdt is not the control FDT,
+*  oftree_from_fdt() will return NULL
+*/
+   tree = oftree_from_fdt(fdt);
+
+   if (!oftree_valid(tree)) {
+   printf("Cannot create oftree\n");
+   return -EINVAL;
+   }
+   *root_node = oftree_root(tree);
+
+   return 0;
+}
+
 const void *ofnode_read_chosen_prop(const char *propname, int *sizep)
 {
ofnode chosen_node;
diff --git a/include/dm/ofnode.h b/include/dm/ofnode.h
index 19e97a90327..5759cac5b30 100644
--- a/include/dm/ofnode.h
+++ b/include/dm/ofnode.h
@@ -936,6 +936,18 @@ ofnode oftree_path(oftree tree, const char *path);
  */
 ofnode oftree_root(oftree tree);
 
+/**
+ * root_ofnode_from_fdt() - Gets the root ofnode given an FDT blob.
+ *  Note, this will fail if OFNODE_MULTI_TREE
+ *  is not set.
+ *
+ * @fdt: Device tree to use
+ * @root_node : Root ofnode
+ *
+ * Return: 0 if OK, -ve on error
+ */
+int root_ofnode_from_fdt(void *fdt, ofnode 

[PATCH v4 0/5] Populate kaslr seed with RNG

2023-11-03 Thread seanedmond
From: Sean Edmond 

This patch series creates a common API (fdt_fixup_kaslr_seed()) for 
populating the kaslr seed in the DTB.  Existing users (kaslrseed,
and ARMv8 sec firmware) have been updated to use this common API.

New functionality has been introduced to populate the kaslr using
the RNG.  This can be enabled with CONFIG_RNG_TPM_SEED.  

changes in v4:
- Fix compile issue when CONFIG_OF_CONTROL not set

changes in v3:
- Populate with RNG device instead of TPM device (this is a more generic 
solution)
- Use event spy to do the FDT fixup
- fix compile error for sandbox for !OFNODE_MULTI_TREE

changes in v2:
- fdt_fixup_kaslr_seed() uses the ofnode API
- Add root_ofnode_from_fdt() to get the root node from an FDT and
  perform error checking on the oftree
- add comments to exported functions
- Add error checking in image_setup_libfdt() for return from
  fdt_tpm_kaslr_seed()
- uclass_get_device() -> uclass_first_device_err()
- Change default config for OFNODE_MULTI_TREE (y if !OF_LIVE)

Dhananjay Phadke (2):
  fdt: common API to populate kaslr seed
  fdt: kaslr seed from RNG device

Sean Edmond (3):
  cmd: kaslrseed: Use common API to fixup FDT
  dm: core: Modify default for OFNODE_MULTI_TREE
  fdt: Fix compile error for !OFNODE_MULTI_TREE

 arch/arm/cpu/armv8/sec_firmware.c | 39 --
 boot/fdt_support.c| 55 +++
 cmd/kaslrseed.c   | 22 +
 drivers/core/Kconfig  |  3 +-
 drivers/core/ofnode.c | 29 
 include/dm/ofnode.h   | 12 +++
 include/fdt_support.h |  9 +
 lib/Kconfig   |  7 
 8 files changed, 130 insertions(+), 46 deletions(-)

-- 
2.42.0



[PATCH v2 3/3] net: bootp: add config option BOOTP_RANDOM_XID

2023-10-23 Thread seanedmond
From: Sean Edmond 

The new config option BOOTP_RANDOM_XID will randomize the transaction ID
for each new BOOT/DHCPv4 exchange.

Signed-off-by: Sean Edmond 
---
 cmd/Kconfig |  7 +++
 net/bootp.c | 31 +--
 2 files changed, 24 insertions(+), 14 deletions(-)

diff --git a/cmd/Kconfig b/cmd/Kconfig
index adbb1a6187..910f465d14 100644
--- a/cmd/Kconfig
+++ b/cmd/Kconfig
@@ -1838,6 +1838,13 @@ config BOOTP_VCI_STRING
default "U-Boot.arm" if ARM
default "U-Boot"
 
+config BOOTP_RANDOM_XID
+   bool "Send random transaction ID to BOOTP/DHCP server"
+   depends on CMD_BOOTP
+   help
+ Selecting this will allow for a random transaction ID to get
+ selected for each BOOTP/DHCPv4 exchange.
+
 if CMD_DHCP6
 
 config DHCP6_PXE_CLIENTARCH
diff --git a/net/bootp.c b/net/bootp.c
index bab17a9ceb..f1ca2efacf 100644
--- a/net/bootp.c
+++ b/net/bootp.c
@@ -822,22 +822,25 @@ void bootp_request(void)
 
/* Only generate a new transaction ID for each new BOOTP request */
if (bootp_try == 1) {
-   /*
-*  Bootp ID is the lower 4 bytes of our ethernet address
-*  plus the current time in ms.
-*/
-   bootp_id = ((u32)net_ethaddr[2] << 24)
-   | ((u32)net_ethaddr[3] << 16)
-   | ((u32)net_ethaddr[4] << 8)
-   | (u32)net_ethaddr[5];
-   bootp_id += get_timer(0);
-   bootp_id = htonl(bootp_id);
-   bootp_add_id(bootp_id);
-   net_copy_u32(>bp_id, _id);
-   } else {
-   net_copy_u32(>bp_id, _id);
+   if (IS_ENABLED(CONFIG_BOOTP_RANDOM_XID)) {
+   srand(get_ticks() + rand());
+   bootp_id = rand();
+   } else {
+   /*
+*  Bootp ID is the lower 4 bytes of our ethernet 
address
+*  plus the current time in ms.
+*/
+   bootp_id = ((u32)net_ethaddr[2] << 24)
+   | ((u32)net_ethaddr[3] << 16)
+   | ((u32)net_ethaddr[4] << 8)
+   | (u32)net_ethaddr[5];
+   bootp_id += get_timer(0);
+   bootp_id = htonl(bootp_id);
+   }
}
 
+   bootp_add_id(bootp_id);
+   net_copy_u32(>bp_id, _id);
/*
 * Calculate proper packet lengths taking into account the
 * variable size of the options field
-- 
2.40.0



[PATCH v2 2/3] net: bootp: BOOTP/DHCPv4 retransmission improvements

2023-10-23 Thread seanedmond
From: Sean Edmond 

This patch introduces 3 improvements to align with RFC 951:
- retransmission backoff interval maximum is configurable
- initial retranmission backoff interval is configurable
- transaction ID is kept the same for each BOOTP/DHCPv4 request

In applications where thousands of nodes are serviced by a single DHCP
server, maximizing the retransmission backoff interval at 2 seconds (the
current u-boot default) exerts high pressure on the DHCP server and
network layer.

RFC 951 “7.2. Client Retransmission Strategy” states that the
retransmission backoff interval should maximize at 60 seconds.  This
patch allows the interval to be configurable using the environment
variable "bootpretransmitperiodmax"

The initial retranmission backoff period defaults to 250ms, which is
also too small for these scenarios with many clients.  This patch makes
the initial retransmission interval to be configurable using the
environment variable "bootpretransmitperiodinit".

Also, on a retransmission it is not expected for the transaction ID to
change (only the 'secs' field should be updated). Let's save the
transaction ID and use the same transaction ID for each BOOTP/DHCPv4
exchange.

Signed-off-by: Sean Edmond 
---
 net/bootp.c | 56 ++---
 1 file changed, 40 insertions(+), 16 deletions(-)

diff --git a/net/bootp.c b/net/bootp.c
index 6800290963..bab17a9ceb 100644
--- a/net/bootp.c
+++ b/net/bootp.c
@@ -42,6 +42,17 @@
  */
 #define TIMEOUT_MS ((3 + (CONFIG_NET_RETRY_COUNT * 5)) * 1000)
 
+/*
+ * According to rfc951 : 7.2. Client Retransmission Strategy
+ * "After the 'average' backoff reaches about 60 seconds, it should be
+ * increased no further, but still randomized."
+ *
+ * U-Boot has saturated this backoff at 2 seconds for a long time.
+ * To modify, set the environment variable "bootpretransmitperiodmax"
+ */
+#define RETRANSMIT_PERIOD_MAX_MS   2000
+#define RETRANSMIT_PERIOD_INIT_MS  250
+
 #ifndef CFG_DHCP_MIN_EXT_LEN   /* minimal length of extension list */
 #define CFG_DHCP_MIN_EXT_LEN 64
 #endif
@@ -53,6 +64,7 @@
 u32bootp_ids[CFG_BOOTP_ID_CACHE_SIZE];
 unsigned int   bootp_num_ids;
 intbootp_try;
+u32bootp_id;
 ulong  bootp_start;
 ulong  bootp_timeout;
 char net_nis_domain[32] = {0,}; /* Our NIS domain */
@@ -60,6 +72,7 @@ char net_hostname[32] = {0,}; /* Our hostname */
 char net_root_path[CONFIG_BOOTP_MAX_ROOT_PATH_LEN] = {0,}; /* Our bootpath */
 
 static ulong time_taken_max;
+static u32   retransmit_period_max_ms;
 
 #if defined(CONFIG_CMD_DHCP)
 static dhcp_state_t dhcp_state = INIT;
@@ -414,8 +427,8 @@ static void bootp_timeout_handler(void)
}
} else {
bootp_timeout *= 2;
-   if (bootp_timeout > 2000)
-   bootp_timeout = 2000;
+   if (bootp_timeout > retransmit_period_max_ms)
+   bootp_timeout = retransmit_period_max_ms;
net_set_timeout_handler(bootp_timeout, bootp_timeout_handler);
bootp_request();
}
@@ -711,10 +724,14 @@ static int bootp_extended(u8 *e)
 
 void bootp_reset(void)
 {
+   char *ep;  /* Environment pointer */
+
bootp_num_ids = 0;
bootp_try = 0;
bootp_start = get_timer(0);
-   bootp_timeout = 250;
+
+   bootp_timeout = env_get_ulong("bootpretransmitperiodinit", 10, 
RETRANSMIT_PERIOD_INIT_MS);
+
 }
 
 void bootp_request(void)
@@ -726,7 +743,6 @@ void bootp_request(void)
 #ifdef CONFIG_BOOTP_RANDOM_DELAY
ulong rand_ms;
 #endif
-   u32 bootp_id;
struct in_addr zero_ip;
struct in_addr bcast_ip;
char *ep;  /* Environment pointer */
@@ -742,6 +758,9 @@ void bootp_request(void)
else
time_taken_max = TIMEOUT_MS;
 
+   retransmit_period_max_ms = env_get_ulong("bootpretransmitperiodmax", 10,
+RETRANSMIT_PERIOD_MAX_MS);
+
 #ifdef CONFIG_BOOTP_RANDOM_DELAY   /* Random BOOTP delay */
if (bootp_try == 0)
srand_mac();
@@ -801,18 +820,23 @@ void bootp_request(void)
extlen = bootp_extended((u8 *)bp->bp_vend);
 #endif
 
-   /*
-*  Bootp ID is the lower 4 bytes of our ethernet address
-*  plus the current time in ms.
-*/
-   bootp_id = ((u32)net_ethaddr[2] << 24)
-   | ((u32)net_ethaddr[3] << 16)
-   | ((u32)net_ethaddr[4] << 8)
-   | (u32)net_ethaddr[5];
-   bootp_id += get_timer(0);
-   bootp_id = htonl(bootp_id);
-   bootp_add_id(bootp_id);
-   net_copy_u32(>bp_id, _id);
+   /* Only generate a new transaction ID for each new BOOTP request */
+   if (bootp_try == 1) {
+   /*
+*  Bootp ID is the lower 4 bytes of our ethernet address
+*  plus the current time in ms.
+*/
+  

[PATCH v2 1/3] net: Get pxe config file from dhcp option 209

2023-10-23 Thread seanedmond
From: Sean Edmond 

Allow dhcp server pass pxe config file full path by using option 209

Signed-off-by: Sean Edmond 
---
 cmd/Kconfig |  4 
 cmd/pxe.c   | 10 ++
 net/bootp.c | 21 +
 3 files changed, 35 insertions(+)

diff --git a/cmd/Kconfig b/cmd/Kconfig
index 5bc0a92d57..adbb1a6187 100644
--- a/cmd/Kconfig
+++ b/cmd/Kconfig
@@ -1826,6 +1826,10 @@ config BOOTP_PXE_CLIENTARCH
default 0x15 if ARM
default 0x0 if X86
 
+config BOOTP_PXE_DHCP_OPTION
+   bool "Request & store 'pxe_configfile' from BOOTP/DHCP server"
+   depends on BOOTP_PXE
+
 config BOOTP_VCI_STRING
string
depends on CMD_BOOTP
diff --git a/cmd/pxe.c b/cmd/pxe.c
index 704589702f..9404f44518 100644
--- a/cmd/pxe.c
+++ b/cmd/pxe.c
@@ -65,6 +65,8 @@ static int pxe_dhcp_option_path(struct pxe_context *ctx, 
unsigned long pxefile_a
int ret = get_pxe_file(ctx, pxelinux_configfile, pxefile_addr_r);
 
free(pxelinux_configfile);
+   /* set to NULL to avoid double-free if DHCP is tried again */
+   pxelinux_configfile = NULL;
 
return ret;
 }
@@ -141,6 +143,14 @@ int pxe_get(ulong pxefile_addr_r, char **bootdirp, ulong 
*sizep, bool use_ipv6)
  env_get("bootfile"), use_ipv6))
return -ENOMEM;
 
+   if (IS_ENABLED(CONFIG_BOOTP_PXE_DHCP_OPTION) &&
+   pxelinux_configfile && !use_ipv6) {
+   if (pxe_dhcp_option_path(, pxefile_addr_r) > 0)
+   goto done;
+
+   goto error_exit;
+   }
+
if (IS_ENABLED(CONFIG_DHCP6_PXE_DHCP_OPTION) &&
pxelinux_configfile && use_ipv6) {
if (pxe_dhcp_option_path(, pxefile_addr_r) > 0)
diff --git a/net/bootp.c b/net/bootp.c
index 7b0f45e18a..6800290963 100644
--- a/net/bootp.c
+++ b/net/bootp.c
@@ -26,6 +26,7 @@
 #ifdef CONFIG_BOOTP_RANDOM_DELAY
 #include "net_rand.h"
 #endif
+#include 
 
 #define BOOTP_VENDOR_MAGIC 0x63825363  /* RFC1048 Magic Cookie */
 
@@ -601,6 +602,10 @@ static int dhcp_extended(u8 *e, int message_type, struct 
in_addr server_ip,
*e++  = 42;
*cnt += 1;
 #endif
+   if (IS_ENABLED(CONFIG_BOOTP_PXE_DHCP_OPTION)) {
+   *e++ = 209; /* PXELINUX Config File */
+   *cnt += 1;
+   }
/* no options, so back up to avoid sending an empty request list */
if (*cnt == 0)
e -= 2;
@@ -909,6 +914,22 @@ static void dhcp_process_options(uchar *popt, uchar *end)
net_boot_file_name[size] = 0;
}
break;
+   case 209:   /* PXELINUX Config File */
+   if (IS_ENABLED(CONFIG_BOOTP_PXE_DHCP_OPTION)) {
+   /* In case it has already been allocated when 
get DHCP Offer packet,
+* free first to avoid memory leak.
+*/
+   if (pxelinux_configfile)
+   free(pxelinux_configfile);
+
+   pxelinux_configfile = (char *)malloc((oplen + 
1) * sizeof(char));
+
+   if (pxelinux_configfile)
+   strlcpy(pxelinux_configfile, popt + 2, 
oplen + 1);
+   else
+   printf("Error: Failed to allocate 
pxelinux_configfile\n");
+   }
+   break;
default:
 #if defined(CONFIG_BOOTP_VENDOREX)
if (dhcp_vendorex_proc(popt))
-- 
2.40.0



[PATCH v2 0/3] BOOTP/DHCPv4 enhancements

2023-10-23 Thread seanedmond
From: Sean Edmond 

In our datacenter application, a single DHCP server is servicing 36000+ clients.
Improvements are required to the DHCPv4 retransmission behavior to align with
RFC and ensure less pressure is exerted on the server:
- retransmission backoff interval maximum is configurable 
  (environment variable bootpretransmitperiodmax)
- initial retransmission backoff interval is configurable 
  (environment variable bootpretransmitperiodinit)
- transaction ID is kept the same for each BOOTP/DHCPv4 request 
  (not recreated on each retry)

For our application we'll use:
- bootpretransmitperiodmax=16000
- bootpretransmitperiodinit=2000

A new configuration BOOTP_RANDOM_XID has been added to enable a randomized
BOOTP/DHCPv4 transaction ID.

Add functionality for DHCPv4 sending/parsing option 209 (PXE config file).
Enabled with Kconfig BOOTP_PXE_DHCP_OPTION.  Note, this patch was
submitted previously but this latest version has been enhanced to
avoid a possible double free().

changes in v2:
- use env_get_ulong() to get environment variables

Sean Edmond (3):
  net: Get pxe config file from dhcp option 209
  net: bootp: BOOTP/DHCPv4 retransmission improvements
  net: bootp: add config option BOOTP_RANDOM_XID

 cmd/Kconfig | 11 
 cmd/pxe.c   | 10 +++
 net/bootp.c | 78 ++---
 3 files changed, 84 insertions(+), 15 deletions(-)

-- 
2.40.0



[PATCH 1/3] net: Get pxe config file from dhcp option 209

2023-09-25 Thread seanedmond
From: Sean Edmond 

Allow dhcp server pass pxe config file full path by using option 209

Signed-off-by: Sean Edmond 
---
 cmd/Kconfig |  4 
 cmd/pxe.c   | 10 ++
 net/bootp.c | 21 +
 3 files changed, 35 insertions(+)

diff --git a/cmd/Kconfig b/cmd/Kconfig
index 43ca10f69c..25c1efc41e 100644
--- a/cmd/Kconfig
+++ b/cmd/Kconfig
@@ -1817,6 +1817,10 @@ config BOOTP_PXE_CLIENTARCH
default 0x15 if ARM
default 0 if X86
 
+config BOOTP_PXE_DHCP_OPTION
+   bool "Request & store 'pxe_configfile' from BOOTP/DHCP server"
+   depends on BOOTP_PXE
+
 config BOOTP_VCI_STRING
string
depends on CMD_BOOTP
diff --git a/cmd/pxe.c b/cmd/pxe.c
index 677142520b..83c4ed5411 100644
--- a/cmd/pxe.c
+++ b/cmd/pxe.c
@@ -65,6 +65,8 @@ static int pxe_dhcp_option_path(struct pxe_context *ctx, 
unsigned long pxefile_a
int ret = get_pxe_file(ctx, pxelinux_configfile, pxefile_addr_r);
 
free(pxelinux_configfile);
+   /* set to NULL to avoid double-free if DHCP is tried again */
+   pxelinux_configfile = NULL;
 
return ret;
 }
@@ -141,6 +143,14 @@ int pxe_get(ulong pxefile_addr_r, char **bootdirp, ulong 
*sizep, bool use_ipv6)
  env_get("bootfile"), use_ipv6))
return -ENOMEM;
 
+   if (IS_ENABLED(CONFIG_BOOTP_PXE_DHCP_OPTION) &&
+   pxelinux_configfile && !use_ipv6) {
+   if (pxe_dhcp_option_path(, pxefile_addr_r) > 0)
+   goto done;
+
+   goto error_exit;
+   }
+
if (IS_ENABLED(CONFIG_DHCP6_PXE_DHCP_OPTION) &&
pxelinux_configfile && use_ipv6) {
if (pxe_dhcp_option_path(, pxefile_addr_r) > 0)
diff --git a/net/bootp.c b/net/bootp.c
index 8b1a4ae2ef..013d54c7ed 100644
--- a/net/bootp.c
+++ b/net/bootp.c
@@ -26,6 +26,7 @@
 #ifdef CONFIG_BOOTP_RANDOM_DELAY
 #include "net_rand.h"
 #endif
+#include 
 
 #define BOOTP_VENDOR_MAGIC 0x63825363  /* RFC1048 Magic Cookie */
 
@@ -604,6 +605,10 @@ static int dhcp_extended(u8 *e, int message_type, struct 
in_addr server_ip,
*e++  = 42;
*cnt += 1;
 #endif
+   if (IS_ENABLED(CONFIG_BOOTP_PXE_DHCP_OPTION)) {
+   *e++ = 209; /* PXELINUX Config File */
+   *cnt += 1;
+   }
/* no options, so back up to avoid sending an empty request list */
if (*cnt == 0)
e -= 2;
@@ -912,6 +917,22 @@ static void dhcp_process_options(uchar *popt, uchar *end)
net_boot_file_name[size] = 0;
}
break;
+   case 209:   /* PXELINUX Config File */
+   if (IS_ENABLED(CONFIG_BOOTP_PXE_DHCP_OPTION)) {
+   /* In case it has already been allocated when 
get DHCP Offer packet,
+* free first to avoid memory leak.
+*/
+   if (pxelinux_configfile)
+   free(pxelinux_configfile);
+
+   pxelinux_configfile = (char *)malloc((oplen + 
1) * sizeof(char));
+
+   if (pxelinux_configfile)
+   strlcpy(pxelinux_configfile, popt + 2, 
oplen + 1);
+   else
+   printf("Error: Failed to allocate 
pxelinux_configfile\n");
+   }
+   break;
default:
 #if defined(CONFIG_BOOTP_VENDOREX)
if (dhcp_vendorex_proc(popt))
-- 
2.40.0



[PATCH 3/3] net: bootp: add config option BOOTP_RANDOM_XID

2023-09-25 Thread seanedmond
From: Sean Edmond 

The new config option BOOTP_RANDOM_XID will randomize the transaction ID
for each new BOOT/DHCPv4 exchange.

Signed-off-by: Sean Edmond 
---
 cmd/Kconfig |  7 +++
 net/bootp.c | 31 +--
 2 files changed, 24 insertions(+), 14 deletions(-)

diff --git a/cmd/Kconfig b/cmd/Kconfig
index 25c1efc41e..4be5be8724 100644
--- a/cmd/Kconfig
+++ b/cmd/Kconfig
@@ -1829,6 +1829,13 @@ config BOOTP_VCI_STRING
default "U-Boot.arm" if ARM
default "U-Boot"
 
+config BOOTP_RANDOM_XID
+   bool "Send random transaction ID to BOOTP/DHCP server"
+   depends on CMD_BOOTP
+   help
+ Selecting this will allow for a random transaction ID to get
+ selected for each BOOTP/DHCPv4 exchange.
+
 if CMD_DHCP6
 
 config DHCP6_PXE_CLIENTARCH
diff --git a/net/bootp.c b/net/bootp.c
index 7248536cc4..5053a1b870 100644
--- a/net/bootp.c
+++ b/net/bootp.c
@@ -832,22 +832,25 @@ void bootp_request(void)
 
/* Only generate a new transaction ID for each new BOOTP request */
if (bootp_try == 1) {
-   /*
-*  Bootp ID is the lower 4 bytes of our ethernet address
-*  plus the current time in ms.
-*/
-   bootp_id = ((u32)net_ethaddr[2] << 24)
-   | ((u32)net_ethaddr[3] << 16)
-   | ((u32)net_ethaddr[4] << 8)
-   | (u32)net_ethaddr[5];
-   bootp_id += get_timer(0);
-   bootp_id = htonl(bootp_id);
-   bootp_add_id(bootp_id);
-   net_copy_u32(>bp_id, _id);
-   } else {
-   net_copy_u32(>bp_id, _id);
+   if (IS_ENABLED(CONFIG_BOOTP_RANDOM_XID)) {
+   srand(get_ticks() + rand());
+   bootp_id = rand();
+   } else {
+   /*
+*  Bootp ID is the lower 4 bytes of our ethernet 
address
+*  plus the current time in ms.
+*/
+   bootp_id = ((u32)net_ethaddr[2] << 24)
+   | ((u32)net_ethaddr[3] << 16)
+   | ((u32)net_ethaddr[4] << 8)
+   | (u32)net_ethaddr[5];
+   bootp_id += get_timer(0);
+   bootp_id = htonl(bootp_id);
+   }
}
 
+   bootp_add_id(bootp_id);
+   net_copy_u32(>bp_id, _id);
/*
 * Calculate proper packet lengths taking into account the
 * variable size of the options field
-- 
2.40.0



[PATCH 2/3] net: bootp: BOOTP/DHCPv4 retransmission improvements

2023-09-25 Thread seanedmond
From: Sean Edmond 

This patch introduces 3 improvements to align with RFC 951:
- retransmission backoff interval maximum is configurable
- initial retranmission backoff interval is configurable
- transaction ID is kept the same for each BOOTP/DHCPv4 request

In applications where thousands of nodes are serviced by a single DHCP
server, maximizing the retransmission backoff interval at 2 seconds (the
current u-boot default) exerts high pressure on the DHCP server and
network layer.

RFC 951 “7.2. Client Retransmission Strategy” states that the
retransmission backoff interval should maximize at 60 seconds.  This
patch allows the interval to be configurable using the environment
variable "bootpretransmitperiodmax"

The initial retranmission backoff period defaults to 250ms, which is
also too small for these scenarios with many clients.  This patch makes
the initial retransmission interval to be configurable using the
environment variable "bootpretransmitperiodinit".

Also, on a retransmission it is not expected for the transaction ID to
change (only the 'secs' field should be updated). Let's save the
transaction ID and use the same transaction ID for each BOOTP/DHCPv4
exchange.

Signed-off-by: Sean Edmond 
---
 net/bootp.c | 63 +++--
 1 file changed, 47 insertions(+), 16 deletions(-)

diff --git a/net/bootp.c b/net/bootp.c
index 013d54c7ed..7248536cc4 100644
--- a/net/bootp.c
+++ b/net/bootp.c
@@ -42,6 +42,17 @@
  */
 #define TIMEOUT_MS ((3 + (CONFIG_NET_RETRY_COUNT * 5)) * 1000)
 
+/*
+ * According to rfc951 : 7.2. Client Retransmission Strategy
+ * "After the 'average' backoff reaches about 60 seconds, it should be
+ * increased no further, but still randomized."
+ *
+ * U-Boot has saturated this backoff at 2 seconds for a long time.
+ * To modify, set the environment variable "bootpretransmitperiodmax"
+ */
+#define RETRANSMIT_PERIOD_MAX_MS   2000
+#define RETRANSMIT_PERIOD_INIT_MS  250
+
 #define PORT_BOOTPS67  /* BOOTP server UDP port */
 #define PORT_BOOTPC68  /* BOOTP client UDP port */
 
@@ -56,6 +67,7 @@
 u32bootp_ids[CFG_BOOTP_ID_CACHE_SIZE];
 unsigned int   bootp_num_ids;
 intbootp_try;
+u32bootp_id;
 ulong  bootp_start;
 ulong  bootp_timeout;
 char net_nis_domain[32] = {0,}; /* Our NIS domain */
@@ -63,6 +75,7 @@ char net_hostname[32] = {0,}; /* Our hostname */
 char net_root_path[CONFIG_BOOTP_MAX_ROOT_PATH_LEN] = {0,}; /* Our bootpath */
 
 static ulong time_taken_max;
+static u32   retransmit_period_max_ms;
 
 #if defined(CONFIG_CMD_DHCP)
 static dhcp_state_t dhcp_state = INIT;
@@ -417,8 +430,8 @@ static void bootp_timeout_handler(void)
}
} else {
bootp_timeout *= 2;
-   if (bootp_timeout > 2000)
-   bootp_timeout = 2000;
+   if (bootp_timeout > retransmit_period_max_ms)
+   bootp_timeout = retransmit_period_max_ms;
net_set_timeout_handler(bootp_timeout, bootp_timeout_handler);
bootp_request();
}
@@ -714,10 +727,18 @@ static int bootp_extended(u8 *e)
 
 void bootp_reset(void)
 {
+   char *ep;  /* Environment pointer */
+
bootp_num_ids = 0;
bootp_try = 0;
bootp_start = get_timer(0);
-   bootp_timeout = 250;
+
+   ep = env_get("bootpretransmitperiodinit");
+   if (ep)
+   bootp_timeout = dectoul(ep, NULL);
+   else
+   bootp_timeout = RETRANSMIT_PERIOD_INIT_MS;
+
 }
 
 void bootp_request(void)
@@ -729,7 +750,6 @@ void bootp_request(void)
 #ifdef CONFIG_BOOTP_RANDOM_DELAY
ulong rand_ms;
 #endif
-   u32 bootp_id;
struct in_addr zero_ip;
struct in_addr bcast_ip;
char *ep;  /* Environment pointer */
@@ -745,6 +765,12 @@ void bootp_request(void)
else
time_taken_max = TIMEOUT_MS;
 
+   ep = env_get("bootpretransmitperiodmax");
+   if (ep)
+   retransmit_period_max_ms = dectoul(ep, NULL);
+   else
+   retransmit_period_max_ms = RETRANSMIT_PERIOD_MAX_MS;
+
 #ifdef CONFIG_BOOTP_RANDOM_DELAY   /* Random BOOTP delay */
if (bootp_try == 0)
srand_mac();
@@ -804,18 +830,23 @@ void bootp_request(void)
extlen = bootp_extended((u8 *)bp->bp_vend);
 #endif
 
-   /*
-*  Bootp ID is the lower 4 bytes of our ethernet address
-*  plus the current time in ms.
-*/
-   bootp_id = ((u32)net_ethaddr[2] << 24)
-   | ((u32)net_ethaddr[3] << 16)
-   | ((u32)net_ethaddr[4] << 8)
-   | (u32)net_ethaddr[5];
-   bootp_id += get_timer(0);
-   bootp_id = htonl(bootp_id);
-   bootp_add_id(bootp_id);
-   net_copy_u32(>bp_id, _id);
+   /* Only generate a new transaction ID for each new BOOTP request */
+   if (bootp_try == 1) {
+   /*
+   

[PATCH 0/3] BOOTP/DHCPv4 enhancements

2023-09-25 Thread seanedmond
From: Sean Edmond 

In our datacenter application, a single DHCP server is servicing 36000+ clients.
Improvements are required to the DHCPv4 retransmission behavior to align with
RFC and ensure less pressure is exerted on the server:
- retransmission backoff interval maximum is configurable 
  (environment variable bootpretransmitperiodmax)
- initial retransmission backoff interval is configurable 
  (environment variable bootpretransmitperiodinit)
- transaction ID is kept the same for each BOOTP/DHCPv4 request 
  (not recreated on each retry)

For our application we'll use:
- bootpretransmitperiodmax=16000
- bootpretransmitperiodinit=2000

A new configuration BOOTP_RANDOM_XID has been added to enable a randomized
BOOTP/DHCPv4 transaction ID.

Add functionality for DHCPv4 sending/parsing option 209 (PXE config file).
Enabled with Kconfig BOOTP_PXE_DHCP_OPTION.  Note, this patch was
submitted previously but this latest version has been enhanced to
avoid a possible double free().

Sean Edmond (3):
  net: Get pxe config file from dhcp option 209
  net: bootp: BOOTP/DHCPv4 retransmission improvements
  net: bootp: add config option BOOTP_RANDOM_XID

 cmd/Kconfig | 11 +++
 cmd/pxe.c   | 10 +++
 net/bootp.c | 85 +++--
 3 files changed, 91 insertions(+), 15 deletions(-)

-- 
2.40.0



[PATCH v3 3/5] cmd: kaslrseed: Use common API to fixup FDT

2023-09-12 Thread seanedmond
From: Sean Edmond 

Use the newly introduced common API fdt_fixup_kaslr_seed() in the
kaslrseed command.

Signed-off-by: Sean Edmond 
---
 cmd/kaslrseed.c | 22 --
 1 file changed, 8 insertions(+), 14 deletions(-)

diff --git a/cmd/kaslrseed.c b/cmd/kaslrseed.c
index 8a1d8120cd..c65607619b 100644
--- a/cmd/kaslrseed.c
+++ b/cmd/kaslrseed.c
@@ -19,7 +19,7 @@ static int do_kaslr_seed(struct cmd_tbl *cmdtp, int flag, int 
argc, char *const
size_t n = 0x8;
struct udevice *dev;
u64 *buf;
-   int nodeoffset;
+   ofnode root;
int ret = CMD_RET_SUCCESS;
 
if (uclass_get_device(UCLASS_RNG, 0, ) || !dev) {
@@ -45,21 +45,15 @@ static int do_kaslr_seed(struct cmd_tbl *cmdtp, int flag, 
int argc, char *const
return CMD_RET_FAILURE;
}
 
-   ret = fdt_check_header(working_fdt);
-   if (ret < 0) {
-   printf("fdt_chosen: %s\n", fdt_strerror(ret));
-   return CMD_RET_FAILURE;
-   }
-
-   nodeoffset = fdt_find_or_add_subnode(working_fdt, 0, "chosen");
-   if (nodeoffset < 0) {
-   printf("Reading chosen node failed\n");
-   return CMD_RET_FAILURE;
+   ret = root_ofnode_from_fdt(working_fdt, );
+   if (ret) {
+   printf("ERROR: Unable to get root ofnode\n");
+   goto CMD_RET_FAILURE;
}
 
-   ret = fdt_setprop(working_fdt, nodeoffset, "kaslr-seed", buf, 
sizeof(buf));
-   if (ret < 0) {
-   printf("Unable to set kaslr-seed on chosen node: %s\n", 
fdt_strerror(ret));
+   ret = fdt_fixup_kaslr_seed(root, buf, sizeof(buf));
+   if (ret) {
+   printf("ERROR: failed to add kaslr-seed to fdt\n");
return CMD_RET_FAILURE;
}
 
-- 
2.40.0



[PATCH v3 1/5] fdt: common API to populate kaslr seed

2023-09-12 Thread seanedmond
From: Dhananjay Phadke 

fdt_fixup_kaslr_seed() will update given ofnode with random seed value.
Source for random seed can be TPM or RNG driver in u-boot or sec
firmware (ARM).

Signed-off-by: Dhananjay Phadke 
Signed-off-by: Sean Edmond 
---
 arch/arm/cpu/armv8/sec_firmware.c | 39 +++
 common/fdt_support.c  | 19 +++
 drivers/core/ofnode.c | 17 ++
 include/dm/ofnode.h   | 12 ++
 include/fdt_support.h |  9 +++
 5 files changed, 71 insertions(+), 25 deletions(-)

diff --git a/arch/arm/cpu/armv8/sec_firmware.c 
b/arch/arm/cpu/armv8/sec_firmware.c
index c0e8726346..5f04cd8aec 100644
--- a/arch/arm/cpu/armv8/sec_firmware.c
+++ b/arch/arm/cpu/armv8/sec_firmware.c
@@ -411,46 +411,35 @@ int sec_firmware_init(const void *sec_firmware_img,
 /*
  * fdt_fix_kaslr - Add kalsr-seed node in Device tree
  * @fdt:   Device tree
- * @eret:  0 in case of error, 1 for success
+ * @eret:  0 for success
  */
 int fdt_fixup_kaslr(void *fdt)
 {
-   int nodeoffset;
-   int err, ret = 0;
-   u8 rand[8];
+   int ret = 0;
 
 #if defined(CONFIG_ARMV8_SEC_FIRMWARE_SUPPORT)
+   u8 rand[8];
+   ofnode root;
+
/* Check if random seed generation is  supported */
if (sec_firmware_support_hwrng() == false) {
printf("WARNING: SEC firmware not running, no kaslr-seed\n");
-   return 0;
+   return -EOPNOTSUPP;
}
 
-   err = sec_firmware_get_random(rand, 8);
-   if (err < 0) {
+   ret = sec_firmware_get_random(rand, 8);
+   if (ret < 0) {
printf("WARNING: No random number to set kaslr-seed\n");
-   return 0;
+   return ret;
}
 
-   err = fdt_check_header(fdt);
-   if (err < 0) {
-   printf("fdt_chosen: %s\n", fdt_strerror(err));
-   return 0;
+   ret = root_ofnode_from_fdt(fdt, );
+   if (ret < 0) {
+   printf("WARNING: Unable to get root ofnode\n");
+   return ret;
}
 
-   /* find or create "/chosen" node. */
-   nodeoffset = fdt_find_or_add_subnode(fdt, 0, "chosen");
-   if (nodeoffset < 0)
-   return 0;
-
-   err = fdt_setprop(fdt, nodeoffset, "kaslr-seed", rand,
- sizeof(rand));
-   if (err < 0) {
-   printf("WARNING: can't set kaslr-seed %s.\n",
-  fdt_strerror(err));
-   return 0;
-   }
-   ret = 1;
+   ret = fdt_fixup_kaslr_seed(root, rand, sizeof(rand));
 #endif
 
return ret;
diff --git a/common/fdt_support.c b/common/fdt_support.c
index 5e49078f8c..52be4375b4 100644
--- a/common/fdt_support.c
+++ b/common/fdt_support.c
@@ -631,6 +631,25 @@ void fdt_fixup_ethernet(void *fdt)
}
 }
 
+int fdt_fixup_kaslr_seed(ofnode node, const u8 *seed, int len)
+{
+   ofnode chosen;
+   int ret;
+
+   /* find or create "/chosen" node. */
+   ret = ofnode_add_subnode(node, "chosen", );
+   if (ret && ret != -EEXIST)
+   return -ENOENT;
+
+   ret = ofnode_write_prop(chosen, "kaslr-seed", seed, len, true);
+   if (ret) {
+   printf("WARNING: can't set kaslr-seed\n");
+   return ret;
+   }
+
+   return 0;
+}
+
 int fdt_record_loadable(void *blob, u32 index, const char *name,
uintptr_t load_addr, u32 size, uintptr_t entry_point,
const char *type, const char *os, const char *arch)
diff --git a/drivers/core/ofnode.c b/drivers/core/ofnode.c
index 8df16e56af..4be21133b8 100644
--- a/drivers/core/ofnode.c
+++ b/drivers/core/ofnode.c
@@ -870,6 +870,23 @@ ofnode oftree_path(oftree tree, const char *path)
}
 }
 
+int root_ofnode_from_fdt(void *fdt, ofnode *root_node)
+{
+   oftree tree;
+   /* If OFNODE_MULTI_TREE is not set, and if fdt is not the control FDT,
+*  oftree_from_fdt() will return NULL
+*/
+   tree = oftree_from_fdt(fdt);
+
+   if (!oftree_valid(tree)) {
+   printf("Cannot create oftree\n");
+   return -EINVAL;
+   }
+   *root_node = oftree_root(tree);
+
+   return 0;
+}
+
 const void *ofnode_read_chosen_prop(const char *propname, int *sizep)
 {
ofnode chosen_node;
diff --git a/include/dm/ofnode.h b/include/dm/ofnode.h
index 0f38b3e736..e79bb62be8 100644
--- a/include/dm/ofnode.h
+++ b/include/dm/ofnode.h
@@ -901,6 +901,18 @@ ofnode oftree_path(oftree tree, const char *path);
  */
 ofnode oftree_root(oftree tree);
 
+/**
+ * root_ofnode_from_fdt() - Gets the root ofnode given an FDT blob.
+ *  Note, this will fail if OFNODE_MULTI_TREE
+ *  is not set.
+ *
+ * @fdt: Device tree to use
+ * @root_node : Root ofnode
+ *
+ * Return: 0 if OK, -ve on error
+ */
+int root_ofnode_from_fdt(void *fdt, ofnode 

[PATCH v3 5/5] fdt: Fix compile error for !OFNODE_MULTI_TREE

2023-09-12 Thread seanedmond
From: Sean Edmond 

Required to fix the following compile error when building sandbox:
/tmp/cci9ibby.ltrans21.ltrans.o: In function `do_cedit_load':
:(.text+0x601d): undefined reference to `oftree_dispose'

Signed-off-by: Sean Edmond 
---
 drivers/core/ofnode.c | 12 ++--
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/drivers/core/ofnode.c b/drivers/core/ofnode.c
index 4be21133b8..f7b3f41077 100644
--- a/drivers/core/ofnode.c
+++ b/drivers/core/ofnode.c
@@ -92,12 +92,6 @@ static oftree oftree_ensure(void *fdt)
return tree;
 }
 
-void oftree_dispose(oftree tree)
-{
-   if (of_live_active())
-   of_live_free(tree.np);
-}
-
 void *ofnode_lookup_fdt(ofnode node)
 {
if (gd->flags & GD_FLG_RELOC) {
@@ -195,6 +189,12 @@ static inline int oftree_find(const void *fdt)
 
 #endif /* OFNODE_MULTI_TREE */
 
+void oftree_dispose(oftree tree)
+{
+   if (of_live_active())
+   of_live_free(tree.np);
+}
+
 /**
  * ofnode_from_tree_offset() - get an ofnode from a tree offset (flat tree)
  *
-- 
2.40.0



[PATCH v3 4/5] dm: core: Modify default for OFNODE_MULTI_TREE

2023-09-12 Thread seanedmond
From: Sean Edmond 

There is a preference to use the "ofnode" API for FDT fixups
moving forward.  The FDT fixup will usually be for the kernel FDT.  To
fixup the kernel FDT with the ofnode API, it's required to set the
OFNODE_MULTI_TREE option.

To ensure existing users of kaslr fdt fixup are not impacted, Let's modify
the default value for OFNODE_MULTI_TREE to ensure it's always set if
!OF_LIVE.  This will cause a 1007 byte increase in the code size.

Signed-off-by: Sean Edmond 
---
 drivers/core/Kconfig | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/core/Kconfig b/drivers/core/Kconfig
index f0d848f45d..38e44ef6fc 100644
--- a/drivers/core/Kconfig
+++ b/drivers/core/Kconfig
@@ -424,7 +424,7 @@ config DM_DEV_READ_INLINE
 
 config OFNODE_MULTI_TREE
bool "Allow the ofnode interface to access any tree"
-   default y if EVENT && !DM_DEV_READ_INLINE && !DM_INLINE_OFNODE
+   default y if !OF_LIVE
help
  Normally U-Boot makes use of its control FDT, the one used to bind
  devices and provide options. In some cases, U-Boot must also process
-- 
2.40.0



[PATCH v3 0/5] Populate kaslr seed with RNG

2023-09-12 Thread seanedmond
From: Sean Edmond 

This patch series creates a common API (fdt_fixup_kaslr_seed()) for 
populating the kaslr seed in the DTB.  Existing users (kaslrseed,
and ARMv8 sec firmware) have been updated to use this common API.

New functionality has been introduced to populate the kaslr using
the RNG.  This can be enabled with CONFIG_RNG_TPM_SEED.  

changes in v3:
- Populate with RNG device instead of TPM device (this is a more generic 
solution)
- Use event spy to do the FDT fixup
- fix compile error for sandbox for !OFNODE_MULTI_TREE

changes in v2:
- fdt_fixup_kaslr_seed() uses the ofnode API
- Add root_ofnode_from_fdt() to get the root node from an FDT and
  perform error checking on the oftree
- add comments to exported functions
- Add error checking in image_setup_libfdt() for return from
  fdt_tpm_kaslr_seed()
- uclass_get_device() -> uclass_first_device_err()
- Change default config for OFNODE_MULTI_TREE (y if !OF_LIVE)


Dhananjay Phadke (2):
  fdt: common API to populate kaslr seed
  fdt: kaslr seed from RNG device

Sean Edmond (3):
  cmd: kaslrseed: Use common API to fixup FDT
  dm: core: Modify default for OFNODE_MULTI_TREE
  fdt: Fix compile error for !OFNODE_MULTI_TREE

 arch/arm/cpu/armv8/sec_firmware.c | 39 --
 cmd/kaslrseed.c   | 22 +
 common/fdt_support.c  | 55 +++
 drivers/core/Kconfig  |  2 +-
 drivers/core/ofnode.c | 29 
 include/dm/ofnode.h   | 12 +++
 include/fdt_support.h |  9 +
 lib/Kconfig   |  7 
 8 files changed, 129 insertions(+), 46 deletions(-)

-- 
2.40.0



[PATCH v3 2/5] fdt: kaslr seed from RNG device

2023-09-12 Thread seanedmond
From: Dhananjay Phadke 

Add support for KASLR seed from the RNG device. Invokes dm_rng_read()
API to read 8-bytes of random bytes.  Performs the FDT fixup using event
spy.  To enable use CONFIG_KASLR_RNG_SEED

Signed-off-by: Dhananjay Phadke 
Signed-off-by: Drew Kluemke 
Signed-off-by: Sean Edmond 
---
 common/fdt_support.c | 36 
 lib/Kconfig  |  7 +++
 2 files changed, 43 insertions(+)

diff --git a/common/fdt_support.c b/common/fdt_support.c
index 52be4375b4..09ce582865 100644
--- a/common/fdt_support.c
+++ b/common/fdt_support.c
@@ -12,7 +12,10 @@
 #include 
 #include 
 #include 
+#include 
 #include 
+#include 
+#include 
 #include 
 #include 
 #include 
@@ -650,6 +653,39 @@ int fdt_fixup_kaslr_seed(ofnode node, const u8 *seed, int 
len)
return 0;
 }
 
+int fdt_rng_kaslr_seed(void *ctx, struct event *event)
+{
+   u8 rand[8] = {0};
+   struct udevice *dev;
+   int ret;
+   oftree tree = event->data.ft_fixup.tree;
+   ofnode root_node = oftree_root(tree);
+
+   ret = uclass_first_device_err(UCLASS_RNG, );
+   if (ret) {
+   printf("ERROR: Failed to find RNG device\n");
+   return ret;
+   }
+
+   ret = dm_rng_read(dev, rand, sizeof(rand));
+   if (ret) {
+   printf("ERROR: RNG read failed, ret=%d\n", ret);
+   return ret;
+   }
+
+   ret = fdt_fixup_kaslr_seed(root_node, rand, sizeof(rand));
+   if (ret) {
+   printf("ERROR: failed to add kaslr-seed to fdt\n");
+   return ret;
+   }
+
+   return 0;
+}
+
+#if defined(CONFIG_KASLR_RNG_SEED)
+EVENT_SPY(EVT_FT_FIXUP, fdt_rng_kaslr_seed);
+#endif
+
 int fdt_record_loadable(void *blob, u32 index, const char *name,
uintptr_t load_addr, u32 size, uintptr_t entry_point,
const char *type, const char *os, const char *arch)
diff --git a/lib/Kconfig b/lib/Kconfig
index 3926652db6..545a14343e 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -465,6 +465,13 @@ config VPL_TPM
  for the low-level TPM interface, but only one TPM is supported at
  a time by the TPM library.
 
+config KASLR_RNG_SEED
+   bool "Use RNG driver for KASLR random seed"
+   depends on DM_RNG
+   help
+ This enables support for using the RNG driver as entropy source for
+ KASLR seed populated in kernel's device tree.
+
 endmenu
 
 menu "Android Verified Boot"
-- 
2.40.0



[PATCH 8/8] doc: rollback: anti-rollback verification

2023-09-12 Thread seanedmond
From: Sean Edmond 

Add documentation for anti-rollback verification, optional properties in
FIT image, and UCLASS_ROLLBACK device.

Signed-off-by: Sean Edmond 
---
 doc/develop/driver-model/index.rst |  1 +
 doc/develop/driver-model/rollback-info.rst | 42 +
 doc/usage/fit/signature.rst| 53 +++---
 doc/usage/fit/source_file_format.rst   | 21 -
 4 files changed, 108 insertions(+), 9 deletions(-)
 create mode 100644 doc/develop/driver-model/rollback-info.rst

diff --git a/doc/develop/driver-model/index.rst 
b/doc/develop/driver-model/index.rst
index 8e12bbd936..bb2d2e8a5d 100644
--- a/doc/develop/driver-model/index.rst
+++ b/doc/develop/driver-model/index.rst
@@ -25,6 +25,7 @@ subsystems
pci-info
pmic-framework
remoteproc-framework
+   rollback-info
serial-howto
soc-framework
spi-howto
diff --git a/doc/develop/driver-model/rollback-info.rst 
b/doc/develop/driver-model/rollback-info.rst
new file mode 100644
index 00..06ba4584a9
--- /dev/null
+++ b/doc/develop/driver-model/rollback-info.rst
@@ -0,0 +1,42 @@
+.. SPDX-License-Identifier: GPL-2.0+
+
+Rollback Driver Guide
+=
+
+Rollback protection is required when there is a need to retire
+previous versions of FIT images due to security flaws in them.
+See :doc:`../../usage/fit/signature` for details on rollback protection.
+
+The rollback driver is intended to provide tamper-evident storage using
+a UCLASS_ROLLBACK device.  It exposes the following APIs which are
+used in the FIT verification process (if FIT_ROLLBACK_CHECK is set):
+- rollback_idx_get()
+- rollback_idx_set()
+
+A TPM based rollback device has been provided as an example.  Users could
+create their own UCLASS_ROLLBACK device to access proprietary secure storage.
+
+TPM 2.0 based rollback devices
+
+
+A TPM-based rollback device has been provided as a reference.  It can be
+enabled with:
+- DM_ROLLBACK
+- ROLLBACK_TPM
+
+The tpm based rollback device should be added as a child node of the TPM in
+the u-boot device tree.  You should provide the property "rollback-nv-index"
+to set the TPM's NV index (if no "rollback-nv-index" is provided, an NV index
+of 0 is assumed).  For example:
+
+   tpm2 {
+   compatible = "sandbox,tpm2";
+
+   rollback@1 {
+   compatible = "tpm,rollback";
+   rollback-nv-index = <0x1001007>;
+   };
+   };
+
+Note, the ROLLBACK_TPM device does not set any policy.  Consumers of this
+driver should add a policy to make it more secure.
\ No newline at end of file
diff --git a/doc/usage/fit/signature.rst b/doc/usage/fit/signature.rst
index 0804bffd1e..30dd529c29 100644
--- a/doc/usage/fit/signature.rst
+++ b/doc/usage/fit/signature.rst
@@ -674,14 +674,53 @@ Sign the fitImage with the hardware key::
 
"model=PKCS%2315%20emulated;manufacturer=ZeitControl;serial=000x;token=OpenPGP%20card%20%28User%20PIN%20%28sig%29%29"
 \
 -K u-boot.dtb -N pkcs11 -r fitImage
 
+Roll-back Protection
+-
 
-Future Work

-
-- Roll-back protection using a TPM is done using the tpm command. This can
-  be scripted, but we might consider a default way of doing this, built into
-  bootm.
-
+Rollback protection is required when there is a need to retire
+previous versions of FIT images due to security flaws in them.
+
+This feature is realized by adding a rollback index as a property
+in the FIT image.  Every time a security flaw is discovered, the
+rollback index is incremented.  For example:
+
++-++
+| FIT version | Rollback index |
++=++
+| 1.0 | 0  |
++-++
+| 1.1 | 0  |
++-++
+| 2.0 | 0  |
++-++
+| Security issue found!|
++-++
+| 1.2 | 1  |
++-++
+| 2.1 | 1  |
++-++
+
+Each sub-image node inside /images node has an optional rollback rollback_index
+("rollback"). This version number is part of signed data and is incremented as
+security flaws are discovered and fixed. If no "rollback" property is present
+in the FIT image, a rollback index of 0 is assumed.
+
+U-Boot stores the last seen "rollback" for a given image type in platform
+specific tamper-evident storage (using a UCLASS_ROLLBACK device).
+See :doc:`../../develop/driver-model/rollback-info` for more information on
+rollback devices.
+
+As part of signature verification, U-Boot enforces rollback
+protection if enabled (with FIT_ROLLBACK_CHECK). The rollback index stored in 
secure
+storage is validated with "rollback" in the sub-image node. If the counter
+in the FIT image is lower than the counter in platform secure storage, image

[PATCH 5/8] dm: test: Add a test for rollback driver

2023-09-12 Thread seanedmond
From: Sean Edmond 

Adds a test for a sandbox and TPM backed rollback driver.

Allows for testing of anti-rollback version number get/set API using the
rollback driver.

Signed-off-by: Sean Edmond 
---
 arch/sandbox/dts/test.dts |  9 +
 configs/sandbox_defconfig |  3 ++
 test/dm/Makefile  |  1 +
 test/dm/rollback.c| 78 +++
 4 files changed, 91 insertions(+)
 create mode 100644 test/dm/rollback.c

diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts
index f351d5cb84..1226bad6a6 100644
--- a/arch/sandbox/dts/test.dts
+++ b/arch/sandbox/dts/test.dts
@@ -1263,6 +1263,10 @@
backlight = < 0 100>;
};
 
+   rollback@0 {
+   compatible = "sandbox,rollback";
+   };
+
scsi {
compatible = "sandbox,scsi";
sandbox,filepath = "scsi.img";
@@ -1376,6 +1380,11 @@
 
tpm2 {
compatible = "sandbox,tpm2";
+
+   rollback@1 {
+   compatible = "tpm,rollback";
+   rollback-nv-index = <0x1001007>;
+   };
};
 
tpm {
diff --git a/configs/sandbox_defconfig b/configs/sandbox_defconfig
index 1cd1c2ed7c..f2bd10fbf0 100644
--- a/configs/sandbox_defconfig
+++ b/configs/sandbox_defconfig
@@ -346,3 +346,6 @@ CONFIG_UNIT_TEST=y
 CONFIG_UT_TIME=y
 CONFIG_UT_DM=y
 CONFIG_ARM_FFA_TRANSPORT=y
+CONFIG_DM_ROLLBACK=y
+CONFIG_ROLLBACK_SANDBOX=y
+CONFIG_ROLLBACK_TPM=y
diff --git a/test/dm/Makefile b/test/dm/Makefile
index 7ed00733c1..3875ec4f4b 100644
--- a/test/dm/Makefile
+++ b/test/dm/Makefile
@@ -104,6 +104,7 @@ obj-$(CONFIG_DM_RNG) += rng.o
 obj-$(CONFIG_DM_RTC) += rtc.o
 obj-$(CONFIG_SCMI_FIRMWARE) += scmi.o
 obj-$(CONFIG_SCSI) += scsi.o
+obj-$(CONFIG_DM_ROLLBACK) += security.o
 obj-$(CONFIG_DM_SERIAL) += serial.o
 obj-$(CONFIG_DM_SPI_FLASH) += sf.o
 obj-$(CONFIG_SIMPLE_BUS) += simple-bus.o
diff --git a/test/dm/rollback.c b/test/dm/rollback.c
new file mode 100644
index 00..a2984797f9
--- /dev/null
+++ b/test/dm/rollback.c
@@ -0,0 +1,78 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2023 Microsoft Corporation
+ * Written by Sean Edmond 
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+/*
+ * get_rollback() - Get a rollback driver of a given driver name
+ *
+ * @devp: Returns the rollback device
+ * @driver_name: Driver name to find
+ * Returns: 0 if OK, -ENODEV if not found
+ */
+static int get_rollback(struct udevice **devp, char *driver_name)
+{
+   struct udevice *dev;
+
+   uclass_foreach_dev_probe(UCLASS_ROLLBACK, dev) {
+   if (strcmp(dev->driver->name, driver_name) == 0) {
+   *devp = dev;
+   return 0;
+   }
+   }
+
+   return -ENODEV;
+}
+
+/* Basic test of rollback driver Anti rollback version number read/write */
+static int test_rollback_idx(struct unit_test_state *uts, char *driver_name)
+{
+   struct udevice *dev;
+   u64 rollback_idx;
+
+   /* get the rollback driver */
+   ut_assertok(get_rollback(, driver_name));
+
+   /* ensure initial value is 0 */
+   rollback_idx_get(dev, _idx);
+   ut_asserteq(0, rollback_idx);
+
+   /* write 1 and ensure it's read back */
+   rollback_idx_set(dev, 1);
+   rollback_idx_get(dev, _idx);
+   ut_asserteq(1, rollback_idx);
+
+   /* write all ones and ensure it's read back */
+   rollback_idx_set(dev, 0xULL);
+   rollback_idx_get(dev, _idx);
+   ut_asserteq(0xULL, rollback_idx);
+
+   return 0;
+}
+
+static int dm_test_rollback_sandbox(struct unit_test_state *uts)
+{
+   ut_assertok(test_rollback_idx(uts, "rollback_sandbox"));
+
+   return 0;
+}
+
+DM_TEST(dm_test_rollback_sandbox, UT_TESTF_SCAN_FDT);
+
+static int dm_test_rollback_tpm(struct unit_test_state *uts)
+{
+   ut_assertok(test_rollback_idx(uts, "rollback_tpm"));
+
+   return 0;
+}
+
+DM_TEST(dm_test_rollback_tpm, UT_TESTF_SCAN_FDT);
-- 
2.40.0



[PATCH 7/8] sandbox: tpm: Fix TPM2_CC_NV_DEFINE_SPACE command

2023-09-12 Thread seanedmond
From: Sean Edmond 

The TPM 2.0 command reference shows "auth" (type TPM2B_AUTH) before
"publicInfo" (type TPM2B_NV_PUBLIC).

The TPM v2 driver was updated to add this field.  The sandbox driver
needs to be updated to match the driver implementation.

Signed-off-by: Sean Edmond 
---
 drivers/tpm/tpm2_tis_sandbox.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/tpm/tpm2_tis_sandbox.c b/drivers/tpm/tpm2_tis_sandbox.c
index e4004cfcca..3e38d28637 100644
--- a/drivers/tpm/tpm2_tis_sandbox.c
+++ b/drivers/tpm/tpm2_tis_sandbox.c
@@ -758,8 +758,10 @@ static int sandbox_tpm2_xfer(struct udevice *dev, const u8 
*sendbuf,
break;
}
case TPM2_CC_NV_DEFINE_SPACE: {
-   int policy_size, index, seq;
+   int policy_size, auth_size, index, seq;
 
+   auth_size = get_unaligned_be16(sent);
+   sent += 2 + auth_size;
policy_size = get_unaligned_be16(sent + 12);
index = get_unaligned_be32(sent + 2);
sent += 14 + policy_size;
-- 
2.40.0



[PATCH 2/8] drivers: rollback: Add TPM2 implementation of rollback devices

2023-09-12 Thread seanedmond
From: Stephen Carlson 

This implementation of the rollback uclass driver allows existing TPM2
devices declared in the device tree to be referenced for storing the OS
anti-rollback counter, using the TPM2 non-volatile storage API.  The
rollback device must be a child of the TPM device.  For example:

tpm2 {
compatible = "sandbox,tpm2";

rollback@1 {
compatible = "tpm,rollback";
rollback-nv-index = <0x1001007>;
};
};

Signed-off-by: Stephen Carlson 
Signed-off-by: Sean Edmond 
---
 MAINTAINERS |   1 +
 drivers/rollback/Makefile   |   1 +
 drivers/rollback/rollback-tpm.c | 117 
 include/tpm-v2.h|  17 +
 lib/tpm-v2.c|  48 +
 5 files changed, 184 insertions(+)
 create mode 100644 drivers/rollback/rollback-tpm.c

diff --git a/MAINTAINERS b/MAINTAINERS
index de14724c27..e5ac889db4 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1446,6 +1446,7 @@ F:drivers/rollback/Kconfig
 F: drivers/rollback/Makefile
 F: drivers/rollback/rollback-sandbox.c
 F: drivers/rollback/rollback-uclass.c
+F: drivers/security/rollback-tpm.c
 
 SEMIHOSTING
 R: Sean Anderson 
diff --git a/drivers/rollback/Makefile b/drivers/rollback/Makefile
index 4e7fa46041..63c08863ca 100644
--- a/drivers/rollback/Makefile
+++ b/drivers/rollback/Makefile
@@ -4,3 +4,4 @@
 
 obj-$(CONFIG_DM_ROLLBACK) += rollback-uclass.o
 obj-$(CONFIG_ROLLBACK_SANDBOX) += rollback-sandbox.o
+obj-$(CONFIG_ROLLBACK_TPM) += rollback-tpm.o
\ No newline at end of file
diff --git a/drivers/rollback/rollback-tpm.c b/drivers/rollback/rollback-tpm.c
new file mode 100644
index 00..3bb6214042
--- /dev/null
+++ b/drivers/rollback/rollback-tpm.c
@@ -0,0 +1,117 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2021 Microsoft, Inc
+ * Written by Stephen Carlson 
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+
+struct rollback_state {
+   u32 nv_index;
+   struct udevice *tpm_dev;
+};
+
+static int tpm_rollback_idx_get(struct udevice *dev, u64 *rollback_idx)
+{
+   struct rollback_state *priv = dev_get_priv(dev);
+   int ret;
+
+   if (!rollback_idx)
+   return -EINVAL;
+
+   ret = tpm2_nv_read_value(priv->tpm_dev, priv->nv_index, rollback_idx, 
sizeof(u64));
+   if (ret) {
+   log(UCLASS_ROLLBACK, LOGL_ERR,
+   "Unable to read rollback number from TPM (ret=%d)\n", ret);
+   return ret;
+   }
+
+   return ret;
+}
+
+static int tpm_rollback_idx_set(struct udevice *dev, u64 rollback_idx)
+{
+   int ret;
+   struct rollback_state *priv = dev_get_priv(dev);
+
+   ret = tpm2_nv_write_value(priv->tpm_dev, priv->nv_index, _idx, 
sizeof(u64));
+   if (ret) {
+   log(UCLASS_ROLLBACK, LOGL_ERR,
+   "Unable to write anti-rollback version to TPM (ret=%d)\n", 
ret);
+   return ret;
+   }
+
+   return 0;
+}
+
+static const struct rollback_ops tpm_rollback_ops = {
+   .rollback_idx_get   = tpm_rollback_idx_get,
+   .rollback_idx_set   = tpm_rollback_idx_set,
+};
+
+static int tpm_rollback_probe(struct udevice *dev)
+{
+   struct rollback_state *priv = dev_get_priv(dev);
+   int ret;
+
+   /* initialize the TPM rollback counter NV index
+* and initial to 0.  Note, this driver provides
+* a NULL policy.
+*/
+   ret = tpm_rollback_counter_init(priv->tpm_dev, priv->nv_index,
+   NULL, 0);
+   if (ret) {
+   log(UCLASS_ROLLBACK, LOGL_ERR,
+   "TPM rollback init failed (ret=%d)\n", ret);
+   return ret;
+   }
+
+   return 0;
+}
+
+static int tpm_rollback_remove(struct udevice *dev)
+{
+   struct rollback_state *priv = dev_get_priv(dev);
+
+   return tpm_close(priv->tpm_dev);
+}
+
+static int tpm_rollback_ofdata_to_platdata(struct udevice *dev)
+{
+   struct udevice *parent_dev;
+   struct rollback_state *priv = dev_get_priv(dev);
+
+   priv->nv_index = (u32)dev_read_u32_default(dev, "rollback-nv-index", 0);
+
+   parent_dev = dev_get_parent(dev);
+
+   if (parent_dev->driver->id == UCLASS_TPM) {
+   priv->tpm_dev = parent_dev;
+   } else {
+   log(UCLASS_ROLLBACK, LOGL_ERR,
+   "TPM rollback must be a child node of a TPM\n");
+   return -EINVAL;
+   }
+
+   return 0;
+}
+
+static const struct udevice_id tpm_rollback_ids[] = {
+   { .compatible = "tpm,rollback" },
+   { }
+};
+
+U_BOOT_DRIVER(rollback_tpm) = {
+   .name   = "rollback_tpm",
+   .id = UCLASS_ROLLBACK,
+   .priv_auto = sizeof(struct rollback_state),
+   .of_match = tpm_rollback_ids,
+   .of_to_plat = tpm_rollback_ofdata_to_platdata,
+   

[PATCH 1/8] drivers: rollback: Add rollback devices to driver model

2023-09-12 Thread seanedmond
From: Stephen Carlson 

Rollback devices currently implement operations to store an OS
anti-rollback monotonic counter. Existing devices such as the Trusted
Platform Module (TPM) already support this operation, but this uclass
provides abstraction for current and future devices that may support
different features.

- New Driver Model uclass UCLASS_ROLLBACK.
- New config CONFIG_DM_ROLLBACK to enable security device support.
- New driver rollback-sandbox matching "rollback,sandbox", enabled with
  new config CONFIG_ROLLBACK_SANDBOX.

Signed-off-by: Stephen Carlson 
Signed-off-by: Sean Edmond 
---
 MAINTAINERS |  9 
 drivers/Kconfig |  2 +
 drivers/Makefile|  1 +
 drivers/rollback/Kconfig| 25 +++
 drivers/rollback/Makefile   |  6 +++
 drivers/rollback/rollback-sandbox.c | 65 +
 drivers/rollback/rollback-uclass.c  | 30 +
 include/dm/uclass-id.h  |  1 +
 include/rollback.h  | 42 +++
 9 files changed, 181 insertions(+)
 create mode 100644 drivers/rollback/Kconfig
 create mode 100644 drivers/rollback/Makefile
 create mode 100644 drivers/rollback/rollback-sandbox.c
 create mode 100644 drivers/rollback/rollback-uclass.c
 create mode 100644 include/rollback.h

diff --git a/MAINTAINERS b/MAINTAINERS
index bf851cffd6..de14724c27 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1438,6 +1438,15 @@ F:   cmd/seama.c
 F: doc/usage/cmd/seama.rst
 F: test/cmd/seama.c
 
+ROLLBACK
+M: Stephen Carlson 
+M: Sean Edmond 
+S: Maintained
+F: drivers/rollback/Kconfig
+F: drivers/rollback/Makefile
+F: drivers/rollback/rollback-sandbox.c
+F: drivers/rollback/rollback-uclass.c
+
 SEMIHOSTING
 R: Sean Anderson 
 S: Orphaned
diff --git a/drivers/Kconfig b/drivers/Kconfig
index a25f6ae02f..faa7cbb72b 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -116,6 +116,8 @@ source "drivers/rtc/Kconfig"
 
 source "drivers/scsi/Kconfig"
 
+source "drivers/rollback/Kconfig"
+
 source "drivers/serial/Kconfig"
 
 source "drivers/smem/Kconfig"
diff --git a/drivers/Makefile b/drivers/Makefile
index efc2a4afb2..f6cfb48cb6 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -98,6 +98,7 @@ obj-$(CONFIG_PCH) += pch/
 obj-$(CONFIG_DM_REBOOT_MODE) += reboot-mode/
 obj-y += rtc/
 obj-y += scsi/
+obj-y += rollback/
 obj-y += sound/
 obj-y += spmi/
 obj-y += watchdog/
diff --git a/drivers/rollback/Kconfig b/drivers/rollback/Kconfig
new file mode 100644
index 00..31f5a3f56d
--- /dev/null
+++ b/drivers/rollback/Kconfig
@@ -0,0 +1,25 @@
+config DM_ROLLBACK
+   bool "Support rollback devices with driver model"
+   depends on DM
+   help
+ This option enables support for the rollback uclass which supports
+ devices intended to provide the anti-rollback feature during
+ boot. These devices might encapsulate existing features of TPM
+ or TEE devices, but can also be dedicated security processors
+ implemented in specific hardware.
+
+config ROLLBACK_SANDBOX
+   bool "Enable sandbox rollback driver"
+   depends on DM_ROLLBACK
+   help
+ This driver supports a simulated rollback device that uses volatile
+ memory to store secure data and begins uninitialized. This
+ implementation allows OS images with security requirements to be
+ loaded in the sandbox environment.
+
+config ROLLBACK_TPM
+   bool "Enable TPM rollback driver"
+   depends on TPM && TPM_V2 && DM_ROLLBACK
+   help
+ This driver supports a rollback device based on existing TPM
+ functionality.
diff --git a/drivers/rollback/Makefile b/drivers/rollback/Makefile
new file mode 100644
index 00..4e7fa46041
--- /dev/null
+++ b/drivers/rollback/Makefile
@@ -0,0 +1,6 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# (C) Copyright 2021 Microsoft, Inc.
+
+obj-$(CONFIG_DM_ROLLBACK) += rollback-uclass.o
+obj-$(CONFIG_ROLLBACK_SANDBOX) += rollback-sandbox.o
diff --git a/drivers/rollback/rollback-sandbox.c 
b/drivers/rollback/rollback-sandbox.c
new file mode 100644
index 00..acbe6d2303
--- /dev/null
+++ b/drivers/rollback/rollback-sandbox.c
@@ -0,0 +1,65 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2021 Microsoft, Inc
+ * Written by Stephen Carlson 
+ */
+
+#include 
+#include 
+#include 
+#include 
+
+static struct rollback_state {
+   u64 rollback_idx;
+};
+
+static int sb_rollback_idx_get(struct udevice *dev, u64 *rollback_idx)
+{
+   struct rollback_state *priv = dev_get_priv(dev);
+
+   if (!rollback_idx)
+   return -EINVAL;
+
+   *rollback_idx = priv->rollback_idx;
+   return 0;
+}
+
+static int sb_rollback_idx_set(struct udevice *dev, u64 rollback_idx)
+{
+   struct rollback_state *priv = dev_get_priv(dev);
+   u64 old_rollback_idx;
+
+   old_rollback_idx = priv->rollback_idx;
+  

[PATCH 6/8] tpm: Fix issues relating to NV Indexes

2023-09-12 Thread seanedmond
From: Sean Edmond 

The TPM 2.0 command reference states that "auth" (type TPM2B_AUTH)
should come before "publicInfo" (type TPM2B_NV_PUBLIC) in the
"TPM2_NV_DefineSpace" command.  Let's add an empty "auth" (size 0), so
that this can work with compliant TPMs.

Make sure that NV index used in tpm2_nv_define_space() can be used
directly in the NV read/write/lock APIs.

Signed-off-by: Sean Edmond 
---
 lib/tpm-v2.c | 20 ++--
 1 file changed, 14 insertions(+), 6 deletions(-)

diff --git a/lib/tpm-v2.c b/lib/tpm-v2.c
index c3c469eb35..d3ecf556d2 100644
--- a/lib/tpm-v2.c
+++ b/lib/tpm-v2.c
@@ -109,7 +109,7 @@ u32 tpm2_nv_define_space(struct udevice *dev, u32 
space_index,
const int platform_len = sizeof(u32);
const int session_hdr_len = 13;
const int message_len = 14;
-   uint offset = TPM2_HDR_LEN + platform_len + session_hdr_len +
+   uint offset = TPM2_HDR_LEN + platform_len + session_hdr_len + 2 +
message_len;
u8 command_v2[COMMAND_BUFFER_SIZE] = {
/* header 10 bytes */
@@ -127,6 +127,9 @@ u32 tpm2_nv_define_space(struct udevice *dev, u32 
space_index,
0,  /* session_attrs */
tpm_u16(0), /* auth_size */
 
+   /* auth value */
+   tpm_u16(0),
+
/* message 14 bytes + policy */
tpm_u16(message_len + nv_policy_size),  /* size */
tpm_u32(space_index),
@@ -206,7 +209,7 @@ u32 tpm2_nv_read_value(struct udevice *dev, u32 index, void 
*data, u32 count)
 
/* handles 8 bytes */
tpm_u32(TPM2_RH_PLATFORM),  /* Primary platform seed */
-   tpm_u32(HR_NV_INDEX + index),   /* Password authorisation */
+   tpm_u32(index), /* nvIndex */
 
/* AUTH_SESSION */
tpm_u32(9), /* Authorization size */
@@ -229,9 +232,14 @@ u32 tpm2_nv_read_value(struct udevice *dev, u32 index, 
void *data, u32 count)
ret = tpm_sendrecv_command(dev, command_v2, response, _len);
if (ret)
return log_msg_ret("read", ret);
+
+   const size_t tag_offset = 0;
+   const size_t size_offset = 2;
+   const size_t code_offset = 6;
+   const size_t data_offset = 16;
if (unpack_byte_string(response, response_len, "wdds",
-  0, , 2, , 6, ,
-  16, data, count))
+  tag_offset, , size_offset, , 
code_offset, ,
+  data_offset, data, count))
return TPM_LIB_ERROR;
 
return 0;
@@ -254,7 +262,7 @@ u32 tpm2_nv_write_value(struct udevice *dev, u32 index, 
const void *data,
 
/* handles 8 bytes */
tpm_u32(auth),  /* Primary platform seed */
-   tpm_u32(HR_NV_INDEX + index),   /* Password authorisation */
+   tpm_u32(index), /* nvIndex */
 
/* AUTH_SESSION */
tpm_u32(9), /* Authorization size */
@@ -643,7 +651,7 @@ u32 tpm2_write_lock(struct udevice *dev, u32 index)
 
/* handles 8 bytes */
tpm_u32(TPM2_RH_PLATFORM),  /* Primary platform seed */
-   tpm_u32(HR_NV_INDEX + index),   /* Password authorisation */
+   tpm_u32(index), /* nvIndex */
 
/* session header 9 bytes */
tpm_u32(9), /* Header size */
-- 
2.40.0



[PATCH 4/8] common: Add OS anti-rollback grace version

2023-09-12 Thread seanedmond
From: Stephen Carlson 

New config CONFIG_FIT_ROLLBACK_CHECK_GRACE to add a one unit grace version
to OS anti-rollback protection, allowing images with anti-rollback
counters exactly one less than the platform value to still be loaded. No
update to the platform anti-rollback counter will be performed in this
case.

Signed-off-by: Stephen Carlson 
Signed-off-by: Sean Edmond 
---
 boot/Kconfig | 10 ++
 boot/image-fit-sig.c |  7 ++-
 2 files changed, 16 insertions(+), 1 deletion(-)

diff --git a/boot/Kconfig b/boot/Kconfig
index 9180a1c8dc..95a717765c 100644
--- a/boot/Kconfig
+++ b/boot/Kconfig
@@ -112,6 +112,16 @@ config FIT_ROLLBACK_CHECK
  when a platform needs to retire previous versions of FIT images due to
  security flaws and prevent devices from being reverted to them.
 
+config FIT_ROLLBACK_CHECK_GRACE
+   bool "Enable FIT Anti rollback grace version"
+   depends on FIT_ARBP
+   default n
+   help
+ Enables a one unit grace version for FIT image anti-rollback 
protection,
+ where anti-rollback protection will still accept a FIT image with an
+ anti-rollback version one less than the current number, but will not
+ update the platform anti-rollback counter in that case.
+
 config FIT_VERBOSE
bool "Show verbose messages when FIT images fail"
depends on FIT
diff --git a/boot/image-fit-sig.c b/boot/image-fit-sig.c
index 91eaf4baa8..5689a316b6 100644
--- a/boot/image-fit-sig.c
+++ b/boot/image-fit-sig.c
@@ -70,6 +70,7 @@ static int fit_image_verify_rollback(const void *fit, int 
image_noffset)
 #if !defined(USE_HOSTCC)
u64 image_rollback;
u64 plat_rollback = 0ULL;
+   u64 target_rollback;
struct udevice *dev;
int ret;
 
@@ -90,7 +91,11 @@ static int fit_image_verify_rollback(const void *fit, int 
image_noffset)
if (ret)
return -EIO;
 
-   if (image_rollback < plat_rollback) {
+   target_rollback = plat_rollback;
+   /* Calculate target anti-rollback version, including grace version if 
enabled */
+   if (CONFIG_IS_ENABLED(FIT_ROLLBACK_CHECK_GRACE) && plat_rollback > 0ULL)
+   target_rollback = plat_rollback - 1ULL;
+   if (image_rollback < target_rollback) {
return -EPERM;
} else if (image_rollback > plat_rollback) {
ret = rollback_idx_set(dev, image_rollback);
-- 
2.40.0



[PATCH 3/8] common: Add OS anti-rollback validation using rollback devices

2023-09-12 Thread seanedmond
From: Stephen Carlson 

New config CONFIG_ROLLBACK_CHECK to enable enforcement of OS anti-rollback
counter during image loading.

Images with an anti-rollback counter value "rollback" declared in the FDT
will be compared against the current device anti-rollback counter value,
and older images will not pass signature validation. If the image is
newer, the device anti-rollback counter value will be updated.

Signed-off-by: Stephen Carlson 
Signed-off-by: Sean Edmond 
---
 boot/Kconfig |  9 +
 boot/image-fit-sig.c | 92 
 boot/image-fit.c | 31 +++
 include/image.h  |  6 ++-
 4 files changed, 137 insertions(+), 1 deletion(-)

diff --git a/boot/Kconfig b/boot/Kconfig
index e8fb03b801..9180a1c8dc 100644
--- a/boot/Kconfig
+++ b/boot/Kconfig
@@ -103,6 +103,15 @@ config FIT_CIPHER
  Enable the feature of data ciphering/unciphering in the tool mkimage
  and in the u-boot support of the FIT image.
 
+config FIT_ROLLBACK_CHECK
+   bool "Enable Anti rollback version check for FIT images"
+   depends on FIT_SIGNATURE
+   default n
+   help
+ Enables FIT image anti-rollback protection. This feature is required
+ when a platform needs to retire previous versions of FIT images due to
+ security flaws and prevent devices from being reverted to them.
+
 config FIT_VERBOSE
bool "Show verbose messages when FIT images fail"
depends on FIT
diff --git a/boot/image-fit-sig.c b/boot/image-fit-sig.c
index 12369896fe..91eaf4baa8 100644
--- a/boot/image-fit-sig.c
+++ b/boot/image-fit-sig.c
@@ -11,6 +11,8 @@
 #include 
 #include 
 #include 
+#include 
+#include 
 DECLARE_GLOBAL_DATA_PTR;
 #endif /* !USE_HOSTCC*/
 #include 
@@ -63,6 +65,44 @@ struct image_region *fit_region_make_list(const void *fit,
return region;
 }
 
+static int fit_image_verify_rollback(const void *fit, int image_noffset)
+{
+#if !defined(USE_HOSTCC)
+   u64 image_rollback;
+   u64 plat_rollback = 0ULL;
+   struct udevice *dev;
+   int ret;
+
+   ret = fit_image_get_rollback(fit, image_noffset, _rollback);
+
+   /* If the FIT doesn't contain the rollback property, assume an
+* anti-rollback version number of 0.  This ensures failure
+* if the platform anti-rollback version number is non-zero
+*/
+   if (ret)
+   image_rollback = 0;
+
+   ret = uclass_first_device_err(UCLASS_ROLLBACK, );
+   if (ret)
+   return ret;
+
+   ret = rollback_idx_get(dev, _rollback);
+   if (ret)
+   return -EIO;
+
+   if (image_rollback < plat_rollback) {
+   return -EPERM;
+   } else if (image_rollback > plat_rollback) {
+   ret = rollback_idx_set(dev, image_rollback);
+   printf(" Updating OS anti-rollback to %llu from %llu\n",
+  image_rollback, plat_rollback);
+   return ret;
+   }
+#endif
+
+   return 0;
+}
+
 static int fit_image_setup_verify(struct image_sign_info *info,
  const void *fit, int noffset,
  const void *key_blob, int required_keynode,
@@ -175,6 +215,16 @@ static int fit_image_verify_sig(const void *fit, int 
image_noffset,
goto error;
}
 
+   if (!tools_build()) {
+   if (FIT_IMAGE_ENABLE_ROLLBACK_CHECK && verified) {
+   ret = fit_image_verify_rollback(fit, image_noffset);
+   if (ret) {
+   err_msg = "Anti-rollback verification failed";
+   goto error;
+   }
+   }
+   }
+
return verified ? 0 : -EPERM;
 
 error:
@@ -385,6 +435,38 @@ static int fit_config_check_sig(const void *fit, int 
noffset, int conf_noffset,
return 0;
 }
 
+static int fit_config_verify_rollback(const void *fit, int conf_noffset,
+ int sig_offset)
+{
+   static const char default_list[] = FIT_KERNEL_PROP "\0"
+   FIT_FDT_PROP;
+   int ret, len;
+   const char *prop, *iname, *end;
+   int image_noffset;
+
+   /* If there is "sign-images" property, use that */
+   prop = fdt_getprop(fit, sig_offset, "sign-images", );
+   if (!prop) {
+   prop = default_list;
+   len = sizeof(default_list);
+   }
+
+   /* Locate the images */
+   end = prop + len;
+   for (iname = prop; iname < end; iname += strlen(iname) + 1) {
+   image_noffset = fit_conf_get_prop_node(fit, conf_noffset,
+  iname, IH_PHASE_NONE);
+   if (image_noffset < 0)
+   return -ENOENT;
+
+   ret = fit_image_verify_rollback(fit, image_noffset);
+   if (ret)
+   return ret;
+   }
+
+   return 

[PATCH 0/5] Add anti-rollback validation feature

2023-09-12 Thread seanedmond
From: Sean Edmond 

Adds Add anti-rollback version protection. Images with an anti-rollback counter
value "rollback" declared in the kernel FDT will be compared against the 
current device 
anti-rollback counter value, and older images will not pass signature 
validation. If the image is newer, the device anti-rollback counter value will
be updated.

The "rollback" value is stored/retrieved using the newly added security driver.
A "TPM backed" and "sandbox backed" security driver have been provided as 
examples.

Adds new configs:
- CONFIG_DM_ROLLBACK : enable security device support
- CONFIG_ROLLBACK_SANDBOX : enables "rollback-sandbox" driver
- CONFIG_ROLLBACK_TPM : Enables "rollback-tpm" driver
- CONFIG_FIT_ROLLBACK_CHECK : enable enforcement of OS anti-rollback counter 
during image loading
- CONFIG_FIT_ROLLBACK_CHECK_GRACE : adds a one unit grace version to OS 
anti-rollback protection

changes in v2:
- arbvn -> rollback_idx
- rollback-tpm is a child of TPM device
- tpm_rollback_counter_init() tries to read NV index, defines and writes 0 if 
it fails
- tpm_rollback_counter_init() moved to tpm-v2.c
- Use tpm_auto_start()
- No error checking in rollback_idx_get()/rollback_idx_set() (intelligence is 
in fit_image_verify_rollback())
- assume "rollback" of 0 if FIT property not found
- "grace period" -> "grace version"
- drop "dm_" prefix in header
- Fix for tpm2_nv_define_space() (add "auth" parameter)
- Make NV index consistent across APIs (define/read/write/lock).  IS THIS 
CORRECT?!
- Add documentation

Sean Edmond (1):
  dm: test: Add a test for security driver

Stephen Carlson (4):
  drivers: security: Add security devices to driver model
  drivers: security: Add TPM2 implementation of security devices
  common: Add OS anti-rollback validation using security devices
  common: Add OS anti-rollback grace period

 MAINTAINERS |   9 ++
 arch/sandbox/dts/test.dts   |   8 ++
 boot/Kconfig|  19 +++
 boot/image-fit-sig.c|  94 +++
 boot/image-fit.c|  23 
 configs/sandbox_defconfig   |   3 +
 drivers/Kconfig |   2 +
 drivers/Makefile|   1 +
 drivers/security/Kconfig|  25 
 drivers/security/Makefile   |   7 ++
 drivers/security/sandbox_security.c |  65 +++
 drivers/security/security-tpm.c | 173 
 drivers/security/security-uclass.c  |  30 +
 include/dm-security.h   |  44 +++
 include/dm/uclass-id.h  |   1 +
 include/image.h |   4 +
 include/tpm-v2.h|   1 +
 test/dm/Makefile|   1 +
 test/dm/security.c  |  78 +
 19 files changed, 588 insertions(+)
 create mode 100644 drivers/security/Kconfig
 create mode 100644 drivers/security/Makefile
 create mode 100644 drivers/security/sandbox_security.c
 create mode 100644 drivers/security/security-tpm.c
 create mode 100644 drivers/security/security-uclass.c
 create mode 100644 include/dm-security.h
 create mode 100644 test/dm/security.c

-- 
2.40.0



[PATCH v2 2/4] fdt: kaslr seed from tpm entropy

2023-08-29 Thread seanedmond
From: Dhananjay Phadke 

Add support for KASLR seed from TPM device. Invokes tpm_get_random()
API to read 8-bytes of random bytes for KASLR.

Signed-off-by: Dhananjay Phadke 
Signed-off-by: Drew Kluemke 
Signed-off-by: Sean Edmond 
---
 boot/image-fdt.c  | 15 +++
 common/fdt_support.c  | 30 ++
 include/fdt_support.h |  8 
 lib/Kconfig   |  9 +
 4 files changed, 62 insertions(+)

diff --git a/boot/image-fdt.c b/boot/image-fdt.c
index f10200f647..ed38ed77b9 100644
--- a/boot/image-fdt.c
+++ b/boot/image-fdt.c
@@ -624,6 +624,21 @@ int image_setup_libfdt(struct bootm_headers *images, void 
*blob,
goto err;
}
 
+   if (IS_ENABLED(CONFIG_KASLR_TPM_SEED)) {
+   ofnode root;
+
+   ret = root_ofnode_from_fdt(blob, );
+   if (ret) {
+   printf("ERROR: Unable to get root ofnode\n");
+   goto err;
+   }
+   ret = fdt_tpm_kaslr_seed(root);
+   if (ret) {
+   printf("ERROR: fdt fixup KASLR failed: %d\n", ret);
+   goto err;
+   }
+   }
+
fdt_ret = optee_copy_fdt_nodes(blob);
if (fdt_ret) {
printf("ERROR: transfer of optee nodes to new fdt failed: %s\n",
diff --git a/common/fdt_support.c b/common/fdt_support.c
index 52be4375b4..d338fcde54 100644
--- a/common/fdt_support.c
+++ b/common/fdt_support.c
@@ -13,6 +13,9 @@
 #include 
 #include 
 #include 
+#include 
+#include 
+#include 
 #include 
 #include 
 #include 
@@ -650,6 +653,33 @@ int fdt_fixup_kaslr_seed(ofnode node, const u8 *seed, int 
len)
return 0;
 }
 
+int fdt_tpm_kaslr_seed(ofnode node)
+{
+   u8 rand[8] = {0};
+   struct udevice *dev;
+   int ret;
+
+   ret = uclass_first_device_err(UCLASS_TPM, );
+   if (ret) {
+   printf("ERROR: Failed to find TPM device\n");
+   return ret;
+   }
+
+   ret = tpm_get_random(dev, rand, sizeof(rand));
+   if (ret) {
+   printf("ERROR: TPM GetRandom failed, ret=%d\n", ret);
+   return ret;
+   }
+
+   ret = fdt_fixup_kaslr_seed(node, rand, sizeof(rand));
+   if (ret) {
+   printf("ERROR: failed to add kaslr-seed to fdt\n");
+   return ret;
+   }
+
+   return 0;
+}
+
 int fdt_record_loadable(void *blob, u32 index, const char *name,
uintptr_t load_addr, u32 size, uintptr_t entry_point,
const char *type, const char *os, const char *arch)
diff --git a/include/fdt_support.h b/include/fdt_support.h
index d967118bed..117ca14ca5 100644
--- a/include/fdt_support.h
+++ b/include/fdt_support.h
@@ -130,6 +130,14 @@ void fdt_fixup_ethernet(void *fdt);
  */
 int fdt_fixup_kaslr_seed(ofnode node, const u8 *seed, int len);
 
+/*
+ * fdt_add_tpm_kaslr_seed - Add kalsr-seed node in Device tree with random
+ * bytes from TPM device
+ * @node:  ofnode
+ * @eret:  0 for success
+ */
+int fdt_tpm_kaslr_seed(ofnode node);
+
 int fdt_find_and_setprop(void *fdt, const char *node, const char *prop,
 const void *val, int len, int create);
 void fdt_fixup_qe_firmware(void *fdt);
diff --git a/lib/Kconfig b/lib/Kconfig
index 3926652db6..1530ef7c86 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -465,6 +465,15 @@ config VPL_TPM
  for the low-level TPM interface, but only one TPM is supported at
  a time by the TPM library.
 
+config KASLR_TPM_SEED
+   bool "Use TPM for KASLR random seed"
+   depends on TPM_V1 || TPM_V2
+   help
+ This enables support for using TPMs as entropy source for KASLR seed
+ populated in kernel's device tree. Both TPMv1 and TPMv2 are supported
+ for the low-level TPM interface, but only one TPM is supported at
+ a time by the library.
+
 endmenu
 
 menu "Android Verified Boot"
-- 
2.40.0



[PATCH v2 4/4] dm: core: Modify default for OFNODE_MULTI_TREE

2023-08-29 Thread seanedmond
From: Sean Edmond 

There is a preference to use the "ofnode" API for FDT fixups
moving forward.  The FDT fixup will usually be for the kernel FDT.  To
fixup the kernel FDT with the ofnode API, it's required to set the
OFNODE_MULTI_TREE option.

To ensure existing users of kaslr fdt fixup are not impacted, Let's modify
the default value for OFNODE_MULTI_TREE to ensure it's always set if
!OF_LIVE.  This will cause a 1007 byte increase in the code size.

Signed-off-by: Sean Edmond 
---
 drivers/core/Kconfig | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/core/Kconfig b/drivers/core/Kconfig
index f0d848f45d..38e44ef6fc 100644
--- a/drivers/core/Kconfig
+++ b/drivers/core/Kconfig
@@ -424,7 +424,7 @@ config DM_DEV_READ_INLINE
 
 config OFNODE_MULTI_TREE
bool "Allow the ofnode interface to access any tree"
-   default y if EVENT && !DM_DEV_READ_INLINE && !DM_INLINE_OFNODE
+   default y if !OF_LIVE
help
  Normally U-Boot makes use of its control FDT, the one used to bind
  devices and provide options. In some cases, U-Boot must also process
-- 
2.40.0



[PATCH v2 3/4] cmd: kaslrseed: Use common API to fixup FDT

2023-08-29 Thread seanedmond
From: Sean Edmond 

Use the newly introduced common API fdt_fixup_kaslr_seed() in the
kaslrseed command.

Signed-off-by: Sean Edmond 
---
 cmd/kaslrseed.c | 22 --
 1 file changed, 8 insertions(+), 14 deletions(-)

diff --git a/cmd/kaslrseed.c b/cmd/kaslrseed.c
index 8a1d8120cd..c65607619b 100644
--- a/cmd/kaslrseed.c
+++ b/cmd/kaslrseed.c
@@ -19,7 +19,7 @@ static int do_kaslr_seed(struct cmd_tbl *cmdtp, int flag, int 
argc, char *const
size_t n = 0x8;
struct udevice *dev;
u64 *buf;
-   int nodeoffset;
+   ofnode root;
int ret = CMD_RET_SUCCESS;
 
if (uclass_get_device(UCLASS_RNG, 0, ) || !dev) {
@@ -45,21 +45,15 @@ static int do_kaslr_seed(struct cmd_tbl *cmdtp, int flag, 
int argc, char *const
return CMD_RET_FAILURE;
}
 
-   ret = fdt_check_header(working_fdt);
-   if (ret < 0) {
-   printf("fdt_chosen: %s\n", fdt_strerror(ret));
-   return CMD_RET_FAILURE;
-   }
-
-   nodeoffset = fdt_find_or_add_subnode(working_fdt, 0, "chosen");
-   if (nodeoffset < 0) {
-   printf("Reading chosen node failed\n");
-   return CMD_RET_FAILURE;
+   ret = root_ofnode_from_fdt(working_fdt, );
+   if (ret) {
+   printf("ERROR: Unable to get root ofnode\n");
+   goto CMD_RET_FAILURE;
}
 
-   ret = fdt_setprop(working_fdt, nodeoffset, "kaslr-seed", buf, 
sizeof(buf));
-   if (ret < 0) {
-   printf("Unable to set kaslr-seed on chosen node: %s\n", 
fdt_strerror(ret));
+   ret = fdt_fixup_kaslr_seed(root, buf, sizeof(buf));
+   if (ret) {
+   printf("ERROR: failed to add kaslr-seed to fdt\n");
return CMD_RET_FAILURE;
}
 
-- 
2.40.0



[PATCH v2 1/4] fdt: common API to populate kaslr seed

2023-08-29 Thread seanedmond
From: Dhananjay Phadke 

fdt_fixup_kaslr_seed() will update given ofnode with random seed value.
Source for random seed can be TPM or RNG driver in u-boot or sec
firmware (ARM).

Signed-off-by: Dhananjay Phadke 
Signed-off-by: Sean Edmond 
---
 arch/arm/cpu/armv8/sec_firmware.c | 39 +++
 common/fdt_support.c  | 19 +++
 drivers/core/ofnode.c | 17 ++
 include/dm/ofnode.h   | 12 ++
 include/fdt_support.h |  9 +++
 5 files changed, 71 insertions(+), 25 deletions(-)

diff --git a/arch/arm/cpu/armv8/sec_firmware.c 
b/arch/arm/cpu/armv8/sec_firmware.c
index c0e8726346..5f04cd8aec 100644
--- a/arch/arm/cpu/armv8/sec_firmware.c
+++ b/arch/arm/cpu/armv8/sec_firmware.c
@@ -411,46 +411,35 @@ int sec_firmware_init(const void *sec_firmware_img,
 /*
  * fdt_fix_kaslr - Add kalsr-seed node in Device tree
  * @fdt:   Device tree
- * @eret:  0 in case of error, 1 for success
+ * @eret:  0 for success
  */
 int fdt_fixup_kaslr(void *fdt)
 {
-   int nodeoffset;
-   int err, ret = 0;
-   u8 rand[8];
+   int ret = 0;
 
 #if defined(CONFIG_ARMV8_SEC_FIRMWARE_SUPPORT)
+   u8 rand[8];
+   ofnode root;
+
/* Check if random seed generation is  supported */
if (sec_firmware_support_hwrng() == false) {
printf("WARNING: SEC firmware not running, no kaslr-seed\n");
-   return 0;
+   return -EOPNOTSUPP;
}
 
-   err = sec_firmware_get_random(rand, 8);
-   if (err < 0) {
+   ret = sec_firmware_get_random(rand, 8);
+   if (ret < 0) {
printf("WARNING: No random number to set kaslr-seed\n");
-   return 0;
+   return ret;
}
 
-   err = fdt_check_header(fdt);
-   if (err < 0) {
-   printf("fdt_chosen: %s\n", fdt_strerror(err));
-   return 0;
+   ret = root_ofnode_from_fdt(fdt, );
+   if (ret < 0) {
+   printf("WARNING: Unable to get root ofnode\n");
+   return ret;
}
 
-   /* find or create "/chosen" node. */
-   nodeoffset = fdt_find_or_add_subnode(fdt, 0, "chosen");
-   if (nodeoffset < 0)
-   return 0;
-
-   err = fdt_setprop(fdt, nodeoffset, "kaslr-seed", rand,
- sizeof(rand));
-   if (err < 0) {
-   printf("WARNING: can't set kaslr-seed %s.\n",
-  fdt_strerror(err));
-   return 0;
-   }
-   ret = 1;
+   ret = fdt_fixup_kaslr_seed(root, rand, sizeof(rand));
 #endif
 
return ret;
diff --git a/common/fdt_support.c b/common/fdt_support.c
index 5e49078f8c..52be4375b4 100644
--- a/common/fdt_support.c
+++ b/common/fdt_support.c
@@ -631,6 +631,25 @@ void fdt_fixup_ethernet(void *fdt)
}
 }
 
+int fdt_fixup_kaslr_seed(ofnode node, const u8 *seed, int len)
+{
+   ofnode chosen;
+   int ret;
+
+   /* find or create "/chosen" node. */
+   ret = ofnode_add_subnode(node, "chosen", );
+   if (ret && ret != -EEXIST)
+   return -ENOENT;
+
+   ret = ofnode_write_prop(chosen, "kaslr-seed", seed, len, true);
+   if (ret) {
+   printf("WARNING: can't set kaslr-seed\n");
+   return ret;
+   }
+
+   return 0;
+}
+
 int fdt_record_loadable(void *blob, u32 index, const char *name,
uintptr_t load_addr, u32 size, uintptr_t entry_point,
const char *type, const char *os, const char *arch)
diff --git a/drivers/core/ofnode.c b/drivers/core/ofnode.c
index 8df16e56af..4be21133b8 100644
--- a/drivers/core/ofnode.c
+++ b/drivers/core/ofnode.c
@@ -870,6 +870,23 @@ ofnode oftree_path(oftree tree, const char *path)
}
 }
 
+int root_ofnode_from_fdt(void *fdt, ofnode *root_node)
+{
+   oftree tree;
+   /* If OFNODE_MULTI_TREE is not set, and if fdt is not the control FDT,
+*  oftree_from_fdt() will return NULL
+*/
+   tree = oftree_from_fdt(fdt);
+
+   if (!oftree_valid(tree)) {
+   printf("Cannot create oftree\n");
+   return -EINVAL;
+   }
+   *root_node = oftree_root(tree);
+
+   return 0;
+}
+
 const void *ofnode_read_chosen_prop(const char *propname, int *sizep)
 {
ofnode chosen_node;
diff --git a/include/dm/ofnode.h b/include/dm/ofnode.h
index 0f38b3e736..e79bb62be8 100644
--- a/include/dm/ofnode.h
+++ b/include/dm/ofnode.h
@@ -901,6 +901,18 @@ ofnode oftree_path(oftree tree, const char *path);
  */
 ofnode oftree_root(oftree tree);
 
+/**
+ * root_ofnode_from_fdt() - Gets the root ofnode given an FDT blob.
+ *  Note, this will fail if OFNODE_MULTI_TREE
+ *  is not set.
+ *
+ * @fdt: Device tree to use
+ * @root_node : Root ofnode
+ *
+ * Return: 0 if OK, -ve on error
+ */
+int root_ofnode_from_fdt(void *fdt, ofnode 

[PATCH v2 0/4] Populate kaslr seed with TPM

2023-08-29 Thread seanedmond
From: Sean Edmond 

This patch series creates a common API (fdt_fixup_kaslr_seed()) for 
populating the kaslr seed in the DTB.  Existing users (kaslrseed,
and ARMv8 sec firmware) have been updated to use this common API.

New functionality has been introduced to populate the kaslr using
the TPM interface.  This can be enabled with CONFIG_KASLR_TPM_SEED.  

changes in v2:
- fdt_fixup_kaslr_seed() uses the ofnode API
- Add root_ofnode_from_fdt() to get the root node from an FDT and
  perform error checking on the oftree
- add comments to exported functions
- Add error checking in image_setup_libfdt() for return from
  fdt_tpm_kaslr_seed()
- uclass_get_device() -> uclass_first_device_err()
- Change default config for OFNODE_MULTI_TREE (y if !OF_LIVE)

Dhananjay Phadke (2):
  fdt: common API to populate kaslr seed
  fdt: kaslr seed from tpm entropy

Sean Edmond (2):
  cmd: kaslrseed: Use common API to fixup FDT
  dm: core: Modify default for OFNODE_MULTI_TREE

 arch/arm/cpu/armv8/sec_firmware.c | 39 +---
 boot/image-fdt.c  | 15 ++
 cmd/kaslrseed.c   | 22 +-
 common/fdt_support.c  | 49 +++
 drivers/core/Kconfig  |  2 +-
 drivers/core/ofnode.c | 17 +++
 include/dm/ofnode.h   | 12 
 include/fdt_support.h | 17 +++
 lib/Kconfig   |  9 ++
 9 files changed, 142 insertions(+), 40 deletions(-)

-- 
2.40.0



[PATCH v2 1/4] fdt: common API to populate kaslr seed

2023-08-29 Thread seanedmond
From: Dhananjay Phadke 

fdt_fixup_kaslr_seed() will update given ofnode with random seed value.
Source for random seed can be TPM or RNG driver in u-boot or sec
firmware (ARM).

Signed-off-by: Dhananjay Phadke 
Signed-off-by: Sean Edmond 
---
 arch/arm/cpu/armv8/sec_firmware.c | 39 +++
 common/fdt_support.c  | 19 +++
 drivers/core/ofnode.c | 17 ++
 include/dm/ofnode.h   | 12 ++
 include/fdt_support.h |  9 +++
 5 files changed, 71 insertions(+), 25 deletions(-)

diff --git a/arch/arm/cpu/armv8/sec_firmware.c 
b/arch/arm/cpu/armv8/sec_firmware.c
index c0e8726346..5f04cd8aec 100644
--- a/arch/arm/cpu/armv8/sec_firmware.c
+++ b/arch/arm/cpu/armv8/sec_firmware.c
@@ -411,46 +411,35 @@ int sec_firmware_init(const void *sec_firmware_img,
 /*
  * fdt_fix_kaslr - Add kalsr-seed node in Device tree
  * @fdt:   Device tree
- * @eret:  0 in case of error, 1 for success
+ * @eret:  0 for success
  */
 int fdt_fixup_kaslr(void *fdt)
 {
-   int nodeoffset;
-   int err, ret = 0;
-   u8 rand[8];
+   int ret = 0;
 
 #if defined(CONFIG_ARMV8_SEC_FIRMWARE_SUPPORT)
+   u8 rand[8];
+   ofnode root;
+
/* Check if random seed generation is  supported */
if (sec_firmware_support_hwrng() == false) {
printf("WARNING: SEC firmware not running, no kaslr-seed\n");
-   return 0;
+   return -EOPNOTSUPP;
}
 
-   err = sec_firmware_get_random(rand, 8);
-   if (err < 0) {
+   ret = sec_firmware_get_random(rand, 8);
+   if (ret < 0) {
printf("WARNING: No random number to set kaslr-seed\n");
-   return 0;
+   return ret;
}
 
-   err = fdt_check_header(fdt);
-   if (err < 0) {
-   printf("fdt_chosen: %s\n", fdt_strerror(err));
-   return 0;
+   ret = root_ofnode_from_fdt(fdt, );
+   if (ret < 0) {
+   printf("WARNING: Unable to get root ofnode\n");
+   return ret;
}
 
-   /* find or create "/chosen" node. */
-   nodeoffset = fdt_find_or_add_subnode(fdt, 0, "chosen");
-   if (nodeoffset < 0)
-   return 0;
-
-   err = fdt_setprop(fdt, nodeoffset, "kaslr-seed", rand,
- sizeof(rand));
-   if (err < 0) {
-   printf("WARNING: can't set kaslr-seed %s.\n",
-  fdt_strerror(err));
-   return 0;
-   }
-   ret = 1;
+   ret = fdt_fixup_kaslr_seed(root, rand, sizeof(rand));
 #endif
 
return ret;
diff --git a/common/fdt_support.c b/common/fdt_support.c
index 5e49078f8c..52be4375b4 100644
--- a/common/fdt_support.c
+++ b/common/fdt_support.c
@@ -631,6 +631,25 @@ void fdt_fixup_ethernet(void *fdt)
}
 }
 
+int fdt_fixup_kaslr_seed(ofnode node, const u8 *seed, int len)
+{
+   ofnode chosen;
+   int ret;
+
+   /* find or create "/chosen" node. */
+   ret = ofnode_add_subnode(node, "chosen", );
+   if (ret && ret != -EEXIST)
+   return -ENOENT;
+
+   ret = ofnode_write_prop(chosen, "kaslr-seed", seed, len, true);
+   if (ret) {
+   printf("WARNING: can't set kaslr-seed\n");
+   return ret;
+   }
+
+   return 0;
+}
+
 int fdt_record_loadable(void *blob, u32 index, const char *name,
uintptr_t load_addr, u32 size, uintptr_t entry_point,
const char *type, const char *os, const char *arch)
diff --git a/drivers/core/ofnode.c b/drivers/core/ofnode.c
index 8df16e56af..4be21133b8 100644
--- a/drivers/core/ofnode.c
+++ b/drivers/core/ofnode.c
@@ -870,6 +870,23 @@ ofnode oftree_path(oftree tree, const char *path)
}
 }
 
+int root_ofnode_from_fdt(void *fdt, ofnode *root_node)
+{
+   oftree tree;
+   /* If OFNODE_MULTI_TREE is not set, and if fdt is not the control FDT,
+*  oftree_from_fdt() will return NULL
+*/
+   tree = oftree_from_fdt(fdt);
+
+   if (!oftree_valid(tree)) {
+   printf("Cannot create oftree\n");
+   return -EINVAL;
+   }
+   *root_node = oftree_root(tree);
+
+   return 0;
+}
+
 const void *ofnode_read_chosen_prop(const char *propname, int *sizep)
 {
ofnode chosen_node;
diff --git a/include/dm/ofnode.h b/include/dm/ofnode.h
index 0f38b3e736..e79bb62be8 100644
--- a/include/dm/ofnode.h
+++ b/include/dm/ofnode.h
@@ -901,6 +901,18 @@ ofnode oftree_path(oftree tree, const char *path);
  */
 ofnode oftree_root(oftree tree);
 
+/**
+ * root_ofnode_from_fdt() - Gets the root ofnode given an FDT blob.
+ *  Note, this will fail if OFNODE_MULTI_TREE
+ *  is not set.
+ *
+ * @fdt: Device tree to use
+ * @root_node : Root ofnode
+ *
+ * Return: 0 if OK, -ve on error
+ */
+int root_ofnode_from_fdt(void *fdt, ofnode 

[PATCH v2 2/4] fdt: kaslr seed from tpm entropy

2023-08-29 Thread seanedmond
From: Dhananjay Phadke 

Add support for KASLR seed from TPM device. Invokes tpm_get_random()
API to read 8-bytes of random bytes for KASLR.

Signed-off-by: Dhananjay Phadke 
Signed-off-by: Drew Kluemke 
Signed-off-by: Sean Edmond 
---
 boot/image-fdt.c  | 15 +++
 common/fdt_support.c  | 30 ++
 include/fdt_support.h |  8 
 lib/Kconfig   |  9 +
 4 files changed, 62 insertions(+)

diff --git a/boot/image-fdt.c b/boot/image-fdt.c
index f10200f647..ed38ed77b9 100644
--- a/boot/image-fdt.c
+++ b/boot/image-fdt.c
@@ -624,6 +624,21 @@ int image_setup_libfdt(struct bootm_headers *images, void 
*blob,
goto err;
}
 
+   if (IS_ENABLED(CONFIG_KASLR_TPM_SEED)) {
+   ofnode root;
+
+   ret = root_ofnode_from_fdt(blob, );
+   if (ret) {
+   printf("ERROR: Unable to get root ofnode\n");
+   goto err;
+   }
+   ret = fdt_tpm_kaslr_seed(root);
+   if (ret) {
+   printf("ERROR: fdt fixup KASLR failed: %d\n", ret);
+   goto err;
+   }
+   }
+
fdt_ret = optee_copy_fdt_nodes(blob);
if (fdt_ret) {
printf("ERROR: transfer of optee nodes to new fdt failed: %s\n",
diff --git a/common/fdt_support.c b/common/fdt_support.c
index 52be4375b4..d338fcde54 100644
--- a/common/fdt_support.c
+++ b/common/fdt_support.c
@@ -13,6 +13,9 @@
 #include 
 #include 
 #include 
+#include 
+#include 
+#include 
 #include 
 #include 
 #include 
@@ -650,6 +653,33 @@ int fdt_fixup_kaslr_seed(ofnode node, const u8 *seed, int 
len)
return 0;
 }
 
+int fdt_tpm_kaslr_seed(ofnode node)
+{
+   u8 rand[8] = {0};
+   struct udevice *dev;
+   int ret;
+
+   ret = uclass_first_device_err(UCLASS_TPM, );
+   if (ret) {
+   printf("ERROR: Failed to find TPM device\n");
+   return ret;
+   }
+
+   ret = tpm_get_random(dev, rand, sizeof(rand));
+   if (ret) {
+   printf("ERROR: TPM GetRandom failed, ret=%d\n", ret);
+   return ret;
+   }
+
+   ret = fdt_fixup_kaslr_seed(node, rand, sizeof(rand));
+   if (ret) {
+   printf("ERROR: failed to add kaslr-seed to fdt\n");
+   return ret;
+   }
+
+   return 0;
+}
+
 int fdt_record_loadable(void *blob, u32 index, const char *name,
uintptr_t load_addr, u32 size, uintptr_t entry_point,
const char *type, const char *os, const char *arch)
diff --git a/include/fdt_support.h b/include/fdt_support.h
index d967118bed..117ca14ca5 100644
--- a/include/fdt_support.h
+++ b/include/fdt_support.h
@@ -130,6 +130,14 @@ void fdt_fixup_ethernet(void *fdt);
  */
 int fdt_fixup_kaslr_seed(ofnode node, const u8 *seed, int len);
 
+/*
+ * fdt_add_tpm_kaslr_seed - Add kalsr-seed node in Device tree with random
+ * bytes from TPM device
+ * @node:  ofnode
+ * @eret:  0 for success
+ */
+int fdt_tpm_kaslr_seed(ofnode node);
+
 int fdt_find_and_setprop(void *fdt, const char *node, const char *prop,
 const void *val, int len, int create);
 void fdt_fixup_qe_firmware(void *fdt);
diff --git a/lib/Kconfig b/lib/Kconfig
index 3926652db6..1530ef7c86 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -465,6 +465,15 @@ config VPL_TPM
  for the low-level TPM interface, but only one TPM is supported at
  a time by the TPM library.
 
+config KASLR_TPM_SEED
+   bool "Use TPM for KASLR random seed"
+   depends on TPM_V1 || TPM_V2
+   help
+ This enables support for using TPMs as entropy source for KASLR seed
+ populated in kernel's device tree. Both TPMv1 and TPMv2 are supported
+ for the low-level TPM interface, but only one TPM is supported at
+ a time by the library.
+
 endmenu
 
 menu "Android Verified Boot"
-- 
2.40.0



[PATCH v2 4/4] dm: core: Modify default for OFNODE_MULTI_TREE

2023-08-29 Thread seanedmond
From: Sean Edmond 

There is a preference to use the "ofnode" API for FDT fixups
moving forward.  The FDT fixup will usually be for the kernel FDT.  To
fixup the kernel FDT with the ofnode API, it's required to set the
OFNODE_MULTI_TREE option.

To ensure existing users of kaslr fdt fixup are not impacted, Let's modify
the default value for OFNODE_MULTI_TREE to ensure it's always set if
!OF_LIVE.  This will cause a 1007 byte increase in the code size.

Signed-off-by: Sean Edmond 
---
 drivers/core/Kconfig | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/core/Kconfig b/drivers/core/Kconfig
index f0d848f45d..38e44ef6fc 100644
--- a/drivers/core/Kconfig
+++ b/drivers/core/Kconfig
@@ -424,7 +424,7 @@ config DM_DEV_READ_INLINE
 
 config OFNODE_MULTI_TREE
bool "Allow the ofnode interface to access any tree"
-   default y if EVENT && !DM_DEV_READ_INLINE && !DM_INLINE_OFNODE
+   default y if !OF_LIVE
help
  Normally U-Boot makes use of its control FDT, the one used to bind
  devices and provide options. In some cases, U-Boot must also process
-- 
2.40.0



[PATCH v2 3/4] cmd: kaslrseed: Use common API to fixup FDT

2023-08-29 Thread seanedmond
From: Sean Edmond 

Use the newly introduced common API fdt_fixup_kaslr_seed() in the
kaslrseed command.

Signed-off-by: Sean Edmond 
---
 cmd/kaslrseed.c | 22 --
 1 file changed, 8 insertions(+), 14 deletions(-)

diff --git a/cmd/kaslrseed.c b/cmd/kaslrseed.c
index 8a1d8120cd..c65607619b 100644
--- a/cmd/kaslrseed.c
+++ b/cmd/kaslrseed.c
@@ -19,7 +19,7 @@ static int do_kaslr_seed(struct cmd_tbl *cmdtp, int flag, int 
argc, char *const
size_t n = 0x8;
struct udevice *dev;
u64 *buf;
-   int nodeoffset;
+   ofnode root;
int ret = CMD_RET_SUCCESS;
 
if (uclass_get_device(UCLASS_RNG, 0, ) || !dev) {
@@ -45,21 +45,15 @@ static int do_kaslr_seed(struct cmd_tbl *cmdtp, int flag, 
int argc, char *const
return CMD_RET_FAILURE;
}
 
-   ret = fdt_check_header(working_fdt);
-   if (ret < 0) {
-   printf("fdt_chosen: %s\n", fdt_strerror(ret));
-   return CMD_RET_FAILURE;
-   }
-
-   nodeoffset = fdt_find_or_add_subnode(working_fdt, 0, "chosen");
-   if (nodeoffset < 0) {
-   printf("Reading chosen node failed\n");
-   return CMD_RET_FAILURE;
+   ret = root_ofnode_from_fdt(working_fdt, );
+   if (ret) {
+   printf("ERROR: Unable to get root ofnode\n");
+   goto CMD_RET_FAILURE;
}
 
-   ret = fdt_setprop(working_fdt, nodeoffset, "kaslr-seed", buf, 
sizeof(buf));
-   if (ret < 0) {
-   printf("Unable to set kaslr-seed on chosen node: %s\n", 
fdt_strerror(ret));
+   ret = fdt_fixup_kaslr_seed(root, buf, sizeof(buf));
+   if (ret) {
+   printf("ERROR: failed to add kaslr-seed to fdt\n");
return CMD_RET_FAILURE;
}
 
-- 
2.40.0



[PATCH 2/4] fdt: kaslr seed from tpm entropy

2023-08-29 Thread seanedmond
From: Dhananjay Phadke 

Add support for KASLR seed from TPM device. Invokes tpm_get_random()
API to read 8-bytes of random bytes for KASLR.

Signed-off-by: Dhananjay Phadke 
Signed-off-by: Drew Kluemke 
Signed-off-by: Sean Edmond 
---
 boot/image-fdt.c  | 15 +++
 common/fdt_support.c  | 30 ++
 include/fdt_support.h |  8 
 lib/Kconfig   |  9 +
 4 files changed, 62 insertions(+)

diff --git a/boot/image-fdt.c b/boot/image-fdt.c
index f10200f647..ed38ed77b9 100644
--- a/boot/image-fdt.c
+++ b/boot/image-fdt.c
@@ -624,6 +624,21 @@ int image_setup_libfdt(struct bootm_headers *images, void 
*blob,
goto err;
}
 
+   if (IS_ENABLED(CONFIG_KASLR_TPM_SEED)) {
+   ofnode root;
+
+   ret = root_ofnode_from_fdt(blob, );
+   if (ret) {
+   printf("ERROR: Unable to get root ofnode\n");
+   goto err;
+   }
+   ret = fdt_tpm_kaslr_seed(root);
+   if (ret) {
+   printf("ERROR: fdt fixup KASLR failed: %d\n", ret);
+   goto err;
+   }
+   }
+
fdt_ret = optee_copy_fdt_nodes(blob);
if (fdt_ret) {
printf("ERROR: transfer of optee nodes to new fdt failed: %s\n",
diff --git a/common/fdt_support.c b/common/fdt_support.c
index 52be4375b4..d338fcde54 100644
--- a/common/fdt_support.c
+++ b/common/fdt_support.c
@@ -13,6 +13,9 @@
 #include 
 #include 
 #include 
+#include 
+#include 
+#include 
 #include 
 #include 
 #include 
@@ -650,6 +653,33 @@ int fdt_fixup_kaslr_seed(ofnode node, const u8 *seed, int 
len)
return 0;
 }
 
+int fdt_tpm_kaslr_seed(ofnode node)
+{
+   u8 rand[8] = {0};
+   struct udevice *dev;
+   int ret;
+
+   ret = uclass_first_device_err(UCLASS_TPM, );
+   if (ret) {
+   printf("ERROR: Failed to find TPM device\n");
+   return ret;
+   }
+
+   ret = tpm_get_random(dev, rand, sizeof(rand));
+   if (ret) {
+   printf("ERROR: TPM GetRandom failed, ret=%d\n", ret);
+   return ret;
+   }
+
+   ret = fdt_fixup_kaslr_seed(node, rand, sizeof(rand));
+   if (ret) {
+   printf("ERROR: failed to add kaslr-seed to fdt\n");
+   return ret;
+   }
+
+   return 0;
+}
+
 int fdt_record_loadable(void *blob, u32 index, const char *name,
uintptr_t load_addr, u32 size, uintptr_t entry_point,
const char *type, const char *os, const char *arch)
diff --git a/include/fdt_support.h b/include/fdt_support.h
index d967118bed..117ca14ca5 100644
--- a/include/fdt_support.h
+++ b/include/fdt_support.h
@@ -130,6 +130,14 @@ void fdt_fixup_ethernet(void *fdt);
  */
 int fdt_fixup_kaslr_seed(ofnode node, const u8 *seed, int len);
 
+/*
+ * fdt_add_tpm_kaslr_seed - Add kalsr-seed node in Device tree with random
+ * bytes from TPM device
+ * @node:  ofnode
+ * @eret:  0 for success
+ */
+int fdt_tpm_kaslr_seed(ofnode node);
+
 int fdt_find_and_setprop(void *fdt, const char *node, const char *prop,
 const void *val, int len, int create);
 void fdt_fixup_qe_firmware(void *fdt);
diff --git a/lib/Kconfig b/lib/Kconfig
index 3926652db6..1530ef7c86 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -465,6 +465,15 @@ config VPL_TPM
  for the low-level TPM interface, but only one TPM is supported at
  a time by the TPM library.
 
+config KASLR_TPM_SEED
+   bool "Use TPM for KASLR random seed"
+   depends on TPM_V1 || TPM_V2
+   help
+ This enables support for using TPMs as entropy source for KASLR seed
+ populated in kernel's device tree. Both TPMv1 and TPMv2 are supported
+ for the low-level TPM interface, but only one TPM is supported at
+ a time by the library.
+
 endmenu
 
 menu "Android Verified Boot"
-- 
2.40.0



[PATCH v2 0/4] Populate kaslr seed with TPM

2023-08-29 Thread seanedmond
From: Sean Edmond 

This patch series creates a common API (fdt_fixup_kaslr_seed()) for 
populating the kaslr seed in the DTB.  Existing users (kaslrseed,
and ARMv8 sec firmware) have been updated to use this common API.

New functionality has been introduced to populate the kaslr using
the TPM interface.  This can be enabled with CONFIG_KASLR_TPM_SEED.  

changes in v2:
- fdt_fixup_kaslr_seed() uses the ofnode API
- Add root_ofnode_from_fdt() to get the root node from an FDT and
  perform error checking on the oftree
- add comments to exported functions
- Add error checking in image_setup_libfdt() for return from
  fdt_tpm_kaslr_seed()
- uclass_get_device() -> uclass_first_device_err()
- Change default config for OFNODE_MULTI_TREE (y if !OF_LIVE)

Dhananjay Phadke (2):
  fdt: common API to populate kaslr seed
  fdt: kaslr seed from tpm entropy

Sean Edmond (2):
  cmd: kaslrseed: Use common API to fixup FDT
  dm: core: Modify default for OFNODE_MULTI_TREE

 arch/arm/cpu/armv8/sec_firmware.c | 39 +---
 boot/image-fdt.c  | 15 ++
 cmd/kaslrseed.c   | 22 +-
 common/fdt_support.c  | 49 +++
 drivers/core/Kconfig  |  2 +-
 drivers/core/ofnode.c | 17 +++
 include/dm/ofnode.h   | 12 
 include/fdt_support.h | 17 +++
 lib/Kconfig   |  9 ++
 9 files changed, 142 insertions(+), 40 deletions(-)

-- 
2.40.0



[PATCH 4/4] dm: core: Modify default for OFNODE_MULTI_TREE

2023-08-29 Thread seanedmond
From: Sean Edmond 

There is a preference to use the "ofnode" API for FDT fixups
moving forward.  The FDT fixup will usually be for the kernel FDT.  To
fixup the kernel FDT with the ofnode API, it's required to set the
OFNODE_MULTI_TREE option.

To ensure exisiting users on kasls fixup are not impacted, Let's modify
the default value for OFNODE_MULTI_TREE to ensure it's always set if
!OF_LIVE.  This will cause a 1007 byte increase in the code size.

Signed-off-by: Sean Edmond 
---
 drivers/core/Kconfig | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/core/Kconfig b/drivers/core/Kconfig
index f0d848f45d..38e44ef6fc 100644
--- a/drivers/core/Kconfig
+++ b/drivers/core/Kconfig
@@ -424,7 +424,7 @@ config DM_DEV_READ_INLINE
 
 config OFNODE_MULTI_TREE
bool "Allow the ofnode interface to access any tree"
-   default y if EVENT && !DM_DEV_READ_INLINE && !DM_INLINE_OFNODE
+   default y if !OF_LIVE
help
  Normally U-Boot makes use of its control FDT, the one used to bind
  devices and provide options. In some cases, U-Boot must also process
-- 
2.40.0



[PATCH 1/4] fdt: common API to populate kaslr seed

2023-08-29 Thread seanedmond
From: Dhananjay Phadke 

fdt_fixup_kaslr_seed() will update given FDT with random seed value.
Source for random seed can be TPM or RNG driver in u-boot or sec
firmware (ARM).

Signed-off-by: Dhananjay Phadke 
Signed-off-by: Sean Edmond 
---
 arch/arm/cpu/armv8/sec_firmware.c | 39 +++
 common/fdt_support.c  | 19 +++
 drivers/core/ofnode.c | 17 ++
 include/dm/ofnode.h   | 12 ++
 include/fdt_support.h |  9 +++
 5 files changed, 71 insertions(+), 25 deletions(-)

diff --git a/arch/arm/cpu/armv8/sec_firmware.c 
b/arch/arm/cpu/armv8/sec_firmware.c
index c0e8726346..5f04cd8aec 100644
--- a/arch/arm/cpu/armv8/sec_firmware.c
+++ b/arch/arm/cpu/armv8/sec_firmware.c
@@ -411,46 +411,35 @@ int sec_firmware_init(const void *sec_firmware_img,
 /*
  * fdt_fix_kaslr - Add kalsr-seed node in Device tree
  * @fdt:   Device tree
- * @eret:  0 in case of error, 1 for success
+ * @eret:  0 for success
  */
 int fdt_fixup_kaslr(void *fdt)
 {
-   int nodeoffset;
-   int err, ret = 0;
-   u8 rand[8];
+   int ret = 0;
 
 #if defined(CONFIG_ARMV8_SEC_FIRMWARE_SUPPORT)
+   u8 rand[8];
+   ofnode root;
+
/* Check if random seed generation is  supported */
if (sec_firmware_support_hwrng() == false) {
printf("WARNING: SEC firmware not running, no kaslr-seed\n");
-   return 0;
+   return -EOPNOTSUPP;
}
 
-   err = sec_firmware_get_random(rand, 8);
-   if (err < 0) {
+   ret = sec_firmware_get_random(rand, 8);
+   if (ret < 0) {
printf("WARNING: No random number to set kaslr-seed\n");
-   return 0;
+   return ret;
}
 
-   err = fdt_check_header(fdt);
-   if (err < 0) {
-   printf("fdt_chosen: %s\n", fdt_strerror(err));
-   return 0;
+   ret = root_ofnode_from_fdt(fdt, );
+   if (ret < 0) {
+   printf("WARNING: Unable to get root ofnode\n");
+   return ret;
}
 
-   /* find or create "/chosen" node. */
-   nodeoffset = fdt_find_or_add_subnode(fdt, 0, "chosen");
-   if (nodeoffset < 0)
-   return 0;
-
-   err = fdt_setprop(fdt, nodeoffset, "kaslr-seed", rand,
- sizeof(rand));
-   if (err < 0) {
-   printf("WARNING: can't set kaslr-seed %s.\n",
-  fdt_strerror(err));
-   return 0;
-   }
-   ret = 1;
+   ret = fdt_fixup_kaslr_seed(root, rand, sizeof(rand));
 #endif
 
return ret;
diff --git a/common/fdt_support.c b/common/fdt_support.c
index 5e49078f8c..52be4375b4 100644
--- a/common/fdt_support.c
+++ b/common/fdt_support.c
@@ -631,6 +631,25 @@ void fdt_fixup_ethernet(void *fdt)
}
 }
 
+int fdt_fixup_kaslr_seed(ofnode node, const u8 *seed, int len)
+{
+   ofnode chosen;
+   int ret;
+
+   /* find or create "/chosen" node. */
+   ret = ofnode_add_subnode(node, "chosen", );
+   if (ret && ret != -EEXIST)
+   return -ENOENT;
+
+   ret = ofnode_write_prop(chosen, "kaslr-seed", seed, len, true);
+   if (ret) {
+   printf("WARNING: can't set kaslr-seed\n");
+   return ret;
+   }
+
+   return 0;
+}
+
 int fdt_record_loadable(void *blob, u32 index, const char *name,
uintptr_t load_addr, u32 size, uintptr_t entry_point,
const char *type, const char *os, const char *arch)
diff --git a/drivers/core/ofnode.c b/drivers/core/ofnode.c
index 8df16e56af..4be21133b8 100644
--- a/drivers/core/ofnode.c
+++ b/drivers/core/ofnode.c
@@ -870,6 +870,23 @@ ofnode oftree_path(oftree tree, const char *path)
}
 }
 
+int root_ofnode_from_fdt(void *fdt, ofnode *root_node)
+{
+   oftree tree;
+   /* If OFNODE_MULTI_TREE is not set, and if fdt is not the control FDT,
+*  oftree_from_fdt() will return NULL
+*/
+   tree = oftree_from_fdt(fdt);
+
+   if (!oftree_valid(tree)) {
+   printf("Cannot create oftree\n");
+   return -EINVAL;
+   }
+   *root_node = oftree_root(tree);
+
+   return 0;
+}
+
 const void *ofnode_read_chosen_prop(const char *propname, int *sizep)
 {
ofnode chosen_node;
diff --git a/include/dm/ofnode.h b/include/dm/ofnode.h
index 0f38b3e736..e79bb62be8 100644
--- a/include/dm/ofnode.h
+++ b/include/dm/ofnode.h
@@ -901,6 +901,18 @@ ofnode oftree_path(oftree tree, const char *path);
  */
 ofnode oftree_root(oftree tree);
 
+/**
+ * root_ofnode_from_fdt() - Gets the root ofnode given an FDT blob.
+ *  Note, this will fail if OFNODE_MULTI_TREE
+ *  is not set.
+ *
+ * @fdt: Device tree to use
+ * @root_node : Root ofnode
+ *
+ * Return: 0 if OK, -ve on error
+ */
+int root_ofnode_from_fdt(void *fdt, ofnode *root_node);

[PATCH 3/4] cmd: kaslrseed: Use common API to fixup FDT

2023-08-29 Thread seanedmond
From: Sean Edmond 

Use the newly introduced common API fdt_fixup_kaslr_seed() in the
kaslrseed command.

Signed-off-by: Sean Edmond 
---
 cmd/kaslrseed.c | 22 --
 1 file changed, 8 insertions(+), 14 deletions(-)

diff --git a/cmd/kaslrseed.c b/cmd/kaslrseed.c
index 8a1d8120cd..c65607619b 100644
--- a/cmd/kaslrseed.c
+++ b/cmd/kaslrseed.c
@@ -19,7 +19,7 @@ static int do_kaslr_seed(struct cmd_tbl *cmdtp, int flag, int 
argc, char *const
size_t n = 0x8;
struct udevice *dev;
u64 *buf;
-   int nodeoffset;
+   ofnode root;
int ret = CMD_RET_SUCCESS;
 
if (uclass_get_device(UCLASS_RNG, 0, ) || !dev) {
@@ -45,21 +45,15 @@ static int do_kaslr_seed(struct cmd_tbl *cmdtp, int flag, 
int argc, char *const
return CMD_RET_FAILURE;
}
 
-   ret = fdt_check_header(working_fdt);
-   if (ret < 0) {
-   printf("fdt_chosen: %s\n", fdt_strerror(ret));
-   return CMD_RET_FAILURE;
-   }
-
-   nodeoffset = fdt_find_or_add_subnode(working_fdt, 0, "chosen");
-   if (nodeoffset < 0) {
-   printf("Reading chosen node failed\n");
-   return CMD_RET_FAILURE;
+   ret = root_ofnode_from_fdt(working_fdt, );
+   if (ret) {
+   printf("ERROR: Unable to get root ofnode\n");
+   goto CMD_RET_FAILURE;
}
 
-   ret = fdt_setprop(working_fdt, nodeoffset, "kaslr-seed", buf, 
sizeof(buf));
-   if (ret < 0) {
-   printf("Unable to set kaslr-seed on chosen node: %s\n", 
fdt_strerror(ret));
+   ret = fdt_fixup_kaslr_seed(root, buf, sizeof(buf));
+   if (ret) {
+   printf("ERROR: failed to add kaslr-seed to fdt\n");
return CMD_RET_FAILURE;
}
 
-- 
2.40.0



[PATCH 2/5] drivers: security: Add TPM2 implementation of security devices

2023-08-11 Thread seanedmond
From: Stephen Carlson 

This implementation of the security uclass driver allows existing TPM2
devices declared in the device tree to be referenced for storing the OS
anti-rollback counter, using the TPM2 non-volatile storage API.

Signed-off-by: Stephen Carlson 
---
 MAINTAINERS |   1 +
 drivers/security/Makefile   |   1 +
 drivers/security/security-tpm.c | 173 
 include/tpm-v2.h|   1 +
 4 files changed, 176 insertions(+)
 create mode 100644 drivers/security/security-tpm.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 73b6943e03..257660a847 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1444,6 +1444,7 @@ S:Maintained
 F: drivers/security/Kconfig
 F: drivers/security/Makefile
 F: drivers/security/sandbox_security.c
+F: drivers/security/security-tpm.c
 F: drivers/security/security-uclass.c
 
 SEMIHOSTING
diff --git a/drivers/security/Makefile b/drivers/security/Makefile
index ed10c3f234..e81966bb4a 100644
--- a/drivers/security/Makefile
+++ b/drivers/security/Makefile
@@ -4,3 +4,4 @@
 
 obj-$(CONFIG_DM_SECURITY) += security-uclass.o
 obj-$(CONFIG_SECURITY_SANDBOX) += sandbox_security.o
+obj-$(CONFIG_SECURITY_TPM) += security-tpm.o
diff --git a/drivers/security/security-tpm.c b/drivers/security/security-tpm.c
new file mode 100644
index 00..9070dd49ac
--- /dev/null
+++ b/drivers/security/security-tpm.c
@@ -0,0 +1,173 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2021 Microsoft, Inc
+ * Written by Stephen Carlson 
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+
+struct security_state {
+   u32 index_arbvn;
+   struct udevice *tpm_dev;
+};
+
+static int tpm_security_init(struct udevice *tpm_dev)
+{
+   int res;
+
+   /* Initialize TPM but allow reuse of existing session */
+   res = tpm_open(tpm_dev);
+   if (res == -EBUSY) {
+   log(UCLASS_SECURITY, LOGL_DEBUG,
+   "Existing TPM session found, reusing\n");
+   } else {
+   if (res) {
+   log(UCLASS_SECURITY, LOGL_ERR,
+   "TPM initialization failed (ret=%d)\n", res);
+   return res;
+   }
+
+   res = tpm2_startup(tpm_dev, TPM2_SU_CLEAR);
+   if (res) {
+   log(UCLASS_SECURITY, LOGL_ERR,
+   "TPM startup failed (ret=%d)\n", res);
+   return res;
+   }
+   }
+
+   return 0;
+}
+
+static int tpm_security_arbvn_get(struct udevice *dev, u64 *arbvn)
+{
+   struct security_state *priv = dev_get_priv(dev);
+   int ret;
+
+   if (!arbvn)
+   return -EINVAL;
+
+   ret = tpm2_nv_read_value(priv->tpm_dev, priv->index_arbvn, arbvn,
+sizeof(u64));
+   if (ret == TPM2_RC_NV_UNINITIALIZED) {
+   /* Expected if no OS image has been loaded before */
+   log(UCLASS_SECURITY, LOGL_INFO,
+   "No previous OS image, defaulting ARBVN to 0\n");
+   *arbvn = 0ULL;
+   } else if (ret) {
+   log(UCLASS_SECURITY, LOGL_ERR,
+   "Unable to read ARBVN from TPM (ret=%d)\n", ret);
+   return ret;
+   }
+
+   return 0;
+}
+
+static int tpm_security_arbvn_set(struct udevice *dev, u64 arbvn)
+{
+   struct security_state *priv = dev_get_priv(dev);
+   struct udevice *tpm_dev = priv->tpm_dev;
+   u64 old_arbvn;
+   int ret;
+
+   ret = tpm_security_arbvn_get(dev, _arbvn);
+   if (ret)
+   return ret;
+
+   if (arbvn < old_arbvn)
+   return -EPERM;
+
+   if (arbvn > old_arbvn) {
+   ret = tpm2_nv_write_value(tpm_dev, priv->index_arbvn, ,
+ sizeof(u64));
+   if (ret) {
+   log(UCLASS_SECURITY, LOGL_ERR,
+   "Unable to write ARBVN to TPM (ret=%d)\n", ret);
+   return ret;
+   }
+   }
+
+   return 0;
+}
+
+static const struct dm_security_ops tpm_security_ops = {
+   .arbvn_get  = tpm_security_arbvn_get,
+   .arbvn_set  = tpm_security_arbvn_set,
+};
+
+static int tpm_security_probe(struct udevice *dev)
+{
+   struct security_state *priv = dev_get_priv(dev);
+   struct udevice *tpm_dev = priv->tpm_dev;
+   u32 index = priv->index_arbvn;
+   int ret;
+
+   if (!tpm_dev) {
+   log(UCLASS_SECURITY, LOGL_ERR,
+   "TPM device not defined in DTS\n");
+   return -EINVAL;
+   }
+
+   ret = tpm_security_init(tpm_dev);
+   if (ret)
+   return ret;
+
+   ret = tpm2_nv_define_space(tpm_dev, index, sizeof(u64), TPMA_NV_PPREAD |
+  TPMA_NV_PPWRITE | TPMA_NV_PLATFORMCREATE,
+  NULL, 0);

[PATCH 3/5] common: Add OS anti-rollback validation using security devices

2023-08-11 Thread seanedmond
From: Stephen Carlson 

New config CONFIG_ARBP to enable enforcement of OS anti-rollback counter
during image loading.

Images with an anti-rollback counter value "arbvn" declared in the FDT will
be compared against the current device anti-rollback counter value, and
older images will not pass signature validation. If the image is newer, the
device anti-rollback counter value will be updated.

Signed-off-by: Stephen Carlson 
---
 boot/Kconfig |  9 +
 boot/image-fit-sig.c | 89 
 boot/image-fit.c | 23 
 include/image.h  |  4 ++
 4 files changed, 125 insertions(+)

diff --git a/boot/Kconfig b/boot/Kconfig
index e8fb03b801..e08c274b7c 100644
--- a/boot/Kconfig
+++ b/boot/Kconfig
@@ -103,6 +103,15 @@ config FIT_CIPHER
  Enable the feature of data ciphering/unciphering in the tool mkimage
  and in the u-boot support of the FIT image.
 
+config FIT_ARBP
+   bool "Enable Anti rollback version check for FIT images"
+   depends on FIT_SIGNATURE
+   default n
+   help
+ Enables FIT image anti-rollback protection. This feature is required
+ when a platform needs to retire previous versions of FIT images due to
+ security flaws and prevent devices from being reverted to them.
+
 config FIT_VERBOSE
bool "Show verbose messages when FIT images fail"
depends on FIT
diff --git a/boot/image-fit-sig.c b/boot/image-fit-sig.c
index 12369896fe..bf3b81a3a3 100644
--- a/boot/image-fit-sig.c
+++ b/boot/image-fit-sig.c
@@ -11,6 +11,8 @@
 #include 
 #include 
 #include 
+#include 
+#include 
 DECLARE_GLOBAL_DATA_PTR;
 #endif /* !USE_HOSTCC*/
 #include 
@@ -63,6 +65,39 @@ struct image_region *fit_region_make_list(const void *fit,
return region;
 }
 
+#if !defined(USE_HOSTCC)
+static int fit_image_verify_arbvn(const void *fit, int image_noffset)
+{
+   u64 image_arbvn;
+   u64 plat_arbvn = 0ULL;
+   struct udevice *dev;
+   int ret;
+
+   ret = fit_image_get_arbvn(fit, image_noffset, _arbvn);
+   if (ret)
+   return 0;
+
+   ret = uclass_first_device_err(UCLASS_SECURITY, );
+   if (ret)
+   return -ENODEV;
+
+   ret = dm_security_arbvn_get(dev, _arbvn);
+   if (ret)
+   return -EIO;
+
+   if (image_arbvn < plat_arbvn) {
+   return -EPERM;
+   } else if (image_arbvn > plat_arbvn) {
+   ret = dm_security_arbvn_set(dev, image_arbvn);
+   printf(" Updating OS anti-rollback to %llu from %llu\n",
+  image_arbvn, plat_arbvn);
+   return ret;
+   }
+
+   return 0;
+}
+#endif
+
 static int fit_image_setup_verify(struct image_sign_info *info,
  const void *fit, int noffset,
  const void *key_blob, int required_keynode,
@@ -175,6 +210,16 @@ static int fit_image_verify_sig(const void *fit, int 
image_noffset,
goto error;
}
 
+#if !defined(USE_HOSTCC)
+   if (FIT_IMAGE_ENABLE_ARBP && verified) {
+   ret = fit_image_verify_arbvn(fit, image_noffset);
+   if (ret) {
+   err_msg = "Anti-rollback verification failed";
+   goto error;
+   }
+   }
+#endif
+
return verified ? 0 : -EPERM;
 
 error:
@@ -385,6 +430,40 @@ static int fit_config_check_sig(const void *fit, int 
noffset, int conf_noffset,
return 0;
 }
 
+#if !defined(USE_HOSTCC)
+static int fit_config_verify_arbvn(const void *fit, int conf_noffset,
+  int sig_offset)
+{
+   static const char default_list[] = FIT_KERNEL_PROP "\0"
+   FIT_FDT_PROP;
+   int ret, len;
+   const char *prop, *iname, *end;
+   int image_noffset;
+
+   /* If there is "sign-images" property, use that */
+   prop = fdt_getprop(fit, sig_offset, "sign-images", );
+   if (!prop) {
+   prop = default_list;
+   len = sizeof(default_list);
+   }
+
+   /* Locate the images */
+   end = prop + len;
+   for (iname = prop; iname < end; iname += strlen(iname) + 1) {
+   image_noffset = fit_conf_get_prop_node(fit, conf_noffset,
+  iname, IH_PHASE_NONE);
+   if (image_noffset < 0)
+   return -ENOENT;
+
+   ret = fit_image_verify_arbvn(fit, image_noffset);
+   if (ret)
+   return ret;
+   }
+
+   return 0;
+}
+#endif
+
 /**
  * fit_config_verify_key() - Verify that a configuration is signed with a key
  *
@@ -444,6 +523,16 @@ static int fit_config_verify_key(const void *fit, int 
conf_noffset,
goto error;
}
 
+#if !defined(USE_HOSTCC)
+   if (FIT_IMAGE_ENABLE_ARBP && verified) {
+   ret = fit_config_verify_arbvn(fit, conf_noffset, noffset);

[PATCH 5/5] dm: test: Add a test for security driver

2023-08-11 Thread seanedmond
From: Sean Edmond 

Adds a test for a sandbox and TPM backed security driver.

Allows for testing of anti-rollback version number get/set API using the
security driver.

Signed-off-by: Sean Edmond 
---
 arch/sandbox/dts/test.dts |  8 
 configs/sandbox_defconfig |  3 ++
 test/dm/Makefile  |  1 +
 test/dm/security.c| 78 +++
 4 files changed, 90 insertions(+)
 create mode 100644 test/dm/security.c

diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts
index f351d5cb84..c87298cd46 100644
--- a/arch/sandbox/dts/test.dts
+++ b/arch/sandbox/dts/test.dts
@@ -1263,6 +1263,14 @@
backlight = < 0 100>;
};
 
+   security@0 {
+   compatible = "sandbox,security";
+   };
+
+   security@1 {
+   compatible = "tpm,security";
+   };
+
scsi {
compatible = "sandbox,scsi";
sandbox,filepath = "scsi.img";
diff --git a/configs/sandbox_defconfig b/configs/sandbox_defconfig
index 1cd1c2ed7c..546873b049 100644
--- a/configs/sandbox_defconfig
+++ b/configs/sandbox_defconfig
@@ -346,3 +346,6 @@ CONFIG_UNIT_TEST=y
 CONFIG_UT_TIME=y
 CONFIG_UT_DM=y
 CONFIG_ARM_FFA_TRANSPORT=y
+CONFIG_DM_SECURITY=y
+CONFIG_SECURITY_SANDBOX=y
+CONFIG_SECURITY_TPM=y
\ No newline at end of file
diff --git a/test/dm/Makefile b/test/dm/Makefile
index 7ed00733c1..d0583c0332 100644
--- a/test/dm/Makefile
+++ b/test/dm/Makefile
@@ -104,6 +104,7 @@ obj-$(CONFIG_DM_RNG) += rng.o
 obj-$(CONFIG_DM_RTC) += rtc.o
 obj-$(CONFIG_SCMI_FIRMWARE) += scmi.o
 obj-$(CONFIG_SCSI) += scsi.o
+obj-$(CONFIG_DM_SECURITY) += security.o
 obj-$(CONFIG_DM_SERIAL) += serial.o
 obj-$(CONFIG_DM_SPI_FLASH) += sf.o
 obj-$(CONFIG_SIMPLE_BUS) += simple-bus.o
diff --git a/test/dm/security.c b/test/dm/security.c
new file mode 100644
index 00..a388a80096
--- /dev/null
+++ b/test/dm/security.c
@@ -0,0 +1,78 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2023 Microsoft Corporation
+ * Written by Sean Edmond 
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+/*
+ * get_security() - Get a security driver of a given driver name
+ *
+ * @devp: Returns the security device
+ * @driver_name: Driver name to find
+ * Returns: 0 if OK, -ENODEV if not found
+ */
+static int get_security(struct udevice **devp, char *driver_name)
+{
+   struct udevice *dev;
+
+   uclass_foreach_dev_probe(UCLASS_SECURITY, dev) {
+   if (strcmp(dev->driver->name, driver_name) == 0) {
+   *devp = dev;
+   return 0;
+   }
+   }
+
+   return -ENODEV;
+}
+
+/* Basic test of security driver Anti rollback version number read/write */
+static int test_security_arbvn(struct unit_test_state *uts, char *driver_name)
+{
+   struct udevice *dev;
+   uint64_t arbvn;
+
+   /* get the security driver */
+   ut_assertok(get_security(, driver_name));
+
+   /* ensure initial value is 0 */
+   dm_security_arbvn_get(dev, );
+   ut_asserteq(0, arbvn);
+
+   /* write 1 and ensure it's read back */
+   dm_security_arbvn_set(dev, 1);
+   dm_security_arbvn_get(dev, );
+   ut_asserteq(1, arbvn);
+
+   /* write all ones and ensure it's read back */
+   dm_security_arbvn_set(dev, 0xULL);
+   dm_security_arbvn_get(dev, );
+   ut_asserteq(0xULL, arbvn);
+
+   return 0;
+}
+
+static int dm_test_security_sandbox(struct unit_test_state *uts)
+{
+   ut_assertok(test_security_arbvn(uts, "security_sandbox"));
+
+   return 0;
+}
+
+DM_TEST(dm_test_security_sandbox, UT_TESTF_SCAN_FDT);
+
+static int dm_test_security_tpm(struct unit_test_state *uts)
+{
+   ut_assertok(test_security_arbvn(uts, "security_tpm"));
+
+   return 0;
+}
+
+DM_TEST(dm_test_security_tpm, UT_TESTF_SCAN_FDT);
-- 
2.40.0



[PATCH 4/5] common: Add OS anti-rollback grace period

2023-08-11 Thread seanedmond
From: Stephen Carlson 

New config CONFIG_FIT_ARBVP_GRACE to add a one unit grace period to OS
anti-rollback protection, allowing images with anti-rollback counters
exactly one less than the platform value to still be loaded. No update to
the platform anti-rollback counter will be performed in this case.

Signed-off-by: Stephen Carlson 
---
 boot/Kconfig | 10 ++
 boot/image-fit-sig.c |  7 ++-
 2 files changed, 16 insertions(+), 1 deletion(-)

diff --git a/boot/Kconfig b/boot/Kconfig
index e08c274b7c..cd16bb8e53 100644
--- a/boot/Kconfig
+++ b/boot/Kconfig
@@ -112,6 +112,16 @@ config FIT_ARBP
  when a platform needs to retire previous versions of FIT images due to
  security flaws and prevent devices from being reverted to them.
 
+config FIT_ARBP_GRACE
+   bool "Enable FIT Anti rollback grace period"
+   depends on FIT_ARBP
+   default n
+   help
+ Enables a one unit grace period for FIT image anti-rollback 
protection,
+ where anti-rollback protection will still accept a FIT image with an
+ anti-rollback version one less than the current number, but will not
+ update the platform anti-rollback counter in that case.
+
 config FIT_VERBOSE
bool "Show verbose messages when FIT images fail"
depends on FIT
diff --git a/boot/image-fit-sig.c b/boot/image-fit-sig.c
index bf3b81a3a3..dc88a4b2cb 100644
--- a/boot/image-fit-sig.c
+++ b/boot/image-fit-sig.c
@@ -70,6 +70,7 @@ static int fit_image_verify_arbvn(const void *fit, int 
image_noffset)
 {
u64 image_arbvn;
u64 plat_arbvn = 0ULL;
+   u64 target_arbvn;
struct udevice *dev;
int ret;
 
@@ -85,7 +86,11 @@ static int fit_image_verify_arbvn(const void *fit, int 
image_noffset)
if (ret)
return -EIO;
 
-   if (image_arbvn < plat_arbvn) {
+   target_arbvn = plat_arbvn;
+   /* Calculate target ARBVN, including grace period if enabled */
+   if (CONFIG_IS_ENABLED(FIT_ARBP_GRACE) && plat_arbvn > 0ULL)
+   target_arbvn = plat_arbvn - 1ULL;
+   if (image_arbvn < target_arbvn) {
return -EPERM;
} else if (image_arbvn > plat_arbvn) {
ret = dm_security_arbvn_set(dev, image_arbvn);
-- 
2.40.0



[PATCH 1/5] drivers: security: Add security devices to driver model

2023-08-11 Thread seanedmond
From: Stephen Carlson 

Security devices currently implement operations to store an OS
anti-rollback monotonic counter. Existing devices such as the Trusted
Platform Module (TPM) already support this operation, but this uclass
provides abstraction for current and future devices that may support
different features.

- New Driver Model uclass UCLASS_SECURITY.
- New config CONFIG_DM_SECURITY to enable security device support.
- New driver sandbox_security matching "security,sandbox", enabled with
  new config CONFIG_SECURITY_SANDBOX.

Signed-off-by: Stephen Carlson 
---
 MAINTAINERS |  8 
 drivers/Kconfig |  2 +
 drivers/Makefile|  1 +
 drivers/security/Kconfig| 25 +++
 drivers/security/Makefile   |  6 +++
 drivers/security/sandbox_security.c | 65 +
 drivers/security/security-uclass.c  | 30 +
 include/dm-security.h   | 44 +++
 include/dm/uclass-id.h  |  1 +
 9 files changed, 182 insertions(+)
 create mode 100644 drivers/security/Kconfig
 create mode 100644 drivers/security/Makefile
 create mode 100644 drivers/security/sandbox_security.c
 create mode 100644 drivers/security/security-uclass.c
 create mode 100644 include/dm-security.h

diff --git a/MAINTAINERS b/MAINTAINERS
index bf851cffd6..73b6943e03 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1438,6 +1438,14 @@ F:   cmd/seama.c
 F: doc/usage/cmd/seama.rst
 F: test/cmd/seama.c
 
+SECURITY
+M: Stephen Carlson 
+S: Maintained
+F: drivers/security/Kconfig
+F: drivers/security/Makefile
+F: drivers/security/sandbox_security.c
+F: drivers/security/security-uclass.c
+
 SEMIHOSTING
 R: Sean Anderson 
 S: Orphaned
diff --git a/drivers/Kconfig b/drivers/Kconfig
index a25f6ae02f..95ea614210 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -116,6 +116,8 @@ source "drivers/rtc/Kconfig"
 
 source "drivers/scsi/Kconfig"
 
+source "drivers/security/Kconfig"
+
 source "drivers/serial/Kconfig"
 
 source "drivers/smem/Kconfig"
diff --git a/drivers/Makefile b/drivers/Makefile
index efc2a4afb2..b670aae5fd 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -98,6 +98,7 @@ obj-$(CONFIG_PCH) += pch/
 obj-$(CONFIG_DM_REBOOT_MODE) += reboot-mode/
 obj-y += rtc/
 obj-y += scsi/
+obj-y += security/
 obj-y += sound/
 obj-y += spmi/
 obj-y += watchdog/
diff --git a/drivers/security/Kconfig b/drivers/security/Kconfig
new file mode 100644
index 00..f7af5c4e78
--- /dev/null
+++ b/drivers/security/Kconfig
@@ -0,0 +1,25 @@
+config DM_SECURITY
+   bool "Support security devices with driver model"
+   depends on DM
+   help
+ This option enables support for the security uclass which supports
+ devices intended to provide additional security features during
+ boot. These devices might encapsulate existing features of TPM
+ or TEE devices, but can also be dedicated security processors
+ implemented in specific hardware.
+
+config SECURITY_SANDBOX
+   bool "Enable sandbox security driver"
+   depends on DM_SECURITY
+   help
+ This driver supports a simulated security device that uses volatile
+ memory to store secure data and begins uninitialized. This
+ implementation allows OS images with security requirements to be
+ loaded in the sandbox environment.
+
+config SECURITY_TPM
+   bool "Enable TPM security driver"
+   depends on TPM && TPM_V2 && DM_SECURITY
+   help
+ This driver supports a security device based on existing TPM
+ functionality.
diff --git a/drivers/security/Makefile b/drivers/security/Makefile
new file mode 100644
index 00..ed10c3f234
--- /dev/null
+++ b/drivers/security/Makefile
@@ -0,0 +1,6 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# (C) Copyright 2021 Microsoft, Inc.
+
+obj-$(CONFIG_DM_SECURITY) += security-uclass.o
+obj-$(CONFIG_SECURITY_SANDBOX) += sandbox_security.o
diff --git a/drivers/security/sandbox_security.c 
b/drivers/security/sandbox_security.c
new file mode 100644
index 00..bcb817a842
--- /dev/null
+++ b/drivers/security/sandbox_security.c
@@ -0,0 +1,65 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2021 Microsoft, Inc
+ * Written by Stephen Carlson 
+ */
+
+#include 
+#include 
+#include 
+#include 
+
+static struct security_state {
+   u64 arbvn;
+};
+
+static int sb_security_arbvn_get(struct udevice *dev, u64 *arbvn)
+{
+   struct security_state *priv = dev_get_priv(dev);
+
+   if (!arbvn)
+   return -EINVAL;
+
+   *arbvn = priv->arbvn;
+   return 0;
+}
+
+static int sb_security_arbvn_set(struct udevice *dev, u64 arbvn)
+{
+   struct security_state *priv = dev_get_priv(dev);
+   u64 old_arbvn;
+
+   old_arbvn = priv->arbvn;
+   if (arbvn < old_arbvn)
+   return -EPERM;
+
+   priv->arbvn = arbvn;
+   return 

[PATCH 0/5] Add anti-rollback validation feature

2023-08-11 Thread seanedmond
From: Sean Edmond 

Adds Add anti-rollback version protection. Images with an anti-rollback counter
value "arbvn" declared in the FDT will be compared against the current device 
anti-rollback counter value, and older images will not pass signature 
validation. If the image is newer, the device anti-rollback counter value will
be updated.

The "arbvn" value is stored/retrieved using the newly added security driver.
A "TPM backed" and "sandbox backed" security driver have been provided as 
examples.

Adds new configs:
- CONFIG_DM_SECURITY : enable security device support
- CONFIG_SECURITY_SANDBOX : enables "sandbox_security" driver
- CONFIG_SECURITY_TPM : Enables "tpm_security" driver
- CONFIG_ARBP : enable enforcement of OS anti-rollback counter during image 
loading
- CONFIG_FIT_ARBVP_GRACE : adds a one unit grace period to OS anti-rollback 
protection

Sean Edmond (1):
  dm: test: Add a test for security driver

Stephen Carlson (4):
  drivers: security: Add security devices to driver model
  drivers: security: Add TPM2 implementation of security devices
  common: Add OS anti-rollback validation using security devices
  common: Add OS anti-rollback grace period

 MAINTAINERS |   9 ++
 arch/sandbox/dts/test.dts   |   8 ++
 boot/Kconfig|  19 +++
 boot/image-fit-sig.c|  94 +++
 boot/image-fit.c|  23 
 configs/sandbox_defconfig   |   3 +
 drivers/Kconfig |   2 +
 drivers/Makefile|   1 +
 drivers/security/Kconfig|  25 
 drivers/security/Makefile   |   7 ++
 drivers/security/sandbox_security.c |  65 +++
 drivers/security/security-tpm.c | 173 
 drivers/security/security-uclass.c  |  30 +
 include/dm-security.h   |  44 +++
 include/dm/uclass-id.h  |   1 +
 include/image.h |   4 +
 include/tpm-v2.h|   1 +
 test/dm/Makefile|   1 +
 test/dm/security.c  |  78 +
 19 files changed, 588 insertions(+)
 create mode 100644 drivers/security/Kconfig
 create mode 100644 drivers/security/Makefile
 create mode 100644 drivers/security/sandbox_security.c
 create mode 100644 drivers/security/security-tpm.c
 create mode 100644 drivers/security/security-uclass.c
 create mode 100644 include/dm-security.h
 create mode 100644 test/dm/security.c

-- 
2.40.0



[PATCH 2/3] fdt: kaslr seed from tpm entropy

2023-08-04 Thread seanedmond
From: Dhananjay Phadke 

Add support for KASLR seed from TPM device. Invokes tpm_get_random()
API to read 8-bytes of random bytes for KASLR.

Signed-off-by: Dhananjay Phadke 
Signed-off-by: Drew Kluemke 
Signed-off-by: Sean Edmond 
---
 boot/image-fdt.c  |  3 +++
 common/fdt_support.c  | 39 ++-
 include/fdt_support.h |  1 +
 lib/Kconfig   |  9 +
 4 files changed, 51 insertions(+), 1 deletion(-)

diff --git a/boot/image-fdt.c b/boot/image-fdt.c
index f10200f647..127443963e 100644
--- a/boot/image-fdt.c
+++ b/boot/image-fdt.c
@@ -624,6 +624,9 @@ int image_setup_libfdt(struct bootm_headers *images, void 
*blob,
goto err;
}
 
+   if (IS_ENABLED(CONFIG_KASLR_TPM_SEED))
+   fdt_tpm_kaslr_seed(blob);
+
fdt_ret = optee_copy_fdt_nodes(blob);
if (fdt_ret) {
printf("ERROR: transfer of optee nodes to new fdt failed: %s\n",
diff --git a/common/fdt_support.c b/common/fdt_support.c
index 35d4f26dbd..1ac33355a0 100644
--- a/common/fdt_support.c
+++ b/common/fdt_support.c
@@ -13,6 +13,10 @@
 #include 
 #include 
 #include 
+#include 
+#include 
+#include 
+#include 
 #include 
 #include 
 #include 
@@ -632,7 +636,7 @@ void fdt_fixup_ethernet(void *fdt)
 }
 
 /*
- * fdt_fix_kaslr_seed - Add kalsr-seed node in Device tree
+ * fdt_fixup_kaslr_seed - Add kaslr-seed node in Device tree
  * @fdt:   Device tree
  * @eret:  0 for success
  */
@@ -662,6 +666,39 @@ int fdt_fixup_kaslr_seed(void *fdt, const u8 *seed, int 
len)
return 0;
 }
 
+/*
+ * fdt_add_tpm_kaslr_seed - Add kalsr-seed node in Device tree with random
+ * bytes from TPM device
+ * @fdt:   Device tree
+ * @eret:  0 for success
+ */
+int fdt_tpm_kaslr_seed(void *fdt)
+{
+   u8 rand[8] = {0};
+   struct udevice *dev;
+   int ret;
+
+   ret = uclass_get_device(UCLASS_TPM, 0, );
+   if (ret) {
+   printf("ERROR: Failed to find TPM device\n");
+   return ret;
+   }
+
+   ret = tpm_get_random(dev, rand, sizeof(rand));
+   if (ret) {
+   printf("ERROR: TPM GetRandom failed, ret=%d\n", ret);
+   return ret;
+   }
+
+   ret = fdt_fixup_kaslr_seed(fdt, rand, sizeof(rand));
+   if (ret) {
+   printf("ERROR: failed to add kaslr-seed to fdt\n");
+   return ret;
+   }
+
+   return 0;
+}
+
 int fdt_record_loadable(void *blob, u32 index, const char *name,
uintptr_t load_addr, u32 size, uintptr_t entry_point,
const char *type, const char *os, const char *arch)
diff --git a/include/fdt_support.h b/include/fdt_support.h
index d74ef4e0a7..9e50db1b96 100644
--- a/include/fdt_support.h
+++ b/include/fdt_support.h
@@ -123,6 +123,7 @@ static inline int fdt_fixup_memory_banks(void *blob, u64 
start[], u64 size[],
 void fdt_fixup_ethernet(void *fdt);
 
 int fdt_fixup_kaslr_seed(void *fdt, const u8 *seed, int len);
+int fdt_tpm_kaslr_seed(void *fdt);
 
 int fdt_find_and_setprop(void *fdt, const char *node, const char *prop,
 const void *val, int len, int create);
diff --git a/lib/Kconfig b/lib/Kconfig
index 3926652db6..1530ef7c86 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -465,6 +465,15 @@ config VPL_TPM
  for the low-level TPM interface, but only one TPM is supported at
  a time by the TPM library.
 
+config KASLR_TPM_SEED
+   bool "Use TPM for KASLR random seed"
+   depends on TPM_V1 || TPM_V2
+   help
+ This enables support for using TPMs as entropy source for KASLR seed
+ populated in kernel's device tree. Both TPMv1 and TPMv2 are supported
+ for the low-level TPM interface, but only one TPM is supported at
+ a time by the library.
+
 endmenu
 
 menu "Android Verified Boot"
-- 
2.40.0



[PATCH 0/3] Populate kaslr seed with TPM

2023-08-04 Thread seanedmond
From: Sean Edmond 

This patch series creates a common API (fdt_fixup_kaslr_seed()) for 
populating the kaslr seed in the DTB.  Existing users (kaslrseed,
and ARMv8 sec firmware) have been updated to use this common API.

New functionality has been introduced to populate the kaslr using
the TPM interface.  This can be enabled with CONFIG_KASLR_TPM_SEED.  

Dhananjay Phadke (2):
  fdt: common API to populate kaslr seed
  fdt: kaslr seed from tpm entropy

Sean Edmond (1):
  cmd: kaslrseed: Use common API to fixup FDT

 arch/arm/cpu/armv8/sec_firmware.c | 32 ---
 boot/image-fdt.c  |  3 ++
 cmd/kaslrseed.c   | 18 ++--
 common/fdt_support.c  | 68 +++
 include/fdt_support.h |  4 ++
 lib/Kconfig   |  9 
 6 files changed, 94 insertions(+), 40 deletions(-)

-- 
2.40.0



[PATCH 1/3] fdt: common API to populate kaslr seed

2023-08-04 Thread seanedmond
From: Dhananjay Phadke 

fdt_fixup_kaslr_seed() will update given FDT with random seed value.
Source for random seed can be TPM or RNG driver in u-boot or sec
firmware (ARM).

Signed-off-by: Dhananjay Phadke 
---
 arch/arm/cpu/armv8/sec_firmware.c | 32 +++
 common/fdt_support.c  | 31 ++
 include/fdt_support.h |  3 +++
 3 files changed, 41 insertions(+), 25 deletions(-)

diff --git a/arch/arm/cpu/armv8/sec_firmware.c 
b/arch/arm/cpu/armv8/sec_firmware.c
index c0e8726346..84ba49924e 100644
--- a/arch/arm/cpu/armv8/sec_firmware.c
+++ b/arch/arm/cpu/armv8/sec_firmware.c
@@ -411,46 +411,28 @@ int sec_firmware_init(const void *sec_firmware_img,
 /*
  * fdt_fix_kaslr - Add kalsr-seed node in Device tree
  * @fdt:   Device tree
- * @eret:  0 in case of error, 1 for success
+ * @eret:  0 for success
  */
 int fdt_fixup_kaslr(void *fdt)
 {
-   int nodeoffset;
-   int err, ret = 0;
-   u8 rand[8];
+   int ret = 0;
 
 #if defined(CONFIG_ARMV8_SEC_FIRMWARE_SUPPORT)
+   u8 rand[8];
+
/* Check if random seed generation is  supported */
if (sec_firmware_support_hwrng() == false) {
printf("WARNING: SEC firmware not running, no kaslr-seed\n");
-   return 0;
+   return -EOPNOTSUPP;
}
 
err = sec_firmware_get_random(rand, 8);
if (err < 0) {
printf("WARNING: No random number to set kaslr-seed\n");
-   return 0;
-   }
-
-   err = fdt_check_header(fdt);
-   if (err < 0) {
-   printf("fdt_chosen: %s\n", fdt_strerror(err));
-   return 0;
+   return ret;
}
 
-   /* find or create "/chosen" node. */
-   nodeoffset = fdt_find_or_add_subnode(fdt, 0, "chosen");
-   if (nodeoffset < 0)
-   return 0;
-
-   err = fdt_setprop(fdt, nodeoffset, "kaslr-seed", rand,
- sizeof(rand));
-   if (err < 0) {
-   printf("WARNING: can't set kaslr-seed %s.\n",
-  fdt_strerror(err));
-   return 0;
-   }
-   ret = 1;
+   ret = fdt_fixup_kaslr_seed(fdt, rand, sizeof(rand));
 #endif
 
return ret;
diff --git a/common/fdt_support.c b/common/fdt_support.c
index 5e49078f8c..35d4f26dbd 100644
--- a/common/fdt_support.c
+++ b/common/fdt_support.c
@@ -631,6 +631,37 @@ void fdt_fixup_ethernet(void *fdt)
}
 }
 
+/*
+ * fdt_fix_kaslr_seed - Add kalsr-seed node in Device tree
+ * @fdt:   Device tree
+ * @eret:  0 for success
+ */
+int fdt_fixup_kaslr_seed(void *fdt, const u8 *seed, int len)
+{
+   int nodeoffset;
+   int err;
+
+   err = fdt_check_header(fdt);
+   if (err < 0) {
+   printf("fdt_chosen: %s\n", fdt_strerror(err));
+   return err;
+   }
+
+   /* find or create "/chosen" node. */
+   nodeoffset = fdt_find_or_add_subnode(fdt, 0, "chosen");
+   if (nodeoffset < 0)
+   return -ENOENT;
+
+   err = fdt_setprop(fdt, nodeoffset, "kaslr-seed", seed, len);
+   if (err < 0) {
+   printf("WARNING: can't set kaslr-seed %s.\n",
+  fdt_strerror(err));
+   return err;
+   }
+
+   return 0;
+}
+
 int fdt_record_loadable(void *blob, u32 index, const char *name,
uintptr_t load_addr, u32 size, uintptr_t entry_point,
const char *type, const char *os, const char *arch)
diff --git a/include/fdt_support.h b/include/fdt_support.h
index 2cd8366898..d74ef4e0a7 100644
--- a/include/fdt_support.h
+++ b/include/fdt_support.h
@@ -121,6 +121,9 @@ static inline int fdt_fixup_memory_banks(void *blob, u64 
start[], u64 size[],
 #endif
 
 void fdt_fixup_ethernet(void *fdt);
+
+int fdt_fixup_kaslr_seed(void *fdt, const u8 *seed, int len);
+
 int fdt_find_and_setprop(void *fdt, const char *node, const char *prop,
 const void *val, int len, int create);
 void fdt_fixup_qe_firmware(void *fdt);
-- 
2.40.0



[PATCH 3/3] cmd: kaslrseed: Use common API to fixup FDT

2023-08-04 Thread seanedmond
From: Sean Edmond 

Use the newly introduced common API fdt_fixup_kaslr_seed() in the
kaslrseed command.

Signed-off-by: Sean Edmond 
---
 cmd/kaslrseed.c | 18 +++---
 1 file changed, 3 insertions(+), 15 deletions(-)

diff --git a/cmd/kaslrseed.c b/cmd/kaslrseed.c
index 8a1d8120cd..82117bc484 100644
--- a/cmd/kaslrseed.c
+++ b/cmd/kaslrseed.c
@@ -45,21 +45,9 @@ static int do_kaslr_seed(struct cmd_tbl *cmdtp, int flag, 
int argc, char *const
return CMD_RET_FAILURE;
}
 
-   ret = fdt_check_header(working_fdt);
-   if (ret < 0) {
-   printf("fdt_chosen: %s\n", fdt_strerror(ret));
-   return CMD_RET_FAILURE;
-   }
-
-   nodeoffset = fdt_find_or_add_subnode(working_fdt, 0, "chosen");
-   if (nodeoffset < 0) {
-   printf("Reading chosen node failed\n");
-   return CMD_RET_FAILURE;
-   }
-
-   ret = fdt_setprop(working_fdt, nodeoffset, "kaslr-seed", buf, 
sizeof(buf));
-   if (ret < 0) {
-   printf("Unable to set kaslr-seed on chosen node: %s\n", 
fdt_strerror(ret));
+   ret = fdt_fixup_kaslr_seed(working_fdt, buf, sizeof(buf));
+   if (ret) {
+   printf("ERROR: failed to add kaslr-seed to fdt\n");
return CMD_RET_FAILURE;
}
 
-- 
2.40.0



[PATCH] drivers: mtd: Add MT25QU128AB params

2023-08-04 Thread seanedmond
From: Godfrey Mwangi 

Add Micron MT25QU128AB flash.

Signed-off-by: Godfrey Mwangi 
---
 drivers/mtd/spi/spi-nor-ids.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/mtd/spi/spi-nor-ids.c b/drivers/mtd/spi/spi-nor-ids.c
index 4587215984..a99bb6125b 100644
--- a/drivers/mtd/spi/spi-nor-ids.c
+++ b/drivers/mtd/spi/spi-nor-ids.c
@@ -299,6 +299,7 @@ const struct flash_info spi_nor_ids[] = {
{ INFO("n25q256a",0x20ba19, 0, 64 * 1024,  512, SECT_4K | 
SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | USE_FSR) },
{ INFO6("mt25qu256a",  0x20bb19, 0x104400, 64 * 1024,  512, SECT_4K | 
SPI_NOR_QUAD_READ | SPI_NOR_4B_OPCODES | USE_FSR) },
{ INFO("n25q256ax1",  0x20bb19, 0, 64 * 1024,  512, SECT_4K | 
SPI_NOR_QUAD_READ | USE_FSR) },
+   { INFO("mt25qu128ab", 0x20bb18, 0, 64 * 1024,  256, SECT_4K | USE_FSR | 
SPI_NOR_QUAD_READ) },
{ INFO6("mt25qu512a",  0x20bb20, 0x104400, 64 * 1024, 1024,
 SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ | 
SPI_NOR_4B_OPCODES |
 USE_FSR) },
-- 
2.40.0



[PATCH] usb: xhci: pet watchdog during transfers

2023-08-04 Thread seanedmond
From: Godfrey Mwangi 

On some platforms with low USB throughput, tranfers
of huge files take a long time and watchdog timer can
expire resulting in hardware reset. Avoid this by
petting the watchdog as long as we have pending transfers.

Signed-off-by: Godfrey Mwangi 
---
 drivers/usb/host/xhci-ring.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index c8260cbdf9..de954314bc 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -18,6 +18,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -758,6 +759,8 @@ int xhci_bulk_tx(struct usb_device *udev, unsigned long 
pipe,
/* Calculate length for next transfer */
addr += trb_buff_len;
trb_buff_len = min((length - running_total), TRB_MAX_BUFF_SIZE);
+
+   schedule();
} while (running_total < length);
 
giveback_first_trb(udev, ep_index, start_cycle, start_trb);
-- 
2.40.0



[PATCH] net: Get pxe config file from dhcp option 209

2023-07-25 Thread seanedmond
From: Sean Edmond 

Allow dhcp server pass pxe config file full path by using option 209

Signed-off-by: Sean Edmond 
---
 cmd/Kconfig |  4 
 cmd/pxe.c   |  8 
 net/bootp.c | 21 +
 3 files changed, 33 insertions(+)

diff --git a/cmd/Kconfig b/cmd/Kconfig
index 2d6e5f993f..998d0c3e80 100644
--- a/cmd/Kconfig
+++ b/cmd/Kconfig
@@ -1806,6 +1806,10 @@ config BOOTP_PXE_CLIENTARCH
default 0x15 if ARM
default 0 if X86
 
+config BOOTP_PXE_DHCP_OPTION
+   bool "Request & store 'pxe_configfile' from BOOTP/DHCP server"
+   depends on BOOTP_PXE
+
 config BOOTP_VCI_STRING
string
depends on CMD_BOOTP
diff --git a/cmd/pxe.c b/cmd/pxe.c
index 677142520b..dd1869f3ba 100644
--- a/cmd/pxe.c
+++ b/cmd/pxe.c
@@ -141,6 +141,14 @@ int pxe_get(ulong pxefile_addr_r, char **bootdirp, ulong 
*sizep, bool use_ipv6)
  env_get("bootfile"), use_ipv6))
return -ENOMEM;
 
+   if (IS_ENABLED(CONFIG_BOOTP_PXE_DHCP_OPTION) &&
+   pxelinux_configfile && !use_ipv6) {
+   if (pxe_dhcp_option_path(, pxefile_addr_r) > 0)
+   goto done;
+
+   goto error_exit;
+   }
+
if (IS_ENABLED(CONFIG_DHCP6_PXE_DHCP_OPTION) &&
pxelinux_configfile && use_ipv6) {
if (pxe_dhcp_option_path(, pxefile_addr_r) > 0)
diff --git a/net/bootp.c b/net/bootp.c
index 8b1a4ae2ef..013d54c7ed 100644
--- a/net/bootp.c
+++ b/net/bootp.c
@@ -26,6 +26,7 @@
 #ifdef CONFIG_BOOTP_RANDOM_DELAY
 #include "net_rand.h"
 #endif
+#include 
 
 #define BOOTP_VENDOR_MAGIC 0x63825363  /* RFC1048 Magic Cookie */
 
@@ -604,6 +605,10 @@ static int dhcp_extended(u8 *e, int message_type, struct 
in_addr server_ip,
*e++  = 42;
*cnt += 1;
 #endif
+   if (IS_ENABLED(CONFIG_BOOTP_PXE_DHCP_OPTION)) {
+   *e++ = 209; /* PXELINUX Config File */
+   *cnt += 1;
+   }
/* no options, so back up to avoid sending an empty request list */
if (*cnt == 0)
e -= 2;
@@ -912,6 +917,22 @@ static void dhcp_process_options(uchar *popt, uchar *end)
net_boot_file_name[size] = 0;
}
break;
+   case 209:   /* PXELINUX Config File */
+   if (IS_ENABLED(CONFIG_BOOTP_PXE_DHCP_OPTION)) {
+   /* In case it has already been allocated when 
get DHCP Offer packet,
+* free first to avoid memory leak.
+*/
+   if (pxelinux_configfile)
+   free(pxelinux_configfile);
+
+   pxelinux_configfile = (char *)malloc((oplen + 
1) * sizeof(char));
+
+   if (pxelinux_configfile)
+   strlcpy(pxelinux_configfile, popt + 2, 
oplen + 1);
+   else
+   printf("Error: Failed to allocate 
pxelinux_configfile\n");
+   }
+   break;
default:
 #if defined(CONFIG_BOOTP_VENDOREX)
if (dhcp_vendorex_proc(popt))
-- 
2.40.0



[PATCH] net: dhcp6: Fix OPT_BOOTFILE_PARAM parsing

2023-07-25 Thread seanedmond
From: Sean Edmond 

RFC 5970 states that OPT_BOOTFILE_PARAM (option 60) can be
multiple parameters that start with a 16-bit length field followed
by the parameter. For example:
[ param-len 1 (16-bits) ] [ parameter 1 (variable length) ]

This fix ensure we're considering "param-len 1" in the parsing.

Signed-off-by: Sean Edmond 
---
 net/dhcpv6.c | 15 ---
 1 file changed, 12 insertions(+), 3 deletions(-)

diff --git a/net/dhcpv6.c b/net/dhcpv6.c
index 73a1067877..4aea779f6f 100644
--- a/net/dhcpv6.c
+++ b/net/dhcpv6.c
@@ -304,7 +304,7 @@ static void dhcp6_parse_ia_options(struct dhcp6_option_hdr 
*ia_ptr, uchar *ia_op
 static void dhcp6_parse_options(uchar *rx_pkt, unsigned int len)
 {
uchar *option_ptr;
-   int sol_max_rt_sec, option_len;
+   int sol_max_rt_sec, option_len, param_len_1;
char *s, *e;
struct dhcp6_option_hdr *option_hdr;
 
@@ -390,14 +390,23 @@ static void dhcp6_parse_options(uchar *rx_pkt, unsigned 
int len)
case DHCP6_OPTION_OPT_BOOTFILE_PARAM:
if (IS_ENABLED(CONFIG_DHCP6_PXE_DHCP_OPTION)) {
debug("DHCP6_OPTION_OPT_BOOTFILE_PARAM 
FOUND\n");
+   /* if CONFIG_DHCP6_PXE_DHCP_OPTION is set the 
PXE config file path
+* is contained in the first OPT_BOOTFILE_PARAM 
argument
+*/
+   param_len_1 = ntohs(*((u16 *)option_ptr));
+   option_ptr += sizeof(u16);
+   if (param_len_1 + sizeof(u16) > option_len) {
+   debug("Invalid BOOTFILE_PARAM 
param_len_1. Skipping\n");
+   break;
+   }
 
if (pxelinux_configfile)
free(pxelinux_configfile);
 
-   pxelinux_configfile = (char 
*)malloc((option_len + 1) *
+   pxelinux_configfile = (char 
*)malloc((param_len_1 + 1) *
  sizeof(char));
if (pxelinux_configfile)
-   strlcpy(pxelinux_configfile, 
option_ptr, option_len + 1);
+   strlcpy(pxelinux_configfile, 
option_ptr, param_len_1 + 1);
else
printf("Error: Failed to allocate 
pxelinux_configfile\n");
 
-- 
2.40.0



[PATCH 2/2] net: dhcp6: Fix VCI string

2023-05-18 Thread seanedmond
From: Sean Edmond 

Change VCI string from "U-boot" to "U-Boot".

Signed-off-by: Sean Edmond 
---
 net/dhcpv6.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/net/dhcpv6.h b/net/dhcpv6.h
index 80ca520432..65c8e4c71d 100644
--- a/net/dhcpv6.h
+++ b/net/dhcpv6.h
@@ -38,7 +38,7 @@
 #define DUID_MAX_SIZE  DUID_LL_SIZE /* only supports DUID-LL currently 
*/
 
 /* vendor-class-data to send in vendor clas option */
-#define DHCP6_VCI_STRING   "U-boot"
+#define DHCP6_VCI_STRING   "U-Boot"
 
 #define DHCP6_MULTICAST_ADDR   "ff02::1:2" /* DHCP multicast address */
 
-- 
2.40.0



[PATCH 1/2] net: ipv6: Fix CID 453851 and CID 436278

2023-05-18 Thread seanedmond
From: Sean Edmond 

CID 453851 : sprintf() shouldn't copy from/to tmp
CID 436278 : DHCP6 option_len should be checked before use

Signed-off-by: Sean Edmond 
---
 cmd/net.c| 12 ++--
 net/dhcpv6.c |  5 +
 2 files changed, 11 insertions(+), 6 deletions(-)

diff --git a/cmd/net.c b/cmd/net.c
index 68d406291e..9e1f40a56e 100644
--- a/cmd/net.c
+++ b/cmd/net.c
@@ -209,7 +209,7 @@ U_BOOT_CMD(
 
 static void netboot_update_env(void)
 {
-   char tmp[44];
+   char tmp[46];
 
if (net_gateway.s_addr) {
ip_to_string(net_gateway, tmp);
@@ -274,20 +274,20 @@ static void netboot_update_env(void)
if (IS_ENABLED(CONFIG_IPV6)) {
if (!ip6_is_unspecified_addr(_ip6) ||
net_prefix_length != 0) {
-   sprintf(tmp, "%pI6c", _ip6);
if (net_prefix_length != 0)
-   sprintf(tmp, "%s/%d", tmp, net_prefix_length);
-
+   snprintf(tmp, sizeof(tmp), "%pI6c/%d", 
_ip6, net_prefix_length);
+   else
+   snprintf(tmp, sizeof(tmp), "%pI6c", _ip6);
env_set("ip6addr", tmp);
}
 
if (!ip6_is_unspecified_addr(_server_ip6)) {
-   sprintf(tmp, "%pI6c", _server_ip6);
+   snprintf(tmp, sizeof(tmp), "%pI6c", _server_ip6);
env_set("serverip6", tmp);
}
 
if (!ip6_is_unspecified_addr(_gateway6)) {
-   sprintf(tmp, "%pI6c", _gateway6);
+   snprintf(tmp, sizeof(tmp), "%pI6c", _gateway6);
env_set("gatewayip6", tmp);
}
}
diff --git a/net/dhcpv6.c b/net/dhcpv6.c
index 0d1c600632..73a1067877 100644
--- a/net/dhcpv6.c
+++ b/net/dhcpv6.c
@@ -316,6 +316,11 @@ static void dhcp6_parse_options(uchar *rx_pkt, unsigned 
int len)
option_ptr = ((uchar *)option_hdr) + sizeof(struct dhcp6_hdr);
option_len = ntohs(option_hdr->option_len);
 
+   if (option_ptr + option_len > rx_pkt + len) {
+   debug("Invalid option length\n");
+   return;
+   }
+
switch (ntohs(option_hdr->option_id)) {
case DHCP6_OPTION_CLIENTID:
if (memcmp(option_ptr, sm_params.duid, option_len)
-- 
2.40.0



[PATCH 0/2] *** minor fixes in DHCP6 ***

2023-05-18 Thread seanedmond
From: Sean Edmond 

Resolves 2 issues:
- coverity CID 453851 and 436278
- Change DHCP6 VCI string from "U-boot" to "U-Boot" (this was found 
  by more detailed testing on our end)

Sean Edmond (2):
  net: ipv6: Fix CID 453851 and CID 436278
  net: dhcp6: Fix VCI string

 cmd/net.c| 12 ++--
 net/dhcpv6.c |  5 +
 net/dhcpv6.h |  2 +-
 3 files changed, 12 insertions(+), 7 deletions(-)

-- 
2.40.0



[PATCH v3 1/3] net: dhcp6: Add DHCPv6 (DHCP for IPv6)

2023-04-11 Thread seanedmond
From: Sean Edmond 

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 
---
 include/net.h |   6 +-
 net/Makefile  |   1 +
 net/dhcpv6.c  | 719 ++
 net/dhcpv6.h  | 256 ++
 net/net.c |  11 +-
 5 files changed, 989 insertions(+), 4 deletions(-)
 create mode 100644 net/dhcpv6.c
 create mode 100644 net/dhcpv6.h

diff --git a/include/net.h b/include/net.h
index 399af5e064..181a6e3b13 100644
--- a/include/net.h
+++ b/include/net.h
@@ -484,6 +484,8 @@ extern char net_hostname[32];   /* Our hostname */
 #ifdef CONFIG_NET
 extern charnet_root_path[CONFIG_BOOTP_MAX_ROOT_PATH_LEN];  /* Our root 
path */
 #endif
+/* Indicates whether the pxe path prefix / config file was specified in dhcp 
option */
+extern char *pxelinux_configfile;
 /** 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 +506,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 charnet_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 00..0d1c600632
--- /dev/null
+++ b/net/dhcpv6.c
@@ -0,0 +1,719 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) Microsoft Corporation
+ * Author: Sean Edmond 
+ *
+ */
+
+/* Simple DHCP6 network layer implementation. */
+
+#include 
+#include 
+#include 
+#include 
+#include "net_rand.h"
+#include "dhcpv6.h"
+
+#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  360
+#define REQ_TIMEOUT_MS 1000
+#define REQ_MAX_RT_MS  3
+#define REQ_MAX_RC 10
+#define MAX_WAIT_TIME_MS   6
+
+/* global variable to track any updates from DHCP6 server */
+int updated_sol_max_rt_ms = SOL_MAX_RT_MS;
+/* state machine parameters/variables */
+struct dhcp6_sm_params sm_params;
+
+static void dhcp6_state_machine(bool timeout, uchar *rx_pkt, unsigned int len);
+
+/* Handle DHCP received packets (set as UDP handler) */
+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);
+}
+
+/**
+ * dhcp6_add_option() - Adds DHCP6 option to a packet
+ * @option_id: The option ID to add (See DHCP6_OPTION_* definitions)
+ * @pkt: A pointer to the current write location of the TX packet
+ *
+ * Return: The number of bytes written into "*pkt"
+ */
+static int dhcp6_add_option(int option_id, uchar *pkt)
+{
+   struct dhcp6_option_duid_ll *duid_opt;
+   struct dhcp6_option_elapsed_time *elapsed_time_opt;
+   struct dhcp6_option_ia_ta *ia_ta_opt;
+   struct dhcp6_option_ia_na *ia_na_opt;
+   struct dhcp6_option_oro *oro_opt;
+   struct dhcp6_option_client_arch *client_arch_opt;
+   struct dhcp6_option_vendor_class *vendor_class_opt;
+   int opt_len;
+   long elapsed_time;
+   size_t vci_strlen;
+   int num_oro = 0;
+   int num_client_arch = 0;
+   int num_vc_data = 0;
+   struct dhcp6_option_hdr *dhcp_option = (struct dhcp6_option_hdr *)pkt;
+   uchar *dhcp_option_start = pkt + sizeof(struct dhcp6_option_hdr);
+
+   dhcp_option->option_id = htons(option_id);
+
+   switch (option_id) {
+   case DHCP6_OPTION_CLIENTID:
+   /* 

[PATCH v3 2/3] net: dhcp6: pxe: Add DHCP/PXE commands for IPv6

2023-04-11 Thread seanedmond
From: Sean Edmond 

Adds commands to support DHCP and PXE with IPv6.

New configs added:
- CMD_DHCP6
- DHCP6_PXE_CLIENTARCH
- DHCP6_PXE_DHCP_OPTION
- DHCP6_ENTERPRISE_ID

New commands added (when IPv6 is enabled):
- dhcp6
- pxe get -ipv6
- pxe boot -ipv6

Signed-off-by: Sean Edmond 
---
 boot/bootmeth_distro.c |  2 +-
 boot/bootmeth_pxe.c|  4 +-
 boot/pxe_utils.c   |  3 +-
 cmd/Kconfig| 26 +
 cmd/net.c  | 23 
 cmd/pxe.c  | 85 ++
 cmd/sysboot.c  |  2 +-
 include/pxe_utils.h| 10 -
 8 files changed, 132 insertions(+), 23 deletions(-)

diff --git a/boot/bootmeth_distro.c b/boot/bootmeth_distro.c
index 356929828b..b4b73ecbf5 100644
--- a/boot/bootmeth_distro.c
+++ b/boot/bootmeth_distro.c
@@ -150,7 +150,7 @@ static int distro_boot(struct udevice *dev, struct bootflow 
*bflow)
info.dev = dev;
info.bflow = bflow;
ret = pxe_setup_ctx(, , distro_getfile, , true,
-   bflow->subdir);
+   bflow->subdir, false);
if (ret)
return log_msg_ret("ctx", -EINVAL);
 
diff --git a/boot/bootmeth_pxe.c b/boot/bootmeth_pxe.c
index ecf8557af8..5a8af2bbd0 100644
--- a/boot/bootmeth_pxe.c
+++ b/boot/bootmeth_pxe.c
@@ -70,7 +70,7 @@ static int distro_pxe_read_bootflow(struct udevice *dev, 
struct bootflow *bflow)
addr = simple_strtoul(addr_str, NULL, 16);
 
log_debug("calling pxe_get()\n");
-   ret = pxe_get(addr, , );
+   ret = pxe_get(addr, , , false);
log_debug("pxe_get() returned %d\n", ret);
if (ret)
return log_msg_ret("pxeb", ret);
@@ -146,7 +146,7 @@ static int distro_pxe_boot(struct udevice *dev, struct 
bootflow *bflow)
info.bflow = bflow;
info.cmdtp = 
ret = pxe_setup_ctx(ctx, , distro_pxe_getfile, , false,
-   bflow->subdir);
+   bflow->subdir, false);
if (ret)
return log_msg_ret("ctx", -EINVAL);
 
diff --git a/boot/pxe_utils.c b/boot/pxe_utils.c
index 3a1e50f2b1..d13c47dd94 100644
--- a/boot/pxe_utils.c
+++ b/boot/pxe_utils.c
@@ -1578,7 +1578,7 @@ void handle_pxe_menu(struct pxe_context *ctx, struct 
pxe_menu *cfg)
 
 int pxe_setup_ctx(struct pxe_context *ctx, struct cmd_tbl *cmdtp,
  pxe_getfile_func getfile, void *userdata,
- bool allow_abs_path, const char *bootfile)
+ bool allow_abs_path, const char *bootfile, bool use_ipv6)
 {
const char *last_slash;
size_t path_len = 0;
@@ -1588,6 +1588,7 @@ int pxe_setup_ctx(struct pxe_context *ctx, struct cmd_tbl 
*cmdtp,
ctx->getfile = getfile;
ctx->userdata = userdata;
ctx->allow_abs_path = allow_abs_path;
+   ctx->use_ipv6 = use_ipv6;
 
/* figure out the boot directory, if there is one */
if (bootfile && strlen(bootfile) >= MAX_TFTP_PATH_LEN)
diff --git a/cmd/Kconfig b/cmd/Kconfig
index e45b8847ae..460f29883a 100644
--- a/cmd/Kconfig
+++ b/cmd/Kconfig
@@ -1673,6 +1673,15 @@ config CMD_DHCP
help
  Boot image via network using DHCP/TFTP protocol
 
+config CMD_DHCP6
+   bool "dhcp6"
+   depends on IPV6
+   help
+ Boot image via network using DHCPv6/TFTP protocol using IPv6.
+
+ Will perform 4-message exchange with DHCPv6 server, requesting
+ the minimum required options to TFTP boot. Complies with RFC 8415.
+
 config BOOTP_MAY_FAIL
bool "Allow for the BOOTP/DHCP server to not be found"
depends on CMD_BOOTP
@@ -1786,6 +1795,23 @@ config BOOTP_VCI_STRING
default "U-Boot.arm" if ARM
default "U-Boot"
 
+if CMD_DHCP6
+
+config DHCP6_PXE_CLIENTARCH
+   hex
+   default 0x16 if ARM64
+   default 0x15 if ARM
+   default 0xFF
+
+config DHCP6_PXE_DHCP_OPTION
+   bool "Request & store 'pxe_configfile' from DHCP6 server"
+
+config DHCP6_ENTERPRISE_ID
+   int "Enterprise ID to send in DHCPv6 Vendor Class Option"
+   default 0
+
+endif
+
 config CMD_TFTPBOOT
bool "tftpboot"
default y
diff --git a/cmd/net.c b/cmd/net.c
index d5e20843dd..76fd2e7d34 100644
--- a/cmd/net.c
+++ b/cmd/net.c
@@ -111,6 +111,29 @@ U_BOOT_CMD(
 );
 #endif
 
+#if defined(CONFIG_CMD_DHCP6)
+static int do_dhcp6(struct cmd_tbl *cmdtp, int flag, int argc,
+   char *const argv[])
+{
+   int i;
+   int dhcp_argc;
+   char *dhcp_argv[] = {NULL, NULL, NULL, NULL};
+
+   /* Add -ipv6 flag for autoload */
+   for (i = 0; i < argc; i++)
+   dhcp_argv[i] = argv[i];
+   dhcp_argc = argc + 1;
+   dhcp_argv[dhcp_argc - 1] =  USE_IP6_CMD_PARAM;
+
+   return netboot_common(DHCP6, cmdtp, dhcp_argc, dhcp_argv);
+}
+
+U_BOOT_CMD(dhcp6,  3,  1,  do_dhcp6,
+  "boot image via network using DHCPv6/TFTP protocol.\n"
+  "Use IPv6 hostIPaddr framed with [] brackets",

[PATCH v3 0/3] net: DHCPv6 protocol and commands

2023-04-11 Thread seanedmond
From: Sean Edmond 

The recently integrated IPv6 patch series relies on the link-local address,
or a statically assigned IPv6 address for network operations.  This patch
series adds IPv6 address assignment through DHCPv6.

The implementation meets the requirements in RFC 8415 for "Client/Server
Exchanges Involving Four Messages":
https://www.rfc-editor.org/rfc/rfc8415

The implementation sends/receives the minimum required DHCPv6 options to 
network boot.

A new command (dhcp6) will execute the protocol.  In addition, IPv6
functionality has been extended to the existing pxe commands ("pxe get"
and "pxe boot").

changes in v3:
- Always instance pxelinux_configfile (allows for clean-up of many ugly #ifdef)
- clean-up includes in dhcpv6.c
- clean-up single line comments
- use strlcpy() for setting pxelinux_configfile
- change API ordering to reduce fordard declarations in dhcpv6.c
- remove  and  include in dhcpv6.h
- Add detailed function header to dhcp6_start()
- Remove conditional include of dhcpv6.h
- Remove inline from pxe_dhcp_option_path()
- Remove ugly "pxe get"/"pxe boot" command definition (specify the maximum
  number of arguments and do number of parameter checking in c code)

changes in v2:
- Add sandbox test in test_net.py
- Add CONFIG_CMD_DHCP6 to sandbox_defconfig
- fix comment style (/**/ instead of //)
- move addition of Kconfig from 1st patch to 2nd patch
- Fix warning (warning: label ‘error_exit’ defined but not used") when 
  CONFIG_DHCP6_PXE_DHCP_OPTION not configured
- Fix dhcp6 command help
- Use net_set_timeout_handler(0, NULL) in dhcpv6.c
- Move USE_IP6_CMD_PARAM back to net6.h

Sean Edmond (3):
  net: dhcp6: Add DHCPv6 (DHCP for IPv6)
  net: dhcp6: pxe: Add DHCP/PXE commands for IPv6
  net: dhcp6: Add a sandbox test for dhcp6

 boot/bootmeth_distro.c|   2 +-
 boot/bootmeth_pxe.c   |   4 +-
 boot/pxe_utils.c  |   3 +-
 cmd/Kconfig   |  26 ++
 cmd/net.c |  23 ++
 cmd/pxe.c |  85 -
 cmd/sysboot.c |   2 +-
 configs/sandbox_defconfig |   1 +
 include/net.h |   6 +-
 include/pxe_utils.h   |  10 +-
 net/Makefile  |   1 +
 net/dhcpv6.c  | 719 ++
 net/dhcpv6.h  | 256 ++
 net/net.c |  11 +-
 test/py/tests/test_net.py |  25 ++
 15 files changed, 1147 insertions(+), 27 deletions(-)
 create mode 100644 net/dhcpv6.c
 create mode 100644 net/dhcpv6.h

-- 
2.40.0



[PATCH v3 3/3] net: dhcp6: Add a sandbox test for dhcp6

2023-04-11 Thread seanedmond
From: Sean Edmond 

Requires proper environment with DHCP6 server provisioned.

Signed-off-by: Sean Edmond 
---
 configs/sandbox_defconfig |  1 +
 test/py/tests/test_net.py | 25 +
 2 files changed, 26 insertions(+)

diff --git a/configs/sandbox_defconfig b/configs/sandbox_defconfig
index ca95b2c5d2..d7ceedd601 100644
--- a/configs/sandbox_defconfig
+++ b/configs/sandbox_defconfig
@@ -341,3 +341,4 @@ CONFIG_UNIT_TEST=y
 CONFIG_UT_TIME=y
 CONFIG_UT_DM=y
 CONFIG_CMD_2048=y
+CONFIG_CMD_DHCP6=y
diff --git a/test/py/tests/test_net.py b/test/py/tests/test_net.py
index 9ca6743afd..0447c0b2e0 100644
--- a/test/py/tests/test_net.py
+++ b/test/py/tests/test_net.py
@@ -29,6 +29,11 @@ env__net_uses_pci = True
 # set to False.
 env__net_dhcp_server = True
 
+# True if a DHCPv6 server is attached to the network, and should be tested.
+# If DHCPv6 testing is not possible or desired, this variable may be omitted or
+# set to False.
+env__net_dhcp6_server = True
+
 # A list of environment variables that should be set in order to configure a
 # static IP. If solely relying on DHCP, this variable may be omitted or set to
 # an empty list.
@@ -58,6 +63,7 @@ env__net_nfs_readable_file = {
 """
 
 net_set_up = False
+net6_set_up = False
 
 def test_net_pre_commands(u_boot_console):
 """Execute any commands required to enable network hardware.
@@ -93,6 +99,25 @@ def test_net_dhcp(u_boot_console):
 global net_set_up
 net_set_up = True
 
+@pytest.mark.buildconfigspec('cmd_dhcp6')
+def test_net_dhcp6(u_boot_console):
+"""Test the dhcp6 command.
+
+The boardenv_* file may be used to enable/disable this test; see the
+comment at the beginning of this file.
+"""
+
+test_dhcp6 = u_boot_console.config.env.get('env__net_dhcp6_server', False)
+if not test_dhcp6:
+pytest.skip('No DHCP6 server available')
+
+u_boot_console.run_command('setenv autoload no')
+output = u_boot_console.run_command('dhcp6')
+assert 'DHCP6 client bound to ' in output
+
+global net6_set_up
+net6_set_up = True
+
 @pytest.mark.buildconfigspec('net')
 def test_net_setup_static(u_boot_console):
 """Set up a static IP configuration.
-- 
2.40.0



[PATCH v2 2/3] net: dhcp6: pxe: Add DHCP/PXE commands for IPv6

2023-04-07 Thread seanedmond
From: Sean Edmond 

Adds commands to support DHCP and PXE with IPv6.

New configs added:
- CMD_DHCP6
- DHCP6_PXE_CLIENTARCH
- DHCP6_PXE_DHCP_OPTION
- DHCP6_ENTERPRISE_ID

New commands added (when IPv6 is enabled):
- dhcp6
- pxe get -ipv6
- pxe boot -ipv6

Signed-off-by: Sean Edmond 
---
 boot/bootmeth_distro.c |  2 +-
 boot/bootmeth_pxe.c|  4 +-
 boot/pxe_utils.c   |  3 +-
 cmd/Kconfig| 26 +
 cmd/net.c  | 23 +++
 cmd/pxe.c  | 86 +-
 cmd/sysboot.c  |  2 +-
 include/pxe_utils.h| 10 -
 8 files changed, 140 insertions(+), 16 deletions(-)

diff --git a/boot/bootmeth_distro.c b/boot/bootmeth_distro.c
index 356929828b..b4b73ecbf5 100644
--- a/boot/bootmeth_distro.c
+++ b/boot/bootmeth_distro.c
@@ -150,7 +150,7 @@ static int distro_boot(struct udevice *dev, struct bootflow 
*bflow)
info.dev = dev;
info.bflow = bflow;
ret = pxe_setup_ctx(, , distro_getfile, , true,
-   bflow->subdir);
+   bflow->subdir, false);
if (ret)
return log_msg_ret("ctx", -EINVAL);
 
diff --git a/boot/bootmeth_pxe.c b/boot/bootmeth_pxe.c
index ecf8557af8..5a8af2bbd0 100644
--- a/boot/bootmeth_pxe.c
+++ b/boot/bootmeth_pxe.c
@@ -70,7 +70,7 @@ static int distro_pxe_read_bootflow(struct udevice *dev, 
struct bootflow *bflow)
addr = simple_strtoul(addr_str, NULL, 16);
 
log_debug("calling pxe_get()\n");
-   ret = pxe_get(addr, , );
+   ret = pxe_get(addr, , , false);
log_debug("pxe_get() returned %d\n", ret);
if (ret)
return log_msg_ret("pxeb", ret);
@@ -146,7 +146,7 @@ static int distro_pxe_boot(struct udevice *dev, struct 
bootflow *bflow)
info.bflow = bflow;
info.cmdtp = 
ret = pxe_setup_ctx(ctx, , distro_pxe_getfile, , false,
-   bflow->subdir);
+   bflow->subdir, false);
if (ret)
return log_msg_ret("ctx", -EINVAL);
 
diff --git a/boot/pxe_utils.c b/boot/pxe_utils.c
index 3a1e50f2b1..d13c47dd94 100644
--- a/boot/pxe_utils.c
+++ b/boot/pxe_utils.c
@@ -1578,7 +1578,7 @@ void handle_pxe_menu(struct pxe_context *ctx, struct 
pxe_menu *cfg)
 
 int pxe_setup_ctx(struct pxe_context *ctx, struct cmd_tbl *cmdtp,
  pxe_getfile_func getfile, void *userdata,
- bool allow_abs_path, const char *bootfile)
+ bool allow_abs_path, const char *bootfile, bool use_ipv6)
 {
const char *last_slash;
size_t path_len = 0;
@@ -1588,6 +1588,7 @@ int pxe_setup_ctx(struct pxe_context *ctx, struct cmd_tbl 
*cmdtp,
ctx->getfile = getfile;
ctx->userdata = userdata;
ctx->allow_abs_path = allow_abs_path;
+   ctx->use_ipv6 = use_ipv6;
 
/* figure out the boot directory, if there is one */
if (bootfile && strlen(bootfile) >= MAX_TFTP_PATH_LEN)
diff --git a/cmd/Kconfig b/cmd/Kconfig
index bab35fc667..8448cf3400 100644
--- a/cmd/Kconfig
+++ b/cmd/Kconfig
@@ -1672,6 +1672,15 @@ config CMD_DHCP
help
  Boot image via network using DHCP/TFTP protocol
 
+config CMD_DHCP6
+   bool "dhcp6"
+   depends on IPV6
+   help
+ Boot image via network using DHCPv6/TFTP protocol using IPv6.
+
+ Will perform 4-message exchange with DHCPv6 server, requesting
+ the minimum required options to TFTP boot. Complies with RFC 8415.
+
 config BOOTP_MAY_FAIL
bool "Allow for the BOOTP/DHCP server to not be found"
depends on CMD_BOOTP
@@ -1785,6 +1794,23 @@ config BOOTP_VCI_STRING
default "U-Boot.arm" if ARM
default "U-Boot"
 
+if CMD_DHCP6
+
+config DHCP6_PXE_CLIENTARCH
+   hex
+   default 0x16 if ARM64
+   default 0x15 if ARM
+   default 0xFF
+
+config DHCP6_PXE_DHCP_OPTION
+   bool "Request & store 'pxe_configfile' from DHCP6 server"
+
+config DHCP6_ENTERPRISE_ID
+   int "Enterprise ID to send in DHCPv6 Vendor Class Option"
+   default 0
+
+endif
+
 config CMD_TFTPBOOT
bool "tftpboot"
default y
diff --git a/cmd/net.c b/cmd/net.c
index d5e20843dd..95529a9d12 100644
--- a/cmd/net.c
+++ b/cmd/net.c
@@ -111,6 +111,29 @@ U_BOOT_CMD(
 );
 #endif
 
+#if defined(CONFIG_CMD_DHCP6)
+static int do_dhcp6(struct cmd_tbl *cmdtp, int flag, int argc,
+   char *const argv[])
+{
+   int i;
+   int dhcp_argc;
+   char *dhcp_argv[] = {NULL, NULL, NULL, NULL};
+
+   /* Add -ipv6 flag for autoload */
+   for (i = 0; i < argc; i++)
+   dhcp_argv[i] = argv[i];
+   dhcp_argc = argc + 1;
+   dhcp_argv[dhcp_argc - 1] =  USE_IP6_CMD_PARAM;
+
+   return netboot_common(DHCP6, cmdtp, dhcp_argc, dhcp_argv);
+}
+
+U_BOOT_CMD(dhcp6,  3,  1,  do_dhcp6,
+  "boot image via network using DHCPv6/TFTP protocol. \n"
+  "Use IPv6 hostIPaddr framed with [] brackets",

[PATCH v2 1/3] net: dhcp6: Add DHCPv6 (DHCP for IPv6)

2023-04-07 Thread seanedmond
From: Sean Edmond 

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 
---
 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

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 charnet_hostname[32];   /* Our hostname 
*/
 #ifdef CONFIG_NET
 extern charnet_root_path[CONFIG_BOOTP_MAX_ROOT_PATH_LEN];  /* Our root 
path */
 #endif
+#if defined(CONFIG_DHCP6_PXE_DHCP_OPTION)
+/* 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 charnet_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 00..9204909c1f
--- /dev/null
+++ b/net/dhcpv6.c
@@ -0,0 +1,735 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) Microsoft Corporation
+ * Author: Sean Edmond 
+ *
+ */
+
+/* Simple DHCP6 network layer implementation. */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include "dhcpv6.h"
+#include 
+#include 
+#include "net_rand.h"
+
+#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  360
+#define REQ_TIMEOUT_MS 1000
+#define REQ_MAX_RT_MS  3
+#define REQ_MAX_RC 10
+#define MAX_WAIT_TIME_MS   6
+
+/* 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);
+
+struct dhcp6_sm_params sm_params;
+
+/*
+ * Handle DHCP received packets (set as UDP handler)
+ */
+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);
+}
+
+/**
+ * dhcp6_add_option() - Adds DHCP6 option to a packet
+ * @option_id: The option ID to add (See DHCP6_OPTION_* definitions)
+ * @pkt: A pointer to the current write location of the TX packet
+ *
+ * Return: The number of bytes written into "*pkt"
+ */
+static int dhcp6_add_option(int option_id, uchar *pkt)
+{
+   struct dhcp6_option_duid_ll *duid_opt;
+   struct dhcp6_option_elapsed_time *elapsed_time_opt;
+   struct dhcp6_option_ia_ta *ia_ta_opt;
+   struct dhcp6_option_ia_na *ia_na_opt;
+   struct dhcp6_option_oro *oro_opt;
+   struct dhcp6_option_client_arch *client_arch_opt;
+   struct dhcp6_option_vendor_class *vendor_class_opt;
+   int opt_len;
+   long elapsed_time;
+   size_t vci_strlen;
+   int num_oro = 0;
+   int num_client_arch = 0;
+   int num_vc_data = 0;
+   struct dhcp6_option_hdr *dhcp_option = (struct 

[PATCH v2 0/3] *** net: DHCPv6 protocol and commands ***

2023-04-07 Thread seanedmond
From: Sean Edmond 

The recently integrated IPv6 patch series relies on the link-local address,
or a statically assigned IPv6 address for network operations.  This patch
series adds IPv6 address assignment through DHCPv6.

The implementation meets the requirements in RFC 8415 for "Client/Server
Exchanges Involving Four Messages":
https://www.rfc-editor.org/rfc/rfc8415

The implementation sends/receives the minimum required DHCPv6 options to 
network boot.

A new command (dhcp6) will execute the protocol.  In addition, IPv6
functionality has been extended to the existing pxe commands ("pxe get"
and "pxe boot").

changes in v2:
- Add sandbox test in test_net.py
- Add CONFIG_CMD_DHCP6 to sandbox_defconfig
- fix comment style (/**/ instead of //)
- move addition of Kconfig from 1st patch to 2nd patch
- Fix warning (warning: label ‘error_exit’ defined but not used") when 
  CONFIG_DHCP6_PXE_DHCP_OPTION not configured
- Fix dhcp6 command help
- Use net_set_timeout_handler(0, NULL) in dhcpv6.c
- Move USE_IP6_CMD_PARAM back to net6.h

Sean Edmond (3):
  net: dhcp6: Add DHCPv6 (DHCP for IPv6)
  net: dhcp6: pxe: Add DHCP/PXE commands for IPv6
  net: dhcp6: Add a sandbox test for dhcp6

 boot/bootmeth_distro.c|   2 +-
 boot/bootmeth_pxe.c   |   4 +-
 boot/pxe_utils.c  |   3 +-
 cmd/Kconfig   |  26 ++
 cmd/net.c |  23 ++
 cmd/pxe.c |  86 -
 cmd/sysboot.c |   2 +-
 configs/sandbox_defconfig |   1 +
 include/net.h |   8 +-
 include/pxe_utils.h   |  10 +-
 net/Makefile  |   1 +
 net/dhcpv6.c  | 735 ++
 net/dhcpv6.h  | 212 +++
 net/net.c |  12 +
 test/py/tests/test_net.py |  25 ++
 15 files changed, 1132 insertions(+), 18 deletions(-)
 create mode 100644 net/dhcpv6.c
 create mode 100644 net/dhcpv6.h

-- 
2.40.0



[PATCH v2 3/3] net: dhcp6: Add a sandbox test for dhcp6

2023-04-07 Thread seanedmond
From: Sean Edmond 

Requires proper environment with DHCP6 server provisioned.

Signed-off-by: Sean Edmond 
---
 configs/sandbox_defconfig |  1 +
 test/py/tests/test_net.py | 25 +
 2 files changed, 26 insertions(+)

diff --git a/configs/sandbox_defconfig b/configs/sandbox_defconfig
index 3a1f14c60f..f65965f864 100644
--- a/configs/sandbox_defconfig
+++ b/configs/sandbox_defconfig
@@ -340,3 +340,4 @@ CONFIG_TEST_FDTDEC=y
 CONFIG_UNIT_TEST=y
 CONFIG_UT_TIME=y
 CONFIG_UT_DM=y
+CONFIG_CMD_DHCP6=y
diff --git a/test/py/tests/test_net.py b/test/py/tests/test_net.py
index 9ca6743afd..0447c0b2e0 100644
--- a/test/py/tests/test_net.py
+++ b/test/py/tests/test_net.py
@@ -29,6 +29,11 @@ env__net_uses_pci = True
 # set to False.
 env__net_dhcp_server = True
 
+# True if a DHCPv6 server is attached to the network, and should be tested.
+# If DHCPv6 testing is not possible or desired, this variable may be omitted or
+# set to False.
+env__net_dhcp6_server = True
+
 # A list of environment variables that should be set in order to configure a
 # static IP. If solely relying on DHCP, this variable may be omitted or set to
 # an empty list.
@@ -58,6 +63,7 @@ env__net_nfs_readable_file = {
 """
 
 net_set_up = False
+net6_set_up = False
 
 def test_net_pre_commands(u_boot_console):
 """Execute any commands required to enable network hardware.
@@ -93,6 +99,25 @@ def test_net_dhcp(u_boot_console):
 global net_set_up
 net_set_up = True
 
+@pytest.mark.buildconfigspec('cmd_dhcp6')
+def test_net_dhcp6(u_boot_console):
+"""Test the dhcp6 command.
+
+The boardenv_* file may be used to enable/disable this test; see the
+comment at the beginning of this file.
+"""
+
+test_dhcp6 = u_boot_console.config.env.get('env__net_dhcp6_server', False)
+if not test_dhcp6:
+pytest.skip('No DHCP6 server available')
+
+u_boot_console.run_command('setenv autoload no')
+output = u_boot_console.run_command('dhcp6')
+assert 'DHCP6 client bound to ' in output
+
+global net6_set_up
+net6_set_up = True
+
 @pytest.mark.buildconfigspec('net')
 def test_net_setup_static(u_boot_console):
 """Set up a static IP configuration.
-- 
2.40.0



[PATCH] net: ipv6: IPv6 environment variable cleanup

2023-02-15 Thread seanedmond
From: Sean Edmond 

Fix "setenv gatewayip6".

Synchronize IPv6 local variables with environment variables
in netboot_update_env()

Signed-off-by: Sean Edmond 
---
 cmd/net.c   | 23 ++-
 include/env_flags.h |  2 +-
 2 files changed, 23 insertions(+), 2 deletions(-)

diff --git a/cmd/net.c b/cmd/net.c
index 88d53d14d5..0161c87529 100644
--- a/cmd/net.c
+++ b/cmd/net.c
@@ -208,7 +208,7 @@ U_BOOT_CMD(
 
 static void netboot_update_env(void)
 {
-   char tmp[22];
+   char tmp[44];
 
if (net_gateway.s_addr) {
ip_to_string(net_gateway, tmp);
@@ -269,6 +269,27 @@ static void netboot_update_env(void)
env_set("ntpserverip", tmp);
}
 #endif
+
+   if (IS_ENABLED(CONFIG_IPV6)) {
+   if (!ip6_is_unspecified_addr(_ip6) ||
+   net_prefix_length != 0) {
+   sprintf(tmp, "%pI6c", _ip6);
+   if (net_prefix_length != 0)
+   sprintf(tmp, "%s/%d", tmp, net_prefix_length);
+
+   env_set("ip6addr", tmp);
+   }
+
+   if (!ip6_is_unspecified_addr(_server_ip6)) {
+   sprintf(tmp, "%pI6c", _server_ip6);
+   env_set("serverip6", tmp);
+   }
+
+   if (!ip6_is_unspecified_addr(_gateway6)) {
+   sprintf(tmp, "%pI6c", _gateway6);
+   env_set("gatewayip6", tmp);
+   }
+   }
 }
 
 /**
diff --git a/include/env_flags.h b/include/env_flags.h
index 6bd574c2bd..7df40c59be 100644
--- a/include/env_flags.h
+++ b/include/env_flags.h
@@ -71,7 +71,7 @@ enum env_flags_varaccess {
 #define NET6_FLAGS \
"ip6addr:s," \
"serverip6:s," \
-   "gatewayip6:s"
+   "gatewayip6:s,"
 #else
 #define NET6_FLAGS
 #endif
-- 
2.39.0



[PATCH 1/2] net: dhcp6: Add DHCPv6 (DHCP for IPv6)

2023-02-01 Thread seanedmond
From: Sean Edmond 

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.

New configs added:
- CMD_DHCP6
- DHCP6_PXE_CLIENTARCH
- DHCP6_PXE_DHCP_OPTION
- DHCP6_ENTERPRISE_ID

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 
---
 cmd/Kconfig   |  26 ++
 include/net.h |   8 +-
 net/Makefile  |   1 +
 net/dhcpv6.c  | 741 ++
 net/dhcpv6.h  | 212 +++
 net/net.c |  12 +
 6 files changed, 998 insertions(+), 2 deletions(-)
 create mode 100644 net/dhcpv6.c
 create mode 100644 net/dhcpv6.h

diff --git a/cmd/Kconfig b/cmd/Kconfig
index dc0446e02e..87813ddbb4 100644
--- a/cmd/Kconfig
+++ b/cmd/Kconfig
@@ -1645,6 +1645,15 @@ config CMD_DHCP
help
  Boot image via network using DHCP/TFTP protocol
 
+config CMD_DHCP6
+   bool "dhcp6"
+   depends on IPV6
+   help
+ Boot image via network using DHCPv6/TFTP protocol using IPv6.
+
+ Will perform 4-message exchange with DHCPv6 server, requesting
+ the minimum required options to TFTP boot. Complies with RFC 8415.
+ 
 config BOOTP_MAY_FAIL
bool "Allow for the BOOTP/DHCP server to not be found"
depends on CMD_BOOTP
@@ -1758,6 +1767,23 @@ config BOOTP_VCI_STRING
default "U-Boot.arm" if ARM
default "U-Boot"
 
+if CMD_DHCP6
+
+config DHCP6_PXE_CLIENTARCH
+   hex
+   default 0x16 if ARM64
+   default 0x15 if ARM
+   default 0xFF
+
+config DHCP6_PXE_DHCP_OPTION
+   bool "Request & store 'pxe_configfile' from DHCP6 server"
+
+config DHCP6_ENTERPRISE_ID
+   int "Enterprise ID to send in DHCPv6 Vendor Class Option"
+   default 0
+
+endif
+
 config CMD_TFTPBOOT
bool "tftpboot"
default y
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 charnet_hostname[32];   /* Our hostname 
*/
 #ifdef CONFIG_NET
 extern charnet_root_path[CONFIG_BOOTP_MAX_ROOT_PATH_LEN];  /* Our root 
path */
 #endif
+#if defined(CONFIG_DHCP6_PXE_DHCP_OPTION)
+/* 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 charnet_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 00..0f0fa291d3
--- /dev/null
+++ b/net/dhcpv6.c
@@ -0,0 +1,741 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) Microsoft Corporation
+ * Author: Sean Edmond 
+ *
+ */
+
+/* Simple DHCP6 network layer implementation. */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include "dhcpv6.h"
+#include 
+#include 
+#include "net_rand.h"
+
+/* Copied from bootp */
+#ifndef CONFIG_NET_RETRY_COUNT
+# define TIMEOUT_COUNT 5   /* # of timeouts before giving up */
+#else
+# define TIMEOUT_COUNT (CONFIG_NET_RETRY_COUNT)
+#endif
+
+#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  360
+#define REQ_TIMEOUT_MS 1000
+#define REQ_MAX_RT_MS  3
+#define REQ_MAX_RC 10
+#define MAX_WAIT_TIME_MS   6
+
+//global variable to track any updates from DHCP6 server
+int updated_sol_max_rt_ms = SOL_MAX_RT_MS;
+
+static void 

[PATCH 2/2] net: dhcp6: pxe: Add DHCP/PXE commands for IPv6

2023-02-01 Thread seanedmond
From: Sean Edmond 

Adds commands to support DHCP and PXE with IPv6.

New commands added (when IPv6 is enabled):
- dhcp6
- pxe get -ipv6
- pxe boot -ipv6

Signed-off-by: Sean Edmond 
---
 boot/bootmeth_distro.c |  2 +-
 boot/bootmeth_pxe.c|  4 +-
 boot/pxe_utils.c   |  3 +-
 cmd/net.c  | 22 +++
 cmd/pxe.c  | 86 +-
 cmd/sysboot.c  |  2 +-
 include/net.h  |  2 +
 include/net6.h |  2 -
 include/pxe_utils.h| 10 -
 9 files changed, 115 insertions(+), 18 deletions(-)

diff --git a/boot/bootmeth_distro.c b/boot/bootmeth_distro.c
index 356929828b..b4b73ecbf5 100644
--- a/boot/bootmeth_distro.c
+++ b/boot/bootmeth_distro.c
@@ -150,7 +150,7 @@ static int distro_boot(struct udevice *dev, struct bootflow 
*bflow)
info.dev = dev;
info.bflow = bflow;
ret = pxe_setup_ctx(, , distro_getfile, , true,
-   bflow->subdir);
+   bflow->subdir, false);
if (ret)
return log_msg_ret("ctx", -EINVAL);
 
diff --git a/boot/bootmeth_pxe.c b/boot/bootmeth_pxe.c
index ecf8557af8..5a8af2bbd0 100644
--- a/boot/bootmeth_pxe.c
+++ b/boot/bootmeth_pxe.c
@@ -70,7 +70,7 @@ static int distro_pxe_read_bootflow(struct udevice *dev, 
struct bootflow *bflow)
addr = simple_strtoul(addr_str, NULL, 16);
 
log_debug("calling pxe_get()\n");
-   ret = pxe_get(addr, , );
+   ret = pxe_get(addr, , , false);
log_debug("pxe_get() returned %d\n", ret);
if (ret)
return log_msg_ret("pxeb", ret);
@@ -146,7 +146,7 @@ static int distro_pxe_boot(struct udevice *dev, struct 
bootflow *bflow)
info.bflow = bflow;
info.cmdtp = 
ret = pxe_setup_ctx(ctx, , distro_pxe_getfile, , false,
-   bflow->subdir);
+   bflow->subdir, false);
if (ret)
return log_msg_ret("ctx", -EINVAL);
 
diff --git a/boot/pxe_utils.c b/boot/pxe_utils.c
index 3a1e50f2b1..d13c47dd94 100644
--- a/boot/pxe_utils.c
+++ b/boot/pxe_utils.c
@@ -1578,7 +1578,7 @@ void handle_pxe_menu(struct pxe_context *ctx, struct 
pxe_menu *cfg)
 
 int pxe_setup_ctx(struct pxe_context *ctx, struct cmd_tbl *cmdtp,
  pxe_getfile_func getfile, void *userdata,
- bool allow_abs_path, const char *bootfile)
+ bool allow_abs_path, const char *bootfile, bool use_ipv6)
 {
const char *last_slash;
size_t path_len = 0;
@@ -1588,6 +1588,7 @@ int pxe_setup_ctx(struct pxe_context *ctx, struct cmd_tbl 
*cmdtp,
ctx->getfile = getfile;
ctx->userdata = userdata;
ctx->allow_abs_path = allow_abs_path;
+   ctx->use_ipv6 = use_ipv6;
 
/* figure out the boot directory, if there is one */
if (bootfile && strlen(bootfile) >= MAX_TFTP_PATH_LEN)
diff --git a/cmd/net.c b/cmd/net.c
index 4227321871..88d53d14d5 100644
--- a/cmd/net.c
+++ b/cmd/net.c
@@ -111,6 +111,28 @@ U_BOOT_CMD(
 );
 #endif
 
+#if defined(CONFIG_CMD_DHCP6)
+static int do_dhcp6(struct cmd_tbl *cmdtp, int flag, int argc,
+   char *const argv[])
+{
+   int i;
+   int dhcp_argc;
+   char *dhcp_argv[] = {NULL, NULL, NULL, NULL};
+
+   /* Add -ipv6 flag for autoload */
+   for (i = 0; i < argc; i++)
+   dhcp_argv[i] = argv[i];
+   dhcp_argc = argc + 1;
+   dhcp_argv[dhcp_argc - 1] =  USE_IP6_CMD_PARAM;
+
+   return netboot_common(DHCP6, cmdtp, dhcp_argc, dhcp_argv);
+}
+
+U_BOOT_CMD(dhcp6,  3,  1,  do_dhcp6,
+  "boot image via network using DHCPv6/TFTP protocol",
+  "[loadAddress] [[hostIPaddr:]bootfilename]");
+#endif
+
 #if defined(CONFIG_CMD_DHCP)
 static int do_dhcp(struct cmd_tbl *cmdtp, int flag, int argc,
   char *const argv[])
diff --git a/cmd/pxe.c b/cmd/pxe.c
index db8e4697f2..ebc44fd661 100644
--- a/cmd/pxe.c
+++ b/cmd/pxe.c
@@ -11,6 +11,10 @@
 
 #include "pxe_utils.h"
 
+#if IS_ENABLED(CONFIG_IPV6)
+#include 
+#endif
+
 #ifdef CONFIG_CMD_NET
 const char *pxe_default_paths[] = {
 #ifdef CONFIG_SYS_SOC
@@ -29,12 +33,20 @@ static int do_get_tftp(struct pxe_context *ctx, const char 
*file_path,
 {
char *tftp_argv[] = {"tftp", NULL, NULL, NULL};
int ret;
+   int num_args;
 
tftp_argv[1] = file_addr;
tftp_argv[2] = (void *)file_path;
+   if (ctx->use_ipv6) {
+   tftp_argv[3] = USE_IP6_CMD_PARAM;
+   num_args = 4;
+   } else {
+   num_args = 3;
+   }
 
-   if (do_tftpb(ctx->cmdtp, 0, 3, tftp_argv))
+   if (do_tftpb(ctx->cmdtp, 0, num_args, tftp_argv))
return -ENOENT;
+
ret = pxe_get_file_size(sizep);
if (ret)
return log_msg_ret("tftp", ret);
@@ -43,6 +55,22 @@ static int do_get_tftp(struct pxe_context *ctx, const char 
*file_path,
return 1;
 }
 
+#if 

[PATCH 0/2] net: DHCPv6 protocol and commands

2023-02-01 Thread seanedmond
From: Sean Edmond 

The recently integrated IPv6 patch series relies on the link-local address,
or a statically assigned IPv6 address for network operations.  This patch
series adds IPv6 address assignment through DHCPv6.

The implementation meets the requirements in RFC 8415 for "Client/Server
Exchanges Involving Four Messages":
https://www.rfc-editor.org/rfc/rfc8415

The implementation sends/receives the minimum required DHCPv6 options to 
network boot.

A new command (dhcp6) will execute the protocol.  In addition, IPv6
functionality has been extended to the existing pxe commands ("pxe get"
and "pxe boot").

Sean Edmond (2):
  net: dhcp6: Add DHCPv6 (DHCP for IPv6)
  net: dhcp6: pxe: Add DHCP/PXE commands for IPv6

 boot/bootmeth_distro.c |   2 +-
 boot/bootmeth_pxe.c|   4 +-
 boot/pxe_utils.c   |   3 +-
 cmd/Kconfig|  26 ++
 cmd/net.c  |  22 ++
 cmd/pxe.c  |  86 -
 cmd/sysboot.c  |   2 +-
 include/net.h  |  10 +-
 include/net6.h |   2 -
 include/pxe_utils.h|  10 +-
 net/Makefile   |   1 +
 net/dhcpv6.c   | 741 +
 net/dhcpv6.h   | 212 
 net/net.c  |  12 +
 14 files changed, 1113 insertions(+), 20 deletions(-)
 create mode 100644 net/dhcpv6.c
 create mode 100644 net/dhcpv6.h

-- 
2.39.0



[PATCH] net: ipv6: Fix IPv6 netmask parsing

2023-01-06 Thread seanedmond
From: Sean Edmond 

It should be possible to specify a netmask when
setting a static IPv6 address.  For example:
setenv ip6addr 2001:cafe:cafe:cafe::100/64

The net_prefix_length and net_ip6 should be updated
properly.

Signed-off-by: Sean Edmond 
---
 net/net6.c | 9 ++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/net/net6.c b/net/net6.c
index fdea078788..75577bcea1 100644
--- a/net/net6.c
+++ b/net/net6.c
@@ -47,10 +47,13 @@ static int on_ip6addr(const char *name, const char *value, 
enum env_op op,
}
 
mask = strchr(value, '/');
-   len = strlen(value);
 
-   if (mask)
-   net_prefix_length = simple_strtoul(value + len, NULL, 10);
+   if (mask) {
+   net_prefix_length = simple_strtoul(mask + 1, NULL, 10);
+   len = mask - value;
+   } else {
+   len = strlen(value);
+   }
 
return string_to_ip6(value, len, _ip6);
 }
-- 
2.39.0



[PATCH] net: tftp: Fix for DATA ACK for block count out of order

2023-01-05 Thread seanedmond
From: Sean Edmond 

In rfc7440, if an ACK is not received by the server or if the
last data block in a window is dropped, the server will timeout and
retransmit the window.  In this case, the block count received will be
less than the internal block count.  In this case, the client
should not ACK.  ACK should only be sent if the received block
count is greater than the expected block count.

Signed-off-by: Sean Edmond 
---
 net/tftp.c | 8 
 1 file changed, 8 insertions(+)

diff --git a/net/tftp.c b/net/tftp.c
index c780c33f37..51e062bddf 100644
--- a/net/tftp.c
+++ b/net/tftp.c
@@ -592,6 +592,14 @@ static void tftp_handler(uchar *pkt, unsigned dest, struct 
in_addr sip,
debug("Received unexpected block: %d, expected: %d\n",
  ntohs(*(__be16 *)pkt),
  (ushort)(tftp_cur_block + 1));
+   /*
+* Only ACK if the block count received is greater than
+* the expected block count, otherwise skip ACK.
+* (required to properly handle the server 
retransmitting
+*  the window)
+*/
+   if ((ushort)(tftp_cur_block + 1) - 
(short)(ntohs(*(__be16 *)pkt)) > 0)
+   break;
/*
 * If one packet is dropped most likely
 * all other buffers in the window
-- 
2.39.0



[PATCH] net: tftp: Fix for DATA ACK for block count out of order

2023-01-05 Thread seanedmond
From: Sean Edmond 

In rfc7440, if an ACK is not received by the server or if the
last data block in a window is dropped, the server will timeout and
retransmit the window.  In this case, the block count received will be
less than the internal block count.  In this case, the client
should not ACK.  ACK should only be sent if the received block
count is greater than the expected block count.

Signed-off-by: Sean Edmond 
---
 net/tftp.c | 8 
 1 file changed, 8 insertions(+)

diff --git a/net/tftp.c b/net/tftp.c
index c780c33f37..51e062bddf 100644
--- a/net/tftp.c
+++ b/net/tftp.c
@@ -592,6 +592,14 @@ static void tftp_handler(uchar *pkt, unsigned dest, struct 
in_addr sip,
debug("Received unexpected block: %d, expected: %d\n",
  ntohs(*(__be16 *)pkt),
  (ushort)(tftp_cur_block + 1));
+   /*
+* Only ACK if the block count received is greater than
+* the expected block count, otherwise skip ACK.
+* (required to properly handle the server 
retransmitting
+*  the window)
+*/
+   if ((ushort)(tftp_cur_block + 1) - 
(short)(ntohs(*(__be16 *)pkt)) > 0)
+   break;
/*
 * If one packet is dropped most likely
 * all other buffers in the window
-- 
2.17.1