summaryrefslogtreecommitdiff
path: root/lib/efi_loader/efi_device_path.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/efi_loader/efi_device_path.c')
-rw-r--r--lib/efi_loader/efi_device_path.c115
1 files changed, 113 insertions, 2 deletions
diff --git a/lib/efi_loader/efi_device_path.c b/lib/efi_loader/efi_device_path.c
index ee387e1dfd4..c0633a736b6 100644
--- a/lib/efi_loader/efi_device_path.c
+++ b/lib/efi_loader/efi_device_path.c
@@ -974,6 +974,116 @@ struct efi_device_path __maybe_unused *efi_dp_from_eth(void)
return start;
}
+/**
+ * efi_dp_from_ipv4() - set device path from IPv4 address
+ *
+ * Set the device path to an ethernet device path as provided by
+ * efi_dp_from_eth() concatenated with a device path of subtype
+ * DEVICE_PATH_SUB_TYPE_MSG_IPV4, and an END node.
+ *
+ * @ip: IPv4 local address
+ * @mask: network mask
+ * @srv: IPv4 remote/server address
+ * Return: pointer to device path, NULL on error
+ */
+static struct efi_device_path *efi_dp_from_ipv4(struct efi_ipv4_address *ip,
+ struct efi_ipv4_address *mask,
+ struct efi_ipv4_address *srv)
+{
+ struct efi_device_path *dp1, *dp2, *pos;
+ struct {
+ struct efi_device_path_ipv4 ipv4dp;
+ struct efi_device_path end;
+ } dp;
+
+ memset(&dp.ipv4dp, 0, sizeof(dp.ipv4dp));
+ dp.ipv4dp.dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE;
+ dp.ipv4dp.dp.sub_type = DEVICE_PATH_SUB_TYPE_MSG_IPV4;
+ dp.ipv4dp.dp.length = sizeof(dp.ipv4dp);
+ dp.ipv4dp.protocol = 6;
+ if (ip)
+ memcpy(&dp.ipv4dp.local_ip_address, ip, sizeof(*ip));
+ if (mask)
+ memcpy(&dp.ipv4dp.subnet_mask, mask, sizeof(*mask));
+ if (srv)
+ memcpy(&dp.ipv4dp.remote_ip_address, srv, sizeof(*srv));
+ pos = &dp.end;
+ memcpy(pos, &END, sizeof(END));
+
+ dp1 = efi_dp_from_eth();
+ if (!dp1)
+ return NULL;
+
+ dp2 = efi_dp_concat(dp1, (const struct efi_device_path *)&dp, 0);
+
+ efi_free_pool(dp1);
+
+ return dp2;
+}
+
+/**
+ * efi_dp_from_http() - set device path from http
+ *
+ * Set the device path to an IPv4 path as provided by efi_dp_from_ipv4
+ * concatenated with a device path of subtype DEVICE_PATH_SUB_TYPE_MSG_URI,
+ * and an END node.
+ *
+ * @server: URI of remote server
+ * Return: pointer to HTTP device path, NULL on error
+ */
+struct efi_device_path *efi_dp_from_http(const char *server)
+{
+ struct efi_device_path *dp1, *dp2;
+ struct efi_device_path_uri *uridp;
+ efi_uintn_t uridp_len;
+ char *pos;
+ char tmp[128];
+ struct efi_ipv4_address ip;
+ struct efi_ipv4_address mask;
+
+ if ((server && strlen("http://") + strlen(server) + 1 > sizeof(tmp)) ||
+ (!server && IS_ENABLED(CONFIG_NET_LWIP)))
+ return NULL;
+
+ efi_net_get_addr(&ip, &mask, NULL);
+
+ dp1 = efi_dp_from_ipv4(&ip, &mask, NULL);
+ if (!dp1)
+ return NULL;
+
+ strcpy(tmp, "http://");
+
+ if (server) {
+ strlcat(tmp, server, sizeof(tmp));
+#if !IS_ENABLED(CONFIG_NET_LWIP)
+ } else {
+ ip_to_string(net_server_ip, tmp + strlen("http://"));
+#endif
+ }
+
+ uridp_len = sizeof(struct efi_device_path) + strlen(tmp) + 1;
+ uridp = efi_alloc(uridp_len + sizeof(END));
+ if (!uridp) {
+ log_err("Out of memory\n");
+ return NULL;
+ }
+ uridp->dp.type = DEVICE_PATH_TYPE_MESSAGING_DEVICE;
+ uridp->dp.sub_type = DEVICE_PATH_SUB_TYPE_MSG_URI;
+ uridp->dp.length = uridp_len;
+ debug("device path: setting uri device path to %s\n", tmp);
+ memcpy(uridp->uri, tmp, strlen(tmp) + 1);
+
+ pos = (char *)uridp + uridp_len;
+ memcpy(pos, &END, sizeof(END));
+
+ dp2 = efi_dp_concat(dp1, (const struct efi_device_path *)uridp, 0);
+
+ efi_free_pool(uridp);
+ efi_free_pool(dp1);
+
+ return dp2;
+}
+
/* Construct a device-path for memory-mapped image */
struct efi_device_path *efi_dp_from_mem(uint32_t memory_type,
uint64_t start_address,
@@ -1074,8 +1184,9 @@ efi_status_t efi_dp_from_name(const char *dev, const char *devnr,
dp = efi_dp_from_mem(EFI_RESERVED_MEMORY_TYPE,
(uintptr_t)image_addr, image_size);
- } else if (IS_ENABLED(CONFIG_NETDEVICES) && !strcmp(dev, "Net")) {
- dp = efi_dp_from_eth();
+ } else if (IS_ENABLED(CONFIG_NETDEVICES) &&
+ (!strcmp(dev, "Net") || !strcmp(dev, "Http"))) {
+ efi_net_get_dp(&dp);
} else if (!strcmp(dev, "Uart")) {
dp = efi_dp_from_uart();
} else {