net/dhcp: Refactor DHCP packet transmission into separate function
In contrast to BOOTP, DHCP uses a 4-way handshake, so requires to send packets more often. Refactor the generation and sending of the BOOTREQUEST packet into a separate function, so that future code can more easily reuse this. Signed-off-by: Andre Przywara <andre.przywara@arm.com> Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
This commit is contained in:
parent
6c0969eed5
commit
f8da4f6154
1 changed files with 116 additions and 87 deletions
|
@ -49,6 +49,8 @@ enum
|
||||||
GRUB_DHCP_OPT_OVERLOAD_SNAME = 2,
|
GRUB_DHCP_OPT_OVERLOAD_SNAME = 2,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define GRUB_BOOTP_MAX_OPTIONS_SIZE 64
|
||||||
|
|
||||||
static const void *
|
static const void *
|
||||||
find_dhcp_option (const struct grub_net_bootp_packet *bp, grub_size_t size,
|
find_dhcp_option (const struct grub_net_bootp_packet *bp, grub_size_t size,
|
||||||
grub_uint8_t opt_code, grub_uint8_t *opt_len)
|
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;
|
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
|
void
|
||||||
grub_net_process_dhcp (struct grub_net_buff *nb,
|
grub_net_process_dhcp (struct grub_net_buff *nb,
|
||||||
struct grub_net_card *card)
|
struct grub_net_card *card)
|
||||||
|
@ -496,6 +604,7 @@ grub_cmd_bootp (struct grub_command *cmd __attribute__ ((unused)),
|
||||||
unsigned j = 0;
|
unsigned j = 0;
|
||||||
int interval;
|
int interval;
|
||||||
grub_err_t err;
|
grub_err_t err;
|
||||||
|
unsigned i;
|
||||||
|
|
||||||
FOR_NET_CARDS (card)
|
FOR_NET_CARDS (card)
|
||||||
{
|
{
|
||||||
|
@ -524,7 +633,6 @@ grub_cmd_bootp (struct grub_command *cmd __attribute__ ((unused)),
|
||||||
card->num_ifaces++;
|
card->num_ifaces++;
|
||||||
if (!ifaces[j].name)
|
if (!ifaces[j].name)
|
||||||
{
|
{
|
||||||
unsigned i;
|
|
||||||
for (i = 0; i < j; i++)
|
for (i = 0; i < j; i++)
|
||||||
grub_free (ifaces[i].name);
|
grub_free (ifaces[i].name);
|
||||||
grub_free (ifaces);
|
grub_free (ifaces);
|
||||||
|
@ -542,100 +650,21 @@ grub_cmd_bootp (struct grub_command *cmd __attribute__ ((unused)),
|
||||||
ifaces[0].prev = &grub_net_network_level_interfaces;
|
ifaces[0].prev = &grub_net_network_level_interfaces;
|
||||||
for (interval = 200; interval < 10000; interval *= 2)
|
for (interval = 200; interval < 10000; interval *= 2)
|
||||||
{
|
{
|
||||||
int done = 0;
|
int need_poll = 0;
|
||||||
for (j = 0; j < ncards; j++)
|
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)
|
if (!ifaces[j].prev)
|
||||||
continue;
|
continue;
|
||||||
nb = grub_netbuff_alloc (sizeof (*pack) + sizeof(dhcp_option_header)
|
|
||||||
+ sizeof(grub_userclass)
|
err = send_dhcp_packet (&ifaces[j]);
|
||||||
+ 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);
|
|
||||||
if (err)
|
if (err)
|
||||||
{
|
{
|
||||||
grub_netbuff_free (nb);
|
grub_print_error ();
|
||||||
return err;
|
continue;
|
||||||
}
|
}
|
||||||
err = grub_netbuff_push (nb, sizeof (*pack) + 64);
|
need_poll = 1;
|
||||||
if (err)
|
|
||||||
{
|
|
||||||
grub_netbuff_free (nb);
|
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
pack = (void *) nb->data;
|
if (!need_poll)
|
||||||
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;
|
|
||||||
}
|
|
||||||
if (!done)
|
|
||||||
break;
|
break;
|
||||||
grub_net_poll_cards (interval, 0);
|
grub_net_poll_cards (interval, 0);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue