diff --git a/ChangeLog b/ChangeLog index e10dcd072..7c0bfb32c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,16 @@ +2012-06-20 Vladimir Serbinenko + + Respect netmask from bootp/dhcp. + + * grub-core/net/bootp.c (parse_dhcp_vendor): Parse mask. + (grub_net_configure_by_dhcp_ack): Use mask and grub_net_add_ipv4_local. + * grub-core/net/net.c (grub_net_add_addr): Split creating local route + into ... + (grub_net_add_ipv4_local): ... this. + (grub_cmd_addaddr): Use grub_net_add_ipv4_local. + * include/grub/net.h (GRUB_NET_BOOTP_NETMASK): New enum value. + (grub_net_add_ipv4_local): New proto. + 2012-06-20 Vladimir Serbinenko * grub-core/loader/i386/linux.c (grub_linux_boot): Setup video before diff --git a/grub-core/net/bootp.c b/grub-core/net/bootp.c index a303bb19c..04fdd57de 100644 --- a/grub-core/net/bootp.c +++ b/grub-core/net/bootp.c @@ -52,7 +52,7 @@ set_env_limn_ro (const char *intername, const char *suffix, } static void -parse_dhcp_vendor (const char *name, void *vend, int limit) +parse_dhcp_vendor (const char *name, void *vend, int limit, int *mask) { grub_uint8_t *ptr, *ptr0; @@ -83,6 +83,17 @@ parse_dhcp_vendor (const char *name, void *vend, int limit) switch (tagtype) { + case GRUB_NET_BOOTP_NETMASK: + if (taglength == 4) + { + int i; + for (i = 0; i < 32; i++) + if (!(ptr[i / 8] & (1 << (7 - (i % 8))))) + break; + *mask = i; + } + break; + case GRUB_NET_BOOTP_ROUTER: if (taglength == 4) { @@ -149,6 +160,7 @@ grub_net_configure_by_dhcp_ack (const char *name, grub_net_network_level_address_t addr; grub_net_link_level_address_t hwaddr; struct grub_net_network_level_interface *inter; + int mask = -1; addr.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4; addr.ipv4 = bp->your_ip; @@ -242,8 +254,9 @@ grub_net_configure_by_dhcp_ack (const char *name, } } if (size > OFFSET_OF (vendor, bp)) - parse_dhcp_vendor (name, &bp->vendor, 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); if (inter->dhcp_ack) { diff --git a/grub-core/net/net.c b/grub-core/net/net.c index 9f1afd1e7..924de2a7d 100644 --- a/grub-core/net/net.c +++ b/grub-core/net/net.c @@ -874,44 +874,53 @@ grub_net_add_addr (const char *name, grub_net_network_level_interface_register (inter); - if (addr->type == GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4) + return inter; +} + +grub_err_t +grub_net_add_ipv4_local (struct grub_net_network_level_interface *inter, + int mask) +{ + grub_uint32_t ip_cpu; + struct grub_net_route *route; + + if (inter->address.type != GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4) + return 0; + + ip_cpu = grub_be_to_cpu32 (inter->address.ipv4); + + if (mask == -1) { - int mask = -1; - grub_uint32_t ip_cpu = grub_be_to_cpu32 (addr->ipv4); if (!(ip_cpu & 0x80000000)) mask = 8; else if (!(ip_cpu & 0x40000000)) mask = 16; else if (!(ip_cpu & 0x20000000)) mask = 24; - else - mask = -1; - if (mask != -1) - { - struct grub_net_route *route; + } + if (mask == -1) + return 0; - route = grub_zalloc (sizeof (*route)); - if (!route) - return NULL; + route = grub_zalloc (sizeof (*route)); + if (!route) + return grub_errno; - route->name = grub_xasprintf ("%s:local", name); - if (!route->name) - { - grub_free (route); - return NULL; - } - - route->target.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4; - route->target.ipv4.base = grub_cpu_to_be32 (ip_cpu & (0xffffffff << (32 - mask))); - route->target.ipv4.masksize = mask; - route->is_gateway = 0; - route->interface = inter; - - grub_net_route_register (route); - } + route->name = grub_xasprintf ("%s:local", inter->name); + if (!route->name) + { + grub_free (route); + return grub_errno; } - return inter; + route->target.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4; + route->target.ipv4.base = grub_cpu_to_be32 (ip_cpu & (0xffffffff << (32 - mask))); + route->target.ipv4.masksize = mask; + route->is_gateway = 0; + route->interface = inter; + + grub_net_route_register (route); + + return 0; } /* FIXME: support MAC specifying. */ @@ -923,6 +932,7 @@ grub_cmd_addaddr (struct grub_command *cmd __attribute__ ((unused)), grub_net_network_level_address_t addr; grub_err_t err; grub_net_interface_flags_t flags = 0; + struct grub_net_network_level_interface *inf; if (argc != 3) return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("three arguments expected")); @@ -944,8 +954,11 @@ grub_cmd_addaddr (struct grub_command *cmd __attribute__ ((unused)), if (card->flags & GRUB_NET_CARD_HWADDRESS_IMMUTABLE) flags |= GRUB_NET_INTERFACE_HWADDRESS_IMMUTABLE; - grub_net_add_addr (args[0], card, &addr, &card->default_address, - flags); + inf = grub_net_add_addr (args[0], card, &addr, &card->default_address, + flags); + if (inf) + grub_net_add_ipv4_local (inf, -1); + return grub_errno; } diff --git a/include/grub/net.h b/include/grub/net.h index 859f81f15..1db05e806 100644 --- a/include/grub/net.h +++ b/include/grub/net.h @@ -409,6 +409,7 @@ struct grub_net_bootp_packet enum { GRUB_NET_BOOTP_PAD = 0x00, + GRUB_NET_BOOTP_NETMASK = 0x01, GRUB_NET_BOOTP_ROUTER = 0x03, GRUB_NET_BOOTP_DNS = 0x06, GRUB_NET_BOOTP_HOSTNAME = 0x0c, @@ -426,6 +427,10 @@ grub_net_configure_by_dhcp_ack (const char *name, 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); + void grub_net_process_dhcp (struct grub_net_buff *nb, struct grub_net_card *card);