* Patches to support UEFI HTTP Boot IPv4 and IPv6
@ 2016-08-03 6:34 Michael Chang
2016-08-03 6:34 ` [PATCH 1/8] misc: fix invalid character recongition in strto*l Michael Chang
` (7 more replies)
0 siblings, 8 replies; 11+ messages in thread
From: Michael Chang @ 2016-08-03 6:34 UTC (permalink / raw)
To: Grub devel; +Cc: Ken Lin
This patch set enables UEFI HTTP Boot suppot for IPv4 and IPv6. It has been
tested on OVMF virtual machine and several physical servers to work. We would
like to contribute the current work to upstream to get better vision and
support in the future through a much larger community.
The first two patches came from Aaron Miller <aaronmiller@fb.com> that fixed
the issue of placing IPv6 address in the brackets which is required by the http
message. We hope upstream could review these two patch as well as long as it
has been sent to the mailing list a few months ago.
[PATCH 1/8] misc: fix invalid character recongition in strto*l
[PATCH 2/8] net: read bracketed ipv6 addrs and port numbers
The following three patches came from my previous net_bootp6 patches and are
reworked quite a bit based on latest review. We did the UEFI HTTP Boot based on
these patches in order to get IPv6 support more completed and sharing the
routines for setting up network interface etc.
[PATCH 3/8] bootp: New net_bootp6 command
[PATCH 4/8] efinet: UEFI IPv6 PXE support
[PATCH 5/8] grub.texi: Add net_bootp6 doument
The last three patches are related to UEFI HTTP boot by means of new introduced
URI device path and UEFI protcols used for obtaining the DNS.
[PATCH 6/8] bootp: Add processing DHCPACK packet from HTTP Boot
[PATCH 7/8] efinet: Setting network from UEFI device path
[PATCH 8/8] efinet: Setting DNS server from UEFI protocol
Thanks,
Michael
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH 1/8] misc: fix invalid character recongition in strto*l
2016-08-03 6:34 Patches to support UEFI HTTP Boot IPv4 and IPv6 Michael Chang
@ 2016-08-03 6:34 ` Michael Chang
2016-08-10 15:51 ` Vladimir 'phcoder' Serbinenko
2016-08-03 6:34 ` [PATCH 2/8] net: read bracketed ipv6 addrs and port numbers Michael Chang
` (6 subsequent siblings)
7 siblings, 1 reply; 11+ messages in thread
From: Michael Chang @ 2016-08-03 6:34 UTC (permalink / raw)
To: Grub devel; +Cc: Ken Lin, Michael Chang
From: Aaron Miller <aaronmiller@fb.com>
Would previously allow digits larger than the base and didn't check that
subtracting the difference from 0-9 to lowercase letters for characters
larger than 9 didn't result in a value lower than 9, which allowed the
parses: ` = 9, _ = 8, ^ = 7, ] = 6, \ = 5, and [ = 4
---
grub-core/kern/misc.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/grub-core/kern/misc.c b/grub-core/kern/misc.c
index d1a54df..3a14d67 100644
--- a/grub-core/kern/misc.c
+++ b/grub-core/kern/misc.c
@@ -394,9 +394,13 @@ grub_strtoull (const char *str, char **end, int base)
if (digit > 9)
{
digit += '0' - 'a' + 10;
- if (digit >= (unsigned long) base)
+ /* digit <= 9 check is needed to keep chars larger than
+ '9' but less than 'a' from being read as numbers */
+ if (digit >= (unsigned long) base || digit <= 9)
break;
}
+ if (digit >= (unsigned long) base)
+ break;
found = 1;
--
2.6.6
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH 2/8] net: read bracketed ipv6 addrs and port numbers
2016-08-03 6:34 Patches to support UEFI HTTP Boot IPv4 and IPv6 Michael Chang
2016-08-03 6:34 ` [PATCH 1/8] misc: fix invalid character recongition in strto*l Michael Chang
@ 2016-08-03 6:34 ` Michael Chang
2016-08-03 8:17 ` Andrei Borzenkov
2016-08-03 6:34 ` [PATCH 3/8] bootp: New net_bootp6 command Michael Chang
` (5 subsequent siblings)
7 siblings, 1 reply; 11+ messages in thread
From: Michael Chang @ 2016-08-03 6:34 UTC (permalink / raw)
To: Grub devel; +Cc: Ken Lin, Michael Chang
From: Aaron Miller <aaronmiller@fb.com>
Allow specifying port numbers for http and tftp paths, and allow ipv6 addresses
to be recognized with brackets around them, which is required to specify a port
number
---
grub-core/net/http.c | 21 ++++++++++---
grub-core/net/net.c | 86 +++++++++++++++++++++++++++++++++++++++++++++++++---
grub-core/net/tftp.c | 6 +++-
include/grub/net.h | 1 +
4 files changed, 104 insertions(+), 10 deletions(-)
diff --git a/grub-core/net/http.c b/grub-core/net/http.c
index 5aa4ad3..f182d7b 100644
--- a/grub-core/net/http.c
+++ b/grub-core/net/http.c
@@ -312,12 +312,14 @@ http_establish (struct grub_file *file, grub_off_t offset, int initial)
int i;
struct grub_net_buff *nb;
grub_err_t err;
+ char* server = file->device->net->server;
+ int port = file->device->net->port;
nb = grub_netbuff_alloc (GRUB_NET_TCP_RESERVE_SIZE
+ sizeof ("GET ") - 1
+ grub_strlen (data->filename)
+ sizeof (" HTTP/1.1\r\nHost: ") - 1
- + grub_strlen (file->device->net->server)
+ + grub_strlen (server) + sizeof (":XXXXXXXXXX")
+ sizeof ("\r\nUser-Agent: " PACKAGE_STRING
"\r\n") - 1
+ sizeof ("Range: bytes=XXXXXXXXXXXXXXXXXXXX"
@@ -356,7 +358,7 @@ http_establish (struct grub_file *file, grub_off_t offset, int initial)
sizeof (" HTTP/1.1\r\nHost: ") - 1);
ptr = nb->tail;
- err = grub_netbuff_put (nb, grub_strlen (file->device->net->server));
+ err = grub_netbuff_put (nb, grub_strlen (server));
if (err)
{
grub_netbuff_free (nb);
@@ -365,6 +367,15 @@ http_establish (struct grub_file *file, grub_off_t offset, int initial)
grub_memcpy (ptr, file->device->net->server,
grub_strlen (file->device->net->server));
+ if (port)
+ {
+ ptr = nb->tail;
+ grub_snprintf ((char *) ptr,
+ sizeof (":XXXXXXXXXX"),
+ ":%d",
+ port);
+ }
+
ptr = nb->tail;
err = grub_netbuff_put (nb,
sizeof ("\r\nUser-Agent: " PACKAGE_STRING "\r\n")
@@ -390,8 +401,10 @@ http_establish (struct grub_file *file, grub_off_t offset, int initial)
grub_netbuff_put (nb, 2);
grub_memcpy (ptr, "\r\n", 2);
- data->sock = grub_net_tcp_open (file->device->net->server,
- HTTP_PORT, http_receive,
+ grub_dprintf ("http", "opening path %s on host %s TCP port %d\n",
+ data->filename, server, port ? port : HTTP_PORT);
+ data->sock = grub_net_tcp_open (server,
+ port ? port : HTTP_PORT, http_receive,
http_err, http_err,
file);
if (!data->sock)
diff --git a/grub-core/net/net.c b/grub-core/net/net.c
index 10773fc..5cc0d2f 100644
--- a/grub-core/net/net.c
+++ b/grub-core/net/net.c
@@ -437,6 +437,12 @@ parse_ip6 (const char *val, grub_uint64_t *ip, const char **rest)
grub_uint16_t newip[8];
const char *ptr = val;
int word, quaddot = -1;
+ int bracketed = 0;
+
+ if (ptr[0] == '[') {
+ bracketed = 1;
+ ptr++;
+ }
if (ptr[0] == ':' && ptr[1] != ':')
return 0;
@@ -475,6 +481,9 @@ parse_ip6 (const char *val, grub_uint64_t *ip, const char **rest)
grub_memset (&newip[quaddot], 0, (7 - word) * sizeof (newip[0]));
}
grub_memcpy (ip, newip, 16);
+ if (bracketed && *ptr == ']') {
+ ptr++;
+ }
if (rest)
*rest = ptr;
return 1;
@@ -1260,8 +1269,10 @@ grub_net_open_real (const char *name)
{
grub_net_app_level_t proto;
const char *protname, *server;
+ char *host;
grub_size_t protnamelen;
int try;
+ int port = 0;
if (grub_strncmp (name, "pxe:", sizeof ("pxe:") - 1) == 0)
{
@@ -1299,6 +1310,72 @@ grub_net_open_real (const char *name)
return NULL;
}
+ char* port_start;
+ /* ipv6 or port specified? */
+ if ((port_start = grub_strchr (server, ':')))
+ {
+ char* ipv6_begin;
+ if((ipv6_begin = grub_strchr (server, '[')))
+ {
+ char* ipv6_end = grub_strchr (server, ']');
+ if(!ipv6_end)
+ {
+ grub_error (GRUB_ERR_NET_BAD_ADDRESS,
+ N_("mismatched [ in address"));
+ return NULL;
+ }
+ /* port number after bracketed ipv6 addr */
+ if(ipv6_end[1] == ':')
+ {
+ port = grub_strtoul (ipv6_end + 2, NULL, 10);
+ if(port > 65535)
+ {
+ grub_error (GRUB_ERR_NET_BAD_ADDRESS,
+ N_("bad port number"));
+ return NULL;
+ }
+ }
+ host = grub_strndup (ipv6_begin, (ipv6_end - ipv6_begin) + 1);
+ }
+ else
+ {
+ if (grub_strchr (port_start + 1, ':'))
+ {
+ int iplen = grub_strlen (server);
+ /* bracket bare ipv6 addrs */
+ host = grub_malloc (iplen + 3);
+ if(!host)
+ {
+ return NULL;
+ }
+ host[0] = '[';
+ grub_memcpy (host + 1, server, iplen);
+ host[iplen + 1] = ']';
+ host[iplen + 2] = '\0';
+ }
+ else
+ {
+ /* hostname:port or ipv4:port */
+ port = grub_strtol (port_start + 1, NULL, 10);
+ if(port > 65535)
+ {
+ grub_error (GRUB_ERR_NET_BAD_ADDRESS,
+ N_("bad port number"));
+ return NULL;
+ }
+ host = grub_strndup (server, port_start - server);
+ }
+ }
+ }
+ else
+ {
+ host = grub_strdup (server);
+ }
+ if (!host)
+ {
+ return NULL;
+ }
+
for (try = 0; try < 2; try++)
{
FOR_NET_APP_LEVEL (proto)
@@ -1308,14 +1385,13 @@ grub_net_open_real (const char *name)
{
grub_net_t ret = grub_zalloc (sizeof (*ret));
if (!ret)
- return NULL;
- ret->protocol = proto;
- ret->server = grub_strdup (server);
- if (!ret->server)
{
- grub_free (ret);
+ grub_free (host);
return NULL;
}
+ ret->protocol = proto;
+ ret->port = port;
+ ret->server = host;
ret->fs = &grub_net_fs;
return ret;
}
diff --git a/grub-core/net/tftp.c b/grub-core/net/tftp.c
index 7d90bf6..a0817a0 100644
--- a/grub-core/net/tftp.c
+++ b/grub-core/net/tftp.c
@@ -314,6 +314,7 @@ tftp_open (struct grub_file *file, const char *filename)
grub_err_t err;
grub_uint8_t *nbd;
grub_net_network_level_address_t addr;
+ int port = file->device->net->port;
data = grub_zalloc (sizeof (*data));
if (!data)
@@ -382,13 +383,16 @@ tftp_open (struct grub_file *file, const char *filename)
err = grub_net_resolve_address (file->device->net->server, &addr);
if (err)
{
+ grub_dprintf ("tftp", "file_size is %llu, block_size is %llu\n",
+ (unsigned long long)data->file_size,
+ (unsigned long long)data->block_size);
destroy_pq (data);
grub_free (data);
return err;
}
data->sock = grub_net_udp_open (addr,
- TFTP_SERVER_PORT, tftp_receive,
+ port ? port : TFTP_SERVER_PORT, tftp_receive,
file);
if (!data->sock)
{
diff --git a/include/grub/net.h b/include/grub/net.h
index 2192fa1..ccc169c 100644
--- a/include/grub/net.h
+++ b/include/grub/net.h
@@ -270,6 +270,7 @@ typedef struct grub_net
{
char *server;
char *name;
+ int port;
grub_net_app_level_t protocol;
grub_net_packets_t packs;
grub_off_t offset;
--
2.6.6
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH 3/8] bootp: New net_bootp6 command
2016-08-03 6:34 Patches to support UEFI HTTP Boot IPv4 and IPv6 Michael Chang
2016-08-03 6:34 ` [PATCH 1/8] misc: fix invalid character recongition in strto*l Michael Chang
2016-08-03 6:34 ` [PATCH 2/8] net: read bracketed ipv6 addrs and port numbers Michael Chang
@ 2016-08-03 6:34 ` Michael Chang
2016-08-03 6:34 ` [PATCH 4/8] efinet: UEFI IPv6 PXE support Michael Chang
` (4 subsequent siblings)
7 siblings, 0 replies; 11+ messages in thread
From: Michael Chang @ 2016-08-03 6:34 UTC (permalink / raw)
To: Grub devel; +Cc: Ken Lin, Michael Chang
Implement new net_bootp6 command for IPv6 network auto configuration via the
DHCPv6 protocol (RFC3315).
Signed-off-by: Michael Chang <mchang@suse.com>
Signed-off-by: Ken Lin <ken.lin@hpe.com>
---
grub-core/net/bootp.c | 908 +++++++++++++++++++++++++++++++++++++++++++++++++-
grub-core/net/ip.c | 39 +++
include/grub/net.h | 72 ++++
3 files changed, 1018 insertions(+), 1 deletion(-)
diff --git a/grub-core/net/bootp.c b/grub-core/net/bootp.c
index 189551a..81173b4 100644
--- a/grub-core/net/bootp.c
+++ b/grub-core/net/bootp.c
@@ -24,6 +24,98 @@
#include <grub/net/netbuff.h>
#include <grub/net/udp.h>
#include <grub/datetime.h>
+#include <grub/time.h>
+#include <grub/list.h>
+
+static int
+dissect_url (const char *url, char **proto, char **host, char **path)
+{
+ const char *p, *ps;
+ grub_size_t l;
+
+ *proto = *host = *path = NULL;
+ ps = p = url;
+
+ while ((p = grub_strchr (p, ':')))
+ {
+ if (grub_strlen (p) < sizeof ("://") - 1)
+ break;
+ if (grub_memcmp (p, "://", sizeof ("://") - 1) == 0)
+ {
+ l = p - ps;
+ *proto = grub_malloc (l + 1);
+ if (!*proto)
+ {
+ grub_print_error ();
+ return 0;
+ }
+
+ grub_memcpy (*proto, ps, l);
+ (*proto)[l] = '\0';
+ p += sizeof ("://") - 1;
+ break;
+ }
+ ++p;
+ }
+
+ if (!*proto)
+ {
+ grub_dprintf ("bootp", "url: %s is not valid, protocol not found\n", url);
+ return 0;
+ }
+
+ ps = p;
+ p = grub_strchr (p, '/');
+
+ if (!p)
+ {
+ grub_dprintf ("bootp", "url: %s is not valid, host/path not found\n", url);
+ grub_free (*proto);
+ *proto = NULL;
+ return 0;
+ }
+
+ l = p - ps;
+
+ if (l > 2 && ps[0] == '[' && ps[l - 1] == ']')
+ {
+ *host = grub_malloc (l - 1);
+ if (!*host)
+ {
+ grub_print_error ();
+ grub_free (*proto);
+ *proto = NULL;
+ return 0;
+ }
+ grub_memcpy (*host, ps + 1, l - 2);
+ (*host)[l - 2] = 0;
+ }
+ else
+ {
+ *host = grub_malloc (l + 1);
+ if (!*host)
+ {
+ grub_print_error ();
+ grub_free (*proto);
+ *proto = NULL;
+ return 0;
+ }
+ grub_memcpy (*host, ps, l);
+ (*host)[l] = 0;
+ }
+
+ *path = grub_strdup (p);
+ if (!*path)
+ {
+ grub_print_error ();
+ grub_free (*host);
+ grub_free (*proto);
+ *host = NULL;
+ *proto = NULL;
+ return 0;
+ }
+ return 1;
+}
static void
parse_dhcp_vendor (const char *name, const void *vend, int limit, int *mask)
@@ -266,6 +358,578 @@ grub_net_configure_by_dhcp_ack (const char *name,
return inter;
}
+/* The default netbuff size for sending DHCPv6 packets which should be
+ large enough to hold the information */
+#define GRUB_DHCP6_DEFAULT_NETBUFF_ALLOC_SIZE 512
+
+struct grub_dhcp6_options
+{
+ grub_uint8_t *client_duid;
+ grub_uint16_t client_duid_len;
+ grub_uint8_t *server_duid;
+ grub_uint16_t server_duid_len;
+ grub_uint32_t iaid;
+ grub_uint32_t t1;
+ grub_uint32_t t2;
+ grub_net_network_level_address_t *ia_addr;
+ grub_uint32_t preferred_lifetime;
+ grub_uint32_t valid_lifetime;
+ grub_net_network_level_address_t *dns_server_addrs;
+ grub_uint16_t num_dns_server;
+ char *boot_file_proto;
+ char *boot_file_server_ip;
+ char *boot_file_path;
+};
+
+typedef struct grub_dhcp6_options *grub_dhcp6_options_t;
+
+struct grub_dhcp6_session
+{
+ struct grub_dhcp6_session *next;
+ struct grub_dhcp6_session **prev;
+ grub_uint32_t iaid;
+ grub_uint32_t transaction_id:24;
+ grub_uint64_t start_time;
+ struct grub_net_dhcp6_option_duid_ll duid;
+ struct grub_net_network_level_interface *iface;
+
+ /* The associated dhcpv6 options */
+ grub_dhcp6_options_t adv;
+ grub_dhcp6_options_t reply;
+};
+
+typedef struct grub_dhcp6_session *grub_dhcp6_session_t;
+
+typedef void (*dhcp6_option_hook_fn) (const struct grub_net_dhcp6_option *opt, void *data);
+
+static void
+foreach_dhcp6_option (const struct grub_net_dhcp6_option *opt, grub_size_t size,
+ dhcp6_option_hook_fn hook, void *hook_data);
+
+static void
+parse_dhcp6_iaaddr (const struct grub_net_dhcp6_option *opt, void *data)
+{
+ grub_dhcp6_options_t dhcp6 = (grub_dhcp6_options_t )data;
+
+ grub_uint16_t code = grub_be_to_cpu16 (opt->code);
+ grub_uint16_t len = grub_be_to_cpu16 (opt->len);
+
+ if (code == GRUB_NET_DHCP6_OPTION_IAADDR)
+ {
+ const struct grub_net_dhcp6_option_iaaddr *iaaddr;
+ iaaddr = (const struct grub_net_dhcp6_option_iaaddr *)opt->data;
+
+ if (len < sizeof (*iaaddr))
+ {
+ grub_dprintf ("bootp", "DHCPv6: code %u with insufficient length %u\n", code, len);
+ return;
+ }
+ if (!dhcp6->ia_addr)
+ {
+ dhcp6->ia_addr = grub_malloc (sizeof(*dhcp6->ia_addr));
+ dhcp6->ia_addr->type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6;
+ dhcp6->ia_addr->ipv6[0] = grub_get_unaligned64 (iaaddr->addr);
+ dhcp6->ia_addr->ipv6[1] = grub_get_unaligned64 (iaaddr->addr + 8);
+ dhcp6->preferred_lifetime = grub_be_to_cpu32 (iaaddr->preferred_lifetime);
+ dhcp6->valid_lifetime = grub_be_to_cpu32 (iaaddr->valid_lifetime);
+ }
+ }
+}
+
+static void
+parse_dhcp6_option (const struct grub_net_dhcp6_option *opt, void *data)
+{
+ grub_dhcp6_options_t dhcp6 = (grub_dhcp6_options_t)data;
+ grub_uint16_t code = grub_be_to_cpu16 (opt->code);
+ grub_uint16_t len = grub_be_to_cpu16 (opt->len);
+
+ switch (code)
+ {
+ case GRUB_NET_DHCP6_OPTION_CLIENTID:
+
+ if (dhcp6->client_duid || !len)
+ {
+ grub_dprintf ("bootp", "Skipped DHCPv6 CLIENTID with length %u\n", len);
+ break;
+ }
+ dhcp6->client_duid = grub_malloc (len);
+ grub_memcpy (dhcp6->client_duid, opt->data, len);
+ dhcp6->client_duid_len = len;
+ break;
+
+ case GRUB_NET_DHCP6_OPTION_SERVERID:
+
+ if (dhcp6->server_duid || !len)
+ {
+ grub_dprintf ("bootp", "Skipped DHCPv6 SERVERID with length %u\n", len);
+ break;
+ }
+ dhcp6->server_duid = grub_malloc (len);
+ grub_memcpy (dhcp6->server_duid, opt->data, len);
+ dhcp6->server_duid_len = len;
+ break;
+
+ case GRUB_NET_DHCP6_OPTION_IA_NA:
+ {
+ const struct grub_net_dhcp6_option_iana *ia_na;
+ grub_uint16_t data_len;
+
+ if (dhcp6->iaid || len < sizeof (*ia_na))
+ {
+ grub_dprintf ("bootp", "Skipped DHCPv6 IA_NA with length %u\n", len);
+ break;
+ }
+ ia_na = (const struct grub_net_dhcp6_option_iana *)opt->data;
+ dhcp6->iaid = grub_be_to_cpu32 (ia_na->iaid);
+ dhcp6->t1 = grub_be_to_cpu32 (ia_na->t1);
+ dhcp6->t2 = grub_be_to_cpu32 (ia_na->t2);
+
+ data_len = len - sizeof (*ia_na);
+ if (data_len)
+ foreach_dhcp6_option ((const struct grub_net_dhcp6_option *)ia_na->data, data_len, parse_dhcp6_iaaddr, dhcp6);
+ }
+ break;
+
+ case GRUB_NET_DHCP6_OPTION_DNS_SERVERS:
+ {
+ const grub_uint8_t *po;
+ grub_uint16_t ln;
+ grub_net_network_level_address_t *la;
+
+ if (!len || len & 0xf)
+ {
+ grub_dprintf ("bootp", "Skip invalid length DHCPv6 DNS_SERVERS \n");
+ break;
+ }
+ dhcp6->num_dns_server = ln = len >> 4;
+ dhcp6->dns_server_addrs = la = grub_zalloc (ln * sizeof (*la));
+
+ for (po = opt->data; ln > 0; po += 0x10, la++, ln--)
+ {
+ la->type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6;
+ la->ipv6[0] = grub_get_unaligned64 (po);
+ la->ipv6[1] = grub_get_unaligned64 (po + 8);
+ la->option = DNS_OPTION_PREFER_IPV6;
+ }
+ }
+ break;
+
+ case GRUB_NET_DHCP6_OPTION_BOOTFILE_URL:
+ dissect_url ((const char *)opt->data,
+ &dhcp6->boot_file_proto,
+ &dhcp6->boot_file_server_ip,
+ &dhcp6->boot_file_path);
+ break;
+
+ default:
+ break;
+ }
+}
+
+static void
+foreach_dhcp6_option (const struct grub_net_dhcp6_option *opt, grub_size_t size, dhcp6_option_hook_fn hook, void *hook_data)
+{
+ while (size)
+ {
+ grub_uint16_t code, len;
+
+ if (size < sizeof (*opt))
+ {
+ grub_dprintf ("bootp", "DHCPv6: Options stopped with remaining size %" PRIxGRUB_SIZE "\n", size);
+ break;
+ }
+ size -= sizeof (*opt);
+ len = grub_be_to_cpu16 (opt->len);
+ code = grub_be_to_cpu16 (opt->code);
+ if (size < len)
+ {
+ grub_dprintf ("bootp", "DHCPv6: Options stopped at out of bound length %u for option %u\n", len, code);
+ break;
+ }
+ if (!len)
+ {
+ grub_dprintf ("bootp", "DHCPv6: Options stopped at zero length option %u\n", code);
+ break;
+ }
+ else
+ {
+ if (hook)
+ hook (opt, hook_data);
+ size -= len;
+ opt = (const struct grub_net_dhcp6_option *)((grub_uint8_t *)opt + len + sizeof (*opt));
+ }
+ }
+}
+
+static grub_dhcp6_options_t
+grub_dhcp6_options_get (const struct grub_net_dhcp6_packet *v6h,
+ grub_size_t size)
+{
+ grub_dhcp6_options_t options;
+
+ if (size < sizeof (*v6h))
+ {
+ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("DHCPv6 packet size too small"));
+ return NULL;
+ }
+
+ options = grub_zalloc (sizeof(*options));
+ if (!options)
+ return NULL;
+
+ foreach_dhcp6_option ((const struct grub_net_dhcp6_option *)v6h->dhcp_options,
+ size - sizeof (*v6h), parse_dhcp6_option, options);
+
+ return options;
+}
+
+static void
+grub_dhcp6_options_free (grub_dhcp6_options_t options)
+{
+ if (options->client_duid)
+ grub_free (options->client_duid);
+ if (options->server_duid)
+ grub_free (options->server_duid);
+ if (options->ia_addr)
+ grub_free (options->ia_addr);
+ if (options->dns_server_addrs)
+ grub_free (options->dns_server_addrs);
+ if (options->boot_file_proto)
+ grub_free (options->boot_file_proto);
+ if (options->boot_file_server_ip)
+ grub_free (options->boot_file_server_ip);
+ if (options->boot_file_path)
+ grub_free (options->boot_file_path);
+
+ grub_free (options);
+}
+
+static grub_dhcp6_session_t grub_dhcp6_sessions;
+#define FOR_DHCP6_SESSIONS(var) FOR_LIST_ELEMENTS (var, grub_dhcp6_sessions)
+
+static void
+grub_net_configure_by_dhcp6_info (const char *name,
+ struct grub_net_card *card,
+ grub_dhcp6_options_t dhcp6,
+ int is_def,
+ int flags,
+ struct grub_net_network_level_interface **ret_inf)
+{
+ grub_net_network_level_netaddress_t netaddr;
+ struct grub_net_network_level_interface *inf;
+
+ if (dhcp6->ia_addr)
+ {
+ inf = grub_net_add_addr (name, card, dhcp6->ia_addr, &card->default_address, flags);
+
+ netaddr.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6;
+ netaddr.ipv6.base[0] = dhcp6->ia_addr->ipv6[0];
+ netaddr.ipv6.base[1] = 0;
+ netaddr.ipv6.masksize = 64;
+ grub_net_add_route (name, netaddr, inf);
+
+ if (ret_inf)
+ *ret_inf = inf;
+ }
+
+ if (dhcp6->dns_server_addrs)
+ {
+ grub_uint16_t i;
+
+ for (i = 0; i < dhcp6->num_dns_server; ++i)
+ grub_net_add_dns_server (dhcp6->dns_server_addrs + i);
+ }
+
+ if (dhcp6->boot_file_path)
+ grub_env_set_net_property (name, "boot_file", dhcp6->boot_file_path,
+ grub_strlen (dhcp6->boot_file_path));
+
+ if (is_def && dhcp6->boot_file_server_ip)
+ {
+ grub_net_default_server = grub_strdup (dhcp6->boot_file_server_ip);
+ grub_env_set ("net_default_interface", name);
+ grub_env_export ("net_default_interface");
+ }
+}
+
+static void
+grub_dhcp6_session_add (struct grub_net_network_level_interface *iface,
+ grub_uint32_t iaid)
+{
+ grub_dhcp6_session_t se;
+ struct grub_datetime date;
+ grub_err_t err;
+ grub_int32_t t = 0;
+
+ se = grub_malloc (sizeof (*se));
+
+ err = grub_get_datetime (&date);
+ if (err || !grub_datetime2unixtime (&date, &t))
+ {
+ grub_errno = GRUB_ERR_NONE;
+ t = 0;
+ }
+
+ se->iface = iface;
+ se->iaid = iaid;
+ se->transaction_id = t;
+ se->start_time = grub_get_time_ms ();
+ se->duid.type = grub_cpu_to_be16_compile_time (3) ;
+ se->duid.hw_type = grub_cpu_to_be16_compile_time (1);
+ grub_memcpy (&se->duid.hwaddr, &iface->hwaddress.mac, sizeof (se->duid.hwaddr));
+ se->adv = NULL;
+ se->reply = NULL;
+ grub_list_push (GRUB_AS_LIST_P (&grub_dhcp6_sessions), GRUB_AS_LIST (se));
+}
+
+static void
+grub_dhcp6_session_remove (grub_dhcp6_session_t se)
+{
+ grub_list_remove (GRUB_AS_LIST (se));
+ if (se->adv)
+ grub_dhcp6_options_free (se->adv);
+ if (se->reply)
+ grub_dhcp6_options_free (se->reply);
+ grub_free (se);
+}
+
+static void
+grub_dhcp6_session_remove_all (void)
+{
+ grub_dhcp6_session_t se;
+
+ FOR_DHCP6_SESSIONS (se)
+ {
+ grub_dhcp6_session_remove (se);
+ se = grub_dhcp6_sessions;
+ }
+}
+
+static grub_err_t
+grub_dhcp6_session_configure_network (grub_dhcp6_session_t se)
+{
+ char *name;
+
+ name = grub_xasprintf ("%s:dhcp6", se->iface->card->name);
+ if (!name)
+ return grub_errno;
+
+ grub_net_configure_by_dhcp6_info (name, se->iface->card, se->reply, 1, 0, 0);
+ grub_free (name);
+
+ return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+grub_dhcp6_session_send_request (grub_dhcp6_session_t se)
+{
+ struct grub_net_buff *nb;
+ struct grub_net_dhcp6_option *opt;
+ struct grub_net_dhcp6_packet *v6h;
+ struct grub_net_dhcp6_option_iana *ia_na;
+ struct grub_net_dhcp6_option_iaaddr *iaaddr;
+ struct udphdr *udph;
+ grub_net_network_level_address_t multicast;
+ grub_net_link_level_address_t ll_multicast;
+ grub_uint64_t elapsed;
+ struct grub_net_network_level_interface *inf = se->iface;
+ grub_dhcp6_options_t dhcp6 = se->adv;
+ grub_err_t err = GRUB_ERR_NONE;
+
+ multicast.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6;
+ multicast.ipv6[0] = grub_cpu_to_be64_compile_time (0xff02ULL << 48);
+ multicast.ipv6[1] = grub_cpu_to_be64_compile_time (0x10002ULL);
+
+ err = grub_net_link_layer_resolve (inf, &multicast, &ll_multicast);
+ if (err)
+ return err;
+
+ nb = grub_netbuff_alloc (GRUB_DHCP6_DEFAULT_NETBUFF_ALLOC_SIZE);
+
+ if (!nb)
+ return grub_errno;
+
+ err = grub_netbuff_reserve (nb, GRUB_DHCP6_DEFAULT_NETBUFF_ALLOC_SIZE);
+ if (err)
+ {
+ grub_netbuff_free (nb);
+ return err;
+ }
+
+ err = grub_netbuff_push (nb, dhcp6->client_duid_len + sizeof (*opt));
+ if (err)
+ {
+ grub_netbuff_free (nb);
+ return err;
+ }
+ opt = (struct grub_net_dhcp6_option *)nb->data;
+ opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_CLIENTID);
+ opt->len = grub_cpu_to_be16 (dhcp6->client_duid_len);
+ grub_memcpy (opt->data, dhcp6->client_duid , dhcp6->client_duid_len);
+
+ err = grub_netbuff_push (nb, dhcp6->server_duid_len + sizeof (*opt));
+ if (err)
+ {
+ grub_netbuff_free (nb);
+ return err;
+ }
+ opt = (struct grub_net_dhcp6_option *)nb->data;
+ opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_SERVERID);
+ opt->len = grub_cpu_to_be16 (dhcp6->server_duid_len);
+ grub_memcpy (opt->data, dhcp6->server_duid , dhcp6->server_duid_len);
+
+ err = grub_netbuff_push (nb, sizeof (*ia_na) + sizeof (*opt));
+ if (err)
+ {
+ grub_netbuff_free (nb);
+ return err;
+ }
+
+ if (dhcp6->ia_addr)
+ {
+ err = grub_netbuff_push (nb, sizeof(*iaaddr) + sizeof (*opt));
+ if (err)
+ {
+ grub_netbuff_free (nb);
+ return err;
+ }
+ }
+ opt = (struct grub_net_dhcp6_option *)nb->data;
+ opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_IA_NA);
+ opt->len = grub_cpu_to_be16 (sizeof (*ia_na));
+ if (dhcp6->ia_addr)
+ opt->len += grub_cpu_to_be16 (sizeof(*iaaddr) + sizeof (*opt));
+
+ ia_na = (struct grub_net_dhcp6_option_iana *)opt->data;
+ ia_na->iaid = grub_cpu_to_be32 (dhcp6->iaid);
+
+ ia_na->t1 = grub_cpu_to_be32 (dhcp6->t1);
+ ia_na->t2 = grub_cpu_to_be32 (dhcp6->t2);
+
+ if (dhcp6->ia_addr)
+ {
+ opt = (struct grub_net_dhcp6_option *)ia_na->data;
+ opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_IAADDR);
+ opt->len = grub_cpu_to_be16 (sizeof (*iaaddr));
+ iaaddr = (struct grub_net_dhcp6_option_iaaddr *)opt->data;
+ grub_set_unaligned64 (iaaddr->addr, dhcp6->ia_addr->ipv6[0]);
+ grub_set_unaligned64 (iaaddr->addr + 8, dhcp6->ia_addr->ipv6[1]);
+
+ iaaddr->preferred_lifetime = grub_cpu_to_be32 (dhcp6->preferred_lifetime);
+ iaaddr->valid_lifetime = grub_cpu_to_be32 (dhcp6->valid_lifetime);
+ }
+
+ err = grub_netbuff_push (nb, sizeof (*opt) + 2 * sizeof (grub_uint16_t));
+ if (err)
+ {
+ grub_netbuff_free (nb);
+ return err;
+ }
+
+ opt = (struct grub_net_dhcp6_option*) nb->data;
+ opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_ORO);
+ opt->len = grub_cpu_to_be16_compile_time (2 * sizeof (grub_uint16_t));
+ grub_set_unaligned16 (opt->data, grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_BOOTFILE_URL));
+ grub_set_unaligned16 (opt->data + 2, grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_DNS_SERVERS));
+
+ err = grub_netbuff_push (nb, sizeof (*opt) + sizeof (grub_uint16_t));
+ if (err)
+ {
+ grub_netbuff_free (nb);
+ return err;
+ }
+ opt = (struct grub_net_dhcp6_option*) nb->data;
+ opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_ELAPSED_TIME);
+ opt->len = grub_cpu_to_be16_compile_time (sizeof (grub_uint16_t));
+
+ /* the time is expressed in hundredths of a second */
+ elapsed = grub_divmod64 (grub_get_time_ms () - se->start_time, 10, 0);
+
+ if (elapsed > 0xffff)
+ elapsed = 0xffff;
+
+ grub_set_unaligned16 (opt->data, grub_cpu_to_be16 ((grub_uint16_t)elapsed));
+
+ err = grub_netbuff_push (nb, sizeof (*v6h));
+ if (err)
+ {
+ grub_netbuff_free (nb);
+ return err;
+ }
+
+ v6h = (struct grub_net_dhcp6_packet *) nb->data;
+ v6h->message_type = GRUB_NET_DHCP6_REQUEST;
+ v6h->transaction_id = se->transaction_id;
+
+ err = grub_netbuff_push (nb, sizeof (*udph));
+ if (err)
+ {
+ grub_netbuff_free (nb);
+ return err;
+ }
+
+ udph = (struct udphdr *) nb->data;
+ udph->src = grub_cpu_to_be16_compile_time (DHCP6_CLIENT_PORT);
+ udph->dst = grub_cpu_to_be16_compile_time (DHCP6_SERVER_PORT);
+ udph->chksum = 0;
+ udph->len = grub_cpu_to_be16 (nb->tail - nb->data);
+
+ udph->chksum = grub_net_ip_transport_checksum (nb, GRUB_NET_IP_UDP,
+ &inf->address,
+ &multicast);
+ err = grub_net_send_ip_packet (inf, &multicast, &ll_multicast, nb,
+ GRUB_NET_IP_UDP);
+
+ grub_netbuff_free (nb);
+
+ return err;
+}
+
+struct grub_net_network_level_interface *
+grub_net_configure_by_dhcpv6_reply (const char *name,
+ struct grub_net_card *card,
+ grub_net_interface_flags_t flags,
+ const struct grub_net_dhcp6_packet *v6h,
+ grub_size_t size,
+ int is_def,
+ char **device, char **path)
+{
+ struct grub_net_network_level_interface *inf;
+ grub_dhcp6_options_t dhcp6;
+
+ dhcp6 = grub_dhcp6_options_get (v6h, size);
+ if (!dhcp6)
+ {
+ grub_print_error ();
+ return NULL;
+ }
+
+ grub_net_configure_by_dhcp6_info (name, card, dhcp6, is_def, flags, &inf);
+
+ if (device && dhcp6->boot_file_proto && dhcp6->boot_file_server_ip)
+ {
+ *device = grub_xasprintf ("%s,%s", dhcp6->boot_file_proto, dhcp6->boot_file_server_ip);
+ grub_print_error ();
+ }
+ if (path && dhcp6->boot_file_path)
+ {
+ *path = grub_strdup (dhcp6->boot_file_path);
+ grub_print_error ();
+ if (*path)
+ {
+ char *slash;
+ slash = grub_strrchr (*path, '/');
+ if (slash)
+ *slash = 0;
+ else
+ **path = 0;
+ }
+ }
+
+ grub_dhcp6_options_free (dhcp6);
+ return inf;
+}
+
void
grub_net_process_dhcp (struct grub_net_buff *nb,
struct grub_net_card *card)
@@ -298,6 +962,77 @@ grub_net_process_dhcp (struct grub_net_buff *nb,
}
}
+grub_err_t
+grub_net_process_dhcp6 (struct grub_net_buff *nb,
+ struct grub_net_card *card __attribute__ ((unused)))
+{
+ const struct grub_net_dhcp6_packet *v6h;
+ grub_dhcp6_session_t se;
+ grub_size_t size;
+ grub_dhcp6_options_t options;
+
+ v6h = (const struct grub_net_dhcp6_packet *) nb->data;
+ size = nb->tail - nb->data;
+
+ options = grub_dhcp6_options_get (v6h, size);
+ if (!options)
+ return grub_errno;
+
+ if (!options->client_duid || !options->server_duid || !options->ia_addr)
+ {
+ grub_dhcp6_options_free (options);
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "Bad DHCPv6 Packet");
+ }
+
+ FOR_DHCP6_SESSIONS (se)
+ {
+ if (se->transaction_id == v6h->transaction_id &&
+ grub_memcmp (options->client_duid, &se->duid, sizeof (se->duid)) == 0 &&
+ se->iaid == options->iaid)
+ break;
+ }
+
+ if (!se)
+ {
+ grub_dprintf ("bootp", "DHCPv6 session not found\n");
+ grub_dhcp6_options_free (options);
+ return GRUB_ERR_NONE;
+ }
+
+ if (v6h->message_type == GRUB_NET_DHCP6_ADVERTISE)
+ {
+ if (se->adv)
+ {
+ grub_dprintf ("bootp", "Skipped DHCPv6 Advertised .. \n");
+ grub_dhcp6_options_free (options);
+ return GRUB_ERR_NONE;
+ }
+
+ se->adv = options;
+ return grub_dhcp6_session_send_request (se);
+ }
+ else if (v6h->message_type == GRUB_NET_DHCP6_REPLY)
+ {
+ if (!se->adv)
+ {
+ grub_dprintf ("bootp", "Skipped DHCPv6 Reply .. \n");
+ grub_dhcp6_options_free (options);
+ return GRUB_ERR_NONE;
+ }
+
+ se->reply = options;
+ grub_dhcp6_session_configure_network (se);
+ grub_dhcp6_session_remove (se);
+ return GRUB_ERR_NONE;
+ }
+ else
+ {
+ grub_dhcp6_options_free (options);
+ }
+
+ return GRUB_ERR_NONE;
+}
+
static char
hexdigit (grub_uint8_t val)
{
@@ -578,7 +1313,174 @@ grub_cmd_bootp (struct grub_command *cmd __attribute__ ((unused)),
return err;
}
-static grub_command_t cmd_getdhcp, cmd_bootp;
+static grub_err_t
+grub_cmd_bootp6 (struct grub_command *cmd __attribute__ ((unused)),
+ int argc, char **args)
+{
+ struct grub_net_card *card;
+ grub_uint32_t iaid = 0;
+ int interval;
+ grub_err_t err;
+ grub_dhcp6_session_t se;
+
+ err = GRUB_ERR_NONE;
+
+ FOR_NET_CARDS (card)
+ {
+ struct grub_net_network_level_interface *iface;
+
+ if (argc > 0 && grub_strcmp (card->name, args[0]) != 0)
+ continue;
+
+ iface = grub_net_ipv6_get_link_local (card, &card->default_address);
+ if (!iface)
+ {
+ grub_dhcp6_session_remove_all ();
+ return grub_errno;
+ }
+
+ grub_dhcp6_session_add (iface, iaid++);
+ }
+
+ for (interval = 200; interval < 10000; interval *= 2)
+ {
+ int done = 1;
+
+ FOR_DHCP6_SESSIONS (se)
+ {
+ struct grub_net_buff *nb;
+ struct grub_net_dhcp6_option *opt;
+ struct grub_net_dhcp6_packet *v6h;
+ struct grub_net_dhcp6_option_duid_ll *duid;
+ struct grub_net_dhcp6_option_iana *ia_na;
+ grub_net_network_level_address_t multicast;
+ grub_net_link_level_address_t ll_multicast;
+ struct udphdr *udph;
+
+ multicast.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6;
+ multicast.ipv6[0] = grub_cpu_to_be64_compile_time (0xff02ULL << 48);
+ multicast.ipv6[1] = grub_cpu_to_be64_compile_time (0x10002ULL);
+
+ err = grub_net_link_layer_resolve (se->iface,
+ &multicast, &ll_multicast);
+ if (err)
+ {
+ grub_dhcp6_session_remove_all ();
+ return err;
+ }
+
+ nb = grub_netbuff_alloc (GRUB_DHCP6_DEFAULT_NETBUFF_ALLOC_SIZE);
+
+ if (!nb)
+ {
+ grub_dhcp6_session_remove_all ();
+ return grub_errno;
+ }
+
+ err = grub_netbuff_reserve (nb, GRUB_DHCP6_DEFAULT_NETBUFF_ALLOC_SIZE);
+ if (err)
+ {
+ grub_dhcp6_session_remove_all ();
+ grub_netbuff_free (nb);
+ return err;
+ }
+
+ err = grub_netbuff_push (nb, sizeof (*opt) + sizeof (grub_uint16_t));
+ if (err)
+ {
+ grub_dhcp6_session_remove_all ();
+ grub_netbuff_free (nb);
+ return err;
+ }
+
+ opt = (struct grub_net_dhcp6_option *)nb->data;
+ opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_ELAPSED_TIME);
+ opt->len = grub_cpu_to_be16_compile_time (sizeof (grub_uint16_t));
+ grub_set_unaligned16 (opt->data, 0);
+
+ err = grub_netbuff_push (nb, sizeof (*opt) + sizeof (*duid));
+ if (err)
+ {
+ grub_dhcp6_session_remove_all ();
+ grub_netbuff_free (nb);
+ return err;
+ }
+
+ opt = (struct grub_net_dhcp6_option *)nb->data;
+ opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_CLIENTID);
+ opt->len = grub_cpu_to_be16 (sizeof (*duid));
+
+ duid = (struct grub_net_dhcp6_option_duid_ll *) opt->data;
+ grub_memcpy (duid, &se->duid, sizeof (*duid));
+
+ err = grub_netbuff_push (nb, sizeof (*opt) + sizeof (*ia_na));
+ if (err)
+ {
+ grub_dhcp6_session_remove_all ();
+ grub_netbuff_free (nb);
+ return err;
+ }
+
+ opt = (struct grub_net_dhcp6_option *)nb->data;
+ opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_IA_NA);
+ opt->len = grub_cpu_to_be16 (sizeof (*ia_na));
+ ia_na = (struct grub_net_dhcp6_option_iana *)opt->data;
+ ia_na->iaid = grub_cpu_to_be32 (se->iaid);
+ ia_na->t1 = 0;
+ ia_na->t2 = 0;
+
+ err = grub_netbuff_push (nb, sizeof (*v6h));
+ if (err)
+ {
+ grub_dhcp6_session_remove_all ();
+ grub_netbuff_free (nb);
+ return err;
+ }
+
+ v6h = (struct grub_net_dhcp6_packet *)nb->data;
+ v6h->message_type = GRUB_NET_DHCP6_SOLICIT;
+ v6h->transaction_id = se->transaction_id;
+
+ grub_netbuff_push (nb, sizeof (*udph));
+
+ udph = (struct udphdr *) nb->data;
+ udph->src = grub_cpu_to_be16_compile_time (DHCP6_CLIENT_PORT);
+ udph->dst = grub_cpu_to_be16_compile_time (DHCP6_SERVER_PORT);
+ udph->chksum = 0;
+ udph->len = grub_cpu_to_be16 (nb->tail - nb->data);
+
+ udph->chksum = grub_net_ip_transport_checksum (nb, GRUB_NET_IP_UDP,
+ &se->iface->address, &multicast);
+
+ err = grub_net_send_ip_packet (se->iface, &multicast,
+ &ll_multicast, nb, GRUB_NET_IP_UDP);
+ done = 0;
+ grub_netbuff_free (nb);
+
+ if (err)
+ {
+ grub_dhcp6_session_remove_all ();
+ return err;
+ }
+ }
+ if (!done)
+ grub_net_poll_cards (interval, 0);
+ }
+
+ FOR_DHCP6_SESSIONS (se)
+ {
+ grub_error_push ();
+ err = grub_error (GRUB_ERR_FILE_NOT_FOUND,
+ N_("couldn't autoconfigure %s"),
+ se->iface->card->name);
+ }
+
+ grub_dhcp6_session_remove_all ();
+
+ return err;
+}
+
+static grub_command_t cmd_getdhcp, cmd_bootp, cmd_bootp6;
void
grub_bootp_init (void)
@@ -589,6 +1491,9 @@ grub_bootp_init (void)
cmd_getdhcp = grub_register_command ("net_get_dhcp_option", grub_cmd_dhcpopt,
N_("VAR INTERFACE NUMBER DESCRIPTION"),
N_("retrieve DHCP option and save it into VAR. If VAR is - then print the value."));
+ cmd_bootp6 = grub_register_command ("net_bootp6", grub_cmd_bootp6,
+ N_("[CARD]"),
+ N_("perform a DHCPv6 autoconfiguration"));
}
void
@@ -596,4 +1501,5 @@ grub_bootp_fini (void)
{
grub_unregister_command (cmd_getdhcp);
grub_unregister_command (cmd_bootp);
+ grub_unregister_command (cmd_bootp6);
}
diff --git a/grub-core/net/ip.c b/grub-core/net/ip.c
index 8c56baa..2a239b5 100644
--- a/grub-core/net/ip.c
+++ b/grub-core/net/ip.c
@@ -238,6 +238,45 @@ handle_dgram (struct grub_net_buff *nb,
{
struct udphdr *udph;
udph = (struct udphdr *) nb->data;
+
+ if (proto == GRUB_NET_IP_UDP && udph->dst == grub_cpu_to_be16_compile_time (DHCP6_CLIENT_PORT))
+ {
+ if (udph->chksum)
+ {
+ grub_uint16_t chk, expected;
+ chk = udph->chksum;
+ udph->chksum = 0;
+ expected = grub_net_ip_transport_checksum (nb,
+ GRUB_NET_IP_UDP,
+ source,
+ dest);
+ if (expected != chk)
+ {
+ grub_dprintf ("net", "Invalid UDP checksum. "
+ "Expected %x, got %x\n",
+ grub_be_to_cpu16 (expected),
+ grub_be_to_cpu16 (chk));
+ grub_netbuff_free (nb);
+ return GRUB_ERR_NONE;
+ }
+ udph->chksum = chk;
+ }
+
+ err = grub_netbuff_pull (nb, sizeof (*udph));
+ if (err)
+ {
+ grub_netbuff_free (nb);
+ return err;
+ }
+
+ err = grub_net_process_dhcp6 (nb, card);
+ if (err)
+ grub_print_error ();
+
+ grub_netbuff_free (nb);
+ return GRUB_ERR_NONE;
+ }
+
if (proto == GRUB_NET_IP_UDP && grub_be_to_cpu16 (udph->dst) == 68)
{
const struct grub_net_bootp_packet *bootp;
diff --git a/include/grub/net.h b/include/grub/net.h
index ccc169c..38a3973 100644
--- a/include/grub/net.h
+++ b/include/grub/net.h
@@ -442,6 +442,66 @@ struct grub_net_bootp_packet
grub_uint8_t vendor[0];
} GRUB_PACKED;
+struct grub_net_dhcp6_packet
+{
+ grub_uint32_t message_type:8;
+ grub_uint32_t transaction_id:24;
+ grub_uint8_t dhcp_options[0];
+} GRUB_PACKED;
+
+struct grub_net_dhcp6_option {
+ grub_uint16_t code;
+ grub_uint16_t len;
+ grub_uint8_t data[0];
+} GRUB_PACKED;
+
+struct grub_net_dhcp6_option_iana {
+ grub_uint32_t iaid;
+ grub_uint32_t t1;
+ grub_uint32_t t2;
+ grub_uint8_t data[0];
+} GRUB_PACKED;
+
+struct grub_net_dhcp6_option_iaaddr {
+ grub_uint8_t addr[16];
+ grub_uint32_t preferred_lifetime;
+ grub_uint32_t valid_lifetime;
+ grub_uint8_t data[0];
+} GRUB_PACKED;
+
+struct grub_net_dhcp6_option_duid_ll
+{
+ grub_uint16_t type;
+ grub_uint16_t hw_type;
+ grub_uint8_t hwaddr[6];
+} GRUB_PACKED;
+
+enum
+ {
+ GRUB_NET_DHCP6_SOLICIT = 1,
+ GRUB_NET_DHCP6_ADVERTISE = 2,
+ GRUB_NET_DHCP6_REQUEST = 3,
+ GRUB_NET_DHCP6_REPLY = 7
+ };
+
+enum
+ {
+ DHCP6_CLIENT_PORT = 546,
+ DHCP6_SERVER_PORT = 547
+ };
+
+enum
+ {
+ GRUB_NET_DHCP6_OPTION_CLIENTID = 1,
+ GRUB_NET_DHCP6_OPTION_SERVERID = 2,
+ GRUB_NET_DHCP6_OPTION_IA_NA = 3,
+ GRUB_NET_DHCP6_OPTION_IAADDR = 5,
+ GRUB_NET_DHCP6_OPTION_ORO = 6,
+ GRUB_NET_DHCP6_OPTION_ELAPSED_TIME = 8,
+ GRUB_NET_DHCP6_OPTION_DNS_SERVERS = 23,
+ GRUB_NET_DHCP6_OPTION_BOOTFILE_URL = 59
+ };
+
#define GRUB_NET_BOOTP_RFC1048_MAGIC_0 0x63
#define GRUB_NET_BOOTP_RFC1048_MAGIC_1 0x82
#define GRUB_NET_BOOTP_RFC1048_MAGIC_2 0x53
@@ -468,6 +528,14 @@ grub_net_configure_by_dhcp_ack (const char *name,
grub_size_t size,
int is_def, char **device, char **path);
+struct grub_net_network_level_interface *
+grub_net_configure_by_dhcpv6_reply (const char *name,
+ struct grub_net_card *card,
+ grub_net_interface_flags_t flags,
+ const struct grub_net_dhcp6_packet *v6,
+ grub_size_t size,
+ int is_def, char **device, char **path);
+
grub_err_t
grub_net_add_ipv4_local (struct grub_net_network_level_interface *inf,
int mask);
@@ -476,6 +544,10 @@ void
grub_net_process_dhcp (struct grub_net_buff *nb,
struct grub_net_card *card);
+grub_err_t
+grub_net_process_dhcp6 (struct grub_net_buff *nb,
+ struct grub_net_card *card);
+
int
grub_net_hwaddr_cmp (const grub_net_link_level_address_t *a,
const grub_net_link_level_address_t *b);
--
2.6.6
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH 4/8] efinet: UEFI IPv6 PXE support
2016-08-03 6:34 Patches to support UEFI HTTP Boot IPv4 and IPv6 Michael Chang
` (2 preceding siblings ...)
2016-08-03 6:34 ` [PATCH 3/8] bootp: New net_bootp6 command Michael Chang
@ 2016-08-03 6:34 ` Michael Chang
2016-08-03 6:34 ` [PATCH 5/8] grub.texi: Add net_bootp6 doument Michael Chang
` (3 subsequent siblings)
7 siblings, 0 replies; 11+ messages in thread
From: Michael Chang @ 2016-08-03 6:34 UTC (permalink / raw)
To: Grub devel; +Cc: Ken Lin, Michael Chang
When grub2 image is booted from UEFI IPv6 PXE, the DHCPv6 Reply packet is
cached in firmware buffer which can be obtained by PXE Base Code protocol. The
network interface can be setup through the parameters in that obtained packet.
Signed-off-by: Michael Chang <mchang@suse.com>
Signed-off-by: Ken Lin <ken.lin@hpe.com>
---
grub-core/net/drivers/efi/efinet.c | 24 +++++++++++++----
include/grub/efi/api.h | 55 +++++++++++++++++++++++++++++++++++++-
2 files changed, 73 insertions(+), 6 deletions(-)
diff --git a/grub-core/net/drivers/efi/efinet.c b/grub-core/net/drivers/efi/efinet.c
index 5388f95..fc90415 100644
--- a/grub-core/net/drivers/efi/efinet.c
+++ b/grub-core/net/drivers/efi/efinet.c
@@ -378,11 +378,25 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device,
if (! pxe)
continue;
pxe_mode = pxe->mode;
- grub_net_configure_by_dhcp_ack (card->name, card, 0,
- (struct grub_net_bootp_packet *)
- &pxe_mode->dhcp_ack,
- sizeof (pxe_mode->dhcp_ack),
- 1, device, path);
+
+ if (pxe_mode->using_ipv6)
+ {
+ grub_net_configure_by_dhcpv6_reply (card->name, card, 0,
+ (struct grub_net_dhcp6_packet *)
+ &pxe_mode->dhcp_ack,
+ sizeof (pxe_mode->dhcp_ack),
+ 1, device, path);
+ if (grub_errno)
+ grub_print_error ();
+ }
+ else
+ {
+ grub_net_configure_by_dhcp_ack (card->name, card, 0,
+ (struct grub_net_bootp_packet *)
+ &pxe_mode->dhcp_ack,
+ sizeof (pxe_mode->dhcp_ack),
+ 1, device, path);
+ }
return;
}
}
diff --git a/include/grub/efi/api.h b/include/grub/efi/api.h
index c7c9f0e..92f9b5a 100644
--- a/include/grub/efi/api.h
+++ b/include/grub/efi/api.h
@@ -1452,14 +1452,67 @@ typedef struct grub_efi_simple_text_output_interface grub_efi_simple_text_output
typedef grub_uint8_t grub_efi_pxe_packet_t[1472];
+typedef struct {
+ grub_uint8_t addr[4];
+} grub_efi_pxe_ipv4_address_t;
+
+typedef struct {
+ grub_uint8_t addr[16];
+} grub_efi_pxe_ipv6_address_t;
+
+typedef struct {
+ grub_uint8_t addr[32];
+} grub_efi_pxe_mac_address_t;
+
+typedef union {
+ grub_uint32_t addr[4];
+ grub_efi_pxe_ipv4_address_t v4;
+ grub_efi_pxe_ipv6_address_t v6;
+} grub_efi_pxe_ip_address_t;
+
+#define GRUB_EFI_PXE_BASE_CODE_MAX_IPCNT 8
+typedef struct {
+ grub_uint8_t filters;
+ grub_uint8_t ip_cnt;
+ grub_uint16_t reserved;
+ grub_efi_pxe_ip_address_t ip_list[GRUB_EFI_PXE_BASE_CODE_MAX_IPCNT];
+} grub_efi_pxe_ip_filter_t;
+
+typedef struct {
+ grub_efi_pxe_ip_address_t ip_addr;
+ grub_efi_pxe_mac_address_t mac_addr;
+} grub_efi_pxe_arp_entry_t;
+
+typedef struct {
+ grub_efi_pxe_ip_address_t ip_addr;
+ grub_efi_pxe_ip_address_t subnet_mask;
+ grub_efi_pxe_ip_address_t gw_addr;
+} grub_efi_pxe_route_entry_t;
+
+
+#define GRUB_EFI_PXE_BASE_CODE_MAX_ARP_ENTRIES 8
+#define GRUB_EFI_PXE_BASE_CODE_MAX_ROUTE_ENTRIES 8
+
typedef struct grub_efi_pxe_mode
{
- grub_uint8_t unused[52];
+ grub_uint8_t started;
+ grub_uint8_t ipv6_available;
+ grub_uint8_t ipv6_supported;
+ grub_uint8_t using_ipv6;
+ grub_uint8_t unused[16];
+ grub_efi_pxe_ip_address_t station_ip;
+ grub_efi_pxe_ip_address_t subnet_mask;
grub_efi_pxe_packet_t dhcp_discover;
grub_efi_pxe_packet_t dhcp_ack;
grub_efi_pxe_packet_t proxy_offer;
grub_efi_pxe_packet_t pxe_discover;
grub_efi_pxe_packet_t pxe_reply;
+ grub_efi_pxe_packet_t pxe_bis_reply;
+ grub_efi_pxe_ip_filter_t ip_filter;
+ grub_uint32_t arp_cache_entries;
+ grub_efi_pxe_arp_entry_t arp_cache[GRUB_EFI_PXE_BASE_CODE_MAX_ARP_ENTRIES];
+ grub_uint32_t route_table_entries;
+ grub_efi_pxe_route_entry_t route_table[GRUB_EFI_PXE_BASE_CODE_MAX_ROUTE_ENTRIES];
} grub_efi_pxe_mode_t;
typedef struct grub_efi_pxe
--
2.6.6
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH 5/8] grub.texi: Add net_bootp6 doument
2016-08-03 6:34 Patches to support UEFI HTTP Boot IPv4 and IPv6 Michael Chang
` (3 preceding siblings ...)
2016-08-03 6:34 ` [PATCH 4/8] efinet: UEFI IPv6 PXE support Michael Chang
@ 2016-08-03 6:34 ` Michael Chang
2016-08-03 6:34 ` [PATCH 6/8] bootp: Add processing DHCPACK packet from HTTP Boot Michael Chang
` (2 subsequent siblings)
7 siblings, 0 replies; 11+ messages in thread
From: Michael Chang @ 2016-08-03 6:34 UTC (permalink / raw)
To: Grub devel; +Cc: Ken Lin, Michael Chang
Update grub documentation for net_bootp6 command.
Signed-off-by: Michael Chang <mchang@suse.com>
Signed-off-by: Ken Lin <ken.lin@hpe.com>
---
docs/grub.texi | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
diff --git a/docs/grub.texi b/docs/grub.texi
index 82f6fa4..60b4aa0 100644
--- a/docs/grub.texi
+++ b/docs/grub.texi
@@ -5173,6 +5173,7 @@ See @uref{http://wiki.xen.org/wiki/XSM} for more detail.
* net_add_dns:: Add a DNS server
* net_add_route:: Add routing entry
* net_bootp:: Perform a bootp autoconfiguration
+* net_bootp6:: Perform a DHCPv6 autoconfiguration
* net_del_addr:: Remove IP address from interface
* net_del_dns:: Remove a DNS server
* net_del_route:: Remove a route entry
@@ -5254,6 +5255,22 @@ Sets environment variable @samp{net_}@var{<card>}@samp{_dhcp_extensionspath}
@end deffn
+@node net_bootp6
+@subsection net_bootp6
+
+@deffn Command net_bootp6 [@var{card}]
+Perform configuration of @var{card} using DHCPv6 protocol. If no card name is
+specified, try to configure all existing cards. If configuration was
+successful, interface with name @var{card}@samp{:dhcp6} and configured address
+is added to @var{card}.
+
+@table @samp
+@item 1 (Domain Name Server)
+Adds all servers from option value to the list of servers used during name
+resolution.
+@end table
+
+@end deffn
@node net_del_addr
@subsection net_del_addr
--
2.6.6
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH 6/8] bootp: Add processing DHCPACK packet from HTTP Boot
2016-08-03 6:34 Patches to support UEFI HTTP Boot IPv4 and IPv6 Michael Chang
` (4 preceding siblings ...)
2016-08-03 6:34 ` [PATCH 5/8] grub.texi: Add net_bootp6 doument Michael Chang
@ 2016-08-03 6:34 ` Michael Chang
2016-08-03 6:34 ` [PATCH 7/8] efinet: Setting network from UEFI device path Michael Chang
2016-08-03 6:34 ` [PATCH 8/8] efinet: Setting DNS server from UEFI protocol Michael Chang
7 siblings, 0 replies; 11+ messages in thread
From: Michael Chang @ 2016-08-03 6:34 UTC (permalink / raw)
To: Grub devel; +Cc: Ken Lin, Michael Chang
The vendor class identifier with the string "HTTPClient" is used to denote the
packet as responding to HTTP boot request. In DHCP4 config, the filename for
HTTP boot is the URL of the boot file while for PXE boot it is the path to the
boot file. As a consequence, the next-server becomes obseleted because the HTTP
URL already contains the server address for the boot file. For DHCP6 config,
there's no difference definition in existing config as dhcp6.bootfile-url can
be used to specify URL for both HTTP and PXE boot file.
This patch adds processing for "HTTPClient" vendor class identifier in DHCPACK
packet by treating it as HTTP format, not as the PXE format.
Signed-off-by: Michael Chang <mchang@suse.com>
Signed-off-by: Ken Lin <ken.lin@hpe.com>
---
grub-core/net/bootp.c | 67 +++++++++++++++++++++++++++++++++++++++++++++++++--
include/grub/net.h | 1 +
2 files changed, 66 insertions(+), 2 deletions(-)
diff --git a/grub-core/net/bootp.c b/grub-core/net/bootp.c
index 81173b4..04f9f3d 100644
--- a/grub-core/net/bootp.c
+++ b/grub-core/net/bootp.c
@@ -207,6 +207,11 @@ parse_dhcp_vendor (const char *name, const void *vend, int limit, int *mask)
taglength);
break;
+ case GRUB_NET_BOOTP_VENDOR_CLASS_IDENTIFIER:
+ grub_env_set_net_property (name, "vendor_class_identifier", (const char *) ptr,
+ taglength);
+ break;
+
case GRUB_NET_BOOTP_EXTENSIONS_PATH:
grub_env_set_net_property (name, "extensionspath", (const char *) ptr,
taglength);
@@ -281,6 +286,66 @@ grub_net_configure_by_dhcp_ack (const char *name,
}
#endif
+ if (size > OFFSET_OF (vendor, bp))
+ {
+ char *cidvar;
+ const char *cid;
+
+ parse_dhcp_vendor (name, &bp->vendor, size - OFFSET_OF (vendor, bp), &mask);
+ cidvar = grub_xasprintf ("net_%s_%s", name, "vendor_class_identifier");
+ cid = grub_env_get (cidvar);
+ grub_free (cidvar);
+
+ if (cid && grub_strcmp (cid, "HTTPClient") == 0)
+ {
+ char *proto, *ip, *pa;
+
+ if (!dissect_url (bp->boot_file, &proto, &ip, &pa))
+ return inter;
+
+ grub_env_set_net_property (name, "boot_file", pa, grub_strlen (pa));
+ if (is_def)
+ {
+ grub_net_default_server = grub_strdup (ip);
+ grub_env_set ("net_default_interface", name);
+ grub_env_export ("net_default_interface");
+ }
+ if (device && !*device)
+ {
+ *device = grub_xasprintf ("%s,%s", proto, ip);
+ grub_print_error ();
+ }
+ if (path)
+ {
+ *path = grub_strdup (pa);
+ grub_print_error ();
+ if (*path)
+ {
+ char *slash;
+ slash = grub_strrchr (*path, '/');
+ if (slash)
+ *slash = 0;
+ else
+ **path = 0;
+ }
+ }
+ grub_net_add_ipv4_local (inter, mask);
+ inter->dhcp_ack = grub_malloc (size);
+ if (inter->dhcp_ack)
+ {
+ grub_memcpy (inter->dhcp_ack, bp, size);
+ inter->dhcp_acklen = size;
+ }
+ else
+ grub_errno = GRUB_ERR_NONE;
+
+ grub_free (proto);
+ grub_free (ip);
+ grub_free (pa);
+ return inter;
+ }
+ }
+
if (size > OFFSET_OF (boot_file, bp))
grub_env_set_net_property (name, "boot_file", bp->boot_file,
sizeof (bp->boot_file));
@@ -342,8 +407,6 @@ grub_net_configure_by_dhcp_ack (const char *name,
**path = 0;
}
}
- if (size > OFFSET_OF (vendor, bp))
- parse_dhcp_vendor (name, &bp->vendor, size - OFFSET_OF (vendor, bp), &mask);
grub_net_add_ipv4_local (inter, mask);
inter->dhcp_ack = grub_malloc (size);
diff --git a/include/grub/net.h b/include/grub/net.h
index 38a3973..e4bf678 100644
--- a/include/grub/net.h
+++ b/include/grub/net.h
@@ -517,6 +517,7 @@ enum
GRUB_NET_BOOTP_DOMAIN = 0x0f,
GRUB_NET_BOOTP_ROOT_PATH = 0x11,
GRUB_NET_BOOTP_EXTENSIONS_PATH = 0x12,
+ GRUB_NET_BOOTP_VENDOR_CLASS_IDENTIFIER = 0x3C,
GRUB_NET_BOOTP_END = 0xff
};
--
2.6.6
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH 7/8] efinet: Setting network from UEFI device path
2016-08-03 6:34 Patches to support UEFI HTTP Boot IPv4 and IPv6 Michael Chang
` (5 preceding siblings ...)
2016-08-03 6:34 ` [PATCH 6/8] bootp: Add processing DHCPACK packet from HTTP Boot Michael Chang
@ 2016-08-03 6:34 ` Michael Chang
2016-08-03 6:34 ` [PATCH 8/8] efinet: Setting DNS server from UEFI protocol Michael Chang
7 siblings, 0 replies; 11+ messages in thread
From: Michael Chang @ 2016-08-03 6:34 UTC (permalink / raw)
To: Grub devel; +Cc: Ken Lin, Michael Chang
The PXE Base Code protocol used to obtain cached PXE DHCPACK packet is no
longer provided for HTTP Boot. Instead, we have to get the HTTP boot
information from the device path nodes defined in following UEFI Specification
sections.
9.3.5.12 IPv4 Device Path
9.3.5.13 IPv6 Device Path
9.3.5.23 Uniform Resource Identifiers (URI) Device Path
This patch basically does:
include/grub/efi/api.h:
Add new structure of Uniform Resource Identifiers (URI) Device Path
grub-core/net/drivers/efi/efinet.c:
Check if PXE Base Code is available, if not it will try to obtain the netboot
information from the device path where the image booted from. The DHCPACK
packet is recoverd from the information in device patch and feed into the same
DHCP packet processing functions to ensure the network interface is setting up
the same way it used to be.
Signed-off-by: Michael Chang <mchang@suse.com>
Signed-off-by: Ken Lin <ken.lin@hpe.com>
---
grub-core/net/drivers/efi/efinet.c | 268 +++++++++++++++++++++++++++++++++++--
include/grub/efi/api.h | 11 ++
2 files changed, 270 insertions(+), 9 deletions(-)
diff --git a/grub-core/net/drivers/efi/efinet.c b/grub-core/net/drivers/efi/efinet.c
index fc90415..2d3b00f 100644
--- a/grub-core/net/drivers/efi/efinet.c
+++ b/grub-core/net/drivers/efi/efinet.c
@@ -23,6 +23,7 @@
#include <grub/efi/api.h>
#include <grub/efi/efi.h>
#include <grub/i18n.h>
+#include <grub/net/netbuff.h>
GRUB_MOD_LICENSE ("GPLv3+");
@@ -324,6 +325,221 @@ grub_efinet_findcards (void)
grub_free (handles);
}
+static struct grub_net_buff *
+grub_efinet_create_dhcp_ack_from_device_path (grub_efi_device_path_t *dp, int *use_ipv6)
+{
+ grub_efi_uint16_t uri_len;
+ grub_efi_device_path_t *ldp, *ddp;
+ grub_efi_uri_device_path_t *uri_dp;
+ struct grub_net_buff *nb;
+ grub_err_t err;
+
+ ddp = grub_efi_duplicate_device_path (dp);
+ ldp = grub_efi_find_last_device_path (ddp);
+
+ if (GRUB_EFI_DEVICE_PATH_TYPE (ldp) != GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE
+ || GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_URI_DEVICE_PATH_SUBTYPE)
+ {
+ grub_free (ddp);
+ return NULL;
+ }
+
+ uri_len = GRUB_EFI_DEVICE_PATH_LENGTH (ldp) > 4 ? GRUB_EFI_DEVICE_PATH_LENGTH (ldp) - 4 : 0;
+
+ if (!uri_len)
+ {
+ grub_free (ddp);
+ return NULL;
+ }
+
+ uri_dp = (grub_efi_uri_device_path_t *) ldp;
+
+ ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE;
+ ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE;
+ ldp->length = sizeof (*ldp);
+
+ ldp = grub_efi_find_last_device_path (ddp);
+
+ if (GRUB_EFI_DEVICE_PATH_TYPE (ldp) != GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE
+ || (GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV4_DEVICE_PATH_SUBTYPE
+ && GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV6_DEVICE_PATH_SUBTYPE))
+ {
+ grub_free (ddp);
+ return NULL;
+ }
+
+ nb = grub_netbuff_alloc (512);
+ if (!nb)
+ return NULL;
+
+ if (GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) == GRUB_EFI_IPV4_DEVICE_PATH_SUBTYPE)
+ {
+ grub_efi_ipv4_device_path_t *ipv4 = (grub_efi_ipv4_device_path_t *) ldp;
+ struct grub_net_bootp_packet *bp;
+ grub_uint8_t *ptr;
+
+ bp = (struct grub_net_bootp_packet *) nb->tail;
+ err = grub_netbuff_put (nb, sizeof (*bp) + 4);
+ if (err)
+ {
+ grub_free (ddp);
+ grub_netbuff_free (nb);
+ return NULL;
+ }
+
+ if (sizeof(bp->boot_file) < uri_len)
+ {
+ grub_free (ddp);
+ grub_netbuff_free (nb);
+ return NULL;
+ }
+ grub_memcpy (bp->boot_file, uri_dp->uri, uri_len);
+ grub_memcpy (&bp->your_ip, ipv4->local_ip_address, sizeof (bp->your_ip));
+ grub_memcpy (&bp->server_ip, ipv4->remote_ip_address, sizeof (bp->server_ip));
+
+ bp->vendor[0] = GRUB_NET_BOOTP_RFC1048_MAGIC_0;
+ bp->vendor[1] = GRUB_NET_BOOTP_RFC1048_MAGIC_1;
+ bp->vendor[2] = GRUB_NET_BOOTP_RFC1048_MAGIC_2;
+ bp->vendor[3] = GRUB_NET_BOOTP_RFC1048_MAGIC_3;
+
+ ptr = nb->tail;
+ err = grub_netbuff_put (nb, sizeof (ipv4->subnet_mask) + 2);
+ if (err)
+ {
+ grub_free (ddp);
+ grub_netbuff_free (nb);
+ return NULL;
+ }
+ *ptr++ = GRUB_NET_BOOTP_NETMASK;
+ *ptr++ = sizeof (ipv4->subnet_mask);
+ grub_memcpy (ptr, ipv4->subnet_mask, sizeof (ipv4->subnet_mask));
+
+ ptr = nb->tail;
+ err = grub_netbuff_put (nb, sizeof (ipv4->gateway_ip_address) + 2);
+ if (err)
+ {
+ grub_free (ddp);
+ grub_netbuff_free (nb);
+ return NULL;
+ }
+ *ptr++ = GRUB_NET_BOOTP_ROUTER;
+ *ptr++ = sizeof (ipv4->gateway_ip_address);
+ grub_memcpy (ptr, ipv4->gateway_ip_address, sizeof (ipv4->gateway_ip_address));
+
+ ptr = nb->tail;
+ err = grub_netbuff_put (nb, sizeof ("HTTPClient") + 1);
+ if (err)
+ {
+ grub_free (ddp);
+ grub_netbuff_free (nb);
+ return NULL;
+ }
+ *ptr++ = GRUB_NET_BOOTP_VENDOR_CLASS_IDENTIFIER;
+ *ptr++ = sizeof ("HTTPClient") - 1;
+ grub_memcpy (ptr, "HTTPClient", sizeof ("HTTPClient") - 1);
+
+ ptr = nb->tail;
+ err = grub_netbuff_put (nb, 1);
+ if (err)
+ {
+ grub_free (ddp);
+ grub_netbuff_free (nb);
+ return NULL;
+ }
+ *ptr = GRUB_NET_BOOTP_END;
+ *use_ipv6 = 0;
+
+ ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE;
+ ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE;
+ ldp->length = sizeof (*ldp);
+ ldp = grub_efi_find_last_device_path (ddp);
+
+ if (GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) == GRUB_EFI_MAC_ADDRESS_DEVICE_PATH_SUBTYPE)
+ {
+ grub_efi_mac_address_device_path_t *mac = (grub_efi_mac_address_device_path_t *) ldp;
+ bp->hw_type = mac->if_type;
+ bp->hw_len = sizeof (bp->mac_addr);
+ grub_memcpy (bp->mac_addr, mac->mac_address, bp->hw_len);
+ }
+ }
+ else
+ {
+ grub_efi_ipv6_device_path_t *ipv6 = (grub_efi_ipv6_device_path_t *) ldp;
+
+ struct grub_net_dhcp6_packet *d6p;
+ struct grub_net_dhcp6_option *opt;
+ struct grub_net_dhcp6_option_iana *iana;
+ struct grub_net_dhcp6_option_iaaddr *iaaddr;
+
+ d6p = (struct grub_net_dhcp6_packet *)nb->tail;
+ err = grub_netbuff_put (nb, sizeof(*d6p));
+ if (err)
+ {
+ grub_free (ddp);
+ grub_netbuff_free (nb);
+ return NULL;
+ }
+ d6p->message_type = GRUB_NET_DHCP6_REPLY;
+
+ opt = (struct grub_net_dhcp6_option *)nb->tail;
+ err = grub_netbuff_put (nb, sizeof(*opt));
+ if (err)
+ {
+ grub_free (ddp);
+ grub_netbuff_free (nb);
+ return NULL;
+ }
+ opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_IA_NA);
+ opt->len = grub_cpu_to_be16_compile_time (sizeof(*iana) + sizeof(*opt) + sizeof(*iaaddr));
+
+ err = grub_netbuff_put (nb, sizeof(*iana));
+ if (err)
+ {
+ grub_free (ddp);
+ grub_netbuff_free (nb);
+ return NULL;
+ }
+
+ opt = (struct grub_net_dhcp6_option *)nb->tail;
+ err = grub_netbuff_put (nb, sizeof(*opt));
+ if (err)
+ {
+ grub_free (ddp);
+ grub_netbuff_free (nb);
+ return NULL;
+ }
+ opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_IAADDR);
+ opt->len = grub_cpu_to_be16_compile_time (sizeof (*iaaddr));
+
+ iaaddr = (struct grub_net_dhcp6_option_iaaddr *)nb->tail;
+ err = grub_netbuff_put (nb, sizeof(*iaaddr));
+ if (err)
+ {
+ grub_free (ddp);
+ grub_netbuff_free (nb);
+ return NULL;
+ }
+ grub_memcpy (iaaddr->addr, ipv6->local_ip_address, sizeof(ipv6->local_ip_address));
+
+ opt = (struct grub_net_dhcp6_option *)nb->tail;
+ err = grub_netbuff_put (nb, sizeof(*opt) + uri_len);
+ if (err)
+ {
+ grub_free (ddp);
+ grub_netbuff_free (nb);
+ return NULL;
+ }
+ opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_BOOTFILE_URL);
+ opt->len = grub_cpu_to_be16 (uri_len);
+ grub_memcpy (opt->data, uri_dp->uri, uri_len);
+
+ *use_ipv6 = 1;
+ }
+
+ grub_free (ddp);
+ return nb;
+}
+
static void
grub_efi_net_config_real (grub_efi_handle_t hnd, char **device,
char **path)
@@ -340,6 +556,11 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device,
grub_efi_device_path_t *cdp;
struct grub_efi_pxe *pxe;
struct grub_efi_pxe_mode *pxe_mode;
+ grub_uint8_t *packet_buf;
+ grub_size_t packet_bufsz ;
+ int ipv6;
+ struct grub_net_buff *nb = NULL;
+
if (card->driver != &efidriver)
continue;
cdp = grub_efi_get_device_path (card->efi_handle);
@@ -359,11 +580,21 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device,
ldp = grub_efi_find_last_device_path (dp);
if (GRUB_EFI_DEVICE_PATH_TYPE (ldp) != GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE
|| (GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV4_DEVICE_PATH_SUBTYPE
- && GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV6_DEVICE_PATH_SUBTYPE))
+ && GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV6_DEVICE_PATH_SUBTYPE
+ && GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_URI_DEVICE_PATH_SUBTYPE))
continue;
dup_dp = grub_efi_duplicate_device_path (dp);
if (!dup_dp)
continue;
+
+ if (GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) == GRUB_EFI_URI_DEVICE_PATH_SUBTYPE)
+ {
+ dup_ldp = grub_efi_find_last_device_path (dup_dp);
+ dup_ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE;
+ dup_ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE;
+ dup_ldp->length = sizeof (*dup_ldp);
+ }
+
dup_ldp = grub_efi_find_last_device_path (dup_dp);
dup_ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE;
dup_ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE;
@@ -375,16 +606,31 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device,
}
pxe = grub_efi_open_protocol (hnd, &pxe_io_guid,
GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL);
- if (! pxe)
- continue;
- pxe_mode = pxe->mode;
+ if (!pxe)
+ {
+ nb = grub_efinet_create_dhcp_ack_from_device_path (dp, &ipv6);
+ if (!nb)
+ {
+ grub_print_error ();
+ continue;
+ }
+ packet_buf = nb->head;
+ packet_bufsz = nb->tail - nb->head;
+ }
+ else
+ {
+ pxe_mode = pxe->mode;
+ packet_buf = (grub_uint8_t *) &pxe_mode->dhcp_ack;
+ packet_bufsz = sizeof (pxe_mode->dhcp_ack);
+ ipv6 = pxe_mode->using_ipv6;
+ }
- if (pxe_mode->using_ipv6)
+ if (ipv6)
{
grub_net_configure_by_dhcpv6_reply (card->name, card, 0,
(struct grub_net_dhcp6_packet *)
- &pxe_mode->dhcp_ack,
- sizeof (pxe_mode->dhcp_ack),
+ packet_buf,
+ packet_bufsz,
1, device, path);
if (grub_errno)
grub_print_error ();
@@ -393,10 +639,14 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device,
{
grub_net_configure_by_dhcp_ack (card->name, card, 0,
(struct grub_net_bootp_packet *)
- &pxe_mode->dhcp_ack,
- sizeof (pxe_mode->dhcp_ack),
+ packet_buf,
+ packet_bufsz,
1, device, path);
}
+
+ if (nb)
+ grub_netbuff_free (nb);
+
return;
}
}
diff --git a/include/grub/efi/api.h b/include/grub/efi/api.h
index 92f9b5a..d5a1256 100644
--- a/include/grub/efi/api.h
+++ b/include/grub/efi/api.h
@@ -825,6 +825,8 @@ struct grub_efi_ipv4_device_path
grub_efi_uint16_t remote_port;
grub_efi_uint16_t protocol;
grub_efi_uint8_t static_ip_address;
+ grub_efi_ipv4_address_t gateway_ip_address;
+ grub_efi_ipv4_address_t subnet_mask;
} GRUB_PACKED;
typedef struct grub_efi_ipv4_device_path grub_efi_ipv4_device_path_t;
@@ -879,6 +881,15 @@ struct grub_efi_sata_device_path
} GRUB_PACKED;
typedef struct grub_efi_sata_device_path grub_efi_sata_device_path_t;
+#define GRUB_EFI_URI_DEVICE_PATH_SUBTYPE 24
+
+struct grub_efi_uri_device_path
+{
+ grub_efi_device_path_t header;
+ grub_efi_uint8_t uri[0];
+} GRUB_PACKED;
+typedef struct grub_efi_uri_device_path grub_efi_uri_device_path_t;
+
#define GRUB_EFI_VENDOR_MESSAGING_DEVICE_PATH_SUBTYPE 10
/* Media Device Path. */
--
2.6.6
^ permalink raw reply related [flat|nested] 11+ messages in thread
* [PATCH 8/8] efinet: Setting DNS server from UEFI protocol
2016-08-03 6:34 Patches to support UEFI HTTP Boot IPv4 and IPv6 Michael Chang
` (6 preceding siblings ...)
2016-08-03 6:34 ` [PATCH 7/8] efinet: Setting network from UEFI device path Michael Chang
@ 2016-08-03 6:34 ` Michael Chang
7 siblings, 0 replies; 11+ messages in thread
From: Michael Chang @ 2016-08-03 6:34 UTC (permalink / raw)
To: Grub devel; +Cc: Ken Lin, Michael Chang
In the URI device path node, any name rahter than address can be used for
looking up the resources so that DNS service become needed to get answer of the
name's address. Unfortunately the DNS is not defined in any of the device path
nodes so that we use the EFI_IP4_CONFIG2_PROTOCOL and EFI_IP6_CONFIG_PROTOCOL
to obtain it.
These two protcols are defined the sections of UEFI specification.
27.5 EFI IPv4 Configuration II Protocol
27.7 EFI IPv6 Configuration Protocol
include/grub/efi/api.h:
Add new structure and protocol UUID of EFI_IP4_CONFIG2_PROTOCOL and
EFI_IP6_CONFIG_PROTOCOL.
grub-core/net/drivers/efi/efinet.c:
Use the EFI_IP4_CONFIG2_PROTOCOL and EFI_IP6_CONFIG_PROTOCOL to obtain the list
of DNS server address for IPv4 and IPv6 respectively. The address of DNS
servers is structured into DHCPACK packet and feed into the same DHCP packet
processing functions to ensure the network interface is setting up the same way
it used to be.
Signed-off-by: Michael Chang <mchang@suse.com>
Signed-off-by: Ken Lin <ken.lin@hpe.com>
---
grub-core/net/drivers/efi/efinet.c | 163 +++++++++++++++++++++++++++++++++++++
include/grub/efi/api.h | 76 +++++++++++++++++
2 files changed, 239 insertions(+)
diff --git a/grub-core/net/drivers/efi/efinet.c b/grub-core/net/drivers/efi/efinet.c
index 2d3b00f..82a28fb 100644
--- a/grub-core/net/drivers/efi/efinet.c
+++ b/grub-core/net/drivers/efi/efinet.c
@@ -30,6 +30,8 @@ GRUB_MOD_LICENSE ("GPLv3+");
/* GUID. */
static grub_efi_guid_t net_io_guid = GRUB_EFI_SIMPLE_NETWORK_GUID;
static grub_efi_guid_t pxe_io_guid = GRUB_EFI_PXE_GUID;
+static grub_efi_guid_t ip4_config_guid = GRUB_EFI_IP4_CONFIG2_PROTOCOL_GUID;
+static grub_efi_guid_t ip6_config_guid = GRUB_EFI_IP6_CONFIG_PROTOCOL_GUID;
static grub_err_t
send_card_buffer (struct grub_net_card *dev,
@@ -325,6 +327,125 @@ grub_efinet_findcards (void)
grub_free (handles);
}
+static grub_efi_handle_t
+grub_efi_locate_device_path (grub_efi_guid_t *protocol, grub_efi_device_path_t *device_path,
+ grub_efi_device_path_t **r_device_path)
+{
+ grub_efi_handle_t handle;
+ grub_efi_status_t status;
+
+ status = efi_call_3 (grub_efi_system_table->boot_services->locate_device_path,
+ protocol, &device_path, &handle);
+
+ if (status != GRUB_EFI_SUCCESS)
+ return 0;
+
+ if (r_device_path)
+ *r_device_path = device_path;
+
+ return handle;
+}
+
+static grub_efi_ipv4_address_t *
+grub_dns_server_ip4_address (grub_efi_device_path_t *dp, grub_efi_uintn_t *num_dns)
+{
+ grub_efi_handle_t hnd;
+ grub_efi_status_t status;
+ grub_efi_ip4_config2_protocol_t *conf;
+ grub_efi_ipv4_address_t *addrs;
+ grub_efi_uintn_t data_size = 1 * sizeof (grub_efi_ipv4_address_t);
+
+ hnd = grub_efi_locate_device_path (&ip4_config_guid, dp, NULL);
+
+ if (!hnd)
+ return 0;
+
+ conf = grub_efi_open_protocol (hnd, &ip4_config_guid,
+ GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL);
+
+ if (!conf)
+ return 0;
+
+ addrs = grub_malloc (data_size);
+ if (!addrs)
+ return 0;
+
+ status = efi_call_4 (conf->get_data, conf,
+ GRUB_EFI_IP4_CONFIG2_DATA_TYPE_DNSSERVER,
+ &data_size, addrs);
+
+ if (status == GRUB_EFI_BUFFER_TOO_SMALL)
+ {
+ grub_free (addrs);
+ addrs = grub_malloc (data_size);
+ if (!addrs)
+ return 0;
+
+ status = efi_call_4 (conf->get_data, conf,
+ GRUB_EFI_IP4_CONFIG2_DATA_TYPE_DNSSERVER,
+ &data_size, addrs);
+ }
+
+ if (status != GRUB_EFI_SUCCESS)
+ {
+ grub_free (addrs);
+ return 0;
+ }
+
+ *num_dns = data_size / sizeof (grub_efi_ipv4_address_t);
+ return addrs;
+}
+
+static grub_efi_ipv6_address_t *
+grub_dns_server_ip6_address (grub_efi_device_path_t *dp, grub_efi_uintn_t *num_dns)
+{
+ grub_efi_handle_t hnd;
+ grub_efi_status_t status;
+ grub_efi_ip6_config_protocol_t *conf;
+ grub_efi_ipv6_address_t *addrs;
+ grub_efi_uintn_t data_size = 1 * sizeof (grub_efi_ipv6_address_t);
+
+ hnd = grub_efi_locate_device_path (&ip6_config_guid, dp, NULL);
+
+ if (!hnd)
+ return 0;
+
+ conf = grub_efi_open_protocol (hnd, &ip6_config_guid,
+ GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL);
+
+ if (!conf)
+ return 0;
+
+ addrs = grub_malloc (data_size);
+ if (!addrs)
+ return 0;
+
+ status = efi_call_4 (conf->get_data, conf,
+ GRUB_EFI_IP6_CONFIG_DATA_TYPE_DNSSERVER,
+ &data_size, addrs);
+
+ if (status == GRUB_EFI_BUFFER_TOO_SMALL)
+ {
+ grub_free (addrs);
+ addrs = grub_malloc (data_size);
+ if (!addrs)
+ return 0;
+
+ status = efi_call_4 (conf->get_data, conf,
+ GRUB_EFI_IP6_CONFIG_DATA_TYPE_DNSSERVER,
+ &data_size, addrs);
+ }
+
+ if (status != GRUB_EFI_SUCCESS)
+ {
+ grub_free (addrs);
+ return 0;
+ }
+
+ *num_dns = data_size / sizeof (grub_efi_ipv6_address_t);
+ return addrs;
+}
+
static struct grub_net_buff *
grub_efinet_create_dhcp_ack_from_device_path (grub_efi_device_path_t *dp, int *use_ipv6)
{
@@ -377,6 +498,8 @@ grub_efinet_create_dhcp_ack_from_device_path (grub_efi_device_path_t *dp, int *u
grub_efi_ipv4_device_path_t *ipv4 = (grub_efi_ipv4_device_path_t *) ldp;
struct grub_net_bootp_packet *bp;
grub_uint8_t *ptr;
+ grub_efi_ipv4_address_t *dns;
+ grub_efi_uintn_t num_dns;
bp = (struct grub_net_bootp_packet *) nb->tail;
err = grub_netbuff_put (nb, sizeof (*bp) + 4);
@@ -438,6 +561,25 @@ grub_efinet_create_dhcp_ack_from_device_path (grub_efi_device_path_t *dp, int *u
*ptr++ = sizeof ("HTTPClient") - 1;
grub_memcpy (ptr, "HTTPClient", sizeof ("HTTPClient") - 1);
+ dns = grub_dns_server_ip4_address (dp, &num_dns);
+ if (dns)
+ {
+ grub_efi_uintn_t size_dns = sizeof (*dns) * num_dns;
+
+ ptr = nb->tail;
+ err = grub_netbuff_put (nb, size_dns + 2);
+ if (err)
+ {
+ grub_free (ddp);
+ grub_netbuff_free (nb);
+ return NULL;
+ }
+ *ptr++ = GRUB_NET_BOOTP_DNS;
+ *ptr++ = size_dns;
+ grub_memcpy (ptr, dns, size_dns);
+ grub_free (dns);
+ }
+
ptr = nb->tail;
err = grub_netbuff_put (nb, 1);
if (err)
@@ -470,6 +612,8 @@ grub_efinet_create_dhcp_ack_from_device_path (grub_efi_device_path_t *dp, int *u
struct grub_net_dhcp6_option *opt;
struct grub_net_dhcp6_option_iana *iana;
struct grub_net_dhcp6_option_iaaddr *iaaddr;
+ grub_efi_ipv6_address_t *dns;
+ grub_efi_uintn_t num_dns;
d6p = (struct grub_net_dhcp6_packet *)nb->tail;
err = grub_netbuff_put (nb, sizeof(*d6p));
@@ -533,6 +677,25 @@ grub_efinet_create_dhcp_ack_from_device_path (grub_efi_device_path_t *dp, int *u
opt->len = grub_cpu_to_be16 (uri_len);
grub_memcpy (opt->data, uri_dp->uri, uri_len);
+ dns = grub_dns_server_ip6_address (dp, &num_dns);
+ if (dns)
+ {
+ grub_efi_uintn_t size_dns = sizeof (*dns) * num_dns;
+
+ opt = (struct grub_net_dhcp6_option *)nb->tail;
+ err = grub_netbuff_put (nb, sizeof(*opt) + size_dns);
+ if (err)
+ {
+ grub_free (ddp);
+ grub_netbuff_free (nb);
+ return NULL;
+ }
+ opt->code = grub_cpu_to_be16_compile_time (GRUB_NET_DHCP6_OPTION_DNS_SERVERS);
+ opt->len = grub_cpu_to_be16 (size_dns);
+ grub_memcpy (opt->data, dns, size_dns);
+ grub_free (dns);
+ }
+
*use_ipv6 = 1;
}
diff --git a/include/grub/efi/api.h b/include/grub/efi/api.h
index d5a1256..99ba068 100644
--- a/include/grub/efi/api.h
+++ b/include/grub/efi/api.h
@@ -334,6 +334,16 @@
{ 0x8B, 0x8C, 0xE2, 0x1B, 0x01, 0xAE, 0xF2, 0xB7 } \
}
+#define GRUB_EFI_IP4_CONFIG2_PROTOCOL_GUID \
+ { 0x5b446ed1, 0xe30b, 0x4faa, \
+ { 0x87, 0x1a, 0x36, 0x54, 0xec, 0xa3, 0x60, 0x80 } \
+ }
+
+#define GRUB_EFI_IP6_CONFIG_PROTOCOL_GUID \
+ { 0x937fe521, 0x95ae, 0x4d1a, \
+ { 0x89, 0x29, 0x48, 0xbc, 0xd9, 0x0a, 0xd3, 0x1a } \
+ }
+
struct grub_efi_sal_system_table
{
grub_uint32_t signature;
@@ -1749,6 +1759,72 @@ struct grub_efi_block_io
};
typedef struct grub_efi_block_io grub_efi_block_io_t;
+enum grub_efi_ip4_config2_data_type {
+ GRUB_EFI_IP4_CONFIG2_DATA_TYPE_INTERFACEINFO,
+ GRUB_EFI_IP4_CONFIG2_DATA_TYPE_POLICY,
+ GRUB_EFI_IP4_CONFIG2_DATA_TYPE_MANUAL_ADDRESS,
+ GRUB_EFI_IP4_CONFIG2_DATA_TYPE_GATEWAY,
+ GRUB_EFI_IP4_CONFIG2_DATA_TYPE_DNSSERVER,
+ GRUB_EFI_IP4_CONFIG2_DATA_TYPE_MAXIMUM
+};
+typedef enum grub_efi_ip4_config2_data_type grub_efi_ip4_config2_data_type_t;
+
+struct grub_efi_ip4_config2_protocol
+{
+ grub_efi_status_t (*set_data) (struct grub_efi_ip4_config2_protocol *this,
+ grub_efi_ip4_config2_data_type_t data_type,
+ grub_efi_uintn_t data_size,
+ void *data);
+
+ grub_efi_status_t (*get_data) (struct grub_efi_ip4_config2_protocol *this,
+ grub_efi_ip4_config2_data_type_t data_type,
+ grub_efi_uintn_t *data_size,
+ void *data);
+
+ grub_efi_status_t (*register_data_notify) (struct grub_efi_ip4_config2_protocol *this,
+ grub_efi_ip4_config2_data_type_t data_type,
+ grub_efi_event_t event);
+
+ grub_efi_status_t (*unregister_datanotify) (struct grub_efi_ip4_config2_protocol *this,
+ grub_efi_ip4_config2_data_type_t data_type,
+ grub_efi_event_t event);
+};
+typedef struct grub_efi_ip4_config2_protocol grub_efi_ip4_config2_protocol_t;
+
+enum grub_efi_ip6_config_data_type {
+ GRUB_EFI_IP6_CONFIG_DATA_TYPE_INTERFACEINFO,
+ GRUB_EFI_IP6_CONFIG_DATA_TYPE_ALT_INTERFACEID,
+ GRUB_EFI_IP6_CONFIG_DATA_TYPE_POLICY,
+ GRUB_EFI_IP6_CONFIG_DATA_TYPE_DUP_ADDR_DETECT_TRANSMITS,
+ GRUB_EFI_IP6_CONFIG_DATA_TYPE_MANUAL_ADDRESS,
+ GRUB_EFI_IP6_CONFIG_DATA_TYPE_GATEWAY,
+ GRUB_EFI_IP6_CONFIG_DATA_TYPE_DNSSERVER,
+ GRUB_EFI_IP6_CONFIG_DATA_TYPE_MAXIMUM
+};
+typedef enum grub_efi_ip6_config_data_type grub_efi_ip6_config_data_type_t;
+
+struct grub_efi_ip6_config_protocol
+{
+ grub_efi_status_t (*set_data) (struct grub_efi_ip6_config_protocol *this,
+ grub_efi_ip6_config_data_type_t data_type,
+ grub_efi_uintn_t data_size,
+ void *data);
+
+ grub_efi_status_t (*get_data) (struct grub_efi_ip6_config_protocol *this,
+ grub_efi_ip6_config_data_type_t data_type,
+ grub_efi_uintn_t *data_size,
+ void *data);
+
+ grub_efi_status_t (*register_data_notify) (struct grub_efi_ip6_config_protocol *this,
+ grub_efi_ip6_config_data_type_t data_type,
+ grub_efi_event_t event);
+
+ grub_efi_status_t (*unregister_datanotify) (struct grub_efi_ip6_config_protocol *this,
+ grub_efi_ip6_config_data_type_t data_type,
+ grub_efi_event_t event);
+};
+typedef struct grub_efi_ip6_config_protocol grub_efi_ip6_config_protocol_t;
+
#if (GRUB_TARGET_SIZEOF_VOID_P == 4) || defined (__ia64__) \
|| defined (__aarch64__) || defined (__MINGW64__) || defined (__CYGWIN__)
--
2.6.6
^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [PATCH 2/8] net: read bracketed ipv6 addrs and port numbers
2016-08-03 6:34 ` [PATCH 2/8] net: read bracketed ipv6 addrs and port numbers Michael Chang
@ 2016-08-03 8:17 ` Andrei Borzenkov
0 siblings, 0 replies; 11+ messages in thread
From: Andrei Borzenkov @ 2016-08-03 8:17 UTC (permalink / raw)
To: The development of GNU GRUB; +Cc: Ken Lin, Michael Chang, aaronmiller
On Wed, Aug 3, 2016 at 9:34 AM, Michael Chang <mchang@suse.com> wrote:
> From: Aaron Miller <aaronmiller@fb.com>
>
> Allow specifying port numbers for http and tftp paths, and allow ipv6 addresses
> to be recognized with brackets around them, which is required to specify a port
> number
> ---
> grub-core/net/http.c | 21 ++++++++++---
> grub-core/net/net.c | 86 +++++++++++++++++++++++++++++++++++++++++++++++++---
> grub-core/net/tftp.c | 6 +++-
> include/grub/net.h | 1 +
> 4 files changed, 104 insertions(+), 10 deletions(-)
>
> diff --git a/grub-core/net/http.c b/grub-core/net/http.c
> index 5aa4ad3..f182d7b 100644
> --- a/grub-core/net/http.c
> +++ b/grub-core/net/http.c
> @@ -312,12 +312,14 @@ http_establish (struct grub_file *file, grub_off_t offset, int initial)
> int i;
> struct grub_net_buff *nb;
> grub_err_t err;
> + char* server = file->device->net->server;
> + int port = file->device->net->port;
>
> nb = grub_netbuff_alloc (GRUB_NET_TCP_RESERVE_SIZE
> + sizeof ("GET ") - 1
> + grub_strlen (data->filename)
> + sizeof (" HTTP/1.1\r\nHost: ") - 1
> - + grub_strlen (file->device->net->server)
> + + grub_strlen (server) + sizeof (":XXXXXXXXXX")
I just wonder why so many X's; port is 16 bit so 5 digits at most + zero byte.
> + sizeof ("\r\nUser-Agent: " PACKAGE_STRING
> "\r\n") - 1
> + sizeof ("Range: bytes=XXXXXXXXXXXXXXXXXXXX"
> @@ -356,7 +358,7 @@ http_establish (struct grub_file *file, grub_off_t offset, int initial)
> sizeof (" HTTP/1.1\r\nHost: ") - 1);
>
> ptr = nb->tail;
> - err = grub_netbuff_put (nb, grub_strlen (file->device->net->server));
> + err = grub_netbuff_put (nb, grub_strlen (server));
> if (err)
> {
> grub_netbuff_free (nb);
> @@ -365,6 +367,15 @@ http_establish (struct grub_file *file, grub_off_t offset, int initial)
> grub_memcpy (ptr, file->device->net->server,
> grub_strlen (file->device->net->server));
>
> + if (port)
As was discussed previously (probably in another version) zero is
valid port number, although granted it is unusual. This applies also
to all other cases below. It would probably be easier to simply always
use port number.
> + {
> + ptr = nb->tail;
> + grub_snprintf ((char *) ptr,
> + sizeof (":XXXXXXXXXX"),
> + ":%d",
> + port);
> + }
> +
> ptr = nb->tail;
> err = grub_netbuff_put (nb,
> sizeof ("\r\nUser-Agent: " PACKAGE_STRING "\r\n")
> @@ -390,8 +401,10 @@ http_establish (struct grub_file *file, grub_off_t offset, int initial)
> grub_netbuff_put (nb, 2);
> grub_memcpy (ptr, "\r\n", 2);
>
> - data->sock = grub_net_tcp_open (file->device->net->server,
> - HTTP_PORT, http_receive,
> + grub_dprintf ("http", "opening path %s on host %s TCP port %d\n",
> + data->filename, server, port ? port : HTTP_PORT);
> + data->sock = grub_net_tcp_open (server,
> + port ? port : HTTP_PORT, http_receive,
See above.
> http_err, http_err,
> file);
> if (!data->sock)
> diff --git a/grub-core/net/net.c b/grub-core/net/net.c
> index 10773fc..5cc0d2f 100644
> --- a/grub-core/net/net.c
> +++ b/grub-core/net/net.c
> @@ -437,6 +437,12 @@ parse_ip6 (const char *val, grub_uint64_t *ip, const char **rest)
> grub_uint16_t newip[8];
> const char *ptr = val;
> int word, quaddot = -1;
> + int bracketed = 0;
> +
> + if (ptr[0] == '[') {
> + bracketed = 1;
> + ptr++;
> + }
>
Bracketed IPv6 address is defined for use in URI. So it has to be
parsed where URI is expected. As far as I can tell, the only reason
for this in this patch is to allow ":" as port separator in net device
syntax that can be avoided, see below.
> if (ptr[0] == ':' && ptr[1] != ':')
> return 0;
> @@ -475,6 +481,9 @@ parse_ip6 (const char *val, grub_uint64_t *ip, const char **rest)
> grub_memset (&newip[quaddot], 0, (7 - word) * sizeof (newip[0]));
> }
> grub_memcpy (ip, newip, 16);
> + if (bracketed && *ptr == ']') {
> + ptr++;
> + }
> if (rest)
> *rest = ptr;
> return 1;
> @@ -1260,8 +1269,10 @@ grub_net_open_real (const char *name)
> {
> grub_net_app_level_t proto;
> const char *protname, *server;
> + char *host;
> grub_size_t protnamelen;
> int try;
> + int port = 0;
>
> if (grub_strncmp (name, "pxe:", sizeof ("pxe:") - 1) == 0)
> {
> @@ -1299,6 +1310,72 @@ grub_net_open_real (const char *name)
> return NULL;
> }
>
> + char* port_start;
> + /* ipv6 or port specified? */
> + if ((port_start = grub_strchr (server, ':')))
I would probably prefer (proto,address[,port]) syntax to avoid all
ambiguity. The question is, do we want to allow further extending
syntax like user/password, but then we could simply allow empty port
part.
And if bracketed addresses should be supported, just parse them here.
> + {
> + char* ipv6_begin;
> + if((ipv6_begin = grub_strchr (server, '[')))
> + {
> + char* ipv6_end = grub_strchr (server, ']');
> + if(!ipv6_end)
> + {
> + grub_error (GRUB_ERR_NET_BAD_ADDRESS,
> + N_("mismatched [ in address"));
> + return NULL;
> + }
> + /* port number after bracketed ipv6 addr */
> + if(ipv6_end[1] == ':')
> + {
> + port = grub_strtoul (ipv6_end + 2, NULL, 10);
> + if(port > 65535)
> + {
> + grub_error (GRUB_ERR_NET_BAD_ADDRESS,
> + N_("bad port number"));
> + return NULL;
> + }
> + }
> + host = grub_strndup (ipv6_begin, (ipv6_end - ipv6_begin) + 1);
This could just as well be ipv6_begin + 1, ipv6_end -1, right?
> + }
> + else
> + {
> + if (grub_strchr (port_start + 1, ':'))
> + {
> + int iplen = grub_strlen (server);
> + /* bracket bare ipv6 addrs */
> + host = grub_malloc (iplen + 3);
> + if(!host)
> + {
> + return NULL;
> + }
> + host[0] = '[';
> + grub_memcpy (host + 1, server, iplen);
> + host[iplen + 1] = ']';
> + host[iplen + 2] = '\0';
> + }
Why add brackets just to strip them as the very first step later?
> + else
> + {
> + /* hostname:port or ipv4:port */
> + port = grub_strtol (port_start + 1, NULL, 10);
> + if(port > 65535)
> + {
> + grub_error (GRUB_ERR_NET_BAD_ADDRESS,
> + N_("bad port number"));
> + return NULL;
> + }
> + host = grub_strndup (server, port_start - server);
> + }
> + }
> + }
> + else
> + {
> + host = grub_strdup (server);
> + }
> + if (!host)
> + {
> + return NULL;
> + }
> +
> for (try = 0; try < 2; try++)
> {
> FOR_NET_APP_LEVEL (proto)
> @@ -1308,14 +1385,13 @@ grub_net_open_real (const char *name)
> {
> grub_net_t ret = grub_zalloc (sizeof (*ret));
> if (!ret)
> - return NULL;
> - ret->protocol = proto;
> - ret->server = grub_strdup (server);
> - if (!ret->server)
> {
> - grub_free (ret);
> + grub_free (host);
> return NULL;
> }
> + ret->protocol = proto;
> + ret->port = port;
May be we could define default port as part of grub_net_app_protocol.
Then all logic to parse port will be localized here. Everything else
just always has well defined port number.
> + ret->server = host;
> ret->fs = &grub_net_fs;
> return ret;
> }
> diff --git a/grub-core/net/tftp.c b/grub-core/net/tftp.c
> index 7d90bf6..a0817a0 100644
> --- a/grub-core/net/tftp.c
> +++ b/grub-core/net/tftp.c
> @@ -314,6 +314,7 @@ tftp_open (struct grub_file *file, const char *filename)
> grub_err_t err;
> grub_uint8_t *nbd;
> grub_net_network_level_address_t addr;
> + int port = file->device->net->port;
>
> data = grub_zalloc (sizeof (*data));
> if (!data)
> @@ -382,13 +383,16 @@ tftp_open (struct grub_file *file, const char *filename)
> err = grub_net_resolve_address (file->device->net->server, &addr);
> if (err)
> {
> + grub_dprintf ("tftp", "file_size is %llu, block_size is %llu\n",
> + (unsigned long long)data->file_size,
> + (unsigned long long)data->block_size);
> destroy_pq (data);
> grub_free (data);
> return err;
> }
>
> data->sock = grub_net_udp_open (addr,
> - TFTP_SERVER_PORT, tftp_receive,
> + port ? port : TFTP_SERVER_PORT, tftp_receive,
See above about zero ports.
> file);
> if (!data->sock)
> {
> diff --git a/include/grub/net.h b/include/grub/net.h
> index 2192fa1..ccc169c 100644
> --- a/include/grub/net.h
> +++ b/include/grub/net.h
> @@ -270,6 +270,7 @@ typedef struct grub_net
> {
> char *server;
> char *name;
> + int port;
> grub_net_app_level_t protocol;
> grub_net_packets_t packs;
> grub_off_t offset;
> --
> 2.6.6
>
>
> _______________________________________________
> Grub-devel mailing list
> Grub-devel@gnu.org
> https://lists.gnu.org/mailman/listinfo/grub-devel
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH 1/8] misc: fix invalid character recongition in strto*l
2016-08-03 6:34 ` [PATCH 1/8] misc: fix invalid character recongition in strto*l Michael Chang
@ 2016-08-10 15:51 ` Vladimir 'phcoder' Serbinenko
0 siblings, 0 replies; 11+ messages in thread
From: Vladimir 'phcoder' Serbinenko @ 2016-08-10 15:51 UTC (permalink / raw)
To: The development of GNU GRUB; +Cc: Ken Lin, Michael Chang
[-- Attachment #1: Type: text/plain, Size: 1504 bytes --]
Fixed, thank you for reporting. I also added a unit test for this. I didn't
use your solution and instead option for a more readable one
Le Wed, Aug 3, 2016 à 8:36 AM, Michael Chang <mchang@suse.com> a écrit :
> From: Aaron Miller <aaronmiller@fb.com>
>
> Would previously allow digits larger than the base and didn't check that
> subtracting the difference from 0-9 to lowercase letters for characters
> larger than 9 didn't result in a value lower than 9, which allowed the
> parses: ` = 9, _ = 8, ^ = 7, ] = 6, \ = 5, and [ = 4
> ---
> grub-core/kern/misc.c | 6 +++++-
> 1 file changed, 5 insertions(+), 1 deletion(-)
>
> diff --git a/grub-core/kern/misc.c b/grub-core/kern/misc.c
> index d1a54df..3a14d67 100644
> --- a/grub-core/kern/misc.c
> +++ b/grub-core/kern/misc.c
> @@ -394,9 +394,13 @@ grub_strtoull (const char *str, char **end, int base)
> if (digit > 9)
> {
> digit += '0' - 'a' + 10;
> - if (digit >= (unsigned long) base)
> + /* digit <= 9 check is needed to keep chars larger than
> + '9' but less than 'a' from being read as numbers */
> + if (digit >= (unsigned long) base || digit <= 9)
> break;
> }
> + if (digit >= (unsigned long) base)
> + break;
>
> found = 1;
>
> --
> 2.6.6
>
>
> _______________________________________________
> Grub-devel mailing list
> Grub-devel@gnu.org
> https://lists.gnu.org/mailman/listinfo/grub-devel
>
[-- Attachment #2: Type: text/html, Size: 2150 bytes --]
^ permalink raw reply [flat|nested] 11+ messages in thread
end of thread, other threads:[~2016-08-10 15:52 UTC | newest]
Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2016-08-03 6:34 Patches to support UEFI HTTP Boot IPv4 and IPv6 Michael Chang
2016-08-03 6:34 ` [PATCH 1/8] misc: fix invalid character recongition in strto*l Michael Chang
2016-08-10 15:51 ` Vladimir 'phcoder' Serbinenko
2016-08-03 6:34 ` [PATCH 2/8] net: read bracketed ipv6 addrs and port numbers Michael Chang
2016-08-03 8:17 ` Andrei Borzenkov
2016-08-03 6:34 ` [PATCH 3/8] bootp: New net_bootp6 command Michael Chang
2016-08-03 6:34 ` [PATCH 4/8] efinet: UEFI IPv6 PXE support Michael Chang
2016-08-03 6:34 ` [PATCH 5/8] grub.texi: Add net_bootp6 doument Michael Chang
2016-08-03 6:34 ` [PATCH 6/8] bootp: Add processing DHCPACK packet from HTTP Boot Michael Chang
2016-08-03 6:34 ` [PATCH 7/8] efinet: Setting network from UEFI device path Michael Chang
2016-08-03 6:34 ` [PATCH 8/8] efinet: Setting DNS server from UEFI protocol Michael Chang
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).