Move DHCP parsing to net module and reintroduce most variables

This commit is contained in:
Vladimir 'phcoder' Serbinenko 2010-09-02 22:10:55 +02:00
parent 0f37e49365
commit 308fad6dc8
4 changed files with 257 additions and 220 deletions

View file

@ -217,21 +217,15 @@ grub_cmd_deladdr (struct grub_command *cmd __attribute__ ((unused)),
return GRUB_ERR_NONE;
}
/*
Currently suppoerted adresses:
IPv4: XXX.XXX.XXX.XXX
*/
#define MAX_STR_ADDR_LEN sizeof ("XXX.XXX.XXX.XXX")
static void
addr_to_str (const grub_net_network_level_address_t *target, char *buf)
void
grub_net_addr_to_str (const grub_net_network_level_address_t *target, char *buf)
{
switch (target->type)
{
case GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4:
{
grub_uint32_t n = grub_be_to_cpu32 (target->ipv4);
grub_snprintf (buf, MAX_STR_ADDR_LEN, "%d.%d.%d.%d",
grub_snprintf (buf, GRUB_NET_MAX_STR_ADDR_LEN, "%d.%d.%d.%d",
((n >> 24) & 0xff), ((n >> 16) & 0xff),
((n >> 8) & 0xff), ((n >> 0) & 0xff));
}
@ -298,9 +292,9 @@ grub_net_network_level_interface_register (struct grub_net_network_level_interfa
}
{
char buf[MAX_STR_ADDR_LEN];
char buf[GRUB_NET_MAX_STR_ADDR_LEN];
char name[grub_strlen (inter->name) + sizeof ("net__ip")];
addr_to_str (&inter->address, buf);
grub_net_addr_to_str (&inter->address, buf);
grub_snprintf (name, sizeof (name), "net_%s_ip", inter->name);
grub_env_set (name, buf);
grub_register_variable_hook (name, 0, addr_set_env);
@ -327,6 +321,8 @@ grub_net_add_addr (const char *name, struct grub_net_card *card,
grub_memcpy (&(inter->hwaddress), &hwaddress, sizeof (inter->hwaddress));
inter->flags = flags;
inter->card = card;
inter->dhcp_ack = NULL;
inter->dhcp_acklen = 0;
grub_net_network_level_interface_register (inter);
@ -502,8 +498,8 @@ print_net_address (const grub_net_network_level_netaddress_t *target)
static void
print_address (const grub_net_network_level_address_t *target)
{
char buf[MAX_STR_ADDR_LEN];
addr_to_str (target, buf);
char buf[GRUB_NET_MAX_STR_ADDR_LEN];
grub_net_addr_to_str (target, buf);
grub_xputs (buf);
}
@ -576,6 +572,145 @@ grub_net_open_real (const char *name)
return NULL;
}
static char *
grub_env_write_readonly (struct grub_env_var *var __attribute__ ((unused)),
const char *val __attribute__ ((unused)))
{
return NULL;
}
static void
set_env_limn_ro (const char *intername, const char *suffix,
char *value, grub_size_t len)
{
char c;
char varname[sizeof ("net_") + grub_strlen (intername) + sizeof ("_")
+ grub_strlen (suffix)];
grub_snprintf (varname, sizeof (varname), "net_%s_%s", intername, suffix);
c = value[len];
value[len] = 0;
grub_env_set (varname, value);
value[len] = c;
grub_register_variable_hook (varname, 0, grub_env_write_readonly);
}
static void
parse_dhcp_vendor (const char *name, void *vend, int limit)
{
grub_uint8_t *ptr, *ptr0;
ptr = ptr0 = vend;
if (grub_be_to_cpu32 (*(grub_uint32_t *) ptr) != GRUB_NET_BOOTP_RFC1048_MAGIC)
return;
ptr = ptr + sizeof (grub_uint32_t);
while (ptr - ptr0 < limit)
{
grub_uint8_t tagtype;
grub_uint8_t taglength;
tagtype = *ptr++;
/* Pad tag. */
if (tagtype == 0)
continue;
/* End tag. */
if (tagtype == 0xff)
return;
taglength = *ptr++;
switch (tagtype)
{
case 12:
set_env_limn_ro (name, "hostname", (char *) ptr, taglength);
break;
case 15:
set_env_limn_ro (name, "domain", (char *) ptr, taglength);
break;
case 17:
set_env_limn_ro (name, "rootpath", (char *) ptr, taglength);
break;
case 18:
set_env_limn_ro (name, "extensionspath", (char *) ptr, taglength);
break;
/* If you need any other options please contact GRUB
developpement team. */
}
ptr += taglength;
}
}
#define OFFSET_OF(x, y) ((grub_uint8_t *)((y)->x) - (grub_uint8_t *)(y))
struct grub_net_network_level_interface *
grub_net_configure_by_dhcp_ack (const char *name, struct grub_net_card *card,
grub_net_interface_flags_t flags,
struct grub_net_bootp_ack *bp,
grub_size_t size)
{
grub_net_network_level_address_t addr;
grub_net_link_level_address_t hwaddr;
struct grub_net_network_level_interface *inter;
addr.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4;
addr.ipv4 = bp->your_ip;
grub_memcpy (hwaddr.mac, bp->mac_addr,
bp->hw_len < sizeof (hwaddr.mac) ? bp->hw_len
: sizeof (hwaddr.mac));
hwaddr.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET;
inter = grub_net_add_addr (name, card, addr, hwaddr, flags);
if (bp->gateway_ip != bp->server_ip)
{
grub_net_network_level_netaddress_t target;
grub_net_network_level_address_t gw;
char rname[grub_strlen (name) + sizeof ("_gw")];
target.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4;
target.ipv4.base = bp->server_ip;
target.ipv4.masksize = 32;
gw.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4;
gw.ipv4 = bp->gateway_ip;
grub_snprintf (rname, sizeof (rname), "%s_gw", name);
grub_net_add_route_gw (rname, target, gw);
}
{
grub_net_network_level_netaddress_t target;
target.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4;
target.ipv4.base = bp->gateway_ip;
target.ipv4.masksize = 32;
grub_net_add_route (name, target, inter);
}
if (size > OFFSET_OF (boot_file, bp))
set_env_limn_ro (name, "boot_file", (char *) bp->boot_file,
sizeof (bp->boot_file));
if (size > OFFSET_OF (server_name, bp))
set_env_limn_ro (name, "dhcp_server_name", (char *) bp->server_name,
sizeof (bp->server_name));
if (size > OFFSET_OF (vendor, bp))
parse_dhcp_vendor (name, &bp->vendor, size - OFFSET_OF (vendor, bp));
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;
return inter;
}
static grub_command_t cmd_addaddr, cmd_deladdr, cmd_addroute, cmd_delroute;
static grub_command_t cmd_lsroutes, cmd_lscards;

View file

@ -35,13 +35,13 @@
#define LINEAR(x) (void *) (((x >> 16) << 4) + (x & 0xFFFF))
struct grub_pxe_bangpxe *grub_pxe_pxenv;
static grub_uint32_t grub_pxe_your_ip;
static grub_uint32_t grub_pxe_default_server_ip;
#if 0
static grub_uint32_t grub_pxe_default_gateway_ip;
#endif
static unsigned grub_pxe_blksize = GRUB_PXE_MIN_BLKSIZE;
static grub_uint32_t pxe_rm_entry = 0;
static grub_file_t curr_file = 0;
static grub_net_link_level_address_t pxe_hwaddr;
struct grub_pxe_data
{
@ -52,7 +52,6 @@ struct grub_pxe_data
char filename[0];
};
static grub_uint32_t pxe_rm_entry = 0;
static struct grub_pxe_bangpxe *
grub_pxe_scan (void)
@ -316,112 +315,6 @@ static struct grub_fs grub_pxefs_fs =
.next = 0
};
static char *
grub_env_write_readonly (struct grub_env_var *var __attribute__ ((unused)),
const char *val __attribute__ ((unused)))
{
return NULL;
}
static void
set_env_limn_ro (const char *varname, char *value, grub_size_t len)
{
char c;
c = value[len];
value[len] = 0;
grub_env_set (varname, value);
value[len] = c;
grub_register_variable_hook (varname, 0, grub_env_write_readonly);
}
static void
parse_dhcp_vendor (void *vend, int limit)
{
grub_uint8_t *ptr, *ptr0;
ptr = ptr0 = vend;
if (grub_be_to_cpu32 (*(grub_uint32_t *) ptr) != 0x63825363)
return;
ptr = ptr + sizeof (grub_uint32_t);
while (ptr - ptr0 < limit)
{
grub_uint8_t tagtype;
grub_uint8_t taglength;
tagtype = *ptr++;
/* Pad tag. */
if (tagtype == 0)
continue;
/* End tag. */
if (tagtype == 0xff)
return;
taglength = *ptr++;
switch (tagtype)
{
case 12:
set_env_limn_ro ("net_pxe_hostname", (char *) ptr, taglength);
break;
case 15:
set_env_limn_ro ("net_pxe_domain", (char *) ptr, taglength);
break;
case 17:
set_env_limn_ro ("net_pxe_rootpath", (char *) ptr, taglength);
break;
case 18:
set_env_limn_ro ("net_pxe_extensionspath", (char *) ptr, taglength);
break;
/* If you need any other options please contact GRUB
developpement team. */
}
ptr += taglength;
}
}
static void
grub_pxe_detect (void)
{
struct grub_pxe_bangpxe *pxenv;
struct grub_pxenv_get_cached_info ci;
struct grub_pxenv_boot_player *bp;
pxenv = grub_pxe_scan ();
if (! pxenv)
return;
ci.packet_type = GRUB_PXENV_PACKET_TYPE_DHCP_ACK;
ci.buffer = 0;
ci.buffer_size = 0;
grub_pxe_call (GRUB_PXENV_GET_CACHED_INFO, &ci, pxe_rm_entry);
if (ci.status)
return;
bp = LINEAR (ci.buffer);
grub_pxe_your_ip = bp->your_ip;
grub_pxe_default_server_ip = bp->server_ip;
grub_pxe_default_gateway_ip = bp->gateway_ip;
grub_memcpy (pxe_hwaddr.mac, bp->mac_addr,
bp->hw_len < sizeof (pxe_hwaddr.mac)
? bp->hw_len : sizeof (pxe_hwaddr.mac));
pxe_hwaddr.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET;
set_env_limn_ro ("net_pxe_boot_file", (char *) bp->boot_file,
sizeof (bp->boot_file));
set_env_limn_ro ("net_pxe_dhcp_server_name", (char *) bp->server_name,
sizeof (bp->server_name));
parse_dhcp_vendor (&bp->vendor, sizeof (bp->vendor));
grub_pxe_pxenv = pxenv;
}
static grub_size_t
grub_pxe_recv (struct grub_net_card *dev __attribute__ ((unused)),
void *buf __attribute__ ((unused)),
@ -461,14 +354,15 @@ grub_pxe_unload (void)
}
}
#if 0
static void
set_ip_env (char *varname, grub_uint32_t ip)
{
char buf[sizeof ("XXX.XXX.XXX.XXX")];
char buf[GRUB_NET_MAX_STR_ADDR_LEN];
grub_net_network_level_address_t addr;
addr.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4;
addr.ipv4 = ip;
grub_snprintf (buf, sizeof (buf), "%d.%d.%d.%d", (ip & 0xff),
(ip >> 8) & 0xff, (ip >> 16) & 0xff, (ip >> 24) & 0xff);
grub_net_addr_to_str (&addr, buf);
grub_env_set (varname, buf);
}
@ -477,25 +371,25 @@ write_ip_env (grub_uint32_t *ip, const char *val)
{
char *buf;
grub_err_t err;
grub_uint32_t newip;
err = parse_ip (val, &newip, 0);
grub_net_network_level_address_t addr;
err = grub_net_resolve_address (val, &addr);
if (err)
return 0;
if (addr.type != GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4)
return NULL;
/* Normalize the IP. */
buf = grub_xasprintf ("%d.%d.%d.%d", (newip & 0xff), (newip >> 8) & 0xff,
(newip >> 16) & 0xff, (newip >> 24) & 0xff);
buf = grub_malloc (GRUB_NET_MAX_STR_ADDR_LEN);
if (!buf)
return 0;
grub_net_addr_to_str (&addr, buf);
*ip = newip;
*ip = addr.ipv4;
return buf;
}
#endif
#if 0
static char *
grub_env_write_pxe_default_server (struct grub_env_var *var
__attribute__ ((unused)),
@ -504,6 +398,7 @@ grub_env_write_pxe_default_server (struct grub_env_var *var
return write_ip_env (&grub_pxe_default_server_ip, val);
}
#if 0
static char *
grub_env_write_pxe_default_gateway (struct grub_env_var *var
__attribute__ ((unused)),
@ -540,60 +435,58 @@ grub_env_write_pxe_blocksize (struct grub_env_var *var __attribute__ ((unused)),
GRUB_MOD_INIT(pxe)
{
grub_pxe_detect ();
if (grub_pxe_pxenv)
{
char *buf;
grub_net_network_level_address_t addr;
struct grub_net_network_level_interface *inter;
#if 0
grub_register_variable_hook ("pxe_default_server", 0,
grub_env_write_pxe_default_server);
grub_register_variable_hook ("pxe_default_gateway", 0,
grub_env_write_pxe_default_gateway);
#endif
grub_register_variable_hook ("pxe_blksize", 0,
grub_env_write_pxe_blocksize);
struct grub_pxe_bangpxe *pxenv;
struct grub_pxenv_get_cached_info ci;
struct grub_net_bootp_ack *bp;
char *buf;
buf = grub_xasprintf ("%d", grub_pxe_blksize);
if (buf)
grub_env_set ("pxe_blksize", buf);
grub_free (buf);
pxenv = grub_pxe_scan ();
if (! pxenv)
return;
ci.packet_type = GRUB_PXENV_PACKET_TYPE_DHCP_ACK;
ci.buffer = 0;
ci.buffer_size = 0;
grub_pxe_call (GRUB_PXENV_GET_CACHED_INFO, &ci, pxe_rm_entry);
if (ci.status)
return;
bp = LINEAR (ci.buffer);
grub_pxe_default_server_ip = bp->server_ip;
grub_pxe_pxenv = pxenv;
set_ip_env ("pxe_default_server", grub_pxe_default_server_ip);
grub_register_variable_hook ("pxe_default_server", 0,
grub_env_write_pxe_default_server);
#if 0
set_ip_env ("pxe_default_server", grub_pxe_default_server_ip);
grub_pxe_default_gateway_ip = bp->gateway_ip;
grub_register_variable_hook ("pxe_default_gateway", 0,
grub_env_write_pxe_default_gateway);
#endif
grub_net_app_level_register (&grub_pxefs_fs);
grub_net_card_register (&grub_pxe_card);
addr.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4;
addr.ipv4 = grub_pxe_your_ip;
inter = grub_net_add_addr ("pxe", &grub_pxe_card, addr, pxe_hwaddr,
GRUB_NET_INTERFACE_PERMANENT
| GRUB_NET_INTERFACE_ADDRESS_IMMUTABLE
| GRUB_NET_INTERFACE_HWADDRESS_IMMUTABLE);
if (grub_pxe_default_gateway_ip != grub_pxe_default_server_ip)
{
grub_net_network_level_netaddress_t target;
grub_net_network_level_address_t gw;
target.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4;
target.ipv4.base = grub_pxe_default_server_ip;
target.ipv4.masksize = 32;
gw.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4;
gw.ipv4 = grub_pxe_default_gateway_ip;
grub_net_add_route_gw ("pxe_gw", target, gw);
}
{
grub_net_network_level_netaddress_t target;
target.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4;
target.ipv4.base = grub_pxe_default_gateway_ip ?
: grub_pxe_default_server_ip;
target.ipv4.masksize = 32;
grub_net_add_route ("pxe", target, inter);
}
}
buf = grub_xasprintf ("%d", grub_pxe_blksize);
if (buf)
grub_env_set ("pxe_blksize", buf);
grub_free (buf);
grub_register_variable_hook ("pxe_blksize", 0,
grub_env_write_pxe_blocksize);
grub_memcpy (grub_pxe_card.default_address.mac, bp->mac_addr,
bp->hw_len < sizeof (grub_pxe_card.default_address.mac)
? bp->hw_len : sizeof (grub_pxe_card.default_address.mac));
grub_pxe_card.default_address.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET;
grub_net_app_level_register (&grub_pxefs_fs);
grub_net_card_register (&grub_pxe_card);
grub_net_configure_by_dhcp_ack ("pxe", &grub_pxe_card,
GRUB_NET_INTERFACE_PERMANENT
| GRUB_NET_INTERFACE_ADDRESS_IMMUTABLE
| GRUB_NET_INTERFACE_HWADDRESS_IMMUTABLE,
bp, GRUB_PXE_BOOTP_SIZE);
}
GRUB_MOD_FINI(pxe)

View file

@ -152,9 +152,9 @@
#define GRUB_PXE_BOOTP_BCAST 0x8000
#if 1
#define GRUB_PXE_BOOTP_DHCPVEND 1024 /* DHCP extended vendor field size. */
#define GRUB_PXE_BOOTP_SIZE (1024 + 236) /* DHCP extended vendor field size. */
#else
#define GRUB_PXE_BOOTP_DHCPVEND 312 /* DHCP standard vendor field size. */
#define GRUB_PXE_BOOTP_SIZE (312 + 236) /* DHCP standard vendor field size. */
#endif
#define GRUB_PXE_MIN_BLKSIZE 512
@ -162,8 +162,6 @@
#define GRUB_PXE_TFTP_PORT 69
#define GRUB_PXE_VM_RFC1048 0x63825363L
#define GRUB_PXE_ERR_LEN 0xFFFFFFFF
#ifndef ASM_FILE
@ -214,38 +212,6 @@ struct grub_pxenv_get_cached_info
grub_uint16_t buffer_limit;
} __attribute__ ((packed));
#define GRUB_PXE_MAC_ADDR_LEN 16
typedef grub_uint8_t grub_pxe_mac_addr_t[GRUB_PXE_MAC_ADDR_LEN];
struct grub_pxenv_boot_player
{
grub_uint8_t opcode;
grub_uint8_t hw_type; /* hardware type. */
grub_uint8_t hw_len; /* hardware addr len. */
grub_uint8_t gate_hops; /* zero it. */
grub_uint32_t ident; /* random number chosen by client. */
grub_uint16_t seconds; /* seconds since did initial bootstrap. */
grub_uint16_t flags;
grub_uint32_t client_ip;
grub_uint32_t your_ip;
grub_uint32_t server_ip;
grub_uint32_t gateway_ip;
grub_pxe_mac_addr_t mac_addr;
grub_uint8_t server_name[64];
grub_uint8_t boot_file[128];
union
{
grub_uint8_t d[GRUB_PXE_BOOTP_DHCPVEND]; /* raw array of vendor/dhcp options. */
struct
{
grub_uint32_t magic; /* DHCP magic cookie. */
grub_uint32_t flags; /* bootp flags/opcodes. */
grub_uint8_t padding[56];
} v;
} vendor;
} __attribute__ ((packed));
struct grub_pxenv_tftp_open
{
grub_uint16_t status;

View file

@ -119,6 +119,8 @@ struct grub_net_network_level_interface
grub_net_network_level_address_t address;
grub_net_link_level_address_t hwaddress;
grub_net_interface_flags_t flags;
struct grub_net_bootp_ack *dhcp_ack;
grub_size_t dhcp_acklen;
void *data;
};
@ -234,4 +236,45 @@ grub_net_add_route_gw (const char *name,
grub_net_network_level_address_t gw);
#define GRUB_NET_BOOTP_MAC_ADDR_LEN 16
typedef grub_uint8_t grub_net_bootp_mac_addr_t[GRUB_NET_BOOTP_MAC_ADDR_LEN];
struct grub_net_bootp_ack
{
grub_uint8_t opcode;
grub_uint8_t hw_type; /* hardware type. */
grub_uint8_t hw_len; /* hardware addr len. */
grub_uint8_t gate_hops; /* zero it. */
grub_uint32_t ident; /* random number chosen by client. */
grub_uint16_t seconds; /* seconds since did initial bootstrap. */
grub_uint16_t flags;
grub_uint32_t client_ip;
grub_uint32_t your_ip;
grub_uint32_t server_ip;
grub_uint32_t gateway_ip;
grub_net_bootp_mac_addr_t mac_addr;
grub_uint8_t server_name[64];
grub_uint8_t boot_file[128];
grub_uint8_t vendor[0];
} __attribute__ ((packed));
#define GRUB_NET_BOOTP_RFC1048_MAGIC 0x63825363L
struct grub_net_network_level_interface *
grub_net_configure_by_dhcp_ack (const char *name, struct grub_net_card *card,
grub_net_interface_flags_t flags,
struct grub_net_bootp_ack *bp,
grub_size_t size);
/*
Currently suppoerted adresses:
IPv4: XXX.XXX.XXX.XXX
*/
#define GRUB_NET_MAX_STR_ADDR_LEN sizeof ("XXX.XXX.XXX.XXX")
void
grub_net_addr_to_str (const grub_net_network_level_address_t *target,
char *buf);
#endif /* ! GRUB_NET_HEADER */