2N/A/*
2N/A * GRUB -- GRand Unified Bootloader
2N/A * Copyright (C) 2010,2011 Free Software Foundation, Inc.
2N/A * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
2N/A *
2N/A * GRUB is free software: you can redistribute it and/or modify
2N/A * it under the terms of the GNU General Public License as published by
2N/A * the Free Software Foundation, either version 3 of the License, or
2N/A * (at your option) any later version.
2N/A *
2N/A * GRUB is distributed in the hope that it will be useful,
2N/A * but WITHOUT ANY WARRANTY; without even the implied warranty of
2N/A * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2N/A * GNU General Public License for more details.
2N/A *
2N/A * You should have received a copy of the GNU General Public License
2N/A * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
2N/A */
2N/A
2N/A#include <grub/net.h>
2N/A#include <grub/env.h>
2N/A#include <grub/i18n.h>
2N/A#include <grub/command.h>
2N/A#include <grub/net/ip.h>
2N/A#include <grub/net/netbuff.h>
2N/A#include <grub/net/udp.h>
2N/A#include <grub/datetime.h>
2N/A
2N/Astatic char *
2N/Agrub_env_write_readonly (struct grub_env_var *var __attribute__ ((unused)),
2N/A const char *val __attribute__ ((unused)))
2N/A{
2N/A return NULL;
2N/A}
2N/A
2N/Astatic void
2N/Aset_env_limn_ro (const char *intername, const char *suffix,
2N/A char *value, grub_size_t len)
2N/A{
2N/A char c;
2N/A char varname[sizeof ("net_") + grub_strlen (intername) + sizeof ("_")
2N/A + grub_strlen (suffix)];
2N/A grub_snprintf (varname, sizeof (varname), "net_%s_%s", intername, suffix);
2N/A c = value[len];
2N/A value[len] = 0;
2N/A grub_env_set (varname, value);
2N/A value[len] = c;
2N/A grub_register_variable_hook (varname, 0, grub_env_write_readonly);
2N/A}
2N/A
2N/Astatic void
2N/Aparse_dhcp_vendor_router_netmask (void *vend, int limit,
2N/A int *masksize, grub_uint32_t *router_ip)
2N/A{
2N/A grub_uint8_t *ptr, *ptr0;
2N/A
2N/A *masksize = -1;
2N/A *router_ip = 0;
2N/A
2N/A ptr = ptr0 = vend;
2N/A
2N/A if (ptr[0] != GRUB_NET_BOOTP_RFC1048_MAGIC_0
2N/A || ptr[1] != GRUB_NET_BOOTP_RFC1048_MAGIC_1
2N/A || ptr[2] != GRUB_NET_BOOTP_RFC1048_MAGIC_2
2N/A || ptr[3] != GRUB_NET_BOOTP_RFC1048_MAGIC_3)
2N/A return;
2N/A ptr = ptr + sizeof (grub_uint32_t);
2N/A while (ptr - ptr0 < limit)
2N/A {
2N/A grub_uint8_t tagtype;
2N/A grub_uint8_t taglength;
2N/A
2N/A tagtype = *ptr++;
2N/A
2N/A grub_dprintf("dhcp", "tagtype = 0x%x\n", tagtype);
2N/A
2N/A /* Pad tag. */
2N/A if (tagtype == GRUB_NET_BOOTP_PAD)
2N/A continue;
2N/A
2N/A /* End tag. */
2N/A if (tagtype == GRUB_NET_BOOTP_END)
2N/A return;
2N/A
2N/A taglength = *ptr++;
2N/A
2N/A switch (tagtype)
2N/A {
2N/A case GRUB_NET_BOOTP_NETMASK:
2N/A if (taglength == 4)
2N/A {
2N/A int i = 0;
2N/A grub_uint32_t invmask = ~grub_be_to_cpu32(*(grub_uint32_t *)ptr);
2N/A /* Calculate the mask size */
2N/A while (invmask)
2N/A {
2N/A invmask >>= 1;
2N/A i++;
2N/A }
2N/A *masksize = (32 - i);
2N/A }
2N/A break;
2N/A
2N/A case GRUB_NET_BOOTP_ROUTER:
2N/A if (taglength >= 4)
2N/A *router_ip = *(grub_uint32_t *)ptr;
2N/A
2N/A break;
2N/A
2N/A default: break;
2N/A }
2N/A
2N/A ptr += taglength;
2N/A }
2N/A}
2N/A
2N/Astatic void
2N/Aparse_dhcp_vendor (const char *name, void *vend, int limit)
2N/A{
2N/A grub_uint8_t *ptr, *ptr0;
2N/A
2N/A ptr = ptr0 = vend;
2N/A
2N/A if (ptr[0] != GRUB_NET_BOOTP_RFC1048_MAGIC_0
2N/A || ptr[1] != GRUB_NET_BOOTP_RFC1048_MAGIC_1
2N/A || ptr[2] != GRUB_NET_BOOTP_RFC1048_MAGIC_2
2N/A || ptr[3] != GRUB_NET_BOOTP_RFC1048_MAGIC_3)
2N/A return;
2N/A ptr = ptr + sizeof (grub_uint32_t);
2N/A while (ptr - ptr0 < limit)
2N/A {
2N/A grub_uint8_t tagtype;
2N/A grub_uint8_t taglength;
2N/A
2N/A tagtype = *ptr++;
2N/A
2N/A grub_dprintf("dhcp", "tagtype = 0x%x\n", tagtype);
2N/A
2N/A /* Pad tag. */
2N/A if (tagtype == GRUB_NET_BOOTP_PAD)
2N/A continue;
2N/A
2N/A /* End tag. */
2N/A if (tagtype == GRUB_NET_BOOTP_END)
2N/A return;
2N/A
2N/A taglength = *ptr++;
2N/A
2N/A grub_dprintf("dhcp", "taglength = 0x%x\n", taglength);
2N/A
2N/A switch (tagtype)
2N/A {
2N/A case GRUB_NET_BOOTP_NETMASK:
2N/A if (taglength == 4)
2N/A {
2N/A char *maskstr = grub_xasprintf ("%d.%d.%d.%d", ptr[0],
2N/A ptr[1], ptr[2], ptr[3]);
2N/A
2N/A set_env_limn_ro (name, "netmask", maskstr, grub_strlen(maskstr));
2N/A grub_free(maskstr);
2N/A }
2N/A break;
2N/A case GRUB_NET_BOOTP_ROUTER:
2N/A if (taglength >= 4)
2N/A {
2N/A grub_net_network_level_netaddress_t target;
2N/A grub_net_network_level_address_t gw;
2N/A char rname[grub_strlen (name) + sizeof (":default")];
2N/A
2N/A target.addr.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4;
2N/A target.addr.ipv4 = 0;
2N/A target.masksize = 0;
2N/A gw.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4;
2N/A grub_memcpy (&gw.ipv4, ptr, sizeof (gw.ipv4));
2N/A grub_snprintf (rname, sizeof (rname), "%s:default", name);
2N/A grub_net_add_route_gw (rname, target, gw);
2N/A }
2N/A break;
2N/A case GRUB_NET_BOOTP_DNS:
2N/A {
2N/A int i;
2N/A for (i = 0; i < taglength / 4; i++)
2N/A {
2N/A struct grub_net_network_level_address s;
2N/A s.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4;
2N/A s.ipv4 = grub_get_unaligned32 (ptr + (i * 4));
2N/A grub_net_add_dns_server (&s);
2N/A }
2N/A }
2N/A break;
2N/A case GRUB_NET_BOOTP_HOSTNAME:
2N/A set_env_limn_ro (name, "hostname", (char *) ptr, taglength);
2N/A break;
2N/A
2N/A case GRUB_NET_BOOTP_DOMAIN:
2N/A set_env_limn_ro (name, "domain", (char *) ptr, taglength);
2N/A break;
2N/A
2N/A case GRUB_NET_BOOTP_ROOT_PATH:
2N/A set_env_limn_ro (name, "rootpath", (char *) ptr, taglength);
2N/A break;
2N/A
2N/A case GRUB_NET_BOOTP_EXTENSIONS_PATH:
2N/A set_env_limn_ro (name, "extensionspath", (char *) ptr, taglength);
2N/A break;
2N/A
2N/A /* If you need any other options please contact GRUB
2N/A development team. */
2N/A }
2N/A
2N/A ptr += taglength;
2N/A }
2N/A}
2N/A
2N/A#define OFFSET_OF(x, y) ((grub_uint8_t *)((y)->x) - (grub_uint8_t *)(y))
2N/A
2N/Astruct grub_net_network_level_interface *
2N/Agrub_net_configure_by_dhcp_ack (const char *name,
2N/A struct grub_net_card *card,
2N/A grub_net_interface_flags_t flags,
2N/A const struct grub_net_bootp_packet *bp,
2N/A grub_size_t size,
2N/A int is_def, char **device, char **path)
2N/A{
2N/A grub_net_network_level_netaddress_t addr;
2N/A grub_uint32_t router_ip = 0;
2N/A grub_net_link_level_address_t hwaddr;
2N/A struct grub_net_network_level_interface *inter;
2N/A
2N/A addr.addr.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4;
2N/A addr.addr.ipv4 = bp->your_ip;
2N/A
2N/A if (size > OFFSET_OF (vendor, bp))
2N/A parse_dhcp_vendor_router_netmask(&bp->vendor,
2N/A size - OFFSET_OF (vendor, bp), &addr.masksize, &router_ip);
2N/A else
2N/A addr.masksize = -1;
2N/A
2N/A if (device)
2N/A *device = 0;
2N/A if (path)
2N/A *path = 0;
2N/A
2N/A grub_memcpy (hwaddr.mac, bp->mac_addr,
2N/A bp->hw_len < sizeof (hwaddr.mac) ? bp->hw_len
2N/A : sizeof (hwaddr.mac));
2N/A hwaddr.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET;
2N/A
2N/A inter = grub_net_add_addr (name, card, &addr, &hwaddr, flags);
2N/A if (! inter)
2N/A {
2N/A grub_print_error ();
2N/A return 0;
2N/A }
2N/A if (bp->gateway_ip)
2N/A {
2N/A grub_net_network_level_netaddress_t target;
2N/A grub_net_network_level_address_t gw;
2N/A char rname[grub_strlen (name) + sizeof (":gw")];
2N/A
2N/A target.addr.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4;
2N/A target.addr.ipv4 = bp->server_ip;
2N/A target.masksize = 32;
2N/A gw.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4;
2N/A gw.ipv4 = bp->gateway_ip;
2N/A grub_snprintf (rname, sizeof (rname), "%s:gw", name);
2N/A grub_net_add_route_gw (rname, target, gw);
2N/A }
2N/A if (bp->gateway_ip || bp->server_ip || router_ip)
2N/A {
2N/A grub_net_network_level_netaddress_t target;
2N/A target.addr.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4;
2N/A target.addr.ipv4 = bp->gateway_ip ? bp->gateway_ip :
2N/A (router_ip ? router_ip : bp->server_ip);
2N/A target.masksize = 32;
2N/A grub_net_add_route (name, target, inter);
2N/A }
2N/A
2N/A if (size > OFFSET_OF (boot_file, bp))
2N/A set_env_limn_ro (name, "boot_file", (char *) bp->boot_file,
2N/A sizeof (bp->boot_file));
2N/A if (is_def)
2N/A grub_net_default_server = 0;
2N/A
2N/A if (bp->server_ip)
2N/A {
2N/A grub_net_default_server = grub_xasprintf ("%d.%d.%d.%d",
2N/A ((grub_uint8_t *) &bp->server_ip)[0],
2N/A ((grub_uint8_t *) &bp->server_ip)[1],
2N/A ((grub_uint8_t *) &bp->server_ip)[2],
2N/A ((grub_uint8_t *) &bp->server_ip)[3]);
2N/A grub_print_error ();
2N/A
2N/A if (device && !*device)
2N/A {
2N/A *device = grub_xasprintf ("tftp,%d.%d.%d.%d",
2N/A ((grub_uint8_t *) &bp->server_ip)[0],
2N/A ((grub_uint8_t *) &bp->server_ip)[1],
2N/A ((grub_uint8_t *) &bp->server_ip)[2],
2N/A ((grub_uint8_t *) &bp->server_ip)[3]);
2N/A grub_print_error ();
2N/A }
2N/A }
2N/A
2N/A if (size > OFFSET_OF (server_name, bp) && bp->server_name[0])
2N/A {
2N/A set_env_limn_ro (name, "dhcp_server_name", (char *) bp->server_name,
2N/A sizeof (bp->server_name));
2N/A if (is_def && !grub_net_default_server)
2N/A {
2N/A grub_net_default_server = grub_strdup (bp->server_name);
2N/A grub_print_error ();
2N/A }
2N/A
2N/A if (device && !*device)
2N/A {
2N/A *device = grub_xasprintf ("tftp,%s", bp->server_name);
2N/A grub_print_error ();
2N/A }
2N/A }
2N/A if (size > OFFSET_OF (boot_file, bp) && path)
2N/A {
2N/A *path = grub_strndup (bp->boot_file, sizeof (bp->boot_file));
2N/A grub_print_error ();
2N/A if (*path)
2N/A {
2N/A char *slash;
2N/A slash = grub_strrchr (*path, '/');
2N/A if (slash)
2N/A *slash = 0;
2N/A else
2N/A **path = 0;
2N/A }
2N/A }
2N/A if (size > OFFSET_OF (vendor, bp))
2N/A parse_dhcp_vendor (name, &bp->vendor, size - OFFSET_OF (vendor, bp));
2N/A
2N/A inter->dhcp_ack = grub_malloc (size);
2N/A if (inter->dhcp_ack)
2N/A {
2N/A grub_memcpy (inter->dhcp_ack, bp, size);
2N/A inter->dhcp_acklen = size;
2N/A }
2N/A else
2N/A grub_errno = GRUB_ERR_NONE;
2N/A
2N/A return inter;
2N/A}
2N/A
2N/Avoid
2N/Agrub_net_process_dhcp (struct grub_net_buff *nb,
2N/A struct grub_net_card *card)
2N/A{
2N/A char *name;
2N/A struct grub_net_network_level_interface *inf;
2N/A
2N/A name = grub_xasprintf ("%s:dhcp", card->name);
2N/A if (!name)
2N/A {
2N/A grub_print_error ();
2N/A return;
2N/A }
2N/A grub_net_configure_by_dhcp_ack (name, card,
2N/A 0, (const struct grub_net_bootp_packet *) nb->data,
2N/A (nb->tail - nb->data), 0, 0, 0);
2N/A grub_free (name);
2N/A if (grub_errno)
2N/A grub_print_error ();
2N/A else
2N/A {
2N/A FOR_NET_NETWORK_LEVEL_INTERFACES(inf)
2N/A if (grub_memcmp (inf->name, card->name, grub_strlen (card->name)) == 0
2N/A && grub_memcmp (inf->name + grub_strlen (card->name),
2N/A ":dhcp_tmp", sizeof (":dhcp_tmp") - 1) == 0)
2N/A {
2N/A grub_net_network_level_interface_unregister (inf);
2N/A break;
2N/A }
2N/A }
2N/A}
2N/A
2N/Astatic char
2N/Ahexdigit (grub_uint8_t val)
2N/A{
2N/A if (val < 10)
2N/A return val + '0';
2N/A return val + 'a' - 10;
2N/A}
2N/A
2N/Astatic grub_err_t
2N/Agrub_cmd_dhcpopt (struct grub_command *cmd __attribute__ ((unused)),
2N/A int argc, char **args)
2N/A{
2N/A struct grub_net_network_level_interface *inter;
2N/A int num;
2N/A grub_uint8_t *ptr;
2N/A grub_uint8_t taglength;
2N/A
2N/A if (argc < 4)
2N/A return grub_error (GRUB_ERR_BAD_ARGUMENT, "4 arguments expected");
2N/A
2N/A FOR_NET_NETWORK_LEVEL_INTERFACES (inter)
2N/A if (grub_strcmp (inter->name, args[1]) == 0)
2N/A break;
2N/A
2N/A if (!inter)
2N/A return grub_error (GRUB_ERR_BAD_ARGUMENT,
2N/A N_("unrecognised interface %s"), args[1]);
2N/A
2N/A if (!inter->dhcp_ack)
2N/A return grub_error (GRUB_ERR_IO, N_("no DHCP info found"));
2N/A
2N/A if (inter->dhcp_acklen <= OFFSET_OF (vendor, inter->dhcp_ack))
2N/A return grub_error (GRUB_ERR_IO, N_("no DHCP options found"));
2N/A
2N/A num = grub_strtoul (args[2], 0, 0);
2N/A if (grub_errno)
2N/A return grub_errno;
2N/A
2N/A ptr = inter->dhcp_ack->vendor;
2N/A
2N/A if (ptr[0] != GRUB_NET_BOOTP_RFC1048_MAGIC_0
2N/A || ptr[1] != GRUB_NET_BOOTP_RFC1048_MAGIC_1
2N/A || ptr[2] != GRUB_NET_BOOTP_RFC1048_MAGIC_2
2N/A || ptr[3] != GRUB_NET_BOOTP_RFC1048_MAGIC_3)
2N/A return grub_error (GRUB_ERR_IO, N_("no DHCP options found"));
2N/A ptr = ptr + sizeof (grub_uint32_t);
2N/A while (1)
2N/A {
2N/A grub_uint8_t tagtype;
2N/A
2N/A if (ptr >= ((grub_uint8_t *) inter->dhcp_ack) + inter->dhcp_acklen)
2N/A return grub_error (GRUB_ERR_IO, N_("no DHCP option %d found"), num);
2N/A
2N/A tagtype = *ptr++;
2N/A
2N/A /* Pad tag. */
2N/A if (tagtype == 0)
2N/A continue;
2N/A
2N/A /* End tag. */
2N/A if (tagtype == 0xff)
2N/A return grub_error (GRUB_ERR_IO, N_("no DHCP option %d found"), num);
2N/A
2N/A taglength = *ptr++;
2N/A
2N/A if (tagtype == num)
2N/A break;
2N/A ptr += taglength;
2N/A }
2N/A
2N/A if (grub_strcmp (args[3], "string") == 0)
2N/A {
2N/A char *val = grub_malloc (taglength + 1);
2N/A if (!val)
2N/A return grub_errno;
2N/A grub_memcpy (val, ptr, taglength);
2N/A val[taglength] = 0;
2N/A if (args[0][0] == '-' && args[0][1] == 0)
2N/A grub_printf ("%s\n", val);
2N/A else
2N/A return grub_env_set (args[0], val);
2N/A return GRUB_ERR_NONE;
2N/A }
2N/A
2N/A if (grub_strcmp (args[3], "number") == 0)
2N/A {
2N/A grub_uint64_t val = 0;
2N/A int i;
2N/A for (i = 0; i < taglength; i++)
2N/A val = (val << 8) | ptr[i];
2N/A if (args[0][0] == '-' && args[0][1] == 0)
2N/A grub_printf ("%llu\n", (unsigned long long) val);
2N/A else
2N/A {
2N/A char valn[64];
2N/A grub_printf (valn, sizeof (valn), "%lld\n", (unsigned long long) val);
2N/A return grub_env_set (args[0], valn);
2N/A }
2N/A return GRUB_ERR_NONE;
2N/A }
2N/A
2N/A if (grub_strcmp (args[3], "hex") == 0)
2N/A {
2N/A char *val = grub_malloc (2 * taglength + 1);
2N/A int i;
2N/A if (!val)
2N/A return grub_errno;
2N/A for (i = 0; i < taglength; i++)
2N/A {
2N/A val[2 * i] = hexdigit (ptr[i] >> 4);
2N/A val[2 * i + 1] = hexdigit (ptr[i] & 0xf);
2N/A }
2N/A val[2 * taglength] = 0;
2N/A if (args[0][0] == '-' && args[0][1] == 0)
2N/A grub_printf ("%s\n", val);
2N/A else
2N/A return grub_env_set (args[0], val);
2N/A return GRUB_ERR_NONE;
2N/A }
2N/A
2N/A return grub_error (GRUB_ERR_BAD_ARGUMENT,
2N/A "unrecognised format specification %s", args[3]);
2N/A}
2N/A
2N/A/* FIXME: allow to specify mac address. */
2N/Astatic grub_err_t
2N/Agrub_cmd_bootp (struct grub_command *cmd __attribute__ ((unused)),
2N/A int argc, char **args)
2N/A{
2N/A struct grub_net_card *card;
2N/A struct grub_net_network_level_interface *ifaces;
2N/A grub_size_t ncards = 0;
2N/A unsigned j = 0;
2N/A int interval;
2N/A grub_err_t err;
2N/A
2N/A FOR_NET_CARDS (card)
2N/A {
2N/A if (argc > 0 && grub_strcmp (card->name, args[0]) != 0)
2N/A continue;
2N/A ncards++;
2N/A }
2N/A
2N/A ifaces = grub_zalloc (ncards * sizeof (ifaces[0]));
2N/A if (!ifaces)
2N/A return grub_errno;
2N/A
2N/A j = 0;
2N/A FOR_NET_CARDS (card)
2N/A {
2N/A if (argc > 0 && grub_strcmp (card->name, args[0]) != 0)
2N/A continue;
2N/A ifaces[j].card = card;
2N/A ifaces[j].next = &ifaces[j+1];
2N/A if (j)
2N/A ifaces[j].prev = &ifaces[j-1].next;
2N/A ifaces[j].name = grub_xasprintf ("%s:dhcp_tmp", card->name);
2N/A card->num_ifaces++;
2N/A if (!ifaces[j].name)
2N/A {
2N/A unsigned i;
2N/A for (i = 0; i < j; i++)
2N/A grub_free (ifaces[i].name);
2N/A grub_free (ifaces);
2N/A return grub_errno;
2N/A }
2N/A ifaces[j].address.addr.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_DHCP_RECV;
2N/A grub_memcpy (&ifaces[j].hwaddress, &card->default_address,
2N/A sizeof (ifaces[j].hwaddress));
2N/A j++;
2N/A }
2N/A ifaces[ncards - 1].next = grub_net_network_level_interfaces;
2N/A if (grub_net_network_level_interfaces)
2N/A grub_net_network_level_interfaces->prev = & ifaces[ncards - 1].next;
2N/A grub_net_network_level_interfaces = &ifaces[0];
2N/A ifaces[0].prev = &grub_net_network_level_interfaces;
2N/A for (interval = 200; interval < 10000; interval *= 2)
2N/A {
2N/A int done = 0;
2N/A for (j = 0; j < ncards; j++)
2N/A {
2N/A struct grub_net_bootp_packet *pack;
2N/A struct grub_datetime date;
2N/A grub_int32_t t;
2N/A struct grub_net_buff *nb;
2N/A struct udphdr *udph;
2N/A grub_net_network_level_address_t target;
2N/A grub_net_link_level_address_t ll_target;
2N/A
2N/A if (!ifaces[j].prev)
2N/A continue;
2N/A nb = grub_netbuff_alloc (sizeof (*pack));
2N/A if (!nb)
2N/A {
2N/A grub_netbuff_free (nb);
2N/A return grub_errno;
2N/A }
2N/A err = grub_netbuff_reserve (nb, sizeof (*pack) + 64 + 128);
2N/A if (err)
2N/A {
2N/A grub_netbuff_free (nb);
2N/A return err;
2N/A }
2N/A err = grub_netbuff_push (nb, sizeof (*pack) + 64);
2N/A if (err)
2N/A {
2N/A grub_netbuff_free (nb);
2N/A return err;
2N/A }
2N/A pack = (void *) nb->data;
2N/A done = 1;
2N/A grub_memset (pack, 0, sizeof (*pack) + 64);
2N/A pack->opcode = 1;
2N/A pack->hw_type = 1;
2N/A pack->hw_len = 6;
2N/A err = grub_get_datetime (&date);
2N/A if (err || !grub_datetime2unixtime (&date, &t))
2N/A {
2N/A grub_errno = GRUB_ERR_NONE;
2N/A t = 0;
2N/A }
2N/A pack->ident = grub_cpu_to_be32 (t);
2N/A pack->seconds = grub_cpu_to_be16 (t);
2N/A
2N/A grub_memcpy (&pack->mac_addr, &ifaces[j].hwaddress.mac, 6);
2N/A
2N/A grub_netbuff_push (nb, sizeof (*udph));
2N/A
2N/A udph = (struct udphdr *) nb->data;
2N/A udph->src = grub_cpu_to_be16 (68);
2N/A udph->dst = grub_cpu_to_be16 (67);
2N/A udph->chksum = 0;
2N/A udph->len = grub_cpu_to_be16 (nb->tail - nb->data);
2N/A target.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4;
2N/A target.ipv4 = 0xffffffff;
2N/A err = grub_net_link_layer_resolve (&ifaces[j], &target, &ll_target);
2N/A if (err)
2N/A return err;
2N/A
2N/A udph->chksum = grub_net_ip_transport_checksum (nb, GRUB_NET_IP_UDP,
2N/A &ifaces[j].address.addr,
2N/A &target);
2N/A
2N/A err = grub_net_send_ip_packet (&ifaces[j], &target, &ll_target, nb,
2N/A GRUB_NET_IP_UDP);
2N/A grub_netbuff_free (nb);
2N/A if (err)
2N/A return err;
2N/A }
2N/A if (!done)
2N/A break;
2N/A grub_net_poll_cards (interval);
2N/A }
2N/A
2N/A err = GRUB_ERR_NONE;
2N/A for (j = 0; j < ncards; j++)
2N/A {
2N/A grub_free (ifaces[j].name);
2N/A if (!ifaces[j].prev)
2N/A continue;
2N/A grub_error_push ();
2N/A grub_net_network_level_interface_unregister (&ifaces[j]);
2N/A err = grub_error (GRUB_ERR_FILE_NOT_FOUND, "couldn't configure %s",
2N/A ifaces[j].card->name);
2N/A }
2N/A
2N/A grub_free (ifaces);
2N/A return err;
2N/A}
2N/A
2N/Astatic grub_command_t cmd_getdhcp, cmd_bootp;
2N/A
2N/Avoid
2N/Agrub_bootp_init (void)
2N/A{
2N/A cmd_bootp = grub_register_command ("net_bootp", grub_cmd_bootp,
2N/A N_("[CARD]"),
2N/A N_("perform a bootp autoconfiguration"));
2N/A cmd_getdhcp = grub_register_command ("net_get_dhcp_option", grub_cmd_dhcpopt,
2N/A N_("VAR INTERFACE NUMBER DESCRIPTION"),
2N/A N_("retrieve DHCP option and save it into VAR. If VAR is - then print the value."));
2N/A}
2N/A
2N/Avoid
2N/Agrub_bootp_fini (void)
2N/A{
2N/A grub_unregister_command (cmd_getdhcp);
2N/A grub_unregister_command (cmd_bootp);
2N/A}