diff --git a/grub-core/net/bootp.c b/grub-core/net/bootp.c index b6076d89f..3902809a4 100644 --- a/grub-core/net/bootp.c +++ b/grub-core/net/bootp.c @@ -49,6 +49,8 @@ enum GRUB_DHCP_OPT_OVERLOAD_SNAME = 2, }; +#define GRUB_BOOTP_MAX_OPTIONS_SIZE 64 + static const void * find_dhcp_option (const struct grub_net_bootp_packet *bp, grub_size_t size, grub_uint8_t opt_code, grub_uint8_t *opt_len) @@ -340,6 +342,112 @@ grub_net_configure_by_dhcp_ack (const char *name, return inter; } +static grub_err_t +send_dhcp_packet (struct grub_net_network_level_interface *iface) +{ + grub_err_t err; + struct grub_net_bootp_packet *pack; + struct grub_datetime date; + grub_int32_t t = 0; + struct grub_net_buff *nb; + struct udphdr *udph; + grub_net_network_level_address_t target; + grub_net_link_level_address_t ll_target; + grub_uint8_t *offset; + + nb = grub_netbuff_alloc (sizeof (*pack) + sizeof(dhcp_option_header) + + sizeof(grub_userclass) + + sizeof(grub_dhcpdiscover) + + sizeof(grub_dhcptime) + + GRUB_BOOTP_MAX_OPTIONS_SIZE + 128); + if (!nb) + return grub_errno; + + err = grub_netbuff_reserve (nb, sizeof (*pack) + sizeof(dhcp_option_header) + + sizeof(grub_userclass) + + sizeof(grub_dhcpdiscover) + + sizeof(grub_dhcptime) + + GRUB_BOOTP_MAX_OPTIONS_SIZE + 128); + if (err) + goto out; + + err = grub_netbuff_push (nb, sizeof(dhcp_option_header) + + sizeof(grub_userclass) + + sizeof(grub_dhcpdiscover) + + sizeof(grub_dhcptime) + + GRUB_BOOTP_MAX_OPTIONS_SIZE); + if (err) + goto out; + + grub_memset (nb->data, 0, sizeof(dhcp_option_header) + + sizeof(grub_userclass) + + sizeof(grub_dhcpdiscover) + + sizeof(grub_dhcptime) + + GRUB_BOOTP_MAX_OPTIONS_SIZE); + + err = grub_netbuff_push (nb, sizeof (*pack)); + if (err) + goto out; + + pack = (void *) nb->data; + grub_memset (pack, 0, sizeof (*pack)); + pack->opcode = 1; + pack->hw_type = 1; + pack->hw_len = 6; + err = grub_get_datetime (&date); + if (err || !grub_datetime2unixtime (&date, &t)) + { + grub_errno = GRUB_ERR_NONE; + t = 0; + } + pack->seconds = grub_cpu_to_be16 (t); + pack->ident = grub_cpu_to_be32 (t); + + grub_memcpy (&pack->mac_addr, &iface->hwaddress.mac, 6); + offset = (grub_uint8_t *)&pack->vendor; + grub_memcpy (offset, dhcp_option_header, sizeof(dhcp_option_header)); + offset += sizeof(dhcp_option_header); + grub_memcpy (offset, grub_dhcpdiscover, sizeof(grub_dhcpdiscover)); + offset += sizeof(grub_dhcpdiscover); + grub_memcpy (offset, grub_userclass, sizeof(grub_userclass)); + offset += sizeof(grub_userclass); + grub_memcpy (offset, grub_dhcptime, sizeof(grub_dhcptime)); + + /* insert Client System Architecture (option 93) */ + offset += sizeof(grub_dhcptime); + offset[0] = 93; + offset[1] = 2; + offset[2] = (GRUB_NET_BOOTP_ARCH >> 8); + offset[3] = (GRUB_NET_BOOTP_ARCH & 0xFF); + + /* option terminator */ + offset[4] = 255; + + grub_netbuff_push (nb, sizeof (*udph)); + + udph = (struct udphdr *) nb->data; + udph->src = grub_cpu_to_be16_compile_time (68); + udph->dst = grub_cpu_to_be16_compile_time (67); + udph->chksum = 0; + udph->len = grub_cpu_to_be16 (nb->tail - nb->data); + target.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4; + target.ipv4 = 0xffffffff; + err = grub_net_link_layer_resolve (iface, &target, &ll_target); + if (err) + goto out; + + udph->chksum = grub_net_ip_transport_checksum (nb, GRUB_NET_IP_UDP, + &iface->address, + &target); + + err = grub_net_send_ip_packet (iface, &target, &ll_target, nb, + GRUB_NET_IP_UDP); + +out: + grub_netbuff_free (nb); + return err; +} + void grub_net_process_dhcp (struct grub_net_buff *nb, struct grub_net_card *card) @@ -496,6 +604,7 @@ grub_cmd_bootp (struct grub_command *cmd __attribute__ ((unused)), unsigned j = 0; int interval; grub_err_t err; + unsigned i; FOR_NET_CARDS (card) { @@ -524,7 +633,6 @@ grub_cmd_bootp (struct grub_command *cmd __attribute__ ((unused)), card->num_ifaces++; if (!ifaces[j].name) { - unsigned i; for (i = 0; i < j; i++) grub_free (ifaces[i].name); grub_free (ifaces); @@ -542,100 +650,21 @@ grub_cmd_bootp (struct grub_command *cmd __attribute__ ((unused)), ifaces[0].prev = &grub_net_network_level_interfaces; for (interval = 200; interval < 10000; interval *= 2) { - int done = 0; + int need_poll = 0; for (j = 0; j < ncards; j++) { - struct grub_net_bootp_packet *pack; - struct grub_datetime date; - grub_int32_t t = 0; - struct grub_net_buff *nb; - struct udphdr *udph; - grub_net_network_level_address_t target; - grub_net_link_level_address_t ll_target; - grub_uint8_t *offset; - if (!ifaces[j].prev) continue; - nb = grub_netbuff_alloc (sizeof (*pack) + sizeof(dhcp_option_header) - + sizeof(grub_userclass) - + sizeof(grub_dhcpdiscover) - + sizeof(grub_dhcptime) + 64 + 128); - if (!nb) - { - grub_netbuff_free (nb); - return grub_errno; - } - err = grub_netbuff_reserve (nb, sizeof (*pack) + 64 + 128); + + err = send_dhcp_packet (&ifaces[j]); if (err) { - grub_netbuff_free (nb); - return err; + grub_print_error (); + continue; } - err = grub_netbuff_push (nb, sizeof (*pack) + 64); - if (err) - { - grub_netbuff_free (nb); - return err; - } - pack = (void *) nb->data; - done = 1; - grub_memset (pack, 0, sizeof (*pack) + 64); - pack->opcode = 1; - pack->hw_type = 1; - pack->hw_len = 6; - err = grub_get_datetime (&date); - if (err || !grub_datetime2unixtime (&date, &t)) - { - grub_errno = GRUB_ERR_NONE; - t = 0; - } - pack->ident = grub_cpu_to_be32 (t); - pack->seconds = grub_cpu_to_be16 (t); - - grub_memcpy (&pack->mac_addr, &ifaces[j].hwaddress.mac, 6); - offset = (grub_uint8_t *)&pack->vendor; - grub_memcpy (offset, dhcp_option_header, sizeof(dhcp_option_header)); - offset += sizeof(dhcp_option_header); - grub_memcpy (offset, grub_dhcpdiscover, sizeof(grub_dhcpdiscover)); - offset += sizeof(grub_dhcpdiscover); - grub_memcpy (offset, grub_userclass, sizeof(grub_userclass)); - offset += sizeof(grub_userclass); - grub_memcpy (offset, grub_dhcptime, sizeof(grub_dhcptime)); - - /* insert Client System Architecture (option 93) */ - offset += sizeof(grub_dhcptime); - offset[0] = 93; - offset[1] = 2; - offset[2] = (GRUB_NET_BOOTP_ARCH >> 8); - offset[3] = (GRUB_NET_BOOTP_ARCH & 0xFF); - - /* option terminator */ - offset[4] = 255; - - grub_netbuff_push (nb, sizeof (*udph)); - - udph = (struct udphdr *) nb->data; - udph->src = grub_cpu_to_be16_compile_time (68); - udph->dst = grub_cpu_to_be16_compile_time (67); - udph->chksum = 0; - udph->len = grub_cpu_to_be16 (nb->tail - nb->data); - target.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4; - target.ipv4 = 0xffffffff; - err = grub_net_link_layer_resolve (&ifaces[j], &target, &ll_target); - if (err) - return err; - - udph->chksum = grub_net_ip_transport_checksum (nb, GRUB_NET_IP_UDP, - &ifaces[j].address, - &target); - - err = grub_net_send_ip_packet (&ifaces[j], &target, &ll_target, nb, - GRUB_NET_IP_UDP); - grub_netbuff_free (nb); - if (err) - return err; + need_poll = 1; } - if (!done) + if (!need_poll) break; grub_net_poll_cards (interval, 0); }