IPv6, TCP, HTTP, ICMP and DNS support. Several cleanups and bugfixes.
* grub-core/Makefile.core.def (net): Add net/dns.c, net/tcp.c, net/icmp.c and net/icmp6.c. (http): New module. (priority_queue): Likewise. * grub-core/io/bufio.c: Rewritten. * grub-core/lib/legacy_parse.c (legacy_command): New argument type TYPE_WITH_CONFIGFILE_OPTION. (legacy_commands): Add bootp and dhcp. (is_option): Handle TYPE_WITH_CONFIGFILE_OPTION. (grub_legacy_parse): Likewise. * grub-core/lib/priority_queue.c: New file. * grub-core/net/arp.c: Add missing license header. (arp_find_entry): Removed. (arp_find_entry): Likewise. (grub_net_arp_resolve): Rename to ... (grub_net_arp_send_request): ...this. (grub_net_arp_receive): New card argument. * grub-core/net/bootp.c (parse_dhcp_vendor): Clean up. Set router and DNS server. (grub_net_configure_by_dhcp_ack): Handle routing information. (grub_cmd_bootp): Set checksum. (grub_bootp_init): Remove net_dhcp. * grub-core/net/dns.c: New file. * grub-core/net/drivers/efi/efinet.c (send_card_buffer): Wait for completion. (get_card_packet): Handle allocation. (grub_efinet_findcards): Set mtu. * grub-core/net/drivers/emu/emunet.c: Add missing license header. (get_card_packet): Handle allocation. (emucard): Set mtu. * grub-core/net/drivers/i386/pc/pxe.c (grub_pxe_recv): Handle allocation (GRUB_MOD_INIT): Set mtu. * grub-core/net/drivers/ieee1275/ofnet.c (grub_ofnetcard_data): Remove mtu. (get_card_packet): Handle allocation. (grub_ofnet_findcards): Set mtu. * grub-core/net/ethernet.c (send_ethernet_packet): Add compile time assert. (grub_net_recv_ethernet_packet): Handle IPv6. * grub-core/net/http.c: New file. * grub-core/net/icmp.c: Likewise. * grub-core/net/icmp6.c: Likewise. * grub-core/net/ip.c (ip6addr): New type. (ip6hdr): Likewise. (reassemble): Likewise. (cmp): New function. (reassembles): New variable. (grub_net_ip_chksum): Handle 0xffff sum and unaligned buffers. (id): New variable. (send_fragmented): New function. (grub_net_send_ip_packet): Rename to ... (grub_net_send_ip4_packet): ... this. Send fragmented if needed. Handle non-UDP. (grub_net_recv_ip_packets): Rename to ... (handle_dgram): ... this. Check checksum. Handle non-UDP. (free_rsm): New function. (free_old_fragments): Likewise. (grub_net_recv_ip4_packets): New function. (grub_net_send_ip6_packet): Likewise. (grub_net_send_ip_packet): Likewise. (grub_net_recv_ip6_packets): Likewise. (grub_net_recv_ip_packets): Likewise. * grub-core/net/net.c (grub_net_link_layer_entry): New struct. (LINK_LAYER_CACHE_SIZE): New const. (link_layer_find_entry): New function. (grub_net_link_layer_add_address): Likewise. (grub_net_link_layer_resolve_check): Likewise. (grub_net_link_layer_resolve): Likewise. (grub_net_ipv6_get_slaac): Likewise. (grub_net_ipv6_get_link_local): Likewise. (grub_cmd_ipv6_autoconf): Likewise. (parse_ip): Handle one number representation. (parse_ip6): New functoion. (match_net): Handle IPv6. (grub_net_resolve_address): Handle IPv6 and DNS. (grub_net_resolve_net_address): Handle IPv6. (route_cmp): New function. (grub_net_route_address): Find best route. (grub_net_addr_to_str): Handle IPv6. (grub_net_addr_cmp): New function. (grub_net_add_addr): Register local route. (print_net_address): Handle net address. (grub_net_poll_cards): Retransmit TCP. (grub_net_poll_cards_idle_real): Likewise. (have_ahead): New function. (grub_net_seek_real): Use underlying seek. (GRUB_MOD_INIT): Register net_ipv6_autoconf and init dns. * grub-core/net/tcp.c: New file. * grub-core/net/tftp.c (tftp_data): Add priority_queue. (cmp): New function. (ack): Likewise. (tftp_receive): Handle unordered input. (destroy_pq): New function. (tftp_close): Close pq. * grub-core/net/udp.c: Put missing license header. (grub_net_udp_socket): New function. (udp_socket_register): Likewise. (grub_net_udp_close): Likewise. (grub_net_recv_udp_packet): Check checksum. * include/grub/efi/api.h (grub_efi_simple_network): Add status. * include/grub/misc.h (grub_memchr): New function. * include/grub/net.h (GRUB_NET_*_SIZE): New enum. (grub_net_card_driver): Return buf in recv. (grub_net_slaac_mac_list): New struct. (grub_network_level_protocol_id): Add ipv6. (grub_net_network_level_addr): Likewise. (grub_net_network_level_net_addr): Likewise. (grub_net_app_protocol): Add seek. (grub_net_socket): Removed. (grub_net_sockets): Likewise. (grub_net_socket_register): Likewise. (grub_net_socket_unregister): Likewise. (FOR_NET_SOCKETS): Likewise. (grub_net_add_addr): Add const. (GRUB_NET_BOOTP_*): New enum. (grub_net_addr_cmp): New proto. (GRUB_NET_MAX_STR_ADDR_LEN): Take IPV6 into account. (GRUB_NET_MAX_STR_HWADDR_LEN): New define. (grub_net_hwaddr_to_str): NEw proto. (FOR_NET_NETWORK_LEVEL_INTERFACES): New macro. (FOR_NET_NETWORK_LEVEL_INTERFACES_SAFE): Handle NULL. (grub_dns_init): New proto. (grub_dns_fini): Likewise. (grub_net_tcp_retransmit): Likewise. (grub_net_link_layer_add_address): Likewise. (grub_net_link_layer_resolve_check): Likewise. (grub_net_link_layer_resolve): Likewise. (grub_net_dns_lookup): Likewise. (grub_net_add_dns_server): Likewise. (grub_net_remove_dns_server): Likewise. (GRUB_NET_TRIES): New const. (GRUB_NET_INTERVAL): Likewise. * include/grub/net/arp.h: Mostly rewritten. * include/grub/net/ethernet.h (grub_net_ethertype_t): New enum. * include/grub/net/ip.h: Mostly rewritten. * include/grub/net/netbuff.h: Indent. * include/grub/net/tcp.h: New file. * include/grub/net/udp.h: Mostly rewritten. * include/grub/priority_queue.h: New file. * include/grub/types.h (PRIdGRUB_SSIZE): New define. (grub_swap_bytes64_compile_time): Likewise. (grub_cpu_to_be16_compile_time): Likewise. (grub_cpu_to_be32_compile_time): Likewise. (grub_cpu_to_be64_compile_time): Likewise. (grub_be_to_cpu64_compile_time): Likewise.
This commit is contained in:
commit
198e150aaf
34 changed files with 5588 additions and 617 deletions
150
ChangeLog
150
ChangeLog
|
@ -1,3 +1,153 @@
|
|||
2011-12-20 Vladimir Serbinenko <phcoder@gmail.com>
|
||||
|
||||
IPv6, TCP, HTTP, ICMP and DNS support. Several cleanups and bugfixes.
|
||||
|
||||
* grub-core/Makefile.core.def (net): Add net/dns.c, net/tcp.c,
|
||||
net/icmp.c and net/icmp6.c.
|
||||
(http): New module.
|
||||
(priority_queue): Likewise.
|
||||
* grub-core/io/bufio.c: Rewritten.
|
||||
* grub-core/lib/legacy_parse.c (legacy_command): New argument type
|
||||
TYPE_WITH_CONFIGFILE_OPTION.
|
||||
(legacy_commands): Add bootp and dhcp.
|
||||
(is_option): Handle TYPE_WITH_CONFIGFILE_OPTION.
|
||||
(grub_legacy_parse): Likewise.
|
||||
* grub-core/lib/priority_queue.c: New file.
|
||||
* grub-core/net/arp.c: Add missing license header.
|
||||
(arp_find_entry): Removed.
|
||||
(arp_find_entry): Likewise.
|
||||
(grub_net_arp_resolve): Rename to ...
|
||||
(grub_net_arp_send_request): ...this.
|
||||
(grub_net_arp_receive): New card argument.
|
||||
* grub-core/net/bootp.c (parse_dhcp_vendor): Clean up.
|
||||
Set router and DNS server.
|
||||
(grub_net_configure_by_dhcp_ack): Handle routing information.
|
||||
(grub_cmd_bootp): Set checksum.
|
||||
(grub_bootp_init): Remove net_dhcp.
|
||||
* grub-core/net/dns.c: New file.
|
||||
* grub-core/net/drivers/efi/efinet.c (send_card_buffer): Wait for
|
||||
completion.
|
||||
(get_card_packet): Handle allocation.
|
||||
(grub_efinet_findcards): Set mtu.
|
||||
* grub-core/net/drivers/emu/emunet.c: Add missing license header.
|
||||
(get_card_packet): Handle allocation.
|
||||
(emucard): Set mtu.
|
||||
* grub-core/net/drivers/i386/pc/pxe.c (grub_pxe_recv): Handle allocation
|
||||
(GRUB_MOD_INIT): Set mtu.
|
||||
* grub-core/net/drivers/ieee1275/ofnet.c (grub_ofnetcard_data): Remove
|
||||
mtu.
|
||||
(get_card_packet): Handle allocation.
|
||||
(grub_ofnet_findcards): Set mtu.
|
||||
* grub-core/net/ethernet.c (send_ethernet_packet): Add compile time
|
||||
assert.
|
||||
(grub_net_recv_ethernet_packet): Handle IPv6.
|
||||
* grub-core/net/http.c: New file.
|
||||
* grub-core/net/icmp.c: Likewise.
|
||||
* grub-core/net/icmp6.c: Likewise.
|
||||
* grub-core/net/ip.c (ip6addr): New type.
|
||||
(ip6hdr): Likewise.
|
||||
(reassemble): Likewise.
|
||||
(cmp): New function.
|
||||
(reassembles): New variable.
|
||||
(grub_net_ip_chksum): Handle 0xffff sum and unaligned buffers.
|
||||
(id): New variable.
|
||||
(send_fragmented): New function.
|
||||
(grub_net_send_ip_packet): Rename to ...
|
||||
(grub_net_send_ip4_packet): ... this. Send fragmented if needed.
|
||||
Handle non-UDP.
|
||||
(grub_net_recv_ip_packets): Rename to ...
|
||||
(handle_dgram): ... this. Check checksum. Handle non-UDP.
|
||||
(free_rsm): New function.
|
||||
(free_old_fragments): Likewise.
|
||||
(grub_net_recv_ip4_packets): New function.
|
||||
(grub_net_send_ip6_packet): Likewise.
|
||||
(grub_net_send_ip_packet): Likewise.
|
||||
(grub_net_recv_ip6_packets): Likewise.
|
||||
(grub_net_recv_ip_packets): Likewise.
|
||||
* grub-core/net/net.c (grub_net_link_layer_entry): New struct.
|
||||
(LINK_LAYER_CACHE_SIZE): New const.
|
||||
(link_layer_find_entry): New function.
|
||||
(grub_net_link_layer_add_address): Likewise.
|
||||
(grub_net_link_layer_resolve_check): Likewise.
|
||||
(grub_net_link_layer_resolve): Likewise.
|
||||
(grub_net_ipv6_get_slaac): Likewise.
|
||||
(grub_net_ipv6_get_link_local): Likewise.
|
||||
(grub_cmd_ipv6_autoconf): Likewise.
|
||||
(parse_ip): Handle one number representation.
|
||||
(parse_ip6): New functoion.
|
||||
(match_net): Handle IPv6.
|
||||
(grub_net_resolve_address): Handle IPv6 and DNS.
|
||||
(grub_net_resolve_net_address): Handle IPv6.
|
||||
(route_cmp): New function.
|
||||
(grub_net_route_address): Find best route.
|
||||
(grub_net_addr_to_str): Handle IPv6.
|
||||
(grub_net_addr_cmp): New function.
|
||||
(grub_net_add_addr): Register local route.
|
||||
(print_net_address): Handle net address.
|
||||
(grub_net_poll_cards): Retransmit TCP.
|
||||
(grub_net_poll_cards_idle_real): Likewise.
|
||||
(have_ahead): New function.
|
||||
(grub_net_seek_real): Use underlying seek.
|
||||
(GRUB_MOD_INIT): Register net_ipv6_autoconf and init dns.
|
||||
* grub-core/net/tcp.c: New file.
|
||||
* grub-core/net/tftp.c (tftp_data): Add priority_queue.
|
||||
(cmp): New function.
|
||||
(ack): Likewise.
|
||||
(tftp_receive): Handle unordered input.
|
||||
(destroy_pq): New function.
|
||||
(tftp_close): Close pq.
|
||||
* grub-core/net/udp.c: Put missing license header.
|
||||
(grub_net_udp_socket): New function.
|
||||
(udp_socket_register): Likewise.
|
||||
(grub_net_udp_close): Likewise.
|
||||
(grub_net_recv_udp_packet): Check checksum.
|
||||
* include/grub/efi/api.h (grub_efi_simple_network): Add status.
|
||||
* include/grub/misc.h (grub_memchr): New function.
|
||||
* include/grub/net.h (GRUB_NET_*_SIZE): New enum.
|
||||
(grub_net_card_driver): Return buf in recv.
|
||||
(grub_net_slaac_mac_list): New struct.
|
||||
(grub_network_level_protocol_id): Add ipv6.
|
||||
(grub_net_network_level_addr): Likewise.
|
||||
(grub_net_network_level_net_addr): Likewise.
|
||||
(grub_net_app_protocol): Add seek.
|
||||
(grub_net_socket): Removed.
|
||||
(grub_net_sockets): Likewise.
|
||||
(grub_net_socket_register): Likewise.
|
||||
(grub_net_socket_unregister): Likewise.
|
||||
(FOR_NET_SOCKETS): Likewise.
|
||||
(grub_net_add_addr): Add const.
|
||||
(GRUB_NET_BOOTP_*): New enum.
|
||||
(grub_net_addr_cmp): New proto.
|
||||
(GRUB_NET_MAX_STR_ADDR_LEN): Take IPV6 into account.
|
||||
(GRUB_NET_MAX_STR_HWADDR_LEN): New define.
|
||||
(grub_net_hwaddr_to_str): NEw proto.
|
||||
(FOR_NET_NETWORK_LEVEL_INTERFACES): New macro.
|
||||
(FOR_NET_NETWORK_LEVEL_INTERFACES_SAFE): Handle NULL.
|
||||
(grub_dns_init): New proto.
|
||||
(grub_dns_fini): Likewise.
|
||||
(grub_net_tcp_retransmit): Likewise.
|
||||
(grub_net_link_layer_add_address): Likewise.
|
||||
(grub_net_link_layer_resolve_check): Likewise.
|
||||
(grub_net_link_layer_resolve): Likewise.
|
||||
(grub_net_dns_lookup): Likewise.
|
||||
(grub_net_add_dns_server): Likewise.
|
||||
(grub_net_remove_dns_server): Likewise.
|
||||
(GRUB_NET_TRIES): New const.
|
||||
(GRUB_NET_INTERVAL): Likewise.
|
||||
* include/grub/net/arp.h: Mostly rewritten.
|
||||
* include/grub/net/ethernet.h (grub_net_ethertype_t): New enum.
|
||||
* include/grub/net/ip.h: Mostly rewritten.
|
||||
* include/grub/net/netbuff.h: Indent.
|
||||
* include/grub/net/tcp.h: New file.
|
||||
* include/grub/net/udp.h: Mostly rewritten.
|
||||
* include/grub/priority_queue.h: New file.
|
||||
* include/grub/types.h (PRIdGRUB_SSIZE): New define.
|
||||
(grub_swap_bytes64_compile_time): Likewise.
|
||||
(grub_cpu_to_be16_compile_time): Likewise.
|
||||
(grub_cpu_to_be32_compile_time): Likewise.
|
||||
(grub_cpu_to_be64_compile_time): Likewise.
|
||||
(grub_be_to_cpu64_compile_time): Likewise.
|
||||
|
||||
2011-12-16 Vladimir Serbinenko <phcoder@gmail.com>
|
||||
|
||||
* grub-core/commands/i386/pc/drivemap.c (int13slot): Replace
|
||||
|
|
|
@ -1642,9 +1642,13 @@ module = {
|
|||
module = {
|
||||
name = net;
|
||||
common = net/net.c;
|
||||
common = net/dns.c;
|
||||
common = net/bootp.c;
|
||||
common = net/ip.c;
|
||||
common = net/udp.c;
|
||||
common = net/tcp.c;
|
||||
common = net/icmp.c;
|
||||
common = net/icmp6.c;
|
||||
common = net/ethernet.c;
|
||||
common = net/arp.c;
|
||||
common = net/netbuff.c;
|
||||
|
@ -1655,6 +1659,11 @@ module = {
|
|||
common = net/tftp.c;
|
||||
};
|
||||
|
||||
module = {
|
||||
name = http;
|
||||
common = net/http.c;
|
||||
};
|
||||
|
||||
module = {
|
||||
name = ofnet;
|
||||
common = net/drivers/ieee1275/ofnet.c;
|
||||
|
@ -1721,6 +1730,11 @@ module = {
|
|||
enable = videomodules;
|
||||
};
|
||||
|
||||
module = {
|
||||
name = priority_queue;
|
||||
common = lib/priority_queue.c;
|
||||
};
|
||||
|
||||
module = {
|
||||
name = time;
|
||||
common = commands/time.c;
|
||||
|
|
|
@ -35,6 +35,7 @@ struct grub_bufio
|
|||
grub_file_t file;
|
||||
grub_size_t block_size;
|
||||
grub_size_t buffer_len;
|
||||
grub_off_t buffer_at;
|
||||
char buffer[0];
|
||||
};
|
||||
typedef struct grub_bufio *grub_bufio_t;
|
||||
|
@ -70,6 +71,7 @@ grub_bufio_open (grub_file_t io, int size)
|
|||
bufio->file = io;
|
||||
bufio->block_size = size;
|
||||
bufio->buffer_len = 0;
|
||||
bufio->buffer_at = 0;
|
||||
|
||||
file->device = io->device;
|
||||
file->offset = 0;
|
||||
|
@ -104,82 +106,86 @@ grub_buffile_open (const char *name, int size)
|
|||
static grub_ssize_t
|
||||
grub_bufio_read (grub_file_t file, char *buf, grub_size_t len)
|
||||
{
|
||||
grub_size_t res = len;
|
||||
grub_size_t res = 0;
|
||||
grub_bufio_t bufio = file->data;
|
||||
grub_uint64_t pos;
|
||||
|
||||
if ((file->offset >= bufio->file->offset) &&
|
||||
(file->offset < bufio->file->offset + bufio->buffer_len))
|
||||
if (file->size == GRUB_FILE_SIZE_UNKNOWN)
|
||||
file->size = bufio->file->size;
|
||||
|
||||
/* First part: use whatever we already have in the buffer. */
|
||||
if ((file->offset >= bufio->buffer_at) &&
|
||||
(file->offset < bufio->buffer_at + bufio->buffer_len))
|
||||
{
|
||||
grub_size_t n;
|
||||
grub_uint64_t pos;
|
||||
|
||||
pos = file->offset - bufio->file->offset;
|
||||
pos = file->offset - bufio->buffer_at;
|
||||
n = bufio->buffer_len - pos;
|
||||
if (n > len)
|
||||
n = len;
|
||||
|
||||
grub_memcpy (buf, &bufio->buffer[pos], n);
|
||||
len -= n;
|
||||
res += n;
|
||||
|
||||
buf += n;
|
||||
}
|
||||
if (! len)
|
||||
return res;
|
||||
|
||||
buf += n;
|
||||
bufio->file->offset += bufio->buffer_len;
|
||||
pos = 0;
|
||||
}
|
||||
else
|
||||
/* Need to read some more. */
|
||||
bufio->buffer_at = grub_divmod64 (file->offset + res + len, bufio->block_size,
|
||||
0) * bufio->block_size;
|
||||
|
||||
/* Now read between file->offset + res and bufio->buffer_at. */
|
||||
if (file->offset + res < bufio->buffer_at)
|
||||
{
|
||||
bufio->file->offset = grub_divmod64 (file->offset, bufio->block_size,
|
||||
&pos);
|
||||
bufio->file->offset *= bufio->block_size;
|
||||
grub_size_t read_now;
|
||||
grub_ssize_t really_read;
|
||||
read_now = bufio->buffer_at - (file->offset + res);
|
||||
grub_file_seek (bufio->file, file->offset + res);
|
||||
really_read = grub_file_read (bufio->file, buf, read_now);
|
||||
if (grub_errno)
|
||||
return -1;
|
||||
if (file->size == GRUB_FILE_SIZE_UNKNOWN)
|
||||
file->size = bufio->file->size;
|
||||
len -= really_read;
|
||||
buf += really_read;
|
||||
res += really_read;
|
||||
|
||||
/* Partial read. File ended unexpectedly. Save the last chunk in buffer.
|
||||
*/
|
||||
if (really_read != (grub_ssize_t) read_now)
|
||||
{
|
||||
bufio->buffer_len = really_read;
|
||||
if (bufio->buffer_len > bufio->block_size)
|
||||
bufio->buffer_len = bufio->block_size;
|
||||
bufio->buffer_at = file->offset + res - bufio->buffer_len;
|
||||
grub_memcpy (&bufio->buffer[0], buf - bufio->buffer_len,
|
||||
bufio->buffer_len);
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
if (pos + len >= bufio->block_size)
|
||||
{
|
||||
if (pos)
|
||||
{
|
||||
grub_size_t n;
|
||||
|
||||
bufio->file->fs->read (bufio->file, bufio->buffer,
|
||||
/* Read into buffer. */
|
||||
grub_file_seek (bufio->file, bufio->buffer_at);
|
||||
bufio->buffer_len = grub_file_read (bufio->file, bufio->buffer,
|
||||
bufio->block_size);
|
||||
if (grub_errno)
|
||||
return -1;
|
||||
if (file->size == GRUB_FILE_SIZE_UNKNOWN)
|
||||
file->size = bufio->file->size;
|
||||
|
||||
n = bufio->block_size - pos;
|
||||
grub_memcpy (buf, &bufio->buffer[pos], n);
|
||||
len -= n;
|
||||
buf += n;
|
||||
bufio->file->offset += bufio->block_size;
|
||||
pos = 0;
|
||||
}
|
||||
|
||||
while (len >= bufio->block_size)
|
||||
if (len < bufio->buffer_len)
|
||||
{
|
||||
bufio->file->fs->read (bufio->file, buf, bufio->block_size);
|
||||
if (grub_errno)
|
||||
return -1;
|
||||
|
||||
len -= bufio->block_size;
|
||||
buf += bufio->block_size;
|
||||
bufio->file->offset += bufio->block_size;
|
||||
grub_memcpy (buf, &bufio->buffer[0], len);
|
||||
res += len;
|
||||
}
|
||||
|
||||
if (! len)
|
||||
else
|
||||
{
|
||||
bufio->buffer_len = 0;
|
||||
return res;
|
||||
grub_memcpy (buf, &bufio->buffer[0], bufio->buffer_len);
|
||||
res += bufio->buffer_len;
|
||||
}
|
||||
}
|
||||
|
||||
bufio->buffer_len = bufio->file->size - bufio->file->offset;
|
||||
if (bufio->buffer_len > bufio->block_size)
|
||||
bufio->buffer_len = bufio->block_size;
|
||||
|
||||
bufio->file->fs->read (bufio->file, bufio->buffer, bufio->buffer_len);
|
||||
if (grub_errno)
|
||||
return -1;
|
||||
|
||||
grub_memcpy (buf, &bufio->buffer[pos], len);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
|
|
@ -42,7 +42,8 @@ struct legacy_command
|
|||
TYPE_BOOL,
|
||||
TYPE_INT,
|
||||
TYPE_REST_VERBATIM,
|
||||
TYPE_VBE_MODE
|
||||
TYPE_VBE_MODE,
|
||||
TYPE_WITH_CONFIGFILE_OPTION
|
||||
} argt[4];
|
||||
enum {
|
||||
FLAG_IGNORE_REST = 0x001,
|
||||
|
@ -67,7 +68,13 @@ static struct legacy_command legacy_commands[] =
|
|||
"Print the blocklist notation of the file FILE."},
|
||||
{"boot", "boot\n", NULL, 0, 0, {}, 0, 0,
|
||||
"Boot the OS/chain-loader which has been loaded."},
|
||||
/* FIXME: bootp unsupported. */
|
||||
{"bootp", "net_bootp; net_ls_addr; if [ x%s = x--with-configfile ]; then "
|
||||
"if net_get_dhcp_option configfile_name pxe 150 string; then "
|
||||
"configfile $configfile_name; fi; fi\n", NULL, 0, 1,
|
||||
{TYPE_WITH_CONFIGFILE_OPTION}, FLAG_IGNORE_REST, "[--with-configfile]",
|
||||
"Initialize a network device via BOOTP. If the option `--with-configfile'"
|
||||
" is given, try to load a configuration file specified by the 150 vendor"
|
||||
" tag."},
|
||||
{"cat", "cat '%s'\n", NULL, 0, 1, {TYPE_FILE}, 0, "FILE",
|
||||
"Print the contents of the file FILE."},
|
||||
{"chainloader", "chainloader %s '%s'\n", NULL, 0,
|
||||
|
@ -105,7 +112,13 @@ static struct legacy_command legacy_commands[] =
|
|||
"[NUM | `saved']",
|
||||
"Set the default entry to entry number NUM (if not specified, it is"
|
||||
" 0, the first entry) or the entry number saved by savedefault."},
|
||||
/* FIXME: dhcp unsupported. */
|
||||
{"dhcp", "net_bootp; net_ls_addr; if [ x%s = x--with-configfile ]; then "
|
||||
"if net_get_dhcp_option configfile_name pxe 150 string; then "
|
||||
"configfile $configfile_name; fi; fi\n", NULL, 0, 1,
|
||||
{TYPE_WITH_CONFIGFILE_OPTION}, FLAG_IGNORE_REST, "[--with-configfile]",
|
||||
"Initialize a network device via BOOTP. If the option `--with-configfile'"
|
||||
" is given, try to load a configuration file specified by the 150 vendor"
|
||||
" tag."},
|
||||
{"displayapm", "lsapm\n", NULL, 0, 0, {}, 0, 0,
|
||||
"Display APM BIOS information."},
|
||||
{"displaymem", "lsmmap\n", NULL, 0, 0, {}, 0, 0,
|
||||
|
@ -414,6 +427,8 @@ is_option (enum arg_type opt, const char *curarg, grub_size_t len)
|
|||
{
|
||||
switch (opt)
|
||||
{
|
||||
case TYPE_WITH_CONFIGFILE_OPTION:
|
||||
return check_option (curarg, "--with-configfile", len);
|
||||
case TYPE_NOAPM_OPTION:
|
||||
return check_option (curarg, "--no-apm", len);
|
||||
case TYPE_FORCE_OPTION:
|
||||
|
@ -665,6 +680,7 @@ grub_legacy_parse (const char *buf, char **entryname, char **suffix)
|
|||
case TYPE_VERBATIM:
|
||||
args[i] = grub_legacy_escape (curarg, curarglen);
|
||||
break;
|
||||
case TYPE_WITH_CONFIGFILE_OPTION:
|
||||
case TYPE_FORCE_OPTION:
|
||||
case TYPE_NOAPM_OPTION:
|
||||
case TYPE_TYPE_OR_NOMEM_OPTION:
|
||||
|
@ -759,6 +775,7 @@ grub_legacy_parse (const char *buf, char **entryname, char **suffix)
|
|||
case TYPE_FILE:
|
||||
case TYPE_REST_VERBATIM:
|
||||
case TYPE_VERBATIM:
|
||||
case TYPE_WITH_CONFIGFILE_OPTION:
|
||||
case TYPE_FORCE_OPTION:
|
||||
case TYPE_NOAPM_OPTION:
|
||||
case TYPE_TYPE_OR_NOMEM_OPTION:
|
||||
|
|
257
grub-core/lib/priority_queue.c
Normal file
257
grub-core/lib/priority_queue.c
Normal file
|
@ -0,0 +1,257 @@
|
|||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2011 Free Software Foundation, Inc.
|
||||
*
|
||||
* GRUB is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GRUB is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef TEST
|
||||
#include <grub/priority_queue.h>
|
||||
#include <grub/mm.h>
|
||||
#include <grub/dl.h>
|
||||
|
||||
GRUB_MOD_LICENSE ("GPLv3+");
|
||||
|
||||
#else
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <queue>
|
||||
|
||||
using namespace std;
|
||||
|
||||
typedef size_t grub_size_t;
|
||||
typedef int (*grub_comparator_t) (const void *a, const void *b);
|
||||
typedef unsigned char grub_uint8_t;
|
||||
#define grub_malloc malloc
|
||||
#define grub_memcpy memcpy
|
||||
#define grub_realloc realloc
|
||||
#define grub_free free
|
||||
|
||||
typedef enum
|
||||
{
|
||||
GRUB_ERR_NONE,
|
||||
grub_errno
|
||||
} grub_err_t;
|
||||
#endif
|
||||
|
||||
struct grub_priority_queue
|
||||
{
|
||||
grub_size_t elsize;
|
||||
grub_size_t allocated;
|
||||
grub_size_t used;
|
||||
grub_comparator_t cmp;
|
||||
void *els;
|
||||
};
|
||||
|
||||
#ifdef TEST
|
||||
typedef struct grub_priority_queue *grub_priority_queue_t;
|
||||
#endif
|
||||
|
||||
static inline void *
|
||||
element (struct grub_priority_queue *pq, grub_size_t k)
|
||||
{
|
||||
return ((grub_uint8_t *) pq->els) + k * pq->elsize;
|
||||
}
|
||||
|
||||
static inline void
|
||||
swap (struct grub_priority_queue *pq, grub_size_t m, grub_size_t n)
|
||||
{
|
||||
grub_uint8_t *p1, *p2;
|
||||
grub_size_t l;
|
||||
p1 = (grub_uint8_t *) element (pq, m);
|
||||
p2 = (grub_uint8_t *) element (pq, n);
|
||||
for (l = pq->elsize; l; l--, p1++, p2++)
|
||||
{
|
||||
grub_uint8_t t;
|
||||
t = *p1;
|
||||
*p1 = *p2;
|
||||
*p2 = t;
|
||||
}
|
||||
}
|
||||
|
||||
static inline grub_size_t
|
||||
parent (grub_size_t v)
|
||||
{
|
||||
return (v - 1) / 2;
|
||||
}
|
||||
|
||||
static inline grub_size_t
|
||||
left_child (grub_size_t v)
|
||||
{
|
||||
return 2 * v + 1;
|
||||
}
|
||||
|
||||
static inline grub_size_t
|
||||
right_child (grub_size_t v)
|
||||
{
|
||||
return 2 * v + 2;
|
||||
}
|
||||
|
||||
void *
|
||||
grub_priority_queue_top (grub_priority_queue_t pq)
|
||||
{
|
||||
if (!pq->used)
|
||||
return 0;
|
||||
return element (pq, 0);
|
||||
}
|
||||
|
||||
void
|
||||
grub_priority_queue_destroy (grub_priority_queue_t pq)
|
||||
{
|
||||
grub_free (pq->els);
|
||||
grub_free (pq);
|
||||
}
|
||||
|
||||
grub_priority_queue_t
|
||||
grub_priority_queue_new (grub_size_t elsize,
|
||||
grub_comparator_t cmp)
|
||||
{
|
||||
struct grub_priority_queue *ret;
|
||||
void *els;
|
||||
els = grub_malloc (elsize * 8);
|
||||
if (!els)
|
||||
return 0;
|
||||
ret = (struct grub_priority_queue *) grub_malloc (sizeof (*ret));
|
||||
if (!ret)
|
||||
{
|
||||
grub_free (els);
|
||||
return 0;
|
||||
}
|
||||
ret->elsize = elsize;
|
||||
ret->allocated = 8;
|
||||
ret->used = 0;
|
||||
ret->cmp = cmp;
|
||||
ret->els = els;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Heap property: pq->cmp (element (pq, p), element (pq, parent (p))) <= 0. */
|
||||
grub_err_t
|
||||
grub_priority_queue_push (grub_priority_queue_t pq, const void *el)
|
||||
{
|
||||
grub_size_t p;
|
||||
if (pq->used == pq->allocated)
|
||||
{
|
||||
void *els;
|
||||
els = grub_realloc (pq->els, pq->elsize * 2 * pq->allocated);
|
||||
if (!els)
|
||||
return grub_errno;
|
||||
pq->allocated *= 2;
|
||||
pq->els = els;
|
||||
}
|
||||
pq->used++;
|
||||
grub_memcpy (element (pq, pq->used - 1), el, pq->elsize);
|
||||
for (p = pq->used - 1; p; p = parent (p))
|
||||
{
|
||||
if (pq->cmp (element (pq, p), element (pq, parent (p))) <= 0)
|
||||
break;
|
||||
swap (pq, p, parent (p));
|
||||
}
|
||||
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
void
|
||||
grub_priority_queue_pop (grub_priority_queue_t pq)
|
||||
{
|
||||
grub_size_t p;
|
||||
|
||||
swap (pq, 0, pq->used - 1);
|
||||
pq->used--;
|
||||
for (p = 0; left_child (p) < pq->used; )
|
||||
{
|
||||
grub_size_t c;
|
||||
if (pq->cmp (element (pq, left_child (p)), element (pq, p)) <= 0
|
||||
&& (right_child (p) >= pq->used
|
||||
|| pq->cmp (element (pq, right_child (p)), element (pq, p)) <= 0))
|
||||
break;
|
||||
if (right_child (p) >= pq->used
|
||||
|| pq->cmp (element (pq, left_child (p)),
|
||||
element (pq, right_child (p))) > 0)
|
||||
c = left_child (p);
|
||||
else
|
||||
c = right_child (p);
|
||||
swap (pq, p, c);
|
||||
p = c;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef TEST
|
||||
|
||||
static int
|
||||
compar (const void *a_, const void *b_)
|
||||
{
|
||||
int a = *(int *) a_;
|
||||
int b = *(int *) b_;
|
||||
if (a < b)
|
||||
return -1;
|
||||
if (a > b)
|
||||
return +1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
priority_queue <int> pq;
|
||||
grub_priority_queue_t pq2;
|
||||
int counter;
|
||||
int s = 0;
|
||||
pq2 = grub_priority_queue_new (sizeof (int), compar);
|
||||
if (!pq2)
|
||||
return 1;
|
||||
srand (1);
|
||||
|
||||
for (counter = 0; counter < 1000000; counter++)
|
||||
{
|
||||
int op = rand () % 10;
|
||||
if (s && *(int *) grub_priority_queue_top (pq2) != pq.top ())
|
||||
{
|
||||
printf ("Error at %d\n", counter);
|
||||
return 2;
|
||||
}
|
||||
if (op < 3 && s)
|
||||
{
|
||||
grub_priority_queue_pop (pq2);
|
||||
pq.pop ();
|
||||
s--;
|
||||
}
|
||||
else
|
||||
{
|
||||
int v = rand ();
|
||||
int e;
|
||||
pq.push (v);
|
||||
e = grub_priority_queue_push (pq2, &v);
|
||||
if (e)
|
||||
return 3;
|
||||
s++;
|
||||
}
|
||||
}
|
||||
while (s)
|
||||
{
|
||||
if (*(int *) grub_priority_queue_top (pq2) != pq.top ())
|
||||
{
|
||||
printf ("Error at the end. %d elements remaining.\n", s);
|
||||
return 4;
|
||||
}
|
||||
grub_priority_queue_pop (pq2);
|
||||
pq.pop ();
|
||||
s--;
|
||||
}
|
||||
printf ("All tests passed successfully\n");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
|
@ -1,3 +1,21 @@
|
|||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2010,2011 Free Software Foundation, Inc.
|
||||
*
|
||||
* GRUB is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GRUB is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <grub/net/arp.h>
|
||||
#include <grub/net/netbuff.h>
|
||||
#include <grub/mm.h>
|
||||
|
@ -6,82 +24,74 @@
|
|||
#include <grub/net/ip.h>
|
||||
#include <grub/time.h>
|
||||
|
||||
static struct arp_entry arp_table[10];
|
||||
static grub_int8_t new_table_entry = -1;
|
||||
/* ARP header operation codes */
|
||||
enum
|
||||
{
|
||||
ARP_REQUEST = 1,
|
||||
ARP_REPLY = 2
|
||||
};
|
||||
|
||||
static void
|
||||
arp_init_table (void)
|
||||
enum
|
||||
{
|
||||
grub_memset (arp_table, 0, sizeof (arp_table));
|
||||
new_table_entry = 0;
|
||||
}
|
||||
/* IANA ARP constant to define hardware type as ethernet. */
|
||||
GRUB_NET_ARPHRD_ETHERNET = 1
|
||||
};
|
||||
|
||||
struct arphdr {
|
||||
grub_uint16_t hrd;
|
||||
grub_uint16_t pro;
|
||||
grub_uint8_t hln;
|
||||
grub_uint8_t pln;
|
||||
grub_uint16_t op;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
static struct arp_entry *
|
||||
arp_find_entry (const grub_net_network_level_address_t *proto)
|
||||
{
|
||||
unsigned i;
|
||||
for (i = 0; i < ARRAY_SIZE (arp_table); i++)
|
||||
{
|
||||
if (arp_table[i].avail == 1 &&
|
||||
arp_table[i].nl_address.ipv4 == proto->ipv4)
|
||||
return &(arp_table[i]);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
grub_err_t
|
||||
grub_net_arp_resolve (struct grub_net_network_level_interface *inf,
|
||||
const grub_net_network_level_address_t *proto_addr,
|
||||
grub_net_link_level_address_t *hw_addr)
|
||||
grub_net_arp_send_request (struct grub_net_network_level_interface *inf,
|
||||
const grub_net_network_level_address_t *proto_addr)
|
||||
{
|
||||
struct arp_entry *entry;
|
||||
struct grub_net_buff nb;
|
||||
struct arphdr *arp_header;
|
||||
grub_net_link_level_address_t target_hw_addr;
|
||||
char *aux, arp_data[128];
|
||||
grub_uint8_t *aux, arp_data[128];
|
||||
grub_err_t err;
|
||||
int i;
|
||||
grub_size_t addrlen;
|
||||
grub_uint16_t etherpro;
|
||||
grub_uint8_t *nbd;
|
||||
|
||||
if (proto_addr->type == GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4
|
||||
&& proto_addr->ipv4 == 0xffffffff)
|
||||
if (proto_addr->type == GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4)
|
||||
{
|
||||
hw_addr->type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET;
|
||||
grub_memset (hw_addr->mac, -1, 6);
|
||||
return GRUB_ERR_NONE;
|
||||
addrlen = 4;
|
||||
etherpro = GRUB_NET_ETHERTYPE_IP;
|
||||
}
|
||||
else
|
||||
return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, "unsupported address family");
|
||||
|
||||
/* Check cache table. */
|
||||
entry = arp_find_entry (proto_addr);
|
||||
if (entry)
|
||||
{
|
||||
*hw_addr = entry->ll_address;
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
/* Build a request packet. */
|
||||
nb.head = arp_data;
|
||||
nb.end = arp_data + sizeof (arp_data);
|
||||
grub_netbuff_clear (&nb);
|
||||
grub_netbuff_reserve (&nb, 128);
|
||||
|
||||
err = grub_netbuff_push (&nb, sizeof (*arp_header) + 2 * (6 + 4));
|
||||
err = grub_netbuff_push (&nb, sizeof (*arp_header) + 2 * (6 + addrlen));
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
arp_header = (struct arphdr *) nb.data;
|
||||
arp_header->hrd = grub_cpu_to_be16 (GRUB_NET_ARPHRD_ETHERNET);
|
||||
arp_header->pro = grub_cpu_to_be16 (GRUB_NET_ETHERTYPE_IP);
|
||||
/* FIXME Add support to ipv6 address. */
|
||||
arp_header->hln = 6;
|
||||
arp_header->pln = 4;
|
||||
arp_header->pro = grub_cpu_to_be16 (etherpro);
|
||||
arp_header->pln = addrlen;
|
||||
arp_header->op = grub_cpu_to_be16 (ARP_REQUEST);
|
||||
aux = (char *) arp_header + sizeof (*arp_header);
|
||||
aux = (grub_uint8_t *) arp_header + sizeof (*arp_header);
|
||||
/* Sender hardware address. */
|
||||
grub_memcpy (aux, &inf->hwaddress.mac, 6);
|
||||
|
||||
aux += 6;
|
||||
/* Sender protocol address */
|
||||
grub_memcpy (aux, &inf->address.ipv4, 4);
|
||||
aux += 4;
|
||||
aux += addrlen;
|
||||
/* Target hardware address */
|
||||
for (i = 0; i < 6; i++)
|
||||
aux[i] = 0x00;
|
||||
|
@ -90,77 +100,78 @@ grub_net_arp_resolve (struct grub_net_network_level_interface *inf,
|
|||
grub_memcpy (aux, &proto_addr->ipv4, 4);
|
||||
grub_memset (&target_hw_addr.mac, 0xff, 6);
|
||||
|
||||
nbd = nb.data;
|
||||
send_ethernet_packet (inf, &nb, target_hw_addr, GRUB_NET_ETHERTYPE_ARP);
|
||||
for (i = 0; i < 3; i++)
|
||||
for (i = 0; i < GRUB_NET_TRIES; i++)
|
||||
{
|
||||
entry = arp_find_entry (proto_addr);
|
||||
if (entry)
|
||||
{
|
||||
grub_memcpy (hw_addr, &entry->ll_address, sizeof (*hw_addr));
|
||||
if (grub_net_link_layer_resolve_check (inf, proto_addr))
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
grub_net_poll_cards (200);
|
||||
grub_net_poll_cards (GRUB_NET_INTERVAL);
|
||||
if (grub_net_link_layer_resolve_check (inf, proto_addr))
|
||||
return GRUB_ERR_NONE;
|
||||
nb.data = nbd;
|
||||
send_ethernet_packet (inf, &nb, target_hw_addr, GRUB_NET_ETHERTYPE_ARP);
|
||||
}
|
||||
|
||||
return grub_error (GRUB_ERR_TIMEOUT, "timeout: could not resolve hardware address");
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
grub_err_t
|
||||
grub_net_arp_receive (struct grub_net_buff *nb)
|
||||
grub_net_arp_receive (struct grub_net_buff *nb,
|
||||
struct grub_net_card *card)
|
||||
{
|
||||
struct arphdr *arp_header = (struct arphdr *) nb->data;
|
||||
struct arp_entry *entry;
|
||||
grub_uint8_t *sender_hardware_address, *sender_protocol_address;
|
||||
grub_uint8_t *target_hardware_address, *target_protocol_address;
|
||||
grub_net_network_level_address_t hwaddress;
|
||||
grub_uint8_t *sender_hardware_address;
|
||||
grub_uint8_t *target_hardware_address;
|
||||
grub_net_network_level_address_t sender_addr, target_addr;
|
||||
grub_net_link_level_address_t sender_hw_addr;
|
||||
struct grub_net_network_level_interface *inf;
|
||||
grub_uint8_t *sender_protocol_address, *target_protocol_address;
|
||||
|
||||
sender_hardware_address =
|
||||
(grub_uint8_t *) arp_header + sizeof (*arp_header);
|
||||
sender_protocol_address = sender_hardware_address + arp_header->hln;
|
||||
target_hardware_address = sender_protocol_address + arp_header->pln;
|
||||
target_protocol_address = target_hardware_address + arp_header->hln;
|
||||
grub_memcpy (&hwaddress.ipv4, sender_protocol_address, 4);
|
||||
|
||||
/* Check if the sender is in the cache table. */
|
||||
entry = arp_find_entry (&hwaddress);
|
||||
/* Update sender hardware address. */
|
||||
if (entry)
|
||||
grub_memcpy (entry->ll_address.mac, sender_hardware_address, 6);
|
||||
else
|
||||
if (grub_be_to_cpu16 (arp_header->pro) == GRUB_NET_ETHERTYPE_IP
|
||||
&& arp_header->pln == 4)
|
||||
{
|
||||
/* Add sender to cache table. */
|
||||
if (new_table_entry == -1)
|
||||
arp_init_table ();
|
||||
entry = &(arp_table[new_table_entry]);
|
||||
entry->avail = 1;
|
||||
grub_memcpy (&entry->nl_address.ipv4, sender_protocol_address, 4);
|
||||
grub_memcpy (entry->ll_address.mac, sender_hardware_address, 6);
|
||||
new_table_entry++;
|
||||
if (new_table_entry == ARRAY_SIZE (arp_table))
|
||||
new_table_entry = 0;
|
||||
sender_addr.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4;
|
||||
target_addr.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4;
|
||||
grub_memcpy (&sender_addr.ipv4, sender_protocol_address, 4);
|
||||
grub_memcpy (&target_addr.ipv4, target_protocol_address, 4);
|
||||
}
|
||||
else
|
||||
return GRUB_ERR_NONE;
|
||||
|
||||
sender_hw_addr.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET;
|
||||
grub_memcpy (sender_hw_addr.mac, sender_hardware_address,
|
||||
sizeof (sender_hw_addr.mac));
|
||||
grub_net_link_layer_add_address (card, &sender_addr, &sender_hw_addr, 1);
|
||||
|
||||
FOR_NET_NETWORK_LEVEL_INTERFACES (inf)
|
||||
{
|
||||
/* Am I the protocol address target? */
|
||||
if (inf->address.type == GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4
|
||||
&& grub_memcmp (target_protocol_address, &inf->address.ipv4, 4) == 0
|
||||
if (grub_net_addr_cmp (&inf->address, &target_addr) == 0
|
||||
&& grub_be_to_cpu16 (arp_header->op) == ARP_REQUEST)
|
||||
{
|
||||
grub_net_link_level_address_t aux;
|
||||
/* Swap hardware fields */
|
||||
grub_memcpy (target_hardware_address, sender_hardware_address,
|
||||
arp_header->hln);
|
||||
grub_net_link_level_address_t target;
|
||||
/* We've already checked that pln is either 4 or 16. */
|
||||
char tmp[arp_header->pln];
|
||||
|
||||
target.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET;
|
||||
grub_memcpy (target.mac, sender_hardware_address, 6);
|
||||
grub_memcpy (target_hardware_address, target.mac, 6);
|
||||
grub_memcpy (sender_hardware_address, inf->hwaddress.mac, 6);
|
||||
grub_memcpy (aux.mac, sender_protocol_address, 6);
|
||||
|
||||
grub_memcpy (tmp, sender_protocol_address, arp_header->pln);
|
||||
grub_memcpy (sender_protocol_address, target_protocol_address,
|
||||
arp_header->pln);
|
||||
grub_memcpy (target_protocol_address, aux.mac, arp_header->pln);
|
||||
grub_memcpy (target_protocol_address, tmp, arp_header->pln);
|
||||
|
||||
/* Change operation to REPLY and send packet */
|
||||
arp_header->op = grub_be_to_cpu16 (ARP_REPLY);
|
||||
grub_memcpy (aux.mac, target_hardware_address, 6);
|
||||
send_ethernet_packet (inf, nb, aux, GRUB_NET_ETHERTYPE_ARP);
|
||||
send_ethernet_packet (inf, nb, target, GRUB_NET_ETHERTYPE_ARP);
|
||||
}
|
||||
}
|
||||
return GRUB_ERR_NONE;
|
||||
|
|
|
@ -68,30 +68,59 @@ parse_dhcp_vendor (const char *name, void *vend, int limit)
|
|||
tagtype = *ptr++;
|
||||
|
||||
/* Pad tag. */
|
||||
if (tagtype == 0)
|
||||
if (tagtype == GRUB_NET_BOOTP_PAD)
|
||||
continue;
|
||||
|
||||
/* End tag. */
|
||||
if (tagtype == 0xff)
|
||||
if (tagtype == GRUB_NET_BOOTP_END)
|
||||
return;
|
||||
|
||||
taglength = *ptr++;
|
||||
|
||||
switch (tagtype)
|
||||
{
|
||||
case 12:
|
||||
case GRUB_NET_BOOTP_ROUTER:
|
||||
if (taglength == 4)
|
||||
{
|
||||
grub_net_network_level_netaddress_t target;
|
||||
grub_net_network_level_address_t gw;
|
||||
char rname[grub_strlen (name) + sizeof (":default")];
|
||||
|
||||
target.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4;
|
||||
target.ipv4.base = 0;
|
||||
target.ipv4.masksize = 0;
|
||||
gw.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4;
|
||||
grub_memcpy (&gw.ipv4, ptr, sizeof (gw.ipv4));
|
||||
grub_snprintf (rname, sizeof (rname), "%s:default", name);
|
||||
grub_net_add_route_gw (rname, target, gw);
|
||||
}
|
||||
break;
|
||||
case GRUB_NET_BOOTP_DNS:
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < taglength / 4; i++)
|
||||
{
|
||||
struct grub_net_network_level_address s;
|
||||
s.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4;
|
||||
s.ipv4 = grub_get_unaligned32 (ptr);
|
||||
grub_net_add_dns_server (&s);
|
||||
ptr += 4;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case GRUB_NET_BOOTP_HOSTNAME:
|
||||
set_env_limn_ro (name, "hostname", (char *) ptr, taglength);
|
||||
break;
|
||||
|
||||
case 15:
|
||||
case GRUB_NET_BOOTP_DOMAIN:
|
||||
set_env_limn_ro (name, "domain", (char *) ptr, taglength);
|
||||
break;
|
||||
|
||||
case 17:
|
||||
case GRUB_NET_BOOTP_ROOT_PATH:
|
||||
set_env_limn_ro (name, "rootpath", (char *) ptr, taglength);
|
||||
break;
|
||||
|
||||
case 18:
|
||||
case GRUB_NET_BOOTP_EXTENSIONS_PATH:
|
||||
set_env_limn_ro (name, "extensionspath", (char *) ptr, taglength);
|
||||
break;
|
||||
|
||||
|
@ -130,24 +159,26 @@ grub_net_configure_by_dhcp_ack (const char *name,
|
|||
: sizeof (hwaddr.mac));
|
||||
hwaddr.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET;
|
||||
|
||||
inter = grub_net_add_addr (name, card, addr, hwaddr, flags);
|
||||
inter = grub_net_add_addr (name, card, &addr, &hwaddr, flags);
|
||||
if (bp->gateway_ip)
|
||||
{
|
||||
grub_net_network_level_netaddress_t target;
|
||||
grub_net_network_level_address_t gw;
|
||||
char rname[grub_strlen (name) + sizeof ("_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_snprintf (rname, sizeof (rname), "%s:gw", name);
|
||||
grub_net_add_route_gw (rname, target, gw);
|
||||
}
|
||||
if (bp->gateway_ip || bp->server_ip)
|
||||
{
|
||||
grub_net_network_level_netaddress_t target;
|
||||
target.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4;
|
||||
target.ipv4.base = bp->gateway_ip;
|
||||
target.ipv4.base = bp->gateway_ip ? bp->gateway_ip : bp->server_ip;
|
||||
target.ipv4.masksize = 32;
|
||||
grub_net_add_route (name, target, inter);
|
||||
}
|
||||
|
@ -377,6 +408,7 @@ grub_cmd_dhcpopt (struct grub_command *cmd __attribute__ ((unused)),
|
|||
"unrecognised format specification %s", args[3]);
|
||||
}
|
||||
|
||||
/* FIXME: allow to specify mac address. */
|
||||
static grub_err_t
|
||||
grub_cmd_bootp (struct grub_command *cmd __attribute__ ((unused)),
|
||||
int argc, char **args)
|
||||
|
@ -439,6 +471,7 @@ grub_cmd_bootp (struct grub_command *cmd __attribute__ ((unused)),
|
|||
struct grub_net_buff *nb;
|
||||
struct udphdr *udph;
|
||||
grub_net_network_level_address_t target;
|
||||
grub_net_link_level_address_t ll_target;
|
||||
|
||||
if (!ifaces[j].prev)
|
||||
continue;
|
||||
|
@ -473,7 +506,7 @@ grub_cmd_bootp (struct grub_command *cmd __attribute__ ((unused)),
|
|||
t = 0;
|
||||
}
|
||||
pack->ident = grub_cpu_to_be32 (t);
|
||||
pack->seconds = 0;//grub_cpu_to_be16 (t);
|
||||
pack->seconds = grub_cpu_to_be16 (t);
|
||||
|
||||
grub_memcpy (&pack->mac_addr, &ifaces[j].hwaddress.mac, 6);
|
||||
|
||||
|
@ -484,11 +517,18 @@ grub_cmd_bootp (struct grub_command *cmd __attribute__ ((unused)),
|
|||
udph->dst = grub_cpu_to_be16 (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;
|
||||
|
||||
err = grub_net_send_ip_packet (&ifaces[j], &target, nb);
|
||||
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;
|
||||
|
@ -514,7 +554,7 @@ grub_cmd_bootp (struct grub_command *cmd __attribute__ ((unused)),
|
|||
return err;
|
||||
}
|
||||
|
||||
static grub_command_t cmd_dhcp, cmd_getdhcp, cmd_bootp;
|
||||
static grub_command_t cmd_getdhcp, cmd_bootp;
|
||||
|
||||
void
|
||||
grub_bootp_init (void)
|
||||
|
@ -522,9 +562,6 @@ grub_bootp_init (void)
|
|||
cmd_bootp = grub_register_command ("net_bootp", grub_cmd_bootp,
|
||||
N_("[CARD]"),
|
||||
N_("perform a bootp autoconfiguration"));
|
||||
cmd_dhcp = grub_register_command ("net_dhcp", grub_cmd_bootp,
|
||||
N_("[CARD]"),
|
||||
N_("perform a bootp autoconfiguration"));
|
||||
cmd_getdhcp = grub_register_command ("net_get_dhcp_option", grub_cmd_dhcpopt,
|
||||
N_("VAR INTERFACE NUMBER DESCRIPTION"),
|
||||
N_("retrieve DHCP option and save it into VAR. If VAR is - then print the value."));
|
||||
|
@ -534,6 +571,5 @@ void
|
|||
grub_bootp_fini (void)
|
||||
{
|
||||
grub_unregister_command (cmd_getdhcp);
|
||||
grub_unregister_command (cmd_dhcp);
|
||||
grub_unregister_command (cmd_bootp);
|
||||
}
|
||||
|
|
695
grub-core/net/dns.c
Normal file
695
grub-core/net/dns.c
Normal file
|
@ -0,0 +1,695 @@
|
|||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2010,2011 Free Software Foundation, Inc.
|
||||
*
|
||||
* GRUB is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GRUB is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <grub/net.h>
|
||||
#include <grub/net/udp.h>
|
||||
#include <grub/command.h>
|
||||
#include <grub/i18n.h>
|
||||
#include <grub/err.h>
|
||||
#include <grub/time.h>
|
||||
|
||||
struct dns_cache_element
|
||||
{
|
||||
char *name;
|
||||
grub_size_t naddresses;
|
||||
struct grub_net_network_level_address *addresses;
|
||||
grub_uint64_t limit_time;
|
||||
};
|
||||
|
||||
#define DNS_CACHE_SIZE 1021
|
||||
#define DNS_HASH_BASE 423
|
||||
|
||||
static struct dns_cache_element dns_cache[DNS_CACHE_SIZE];
|
||||
static struct grub_net_network_level_address *dns_servers;
|
||||
static grub_size_t dns_nservers, dns_servers_alloc;
|
||||
|
||||
grub_err_t
|
||||
grub_net_add_dns_server (const struct grub_net_network_level_address *s)
|
||||
{
|
||||
if (dns_servers_alloc <= dns_nservers)
|
||||
{
|
||||
int na = dns_servers_alloc * 2;
|
||||
struct grub_net_network_level_address *ns;
|
||||
if (na < 8)
|
||||
na = 8;
|
||||
ns = grub_malloc (na * sizeof (ns[0]));
|
||||
if (!ns)
|
||||
return grub_errno;
|
||||
dns_servers_alloc = na;
|
||||
dns_servers = ns;
|
||||
}
|
||||
dns_servers[dns_nservers++] = *s;
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
void
|
||||
grub_net_remove_dns_server (const struct grub_net_network_level_address *s)
|
||||
{
|
||||
grub_size_t i;
|
||||
for (i = 0; i < dns_nservers; i++)
|
||||
if (grub_net_addr_cmp (s, &dns_servers[i]) == 0)
|
||||
break;
|
||||
if (i < dns_nservers)
|
||||
{
|
||||
dns_servers[i] = dns_servers[dns_nservers - 1];
|
||||
dns_nservers--;
|
||||
}
|
||||
}
|
||||
|
||||
struct dns_header
|
||||
{
|
||||
grub_uint16_t id;
|
||||
grub_uint8_t flags;
|
||||
grub_uint8_t ra_z_r_code;
|
||||
grub_uint16_t qdcount;
|
||||
grub_uint16_t ancount;
|
||||
grub_uint16_t nscount;
|
||||
grub_uint16_t arcount;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
enum
|
||||
{
|
||||
FLAGS_RESPONSE = 0x80,
|
||||
FLAGS_OPCODE = 0x78,
|
||||
FLAGS_RD = 0x01
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
ERRCODE_MASK = 0x0f
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
DNS_PORT = 53
|
||||
};
|
||||
|
||||
struct recv_data
|
||||
{
|
||||
grub_size_t *naddresses;
|
||||
struct grub_net_network_level_address **addresses;
|
||||
int cache;
|
||||
grub_uint16_t id;
|
||||
int dns_err;
|
||||
char *name;
|
||||
const char *oname;
|
||||
};
|
||||
|
||||
static inline int
|
||||
hash (const char *str)
|
||||
{
|
||||
int v = 0, xn = 1;
|
||||
const char *ptr;
|
||||
for (ptr = str; *ptr; )
|
||||
{
|
||||
v = (v + xn * *ptr);
|
||||
xn = (DNS_HASH_BASE * xn) % DNS_CACHE_SIZE;
|
||||
ptr++;
|
||||
if (((ptr - str) & 0x3ff) == 0)
|
||||
v %= DNS_CACHE_SIZE;
|
||||
}
|
||||
return v % DNS_CACHE_SIZE;
|
||||
}
|
||||
|
||||
static int
|
||||
check_name_real (const grub_uint8_t *name_at, const grub_uint8_t *head,
|
||||
const grub_uint8_t *tail, const char *check_with,
|
||||
int *length, char *set)
|
||||
{
|
||||
const char *readable_ptr = check_with;
|
||||
const grub_uint8_t *ptr;
|
||||
char *optr = set;
|
||||
int bytes_processed = 0;
|
||||
if (length)
|
||||
*length = 0;
|
||||
for (ptr = name_at; ptr < tail && bytes_processed < tail - head + 2; )
|
||||
{
|
||||
/* End marker. */
|
||||
if (!*ptr)
|
||||
{
|
||||
if (length && *length)
|
||||
(*length)--;
|
||||
if (optr && optr != set)
|
||||
optr--;
|
||||
if (optr)
|
||||
*optr = 0;
|
||||
return !readable_ptr || (*readable_ptr == 0);
|
||||
}
|
||||
if (*ptr & 0xc0)
|
||||
{
|
||||
bytes_processed += 2;
|
||||
if (ptr + 1 >= tail)
|
||||
return 0;
|
||||
ptr = head + (((ptr[0] & 0x3f) << 8) | ptr[1]);
|
||||
continue;
|
||||
}
|
||||
if (readable_ptr && grub_memcmp (ptr + 1, readable_ptr, *ptr) != 0)
|
||||
return 0;
|
||||
if (grub_memchr (ptr + 1, 0, *ptr)
|
||||
|| grub_memchr (ptr + 1, '.', *ptr))
|
||||
return 0;
|
||||
if (readable_ptr)
|
||||
readable_ptr += *ptr;
|
||||
if (readable_ptr && *readable_ptr != '.' && *readable_ptr != 0)
|
||||
return 0;
|
||||
bytes_processed += *ptr + 1;
|
||||
if (length)
|
||||
*length += *ptr + 1;
|
||||
if (optr)
|
||||
{
|
||||
grub_memcpy (optr, ptr + 1, *ptr);
|
||||
optr += *ptr;
|
||||
}
|
||||
if (optr)
|
||||
*optr++ = '.';
|
||||
if (readable_ptr && *readable_ptr)
|
||||
readable_ptr++;
|
||||
ptr += *ptr + 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
check_name (const grub_uint8_t *name_at, const grub_uint8_t *head,
|
||||
const grub_uint8_t *tail, const char *check_with)
|
||||
{
|
||||
return check_name_real (name_at, head, tail, check_with, NULL, NULL);
|
||||
}
|
||||
|
||||
static char *
|
||||
get_name (const grub_uint8_t *name_at, const grub_uint8_t *head,
|
||||
const grub_uint8_t *tail)
|
||||
{
|
||||
int length;
|
||||
char *ret;
|
||||
|
||||
if (!check_name_real (name_at, head, tail, NULL, &length, NULL))
|
||||
return NULL;
|
||||
ret = grub_malloc (length + 1);
|
||||
if (!ret)
|
||||
return NULL;
|
||||
if (!check_name_real (name_at, head, tail, NULL, NULL, ret))
|
||||
{
|
||||
grub_free (ret);
|
||||
return NULL;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
enum
|
||||
{
|
||||
DNS_CLASS_A = 1,
|
||||
DNS_CLASS_CNAME = 5,
|
||||
DNS_CLASS_AAAA = 28
|
||||
};
|
||||
|
||||
static grub_err_t
|
||||
recv_hook (grub_net_udp_socket_t sock __attribute__ ((unused)),
|
||||
struct grub_net_buff *nb,
|
||||
void *data_)
|
||||
{
|
||||
struct dns_header *head;
|
||||
struct recv_data *data = data_;
|
||||
int i, j;
|
||||
grub_uint8_t *ptr, *reparse_ptr;
|
||||
int redirect_cnt = 0;
|
||||
char *redirect_save = NULL;
|
||||
grub_uint32_t ttl_all = ~0U;
|
||||
|
||||
head = (struct dns_header *) nb->data;
|
||||
ptr = (grub_uint8_t *) (head + 1);
|
||||
if (ptr >= nb->tail)
|
||||
{
|
||||
grub_netbuff_free (nb);
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
if (head->id != data->id)
|
||||
{
|
||||
grub_netbuff_free (nb);
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
if (!(head->flags & FLAGS_RESPONSE) || (head->flags & FLAGS_OPCODE))
|
||||
{
|
||||
grub_netbuff_free (nb);
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
if (head->ra_z_r_code & ERRCODE_MASK)
|
||||
{
|
||||
data->dns_err = 1;
|
||||
grub_netbuff_free (nb);
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
for (i = 0; i < grub_cpu_to_be16 (head->qdcount); i++)
|
||||
{
|
||||
if (ptr >= nb->tail)
|
||||
{
|
||||
grub_netbuff_free (nb);
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
while (ptr < nb->tail && !((*ptr & 0xc0) || *ptr == 0))
|
||||
ptr += *ptr + 1;
|
||||
if (ptr < nb->tail && (*ptr & 0xc0))
|
||||
ptr++;
|
||||
ptr++;
|
||||
ptr += 4;
|
||||
}
|
||||
*data->addresses = grub_malloc (sizeof ((*data->addresses)[0])
|
||||
* grub_cpu_to_be16 (head->ancount));
|
||||
if (!*data->addresses)
|
||||
{
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
grub_netbuff_free (nb);
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
reparse_ptr = ptr;
|
||||
reparse:
|
||||
for (i = 0, ptr = reparse_ptr; i < grub_cpu_to_be16 (head->ancount); i++)
|
||||
{
|
||||
int ignored = 0;
|
||||
grub_uint8_t class;
|
||||
grub_uint32_t ttl = 0;
|
||||
grub_uint16_t length;
|
||||
if (ptr >= nb->tail)
|
||||
{
|
||||
if (!*data->naddresses)
|
||||
grub_free (*data->addresses);
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
ignored = !check_name (ptr, nb->data, nb->tail, data->name);
|
||||
while (ptr < nb->tail && !((*ptr & 0xc0) || *ptr == 0))
|
||||
ptr += *ptr + 1;
|
||||
if (ptr < nb->tail && (*ptr & 0xc0))
|
||||
ptr++;
|
||||
ptr++;
|
||||
if (ptr + 10 >= nb->tail)
|
||||
{
|
||||
if (!*data->naddresses)
|
||||
grub_free (*data->addresses);
|
||||
grub_netbuff_free (nb);
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
if (*ptr++ != 0)
|
||||
ignored = 1;
|
||||
class = *ptr++;
|
||||
if (*ptr++ != 0)
|
||||
ignored = 1;
|
||||
if (*ptr++ != 1)
|
||||
ignored = 1;
|
||||
for (j = 0; j < 4; j++)
|
||||
{
|
||||
ttl <<= 8;
|
||||
ttl |= *ptr++;
|
||||
}
|
||||
length = *ptr++ << 8;
|
||||
length |= *ptr++;
|
||||
if (ptr + length > nb->tail)
|
||||
{
|
||||
if (!*data->naddresses)
|
||||
grub_free (*data->addresses);
|
||||
grub_netbuff_free (nb);
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
if (!ignored)
|
||||
{
|
||||
if (ttl_all > ttl)
|
||||
ttl_all = ttl;
|
||||
switch (class)
|
||||
{
|
||||
case DNS_CLASS_A:
|
||||
if (length != 4)
|
||||
break;
|
||||
(*data->addresses)[*data->naddresses].type
|
||||
= GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4;
|
||||
grub_memcpy (&(*data->addresses)[*data->naddresses].ipv4,
|
||||
ptr, 4);
|
||||
(*data->naddresses)++;
|
||||
break;
|
||||
case DNS_CLASS_AAAA:
|
||||
if (length != 16)
|
||||
break;
|
||||
(*data->addresses)[*data->naddresses].type
|
||||
= GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6;
|
||||
grub_memcpy (&(*data->addresses)[*data->naddresses].ipv6,
|
||||
ptr, 16);
|
||||
(*data->naddresses)++;
|
||||
break;
|
||||
case DNS_CLASS_CNAME:
|
||||
if (!(redirect_cnt & (redirect_cnt - 1)))
|
||||
{
|
||||
grub_free (redirect_save);
|
||||
redirect_save = data->name;
|
||||
}
|
||||
else
|
||||
grub_free (data->name);
|
||||
redirect_cnt++;
|
||||
data->name = get_name (ptr, nb->data, nb->tail);
|
||||
if (!data->name)
|
||||
{
|
||||
data->dns_err = 1;
|
||||
grub_errno = 0;
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
grub_dprintf ("dns", "CNAME %s\n", data->name);
|
||||
if (grub_strcmp (redirect_save, data->name) == 0)
|
||||
{
|
||||
data->dns_err = 1;
|
||||
grub_free (redirect_save);
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
goto reparse;
|
||||
}
|
||||
}
|
||||
ptr += length;
|
||||
}
|
||||
if (ttl_all && *data->naddresses && data->cache)
|
||||
{
|
||||
int h;
|
||||
grub_dprintf ("dns", "caching for %d seconds\n", ttl_all);
|
||||
h = hash (data->oname);
|
||||
grub_free (dns_cache[h].name);
|
||||
dns_cache[h].name = 0;
|
||||
grub_free (dns_cache[h].addresses);
|
||||
dns_cache[h].addresses = 0;
|
||||
dns_cache[h].name = grub_strdup (data->oname);
|
||||
dns_cache[h].naddresses = *data->naddresses;
|
||||
dns_cache[h].addresses = grub_malloc (*data->naddresses
|
||||
* sizeof (dns_cache[h].addresses[0]));
|
||||
dns_cache[h].limit_time = grub_get_time_ms () + 1000 * ttl_all;
|
||||
if (!dns_cache[h].addresses || !dns_cache[h].name)
|
||||
{
|
||||
grub_free (dns_cache[h].name);
|
||||
dns_cache[h].name = 0;
|
||||
grub_free (dns_cache[h].addresses);
|
||||
dns_cache[h].addresses = 0;
|
||||
}
|
||||
grub_memcpy (dns_cache[h].addresses, *data->addresses,
|
||||
*data->naddresses
|
||||
* sizeof (dns_cache[h].addresses[0]));
|
||||
}
|
||||
grub_netbuff_free (nb);
|
||||
grub_free (redirect_save);
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
grub_err_t
|
||||
grub_net_dns_lookup (const char *name,
|
||||
const struct grub_net_network_level_address *servers,
|
||||
grub_size_t n_servers,
|
||||
grub_size_t *naddresses,
|
||||
struct grub_net_network_level_address **addresses,
|
||||
int cache)
|
||||
{
|
||||
grub_size_t send_servers = 0;
|
||||
grub_size_t i, j;
|
||||
struct grub_net_buff *nb;
|
||||
grub_net_udp_socket_t sockets[n_servers];
|
||||
grub_uint8_t *optr;
|
||||
const char *iptr;
|
||||
struct dns_header *head;
|
||||
static grub_uint16_t id = 1;
|
||||
grub_err_t err = GRUB_ERR_NONE;
|
||||
struct recv_data data = {naddresses, addresses, cache,
|
||||
grub_cpu_to_be16 (id++), 0, 0, name};
|
||||
grub_uint8_t *nbd;
|
||||
int have_server = 0;
|
||||
|
||||
if (!servers)
|
||||
{
|
||||
servers = dns_servers;
|
||||
n_servers = dns_nservers;
|
||||
}
|
||||
|
||||
if (!n_servers)
|
||||
return grub_error (GRUB_ERR_BAD_ARGUMENT, "no DNS servers");
|
||||
|
||||
*naddresses = 0;
|
||||
if (cache)
|
||||
{
|
||||
int h;
|
||||
h = hash (name);
|
||||
if (dns_cache[h].name && grub_strcmp (dns_cache[h].name, name) == 0
|
||||
&& grub_get_time_ms () < dns_cache[h].limit_time)
|
||||
{
|
||||
grub_dprintf ("dns", "retrieved from cache\n");
|
||||
*addresses = grub_malloc (dns_cache[h].naddresses
|
||||
* sizeof ((*addresses)[0]));
|
||||
if (!*addresses)
|
||||
return grub_errno;
|
||||
*naddresses = dns_cache[h].naddresses;
|
||||
grub_memcpy (*addresses, dns_cache[h].addresses,
|
||||
dns_cache[h].naddresses
|
||||
* sizeof ((*addresses)[0]));
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
data.name = grub_strdup (name);
|
||||
if (!data.name)
|
||||
return grub_errno;
|
||||
|
||||
nb = grub_netbuff_alloc (GRUB_NET_OUR_MAX_IP_HEADER_SIZE
|
||||
+ GRUB_NET_MAX_LINK_HEADER_SIZE
|
||||
+ GRUB_NET_UDP_HEADER_SIZE
|
||||
+ sizeof (struct dns_header)
|
||||
+ grub_strlen (name) + 2 + 4
|
||||
+ 2 + 4);
|
||||
if (!nb)
|
||||
{
|
||||
grub_free (data.name);
|
||||
return grub_errno;
|
||||
}
|
||||
grub_netbuff_reserve (nb, GRUB_NET_OUR_MAX_IP_HEADER_SIZE
|
||||
+ GRUB_NET_MAX_LINK_HEADER_SIZE
|
||||
+ GRUB_NET_UDP_HEADER_SIZE);
|
||||
grub_netbuff_put (nb, sizeof (struct dns_header)
|
||||
+ grub_strlen (name) + 2 + 4 + 2 + 4);
|
||||
head = (struct dns_header *) nb->data;
|
||||
optr = (grub_uint8_t *) (head + 1);
|
||||
for (iptr = name; *iptr; )
|
||||
{
|
||||
const char *dot;
|
||||
dot = grub_strchr (iptr, '.');
|
||||
if (!dot)
|
||||
dot = iptr + grub_strlen (iptr);
|
||||
if ((dot - iptr) >= 64)
|
||||
{
|
||||
grub_free (data.name);
|
||||
return grub_error (GRUB_ERR_BAD_ARGUMENT,
|
||||
"domain component is too long");
|
||||
}
|
||||
*optr = (dot - iptr);
|
||||
optr++;
|
||||
grub_memcpy (optr, iptr, dot - iptr);
|
||||
optr += dot - iptr;
|
||||
iptr = dot;
|
||||
if (*iptr)
|
||||
iptr++;
|
||||
}
|
||||
*optr++ = 0;
|
||||
|
||||
/* Type: A. */
|
||||
*optr++ = 0;
|
||||
*optr++ = 1;
|
||||
|
||||
/* Class. */
|
||||
*optr++ = 0;
|
||||
*optr++ = 1;
|
||||
|
||||
/* Compressed name. */
|
||||
*optr++ = 0xc0;
|
||||
*optr++ = 0x0c;
|
||||
/* Type: AAAA. */
|
||||
*optr++ = 0;
|
||||
*optr++ = 28;
|
||||
|
||||
/* Class. */
|
||||
*optr++ = 0;
|
||||
*optr++ = 1;
|
||||
|
||||
head->id = data.id;
|
||||
head->flags = FLAGS_RD;
|
||||
head->ra_z_r_code = 0;
|
||||
head->qdcount = grub_cpu_to_be16_compile_time (2);
|
||||
head->ancount = grub_cpu_to_be16_compile_time (0);
|
||||
head->nscount = grub_cpu_to_be16_compile_time (0);
|
||||
head->arcount = grub_cpu_to_be16_compile_time (0);
|
||||
|
||||
nbd = nb->data;
|
||||
|
||||
for (i = 0; i < n_servers * 4; i++)
|
||||
{
|
||||
/* Connect to a next server. */
|
||||
while (!(i & 1) && send_servers < n_servers)
|
||||
{
|
||||
sockets[send_servers] = grub_net_udp_open (servers[send_servers],
|
||||
DNS_PORT,
|
||||
recv_hook,
|
||||
&data);
|
||||
send_servers++;
|
||||
if (!sockets[send_servers - 1])
|
||||
{
|
||||
err = grub_errno;
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
}
|
||||
else
|
||||
{
|
||||
have_server = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!have_server)
|
||||
goto out;
|
||||
if (*data.naddresses)
|
||||
goto out;
|
||||
for (j = 0; j < send_servers; j++)
|
||||
{
|
||||
grub_err_t err2;
|
||||
if (!sockets[j])
|
||||
continue;
|
||||
nb->data = nbd;
|
||||
err2 = grub_net_send_udp_packet (sockets[j], nb);
|
||||
if (err2)
|
||||
{
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
err = err2;
|
||||
}
|
||||
if (*data.naddresses)
|
||||
goto out;
|
||||
}
|
||||
grub_net_poll_cards (200);
|
||||
}
|
||||
out:
|
||||
grub_free (data.name);
|
||||
grub_netbuff_free (nb);
|
||||
for (j = 0; j < send_servers; j++)
|
||||
grub_net_udp_close (sockets[j]);
|
||||
|
||||
if (*data.naddresses)
|
||||
return GRUB_ERR_NONE;
|
||||
if (data.dns_err)
|
||||
return grub_error (GRUB_ERR_NET_NO_DOMAIN, "no DNS domain found");
|
||||
|
||||
if (err)
|
||||
{
|
||||
grub_errno = err;
|
||||
return err;
|
||||
}
|
||||
return grub_error (GRUB_ERR_TIMEOUT, "no DNS reply received");
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_cmd_nslookup (struct grub_command *cmd __attribute__ ((unused)),
|
||||
int argc, char **args)
|
||||
{
|
||||
grub_err_t err;
|
||||
struct grub_net_network_level_address server;
|
||||
grub_size_t naddresses, i;
|
||||
struct grub_net_network_level_address *addresses;
|
||||
if (argc != 2)
|
||||
return grub_error (GRUB_ERR_BAD_ARGUMENT, "2 arguments expected");
|
||||
err = grub_net_resolve_address (args[1], &server);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = grub_net_dns_lookup (args[0], &server, 1, &naddresses, &addresses, 0);
|
||||
if (err)
|
||||
return err;
|
||||
for (i = 0; i < naddresses; i++)
|
||||
{
|
||||
char buf[GRUB_NET_MAX_STR_ADDR_LEN];
|
||||
grub_net_addr_to_str (&addresses[i], buf);
|
||||
grub_printf ("%s\n", buf);
|
||||
}
|
||||
grub_free (addresses);
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_cmd_list_dns (struct grub_command *cmd __attribute__ ((unused)),
|
||||
int argc __attribute__ ((unused)),
|
||||
char **args __attribute__ ((unused)))
|
||||
{
|
||||
grub_size_t i;
|
||||
for (i = 0; i < dns_nservers; i++)
|
||||
{
|
||||
char buf[GRUB_NET_MAX_STR_ADDR_LEN];
|
||||
grub_net_addr_to_str (&dns_servers[i], buf);
|
||||
grub_printf ("%s\n", buf);
|
||||
}
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_cmd_add_dns (struct grub_command *cmd __attribute__ ((unused)),
|
||||
int argc, char **args)
|
||||
{
|
||||
grub_err_t err;
|
||||
struct grub_net_network_level_address server;
|
||||
|
||||
if (argc != 1)
|
||||
return grub_error (GRUB_ERR_BAD_ARGUMENT, "1 argument expected");
|
||||
err = grub_net_resolve_address (args[0], &server);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return grub_net_add_dns_server (&server);
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_cmd_del_dns (struct grub_command *cmd __attribute__ ((unused)),
|
||||
int argc, char **args)
|
||||
{
|
||||
grub_err_t err;
|
||||
struct grub_net_network_level_address server;
|
||||
|
||||
if (argc != 1)
|
||||
return grub_error (GRUB_ERR_BAD_ARGUMENT, "1 argument expected");
|
||||
err = grub_net_resolve_address (args[1], &server);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return grub_net_add_dns_server (&server);
|
||||
}
|
||||
|
||||
static grub_command_t cmd, cmd_add, cmd_del, cmd_list;
|
||||
|
||||
void
|
||||
grub_dns_init (void)
|
||||
{
|
||||
cmd = grub_register_command ("net_nslookup", grub_cmd_nslookup,
|
||||
"ADDRESS DNSSERVER",
|
||||
N_("Perform a DNS lookup"));
|
||||
cmd_add = grub_register_command ("net_add_dns", grub_cmd_add_dns,
|
||||
"DNSSERVER",
|
||||
N_("Add a DNS server"));
|
||||
cmd_del = grub_register_command ("net_del_dns", grub_cmd_del_dns,
|
||||
"DNSSERVER",
|
||||
N_("Remove a DNS server"));
|
||||
cmd_list = grub_register_command ("net_ls_dns", grub_cmd_list_dns,
|
||||
NULL, N_("List DNS servers"));
|
||||
}
|
||||
|
||||
void
|
||||
grub_dns_fini (void)
|
||||
{
|
||||
grub_unregister_command (cmd);
|
||||
grub_unregister_command (cmd_add);
|
||||
grub_unregister_command (cmd_del);
|
||||
grub_unregister_command (cmd_list);
|
||||
}
|
|
@ -35,50 +35,83 @@ send_card_buffer (const struct grub_net_card *dev,
|
|||
{
|
||||
grub_efi_status_t st;
|
||||
grub_efi_simple_network_t *net = dev->efi_net;
|
||||
grub_uint64_t limit_time = grub_get_time_ms () + 4000;
|
||||
st = efi_call_7 (net->transmit, net, 0, (pack->tail - pack->data),
|
||||
pack->data, NULL, NULL, NULL);
|
||||
if (st != GRUB_EFI_SUCCESS)
|
||||
return grub_error (GRUB_ERR_IO, "Couldn't send network packet.");
|
||||
return grub_error (GRUB_ERR_IO, "couldn't send network packet");
|
||||
while (1)
|
||||
{
|
||||
void *txbuf = NULL;
|
||||
st = efi_call_3 (net->get_status, net, 0, &txbuf);
|
||||
if (st != GRUB_EFI_SUCCESS)
|
||||
return grub_error (GRUB_ERR_IO, "couldn't send network packet");
|
||||
if (txbuf)
|
||||
return GRUB_ERR_NONE;
|
||||
if (limit_time < grub_get_time_ms ())
|
||||
return grub_error (GRUB_ERR_TIMEOUT, "couldn't send network packet");
|
||||
}
|
||||
}
|
||||
|
||||
static grub_ssize_t
|
||||
get_card_packet (const struct grub_net_card *dev,
|
||||
struct grub_net_buff *nb)
|
||||
static struct grub_net_buff *
|
||||
get_card_packet (const struct grub_net_card *dev)
|
||||
{
|
||||
grub_efi_simple_network_t *net = dev->efi_net;
|
||||
grub_err_t err;
|
||||
grub_efi_status_t st;
|
||||
grub_efi_uintn_t bufsize = 1500;
|
||||
grub_efi_uintn_t bufsize = 1536;
|
||||
struct grub_net_buff *nb;
|
||||
|
||||
err = grub_netbuff_clear (nb);
|
||||
if (err)
|
||||
return -1;
|
||||
nb = grub_netbuff_alloc (bufsize);
|
||||
if (!nb)
|
||||
return NULL;
|
||||
|
||||
err = grub_netbuff_put (nb, 1500);
|
||||
if (err)
|
||||
return -1;
|
||||
/* Reserve 2 bytes so that 2 + 14/18 bytes of ethernet header is divisible
|
||||
by 4. So that IP header is aligned on 4 bytes. */
|
||||
grub_netbuff_reserve (nb, 2);
|
||||
if (!nb)
|
||||
{
|
||||
grub_netbuff_free (nb);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
st = efi_call_7 (net->receive, net, NULL, &bufsize,
|
||||
nb->data, NULL, NULL, NULL);
|
||||
if (st == GRUB_EFI_BUFFER_TOO_SMALL)
|
||||
{
|
||||
err = grub_netbuff_put (nb, bufsize - 1500);
|
||||
if (err)
|
||||
return -1;
|
||||
grub_netbuff_free (nb);
|
||||
|
||||
bufsize = ALIGN_UP (bufsize, 32);
|
||||
|
||||
nb = grub_netbuff_alloc (bufsize);
|
||||
if (!nb)
|
||||
return NULL;
|
||||
|
||||
/* Reserve 2 bytes so that 2 + 14/18 bytes of ethernet header is divisible
|
||||
by 4. So that IP header is aligned on 4 bytes. */
|
||||
grub_netbuff_reserve (nb, 2);
|
||||
if (!nb)
|
||||
{
|
||||
grub_netbuff_free (nb);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
st = efi_call_7 (net->receive, net, NULL, &bufsize,
|
||||
nb->data, NULL, NULL, NULL);
|
||||
}
|
||||
if (st != GRUB_EFI_SUCCESS)
|
||||
{
|
||||
grub_netbuff_clear (nb);
|
||||
return -1;
|
||||
grub_netbuff_free (nb);
|
||||
return NULL;
|
||||
}
|
||||
err = grub_netbuff_unput (nb, (nb->tail - nb->data) - bufsize);
|
||||
err = grub_netbuff_put (nb, bufsize);
|
||||
if (err)
|
||||
return -1;
|
||||
{
|
||||
grub_netbuff_free (nb);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return bufsize;
|
||||
return nb;
|
||||
}
|
||||
|
||||
static struct grub_net_card_driver efidriver =
|
||||
|
@ -136,6 +169,7 @@ grub_efinet_findcards (void)
|
|||
card->driver = &efidriver;
|
||||
card->flags = 0;
|
||||
card->default_address.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET;
|
||||
card->mtu = net->mode->max_packet_size;
|
||||
grub_memcpy (card->default_address.mac,
|
||||
net->mode->current_address,
|
||||
sizeof (card->default_address.mac));
|
||||
|
|
|
@ -1,3 +1,20 @@
|
|||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2010,2011 Free Software Foundation, Inc.
|
||||
*
|
||||
* GRUB is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GRUB is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <grub/dl.h>
|
||||
#include <grub/net/netbuff.h>
|
||||
|
@ -11,6 +28,8 @@
|
|||
#include <unistd.h>
|
||||
#include <grub/term.h>
|
||||
|
||||
GRUB_MOD_LICENSE ("GPLv3+");
|
||||
|
||||
static int fd;
|
||||
|
||||
static grub_err_t
|
||||
|
@ -26,19 +45,34 @@ send_card_buffer (const struct grub_net_card *dev __attribute__ ((unused)),
|
|||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
static grub_ssize_t
|
||||
get_card_packet (const struct grub_net_card *dev __attribute__ ((unused)),
|
||||
struct grub_net_buff *pack)
|
||||
static struct grub_net_buff *
|
||||
get_card_packet (const struct grub_net_card *dev __attribute__ ((unused)))
|
||||
{
|
||||
ssize_t actual;
|
||||
struct grub_net_buff *nb;
|
||||
|
||||
grub_netbuff_clear (pack);
|
||||
actual = read (fd, pack->data, 1500);
|
||||
nb = grub_netbuff_alloc (1536);
|
||||
if (!nb)
|
||||
return NULL;
|
||||
|
||||
/* Reserve 2 bytes so that 2 + 14/18 bytes of ethernet header is divisible
|
||||
by 4. So that IP header is aligned on 4 bytes. */
|
||||
grub_netbuff_reserve (nb, 2);
|
||||
if (!nb)
|
||||
{
|
||||
grub_netbuff_free (nb);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
actual = read (fd, nb->data, 1536);
|
||||
if (actual < 0)
|
||||
return -1;
|
||||
grub_netbuff_put (pack, actual);
|
||||
{
|
||||
grub_netbuff_free (nb);
|
||||
return NULL;
|
||||
}
|
||||
grub_netbuff_put (nb, actual);
|
||||
|
||||
return actual;
|
||||
return nb;
|
||||
}
|
||||
|
||||
static struct grub_net_card_driver emudriver =
|
||||
|
@ -52,6 +86,7 @@ static struct grub_net_card emucard =
|
|||
{
|
||||
.name = "emu0",
|
||||
.driver = &emudriver,
|
||||
.mtu = 1500,
|
||||
.default_address = {
|
||||
.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET,
|
||||
{.mac = {0, 1, 2, 3, 4, 5}}
|
||||
|
|
|
@ -164,14 +164,13 @@ grub_pxe_scan (void)
|
|||
return bangpxe;
|
||||
}
|
||||
|
||||
static grub_ssize_t
|
||||
grub_pxe_recv (const struct grub_net_card *dev __attribute__ ((unused)),
|
||||
struct grub_net_buff *buf)
|
||||
static struct grub_net_buff *
|
||||
grub_pxe_recv (const struct grub_net_card *dev __attribute__ ((unused)))
|
||||
{
|
||||
struct grub_pxe_undi_isr *isr;
|
||||
static int in_progress = 0;
|
||||
char *ptr, *end;
|
||||
int len;
|
||||
grub_uint8_t *ptr, *end;
|
||||
struct grub_net_buff *buf;
|
||||
|
||||
isr = (void *) GRUB_MEMORY_MACHINE_SCRATCH_ADDR;
|
||||
|
||||
|
@ -183,7 +182,7 @@ grub_pxe_recv (const struct grub_net_card *dev __attribute__ ((unused)),
|
|||
if (isr->status || isr->func_flag != GRUB_PXE_ISR_OUT_OURS)
|
||||
{
|
||||
in_progress = 0;
|
||||
return -1;
|
||||
return NULL;
|
||||
}
|
||||
grub_memset (isr, 0, sizeof (*isr));
|
||||
isr->func_flag = GRUB_PXE_ISR_IN_PROCESS;
|
||||
|
@ -201,17 +200,27 @@ grub_pxe_recv (const struct grub_net_card *dev __attribute__ ((unused)),
|
|||
if (isr->status || isr->func_flag == GRUB_PXE_ISR_OUT_DONE)
|
||||
{
|
||||
in_progress = 0;
|
||||
return -1;
|
||||
return NULL;
|
||||
}
|
||||
grub_memset (isr, 0, sizeof (*isr));
|
||||
isr->func_flag = GRUB_PXE_ISR_IN_GET_NEXT;
|
||||
grub_pxe_call (GRUB_PXENV_UNDI_ISR, isr, pxe_rm_entry);
|
||||
}
|
||||
|
||||
grub_netbuff_put (buf, isr->frame_len);
|
||||
buf = grub_netbuff_alloc (isr->frame_len);
|
||||
if (!buf)
|
||||
return NULL;
|
||||
/* Reserve 2 bytes so that 2 + 14/18 bytes of ethernet header is divisible
|
||||
by 4. So that IP header is aligned on 4 bytes. */
|
||||
grub_netbuff_reserve (buf, 2);
|
||||
if (!buf)
|
||||
{
|
||||
grub_netbuff_free (buf);
|
||||
return NULL;
|
||||
}
|
||||
ptr = buf->data;
|
||||
end = ptr + isr->frame_len;
|
||||
len = isr->frame_len;
|
||||
grub_netbuff_put (buf, isr->frame_len);
|
||||
grub_memcpy (ptr, LINEAR (isr->buffer), isr->buffer_len);
|
||||
ptr += isr->buffer_len;
|
||||
while (ptr < end)
|
||||
|
@ -222,7 +231,8 @@ grub_pxe_recv (const struct grub_net_card *dev __attribute__ ((unused)),
|
|||
if (isr->status || isr->func_flag != GRUB_PXE_ISR_OUT_RECEIVE)
|
||||
{
|
||||
in_progress = 1;
|
||||
return -1;
|
||||
grub_netbuff_free (buf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
grub_memcpy (ptr, LINEAR (isr->buffer), isr->buffer_len);
|
||||
|
@ -230,7 +240,7 @@ grub_pxe_recv (const struct grub_net_card *dev __attribute__ ((unused)),
|
|||
}
|
||||
in_progress = 1;
|
||||
|
||||
return len;
|
||||
return buf;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
|
@ -345,6 +355,7 @@ GRUB_MOD_INIT(pxe)
|
|||
if (i == sizeof (grub_pxe_card.default_address.mac))
|
||||
grub_memcpy (grub_pxe_card.default_address.mac, ui->permanent_addr,
|
||||
sizeof (grub_pxe_card.default_address.mac));
|
||||
grub_pxe_card.mtu = ui->mtu;
|
||||
|
||||
grub_pxe_card.default_address.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET;
|
||||
|
||||
|
|
|
@ -28,7 +28,6 @@ struct grub_ofnetcard_data
|
|||
{
|
||||
char *path;
|
||||
grub_ieee1275_ihandle_t handle;
|
||||
grub_uint32_t mtu;
|
||||
};
|
||||
|
||||
static grub_err_t
|
||||
|
@ -74,25 +73,35 @@ send_card_buffer (const struct grub_net_card *dev, struct grub_net_buff *pack)
|
|||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
static grub_ssize_t
|
||||
get_card_packet (const struct grub_net_card *dev, struct grub_net_buff *nb)
|
||||
static struct grub_net_buff *
|
||||
get_card_packet (const struct grub_net_card *dev)
|
||||
{
|
||||
grub_ssize_t actual;
|
||||
int rc;
|
||||
struct grub_ofnetcard_data *data = dev->data;
|
||||
grub_uint64_t start_time;
|
||||
struct grub_net_buff *nb;
|
||||
|
||||
grub_netbuff_clear (nb);
|
||||
nb = grub_netbuff_alloc (dev->mtu + 64);
|
||||
/* Reserve 2 bytes so that 2 + 14/18 bytes of ethernet header is divisible
|
||||
by 4. So that IP header is aligned on 4 bytes. */
|
||||
grub_netbuff_reserve (nb, 2);
|
||||
if (!nb)
|
||||
{
|
||||
grub_netbuff_free (nb);
|
||||
return NULL;
|
||||
}
|
||||
start_time = grub_get_time_ms ();
|
||||
do
|
||||
rc = grub_ieee1275_read (data->handle, nb->data, data->mtu, &actual);
|
||||
rc = grub_ieee1275_read (data->handle, nb->data, dev->mtu + 64, &actual);
|
||||
while ((actual <= 0 || rc < 0) && (grub_get_time_ms () - start_time < 200));
|
||||
if (actual)
|
||||
{
|
||||
grub_netbuff_put (nb, actual);
|
||||
return actual;
|
||||
return nb;
|
||||
}
|
||||
return -1;
|
||||
grub_netbuff_free (nb);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct grub_net_card_driver ofdriver =
|
||||
|
@ -228,11 +237,14 @@ grub_ofnet_findcards (void)
|
|||
|
||||
grub_ieee1275_finddevice (ofdata->path, &devhandle);
|
||||
|
||||
if (grub_ieee1275_get_integer_property
|
||||
(devhandle, "max-frame-size", &(ofdata->mtu),
|
||||
sizeof (ofdata->mtu), 0))
|
||||
{
|
||||
ofdata->mtu = 1500;
|
||||
grub_uint32_t t;
|
||||
if (grub_ieee1275_get_integer_property (devhandle,
|
||||
"max-frame-size", &t,
|
||||
sizeof (t), 0))
|
||||
card->mtu = 1500;
|
||||
else
|
||||
card->mtu = t;
|
||||
}
|
||||
|
||||
if (grub_ieee1275_get_property (devhandle, "mac-address",
|
||||
|
|
|
@ -52,11 +52,13 @@ grub_err_t
|
|||
send_ethernet_packet (struct grub_net_network_level_interface *inf,
|
||||
struct grub_net_buff *nb,
|
||||
grub_net_link_level_address_t target_addr,
|
||||
grub_uint16_t ethertype)
|
||||
grub_net_ethertype_t ethertype)
|
||||
{
|
||||
struct etherhdr *eth;
|
||||
grub_err_t err;
|
||||
|
||||
COMPILE_TIME_ASSERT (sizeof (*eth) < GRUB_NET_MAX_LINK_HEADER_SIZE);
|
||||
|
||||
err = grub_netbuff_push (nb, sizeof (*eth));
|
||||
if (err)
|
||||
return err;
|
||||
|
@ -79,13 +81,14 @@ send_ethernet_packet (struct grub_net_network_level_interface *inf,
|
|||
|
||||
grub_err_t
|
||||
grub_net_recv_ethernet_packet (struct grub_net_buff *nb,
|
||||
const struct grub_net_card * card)
|
||||
struct grub_net_card *card)
|
||||
{
|
||||
struct etherhdr *eth;
|
||||
struct llchdr *llch;
|
||||
struct snaphdr *snaph;
|
||||
grub_uint16_t type;
|
||||
grub_net_ethertype_t type;
|
||||
grub_net_link_level_address_t hwaddress;
|
||||
grub_net_link_level_address_t src_hwaddress;
|
||||
grub_err_t err;
|
||||
|
||||
eth = (struct etherhdr *) nb->data;
|
||||
|
@ -111,19 +114,20 @@ grub_net_recv_ethernet_packet (struct grub_net_buff * nb,
|
|||
|
||||
hwaddress.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET;
|
||||
grub_memcpy (hwaddress.mac, eth->dst, sizeof (hwaddress.mac));
|
||||
src_hwaddress.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET;
|
||||
grub_memcpy (src_hwaddress.mac, eth->src, sizeof (src_hwaddress.mac));
|
||||
|
||||
switch (type)
|
||||
{
|
||||
/* ARP packet. */
|
||||
if (type == GRUB_NET_ETHERTYPE_ARP)
|
||||
{
|
||||
grub_net_arp_receive (nb);
|
||||
case GRUB_NET_ETHERTYPE_ARP:
|
||||
grub_net_arp_receive (nb, card);
|
||||
grub_netbuff_free (nb);
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
/* IP packet. */
|
||||
if (type == GRUB_NET_ETHERTYPE_IP)
|
||||
{
|
||||
grub_net_recv_ip_packets (nb, card, &hwaddress);
|
||||
return GRUB_ERR_NONE;
|
||||
case GRUB_NET_ETHERTYPE_IP:
|
||||
case GRUB_NET_ETHERTYPE_IP6:
|
||||
return grub_net_recv_ip_packets (nb, card, &hwaddress, &src_hwaddress);
|
||||
}
|
||||
grub_netbuff_free (nb);
|
||||
return GRUB_ERR_NONE;
|
||||
|
|
510
grub-core/net/http.c
Normal file
510
grub-core/net/http.c
Normal file
|
@ -0,0 +1,510 @@
|
|||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2010,2011 Free Software Foundation, Inc.
|
||||
*
|
||||
* GRUB is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GRUB is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <grub/misc.h>
|
||||
#include <grub/net/tcp.h>
|
||||
#include <grub/net/ip.h>
|
||||
#include <grub/net/ethernet.h>
|
||||
#include <grub/net/netbuff.h>
|
||||
#include <grub/net.h>
|
||||
#include <grub/mm.h>
|
||||
#include <grub/dl.h>
|
||||
#include <grub/file.h>
|
||||
|
||||
GRUB_MOD_LICENSE ("GPLv3+");
|
||||
|
||||
enum
|
||||
{
|
||||
HTTP_PORT = 80
|
||||
};
|
||||
|
||||
|
||||
typedef struct http_data
|
||||
{
|
||||
char *current_line;
|
||||
grub_size_t current_line_len;
|
||||
int headers_recv;
|
||||
int first_line_recv;
|
||||
int size_recv;
|
||||
grub_net_tcp_socket_t sock;
|
||||
char *filename;
|
||||
grub_err_t err;
|
||||
char *errmsg;
|
||||
int chunked;
|
||||
grub_size_t chunk_rem;
|
||||
int in_chunk_len;
|
||||
} *http_data_t;
|
||||
|
||||
static grub_off_t
|
||||
have_ahead (struct grub_file *file)
|
||||
{
|
||||
grub_net_t net = file->device->net;
|
||||
grub_off_t ret = net->offset;
|
||||
struct grub_net_packet *pack;
|
||||
for (pack = net->packs.first; pack; pack = pack->next)
|
||||
ret += pack->nb->tail - pack->nb->data;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
parse_line (grub_file_t file, http_data_t data, char *ptr, grub_size_t len)
|
||||
{
|
||||
char *end = ptr + len;
|
||||
while (end > ptr && *(end - 1) == '\r')
|
||||
end--;
|
||||
*end = 0;
|
||||
/* Trailing CRLF. */
|
||||
if (data->in_chunk_len == 1)
|
||||
{
|
||||
data->in_chunk_len = 2;
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
if (data->in_chunk_len == 2)
|
||||
{
|
||||
data->chunk_rem = grub_strtoul (ptr, 0, 16);
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
if (data->chunk_rem == 0)
|
||||
{
|
||||
file->device->net->eof = 1;
|
||||
if (file->size == GRUB_FILE_SIZE_UNKNOWN)
|
||||
file->size = have_ahead (file);
|
||||
}
|
||||
data->in_chunk_len = 0;
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
if (ptr == end)
|
||||
{
|
||||
data->headers_recv = 1;
|
||||
if (data->chunked)
|
||||
data->in_chunk_len = 2;
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
if (!data->first_line_recv)
|
||||
{
|
||||
int code;
|
||||
if (grub_memcmp (ptr, "HTTP/1.1 ", sizeof ("HTTP/1.1 ") - 1) != 0)
|
||||
return grub_error (GRUB_ERR_NET_INVALID_RESPONSE,
|
||||
"unsupported HTTP response");
|
||||
ptr += sizeof ("HTTP/1.1 ") - 1;
|
||||
code = grub_strtoul (ptr, &ptr, 10);
|
||||
if (grub_errno)
|
||||
return grub_errno;
|
||||
switch (code)
|
||||
{
|
||||
case 200:
|
||||
break;
|
||||
case 404:
|
||||
data->err = GRUB_ERR_FILE_NOT_FOUND;
|
||||
data->errmsg = grub_xasprintf ("file `%s' not found", data->filename);
|
||||
return GRUB_ERR_NONE;
|
||||
default:
|
||||
data->err = GRUB_ERR_NET_UNKNOWN_ERROR;
|
||||
data->errmsg = grub_xasprintf ("unsupported HTTP error %d: %s",
|
||||
code, ptr);
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
data->first_line_recv = 1;
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
if (grub_memcmp (ptr, "Content-Length: ", sizeof ("Content-Length: ") - 1)
|
||||
== 0 && !data->size_recv)
|
||||
{
|
||||
ptr += sizeof ("Content-Length: ") - 1;
|
||||
file->size = grub_strtoull (ptr, &ptr, 10);
|
||||
data->size_recv = 1;
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
if (grub_memcmp (ptr, "Transfer-Encoding: chunked",
|
||||
sizeof ("Transfer-Encoding: chunked") - 1) == 0)
|
||||
{
|
||||
data->chunked = 1;
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
static void
|
||||
http_err (grub_net_tcp_socket_t sock __attribute__ ((unused)),
|
||||
void *f)
|
||||
{
|
||||
grub_file_t file = f;
|
||||
http_data_t data = file->data;
|
||||
|
||||
if (data->sock)
|
||||
grub_net_tcp_close (data->sock, GRUB_NET_TCP_ABORT);
|
||||
if (data->current_line)
|
||||
grub_free (data->current_line);
|
||||
grub_free (data);
|
||||
file->device->net->eof = 1;
|
||||
if (file->size == GRUB_FILE_SIZE_UNKNOWN)
|
||||
file->size = have_ahead (file);
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
http_receive (grub_net_tcp_socket_t sock __attribute__ ((unused)),
|
||||
struct grub_net_buff *nb,
|
||||
void *f)
|
||||
{
|
||||
grub_file_t file = f;
|
||||
http_data_t data = file->data;
|
||||
grub_err_t err;
|
||||
|
||||
while (1)
|
||||
{
|
||||
char *ptr = (char *) nb->data;
|
||||
if ((!data->headers_recv || data->in_chunk_len) && data->current_line)
|
||||
{
|
||||
int have_line = 1;
|
||||
char *t;
|
||||
ptr = grub_memchr (nb->data, '\n', nb->tail - nb->data);
|
||||
if (ptr)
|
||||
ptr++;
|
||||
else
|
||||
{
|
||||
have_line = 0;
|
||||
ptr = (char *) nb->tail;
|
||||
}
|
||||
t = grub_realloc (data->current_line,
|
||||
data->current_line_len + (ptr - (char *) nb->data));
|
||||
if (!t)
|
||||
{
|
||||
grub_netbuff_free (nb);
|
||||
grub_net_tcp_close (data->sock, GRUB_NET_TCP_ABORT);
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
data->current_line = t;
|
||||
grub_memcpy (data->current_line + data->current_line_len,
|
||||
nb->data, ptr - (char *) nb->data);
|
||||
data->current_line_len += ptr - (char *) nb->data;
|
||||
if (!have_line)
|
||||
{
|
||||
grub_netbuff_free (nb);
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
err = parse_line (file, data, data->current_line,
|
||||
data->current_line_len);
|
||||
grub_free (data->current_line);
|
||||
data->current_line = 0;
|
||||
data->current_line_len = 0;
|
||||
if (err)
|
||||
{
|
||||
grub_net_tcp_close (data->sock, GRUB_NET_TCP_ABORT);
|
||||
grub_netbuff_free (nb);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
while (ptr < (char *) nb->tail && (!data->headers_recv
|
||||
|| data->in_chunk_len))
|
||||
{
|
||||
char *ptr2;
|
||||
ptr2 = grub_memchr (ptr, '\n', (char *) nb->tail - ptr);
|
||||
if (!ptr2)
|
||||
{
|
||||
data->current_line = grub_malloc ((char *) nb->tail - ptr);
|
||||
if (!data->current_line)
|
||||
{
|
||||
grub_netbuff_free (nb);
|
||||
grub_net_tcp_close (data->sock, GRUB_NET_TCP_ABORT);
|
||||
return grub_errno;
|
||||
}
|
||||
data->current_line_len = (char *) nb->tail - ptr;
|
||||
grub_memcpy (data->current_line, ptr, data->current_line_len);
|
||||
grub_netbuff_free (nb);
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
err = parse_line (file, data, ptr, ptr2 - ptr);
|
||||
if (err)
|
||||
{
|
||||
grub_net_tcp_close (data->sock, GRUB_NET_TCP_ABORT);
|
||||
grub_netbuff_free (nb);
|
||||
return err;
|
||||
}
|
||||
ptr = ptr2 + 1;
|
||||
}
|
||||
|
||||
if (((char *) nb->tail - ptr) <= 0)
|
||||
{
|
||||
grub_netbuff_free (nb);
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
err = grub_netbuff_pull (nb, ptr - (char *) nb->data);
|
||||
if (err)
|
||||
{
|
||||
grub_net_tcp_close (data->sock, GRUB_NET_TCP_ABORT);
|
||||
grub_netbuff_free (nb);
|
||||
return err;
|
||||
}
|
||||
if (!(data->chunked && (grub_ssize_t) data->chunk_rem
|
||||
< nb->tail - nb->data))
|
||||
{
|
||||
grub_net_put_packet (&file->device->net->packs, nb);
|
||||
if (data->chunked)
|
||||
data->chunk_rem -= nb->tail - nb->data;
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
if (data->chunk_rem)
|
||||
{
|
||||
struct grub_net_buff *nb2;
|
||||
nb2 = grub_netbuff_alloc (data->chunk_rem);
|
||||
if (!nb2)
|
||||
return grub_errno;
|
||||
grub_netbuff_put (nb2, data->chunk_rem);
|
||||
grub_memcpy (nb2->data, nb->data, data->chunk_rem);
|
||||
grub_net_put_packet (&file->device->net->packs, nb2);
|
||||
grub_netbuff_pull (nb, data->chunk_rem);
|
||||
}
|
||||
data->in_chunk_len = 1;
|
||||
}
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
http_establish (struct grub_file *file, grub_off_t offset, int initial)
|
||||
{
|
||||
http_data_t data = file->data;
|
||||
grub_uint8_t *ptr;
|
||||
int i;
|
||||
struct grub_net_buff *nb;
|
||||
grub_err_t err;
|
||||
|
||||
nb = grub_netbuff_alloc (GRUB_NET_TCP_RESERVE_SIZE
|
||||
+ sizeof ("GET ") - 1
|
||||
+ grub_strlen (data->filename)
|
||||
+ sizeof (" HTTP/1.1\r\nHost: ") - 1
|
||||
+ grub_strlen (file->device->net->server)
|
||||
+ sizeof ("\r\nUser-Agent: " PACKAGE_STRING
|
||||
"\r\n") - 1
|
||||
+ sizeof ("Content-Range: bytes XXXXXXXXXXXXXXXXXXXX"
|
||||
"-XXXXXXXXXXXXXXXXXXXX/"
|
||||
"XXXXXXXXXXXXXXXXXXXX\r\n\r\n"));
|
||||
if (!nb)
|
||||
return grub_errno;
|
||||
|
||||
grub_netbuff_reserve (nb, GRUB_NET_TCP_RESERVE_SIZE);
|
||||
ptr = nb->tail;
|
||||
err = grub_netbuff_put (nb, sizeof ("GET ") - 1);
|
||||
if (err)
|
||||
{
|
||||
grub_netbuff_free (nb);
|
||||
return err;
|
||||
}
|
||||
grub_memcpy (ptr, "GET ", sizeof ("GET ") - 1);
|
||||
|
||||
ptr = nb->tail;
|
||||
|
||||
err = grub_netbuff_put (nb, grub_strlen (data->filename));
|
||||
if (err)
|
||||
{
|
||||
grub_netbuff_free (nb);
|
||||
return err;
|
||||
}
|
||||
grub_memcpy (ptr, data->filename, grub_strlen (data->filename));
|
||||
|
||||
ptr = nb->tail;
|
||||
err = grub_netbuff_put (nb, sizeof (" HTTP/1.1\r\nHost: ") - 1);
|
||||
if (err)
|
||||
{
|
||||
grub_netbuff_free (nb);
|
||||
return err;
|
||||
}
|
||||
grub_memcpy (ptr, " HTTP/1.1\r\nHost: ",
|
||||
sizeof (" HTTP/1.1\r\nHost: ") - 1);
|
||||
|
||||
ptr = nb->tail;
|
||||
err = grub_netbuff_put (nb, grub_strlen (file->device->net->server));
|
||||
if (err)
|
||||
{
|
||||
grub_netbuff_free (nb);
|
||||
return err;
|
||||
}
|
||||
grub_memcpy (ptr, file->device->net->server,
|
||||
grub_strlen (file->device->net->server));
|
||||
|
||||
ptr = nb->tail;
|
||||
err = grub_netbuff_put (nb,
|
||||
sizeof ("\r\nUser-Agent: " PACKAGE_STRING "\r\n")
|
||||
- 1);
|
||||
if (err)
|
||||
{
|
||||
grub_netbuff_free (nb);
|
||||
return err;
|
||||
}
|
||||
grub_memcpy (ptr, "\r\nUser-Agent: " PACKAGE_STRING "\r\n",
|
||||
sizeof ("\r\nUser-Agent: " PACKAGE_STRING "\r\n") - 1);
|
||||
if (!initial)
|
||||
{
|
||||
ptr = nb->tail;
|
||||
grub_snprintf ((char *) ptr,
|
||||
sizeof ("Content-Range: bytes XXXXXXXXXXXXXXXXXXXX-"
|
||||
"XXXXXXXXXXXXXXXXXXXX/XXXXXXXXXXXXXXXXXXXX\r\n"
|
||||
"\r\n"),
|
||||
"Content-Range: bytes %" PRIuGRUB_UINT64_T "-%"
|
||||
PRIuGRUB_UINT64_T "/%" PRIuGRUB_UINT64_T "\r\n\r\n",
|
||||
offset, file->size - 1, file->size);
|
||||
grub_netbuff_put (nb, grub_strlen ((char *) ptr));
|
||||
}
|
||||
ptr = nb->tail;
|
||||
grub_netbuff_put (nb, 2);
|
||||
grub_memcpy (ptr, "\r\n", 2);
|
||||
|
||||
data->sock = grub_net_tcp_open (file->device->net->server,
|
||||
HTTP_PORT, http_receive,
|
||||
http_err, http_err,
|
||||
file);
|
||||
if (!data->sock)
|
||||
{
|
||||
grub_netbuff_free (nb);
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
// grub_net_poll_cards (5000);
|
||||
|
||||
err = grub_net_send_tcp_packet (data->sock, nb, 1);
|
||||
if (err)
|
||||
{
|
||||
grub_net_tcp_close (data->sock, GRUB_NET_TCP_ABORT);
|
||||
return err;
|
||||
}
|
||||
|
||||
for (i = 0; !data->headers_recv && i < 100; i++)
|
||||
{
|
||||
grub_net_tcp_retransmit ();
|
||||
grub_net_poll_cards (300);
|
||||
}
|
||||
|
||||
if (!data->headers_recv)
|
||||
{
|
||||
grub_net_tcp_close (data->sock, GRUB_NET_TCP_ABORT);
|
||||
if (data->err)
|
||||
{
|
||||
char *str = data->errmsg;
|
||||
err = grub_error (data->err, "%s", str);
|
||||
grub_free (str);
|
||||
return data->err;
|
||||
}
|
||||
return grub_error (GRUB_ERR_TIMEOUT, "timeout opening http");
|
||||
}
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
http_seek (struct grub_file *file, grub_off_t off)
|
||||
{
|
||||
struct http_data *old_data, *data;
|
||||
grub_err_t err;
|
||||
old_data = file->data;
|
||||
/* FIXME: Reuse socket? */
|
||||
grub_net_tcp_close (old_data->sock, GRUB_NET_TCP_ABORT);
|
||||
|
||||
while (file->device->net->packs.first)
|
||||
{
|
||||
grub_netbuff_free (file->device->net->packs.first->nb);
|
||||
grub_net_remove_packet (file->device->net->packs.first);
|
||||
}
|
||||
|
||||
file->device->net->offset = off;
|
||||
|
||||
data = grub_zalloc (sizeof (*data));
|
||||
if (!data)
|
||||
return grub_errno;
|
||||
|
||||
data->size_recv = 1;
|
||||
data->filename = old_data->filename;
|
||||
if (!data->filename)
|
||||
{
|
||||
grub_free (data);
|
||||
return grub_errno;
|
||||
}
|
||||
grub_free (old_data);
|
||||
|
||||
file->data = data;
|
||||
err = http_establish (file, off, 0);
|
||||
if (err)
|
||||
{
|
||||
grub_free (data->filename);
|
||||
grub_free (data);
|
||||
return err;
|
||||
}
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
http_open (struct grub_file *file, const char *filename)
|
||||
{
|
||||
grub_err_t err;
|
||||
struct http_data *data;
|
||||
|
||||
data = grub_zalloc (sizeof (*data));
|
||||
if (!data)
|
||||
return grub_errno;
|
||||
file->size = GRUB_FILE_SIZE_UNKNOWN;
|
||||
|
||||
data->filename = grub_strdup (filename);
|
||||
if (!data->filename)
|
||||
{
|
||||
grub_free (data);
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
file->not_easily_seekable = 0;
|
||||
file->data = data;
|
||||
|
||||
err = http_establish (file, 0, 1);
|
||||
if (err)
|
||||
{
|
||||
grub_free (data->filename);
|
||||
grub_free (data);
|
||||
return err;
|
||||
}
|
||||
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
http_close (struct grub_file *file)
|
||||
{
|
||||
http_data_t data = file->data;
|
||||
|
||||
if (data->sock)
|
||||
grub_net_tcp_close (data->sock, GRUB_NET_TCP_ABORT);
|
||||
if (data->current_line)
|
||||
grub_free (data->current_line);
|
||||
grub_free (data);
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
static struct grub_net_app_protocol grub_http_protocol =
|
||||
{
|
||||
.name = "http",
|
||||
.open = http_open,
|
||||
.close = http_close,
|
||||
.seek = http_seek
|
||||
};
|
||||
|
||||
GRUB_MOD_INIT (http)
|
||||
{
|
||||
grub_net_app_level_register (&grub_http_protocol);
|
||||
}
|
||||
|
||||
GRUB_MOD_FINI (http)
|
||||
{
|
||||
grub_net_app_level_unregister (&grub_http_protocol);
|
||||
}
|
122
grub-core/net/icmp.c
Normal file
122
grub-core/net/icmp.c
Normal file
|
@ -0,0 +1,122 @@
|
|||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2010,2011 Free Software Foundation, Inc.
|
||||
*
|
||||
* GRUB is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GRUB is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <grub/net.h>
|
||||
#include <grub/net/ip.h>
|
||||
#include <grub/net/netbuff.h>
|
||||
|
||||
struct icmp_header
|
||||
{
|
||||
grub_uint8_t type;
|
||||
grub_uint8_t code;
|
||||
grub_uint16_t checksum;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct ping_header
|
||||
{
|
||||
grub_uint16_t id;
|
||||
grub_uint16_t seq;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
enum
|
||||
{
|
||||
ICMP_ECHO_REPLY = 0,
|
||||
ICMP_ECHO = 8,
|
||||
};
|
||||
|
||||
grub_err_t
|
||||
grub_net_recv_icmp_packet (struct grub_net_buff *nb,
|
||||
struct grub_net_network_level_interface *inf,
|
||||
const grub_net_link_level_address_t *ll_src,
|
||||
const grub_net_network_level_address_t *src)
|
||||
{
|
||||
struct icmp_header *icmph;
|
||||
grub_err_t err;
|
||||
grub_uint16_t checksum;
|
||||
|
||||
/* Ignore broadcast. */
|
||||
if (!inf)
|
||||
{
|
||||
grub_netbuff_free (nb);
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
icmph = (struct icmp_header *) nb->data;
|
||||
|
||||
if (nb->tail - nb->data < (grub_ssize_t) sizeof (*icmph))
|
||||
{
|
||||
grub_netbuff_free (nb);
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
checksum = icmph->checksum;
|
||||
icmph->checksum = 0;
|
||||
if (checksum != grub_net_ip_chksum (nb->data, nb->tail - nb->data))
|
||||
{
|
||||
icmph->checksum = checksum;
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
icmph->checksum = checksum;
|
||||
|
||||
err = grub_netbuff_pull (nb, sizeof (*icmph));
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
switch (icmph->type)
|
||||
{
|
||||
case ICMP_ECHO:
|
||||
{
|
||||
struct grub_net_buff *nb_reply;
|
||||
struct icmp_header *icmphr;
|
||||
if (icmph->code)
|
||||
break;
|
||||
nb_reply = grub_netbuff_alloc (nb->tail - nb->data + 512);
|
||||
if (!nb_reply)
|
||||
{
|
||||
grub_netbuff_free (nb);
|
||||
return grub_errno;
|
||||
}
|
||||
err = grub_netbuff_reserve (nb_reply, nb->tail - nb->data + 512);
|
||||
if (err)
|
||||
goto ping_fail;
|
||||
err = grub_netbuff_push (nb_reply, nb->tail - nb->data);
|
||||
if (err)
|
||||
goto ping_fail;
|
||||
grub_memcpy (nb_reply->data, nb->data, nb->tail - nb->data);
|
||||
err = grub_netbuff_push (nb_reply, sizeof (*icmphr));
|
||||
if (err)
|
||||
goto ping_fail;
|
||||
icmphr = (struct icmp_header *) nb_reply->data;
|
||||
icmphr->type = ICMP_ECHO_REPLY;
|
||||
icmphr->code = 0;
|
||||
icmphr->checksum = 0;
|
||||
icmphr->checksum = grub_net_ip_chksum ((void *) nb_reply->data,
|
||||
nb_reply->tail - nb_reply->data);
|
||||
err = grub_net_send_ip_packet (inf, src, ll_src,
|
||||
nb_reply, GRUB_NET_IP_ICMP);
|
||||
|
||||
ping_fail:
|
||||
grub_netbuff_free (nb);
|
||||
grub_netbuff_free (nb_reply);
|
||||
return err;
|
||||
}
|
||||
};
|
||||
|
||||
grub_netbuff_free (nb);
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
529
grub-core/net/icmp6.c
Normal file
529
grub-core/net/icmp6.c
Normal file
|
@ -0,0 +1,529 @@
|
|||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2010,2011 Free Software Foundation, Inc.
|
||||
*
|
||||
* GRUB is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GRUB is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <grub/net.h>
|
||||
#include <grub/net/ip.h>
|
||||
#include <grub/net/netbuff.h>
|
||||
|
||||
struct icmp_header
|
||||
{
|
||||
grub_uint8_t type;
|
||||
grub_uint8_t code;
|
||||
grub_uint16_t checksum;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct ping_header
|
||||
{
|
||||
grub_uint16_t id;
|
||||
grub_uint16_t seq;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct router_adv
|
||||
{
|
||||
grub_uint8_t ttl;
|
||||
grub_uint8_t flags;
|
||||
grub_uint16_t router_lifetime;
|
||||
grub_uint32_t reachable_time;
|
||||
grub_uint32_t retrans_timer;
|
||||
grub_uint8_t options[0];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct option_header
|
||||
{
|
||||
grub_uint8_t type;
|
||||
grub_uint8_t len;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct prefix_option
|
||||
{
|
||||
struct option_header header;
|
||||
grub_uint8_t prefixlen;
|
||||
grub_uint8_t flags;
|
||||
grub_uint32_t valid_lifetime;
|
||||
grub_uint32_t prefered_lifetime;
|
||||
grub_uint32_t reserved;
|
||||
grub_uint64_t prefix[2];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct neighbour_solicit
|
||||
{
|
||||
grub_uint32_t reserved;
|
||||
grub_uint64_t target[2];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct neighbour_advertise
|
||||
{
|
||||
grub_uint32_t flags;
|
||||
grub_uint64_t target[2];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
enum
|
||||
{
|
||||
FLAG_SLAAC = 0x40
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
ICMP6_ECHO = 128,
|
||||
ICMP6_ECHO_REPLY = 129,
|
||||
ICMP6_ROUTER_ADVERTISE = 134,
|
||||
ICMP6_NEIGHBOUR_SOLICIT = 135,
|
||||
ICMP6_NEIGHBOUR_ADVERTISE = 136,
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
OPTION_SOURCE_LINK_LAYER_ADDRESS = 1,
|
||||
OPTION_TARGET_LINK_LAYER_ADDRESS = 2,
|
||||
OPTION_PREFIX = 3
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
FLAG_SOLICITED = (1 << 30),
|
||||
FLAG_OVERRIDE = (1 << 29)
|
||||
};
|
||||
|
||||
grub_err_t
|
||||
grub_net_recv_icmp6_packet (struct grub_net_buff *nb,
|
||||
struct grub_net_card *card,
|
||||
struct grub_net_network_level_interface *inf,
|
||||
const grub_net_link_level_address_t *ll_src,
|
||||
const grub_net_network_level_address_t *source,
|
||||
const grub_net_network_level_address_t *dest,
|
||||
grub_uint8_t ttl)
|
||||
{
|
||||
struct icmp_header *icmph;
|
||||
grub_err_t err;
|
||||
grub_uint16_t checksum;
|
||||
|
||||
icmph = (struct icmp_header *) nb->data;
|
||||
|
||||
if (nb->tail - nb->data < (grub_ssize_t) sizeof (*icmph))
|
||||
{
|
||||
grub_netbuff_free (nb);
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
checksum = icmph->checksum;
|
||||
icmph->checksum = 0;
|
||||
if (checksum != grub_net_ip_transport_checksum (nb,
|
||||
GRUB_NET_IP_ICMPV6,
|
||||
source,
|
||||
dest))
|
||||
{
|
||||
grub_dprintf ("net", "invalid ICMPv6 checksum: %04x instead of %04x\n",
|
||||
checksum,
|
||||
grub_net_ip_transport_checksum (nb,
|
||||
GRUB_NET_IP_ICMPV6,
|
||||
source,
|
||||
dest));
|
||||
icmph->checksum = checksum;
|
||||
grub_netbuff_free (nb);
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
icmph->checksum = checksum;
|
||||
|
||||
err = grub_netbuff_pull (nb, sizeof (*icmph));
|
||||
if (err)
|
||||
{
|
||||
grub_netbuff_free (nb);
|
||||
return err;
|
||||
}
|
||||
|
||||
grub_dprintf ("net", "ICMPv6 message: %02x, %02x\n",
|
||||
icmph->type, icmph->code);
|
||||
switch (icmph->type)
|
||||
{
|
||||
case ICMP6_ECHO:
|
||||
/* Don't accept multicast pings. */
|
||||
if (!inf)
|
||||
break;
|
||||
{
|
||||
struct grub_net_buff *nb_reply;
|
||||
struct icmp_header *icmphr;
|
||||
if (icmph->code)
|
||||
break;
|
||||
nb_reply = grub_netbuff_alloc (nb->tail - nb->data + 512);
|
||||
if (!nb_reply)
|
||||
{
|
||||
grub_netbuff_free (nb);
|
||||
return grub_errno;
|
||||
}
|
||||
err = grub_netbuff_reserve (nb_reply, nb->tail - nb->data + 512);
|
||||
if (err)
|
||||
goto ping_fail;
|
||||
err = grub_netbuff_push (nb_reply, nb->tail - nb->data);
|
||||
if (err)
|
||||
goto ping_fail;
|
||||
grub_memcpy (nb_reply->data, nb->data, nb->tail - nb->data);
|
||||
err = grub_netbuff_push (nb_reply, sizeof (*icmphr));
|
||||
if (err)
|
||||
goto ping_fail;
|
||||
icmphr = (struct icmp_header *) nb_reply->data;
|
||||
icmphr->type = ICMP6_ECHO_REPLY;
|
||||
icmphr->code = 0;
|
||||
icmphr->checksum = 0;
|
||||
icmphr->checksum = grub_net_ip_transport_checksum (nb_reply,
|
||||
GRUB_NET_IP_ICMPV6,
|
||||
&inf->address,
|
||||
source);
|
||||
err = grub_net_send_ip_packet (inf, source, ll_src, nb_reply,
|
||||
GRUB_NET_IP_ICMPV6);
|
||||
|
||||
ping_fail:
|
||||
grub_netbuff_free (nb);
|
||||
grub_netbuff_free (nb_reply);
|
||||
return err;
|
||||
}
|
||||
case ICMP6_NEIGHBOUR_SOLICIT:
|
||||
{
|
||||
struct neighbour_solicit *nbh;
|
||||
struct grub_net_buff *nb_reply;
|
||||
struct option_header *ohdr;
|
||||
struct neighbour_advertise *adv;
|
||||
struct icmp_header *icmphr;
|
||||
grub_uint8_t *ptr;
|
||||
|
||||
if (icmph->code)
|
||||
break;
|
||||
if (ttl != 0xff)
|
||||
break;
|
||||
nbh = (struct neighbour_solicit *) nb->data;
|
||||
err = grub_netbuff_pull (nb, sizeof (struct router_adv));
|
||||
if (err)
|
||||
{
|
||||
grub_netbuff_free (nb);
|
||||
return err;
|
||||
}
|
||||
for (ptr = (grub_uint8_t *) nb->data; ptr < nb->tail;
|
||||
ptr += ohdr->len * 8)
|
||||
{
|
||||
ohdr = (struct option_header *) ptr;
|
||||
if (ohdr->len == 0 || ptr + 8 * ohdr->len > nb->tail)
|
||||
{
|
||||
grub_netbuff_free (nb);
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
if (ohdr->type == OPTION_SOURCE_LINK_LAYER_ADDRESS
|
||||
&& ohdr->len == 1)
|
||||
{
|
||||
grub_net_link_level_address_t ll_address;
|
||||
ll_address.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET;
|
||||
grub_memcpy (ll_address.mac, ohdr + 1, sizeof (ll_address.mac));
|
||||
grub_net_link_layer_add_address (card, source, &ll_address, 0);
|
||||
}
|
||||
}
|
||||
FOR_NET_NETWORK_LEVEL_INTERFACES (inf)
|
||||
{
|
||||
if (inf->card == card
|
||||
&& inf->address.type == GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6
|
||||
&& grub_memcmp (&inf->address.ipv6, &nbh->target, 16) == 0)
|
||||
break;
|
||||
}
|
||||
if (!inf)
|
||||
break;
|
||||
|
||||
nb_reply = grub_netbuff_alloc (sizeof (struct neighbour_advertise)
|
||||
+ sizeof (struct option_header)
|
||||
+ 6
|
||||
+ sizeof (struct icmp_header)
|
||||
+ GRUB_NET_OUR_IPV6_HEADER_SIZE
|
||||
+ GRUB_NET_MAX_LINK_HEADER_SIZE);
|
||||
if (!nb_reply)
|
||||
{
|
||||
grub_netbuff_free (nb);
|
||||
return grub_errno;
|
||||
}
|
||||
err = grub_netbuff_reserve (nb_reply,
|
||||
sizeof (struct neighbour_advertise)
|
||||
+ sizeof (struct option_header)
|
||||
+ 6
|
||||
+ sizeof (struct icmp_header)
|
||||
+ GRUB_NET_OUR_IPV6_HEADER_SIZE
|
||||
+ GRUB_NET_MAX_LINK_HEADER_SIZE);
|
||||
if (err)
|
||||
goto ndp_fail;
|
||||
|
||||
err = grub_netbuff_push (nb_reply, 6);
|
||||
if (err)
|
||||
goto ndp_fail;
|
||||
grub_memcpy (nb_reply->data, inf->hwaddress.mac, 6);
|
||||
err = grub_netbuff_push (nb_reply, sizeof (*ohdr));
|
||||
if (err)
|
||||
goto ndp_fail;
|
||||
ohdr = (struct option_header *) nb_reply->data;
|
||||
ohdr->type = OPTION_TARGET_LINK_LAYER_ADDRESS;
|
||||
ohdr->len = 1;
|
||||
err = grub_netbuff_push (nb_reply, sizeof (*adv));
|
||||
if (err)
|
||||
goto ndp_fail;
|
||||
adv = (struct neighbour_advertise *) nb_reply->data;
|
||||
adv->flags = grub_cpu_to_be32_compile_time (FLAG_SOLICITED
|
||||
| FLAG_OVERRIDE);
|
||||
grub_memcpy (&adv->target, &nbh->target, 16);
|
||||
|
||||
err = grub_netbuff_push (nb_reply, sizeof (*icmphr));
|
||||
if (err)
|
||||
goto ndp_fail;
|
||||
icmphr = (struct icmp_header *) nb_reply->data;
|
||||
icmphr->type = ICMP6_NEIGHBOUR_ADVERTISE;
|
||||
icmphr->code = 0;
|
||||
icmphr->checksum = 0;
|
||||
icmphr->checksum = grub_net_ip_transport_checksum (nb_reply,
|
||||
GRUB_NET_IP_ICMPV6,
|
||||
&inf->address,
|
||||
source);
|
||||
err = grub_net_send_ip_packet (inf, source, ll_src, nb_reply,
|
||||
GRUB_NET_IP_ICMPV6);
|
||||
|
||||
ndp_fail:
|
||||
grub_netbuff_free (nb);
|
||||
grub_netbuff_free (nb_reply);
|
||||
return err;
|
||||
}
|
||||
case ICMP6_NEIGHBOUR_ADVERTISE:
|
||||
{
|
||||
struct neighbour_advertise *nbh;
|
||||
grub_uint8_t *ptr;
|
||||
struct option_header *ohdr;
|
||||
|
||||
if (icmph->code)
|
||||
break;
|
||||
if (ttl != 0xff)
|
||||
break;
|
||||
nbh = (struct neighbour_advertise *) nb->data;
|
||||
err = grub_netbuff_pull (nb, sizeof (*nbh));
|
||||
if (err)
|
||||
{
|
||||
grub_netbuff_free (nb);
|
||||
return err;
|
||||
}
|
||||
|
||||
for (ptr = (grub_uint8_t *) nb->data; ptr < nb->tail;
|
||||
ptr += ohdr->len * 8)
|
||||
{
|
||||
ohdr = (struct option_header *) ptr;
|
||||
if (ohdr->len == 0 || ptr + 8 * ohdr->len > nb->tail)
|
||||
{
|
||||
grub_netbuff_free (nb);
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
if (ohdr->type == OPTION_TARGET_LINK_LAYER_ADDRESS
|
||||
&& ohdr->len == 1)
|
||||
{
|
||||
grub_net_link_level_address_t ll_address;
|
||||
ll_address.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET;
|
||||
grub_memcpy (ll_address.mac, ohdr + 1, sizeof (ll_address.mac));
|
||||
grub_net_link_layer_add_address (card, source, &ll_address, 0);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ICMP6_ROUTER_ADVERTISE:
|
||||
{
|
||||
grub_uint8_t *ptr;
|
||||
struct option_header *ohdr;
|
||||
if (icmph->code)
|
||||
break;
|
||||
err = grub_netbuff_pull (nb, sizeof (struct router_adv));
|
||||
if (err)
|
||||
{
|
||||
grub_netbuff_free (nb);
|
||||
return err;
|
||||
}
|
||||
for (ptr = (grub_uint8_t *) nb->data; ptr < nb->tail;
|
||||
ptr += ohdr->len * 8)
|
||||
{
|
||||
ohdr = (struct option_header *) ptr;
|
||||
if (ohdr->len == 0 || ptr + 8 * ohdr->len > nb->tail)
|
||||
{
|
||||
grub_netbuff_free (nb);
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
if (ohdr->type == OPTION_SOURCE_LINK_LAYER_ADDRESS
|
||||
&& ohdr->len == 1)
|
||||
{
|
||||
grub_net_link_level_address_t ll_address;
|
||||
ll_address.type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET;
|
||||
grub_memcpy (ll_address.mac, ohdr + 1, sizeof (ll_address.mac));
|
||||
grub_net_link_layer_add_address (card, source, &ll_address, 0);
|
||||
}
|
||||
if (ohdr->type == OPTION_PREFIX && ohdr->len == 4)
|
||||
{
|
||||
struct prefix_option *opt = (struct prefix_option *) ptr;
|
||||
struct grub_net_slaac_mac_list *slaac;
|
||||
if (!(opt->flags & FLAG_SLAAC)
|
||||
|| (grub_be_to_cpu64 (opt->prefix[0]) >> 48) == 0xfe80
|
||||
|| (grub_be_to_cpu32 (opt->prefered_lifetime)
|
||||
> grub_be_to_cpu32 (opt->valid_lifetime))
|
||||
|| opt->prefixlen != 64)
|
||||
{
|
||||
grub_dprintf ("net", "discarded prefix: %d, %d, %d, %d\n",
|
||||
!(opt->flags & FLAG_SLAAC),
|
||||
(grub_be_to_cpu64 (opt->prefix[0]) >> 48) == 0xfe80,
|
||||
(grub_be_to_cpu32 (opt->prefered_lifetime)
|
||||
> grub_be_to_cpu32 (opt->valid_lifetime)),
|
||||
opt->prefixlen != 64);
|
||||
continue;
|
||||
}
|
||||
for (slaac = card->slaac_list; slaac; slaac = slaac->next)
|
||||
{
|
||||
grub_net_network_level_address_t addr;
|
||||
grub_net_network_level_netaddress_t netaddr;
|
||||
|
||||
if (slaac->address.type
|
||||
!= GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET)
|
||||
continue;
|
||||
addr.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6;
|
||||
addr.ipv6[0] = opt->prefix[0];
|
||||
addr.ipv6[1] = grub_net_ipv6_get_id (&slaac->address);
|
||||
netaddr.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6;
|
||||
netaddr.ipv6.base[0] = opt->prefix[0];
|
||||
netaddr.ipv6.base[1] = 0;
|
||||
netaddr.ipv6.masksize = 64;
|
||||
|
||||
FOR_NET_NETWORK_LEVEL_INTERFACES (inf)
|
||||
{
|
||||
if (inf->card == card
|
||||
&& grub_net_addr_cmp (&inf->address, &addr) == 0)
|
||||
break;
|
||||
}
|
||||
/* Update lease time if needed here once we have
|
||||
lease times. */
|
||||
if (inf)
|
||||
continue;
|
||||
|
||||
grub_dprintf ("net", "creating slaac\n");
|
||||
|
||||
{
|
||||
char name[grub_strlen (slaac->name)
|
||||
+ sizeof (":XXXXXXXXXXXXXXXXXXXX")];
|
||||
grub_snprintf (name, sizeof (name), "%s:%d",
|
||||
slaac->name, slaac->slaac_counter++);
|
||||
inf = grub_net_add_addr (name,
|
||||
card, &addr,
|
||||
&slaac->address, 0);
|
||||
grub_net_add_route (name, netaddr, inf);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ptr != nb->tail)
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
grub_netbuff_free (nb);
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
grub_err_t
|
||||
grub_net_icmp6_send_request (struct grub_net_network_level_interface *inf,
|
||||
const grub_net_network_level_address_t *proto_addr)
|
||||
{
|
||||
struct grub_net_buff *nb;
|
||||
grub_err_t err = GRUB_ERR_NONE;
|
||||
int i;
|
||||
struct option_header *ohdr;
|
||||
struct neighbour_solicit *sol;
|
||||
struct icmp_header *icmphr;
|
||||
grub_net_network_level_address_t multicast;
|
||||
grub_net_link_level_address_t ll_multicast;
|
||||
grub_uint8_t *nbd;
|
||||
multicast.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6;
|
||||
multicast.ipv6[0] = grub_be_to_cpu64_compile_time (0xff02ULL << 48);
|
||||
multicast.ipv6[1] = (grub_be_to_cpu64_compile_time (0x01ff000000ULL)
|
||||
| (proto_addr->ipv6[1]
|
||||
& grub_be_to_cpu64_compile_time (0xffffff)));
|
||||
|
||||
err = grub_net_link_layer_resolve (inf, &multicast, &ll_multicast);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
nb = grub_netbuff_alloc (sizeof (struct neighbour_solicit)
|
||||
+ sizeof (struct option_header)
|
||||
+ 6
|
||||
+ sizeof (struct icmp_header)
|
||||
+ GRUB_NET_OUR_IPV6_HEADER_SIZE
|
||||
+ GRUB_NET_MAX_LINK_HEADER_SIZE);
|
||||
if (!nb)
|
||||
return grub_errno;
|
||||
err = grub_netbuff_reserve (nb,
|
||||
sizeof (struct neighbour_solicit)
|
||||
+ sizeof (struct option_header)
|
||||
+ 6
|
||||
+ sizeof (struct icmp_header)
|
||||
+ GRUB_NET_OUR_IPV6_HEADER_SIZE
|
||||
+ GRUB_NET_MAX_LINK_HEADER_SIZE);
|
||||
err = grub_netbuff_push (nb, 6);
|
||||
if (err)
|
||||
goto fail;
|
||||
|
||||
grub_memcpy (nb->data, inf->hwaddress.mac, 6);
|
||||
err = grub_netbuff_push (nb, sizeof (*ohdr));
|
||||
if (err)
|
||||
goto fail;
|
||||
|
||||
ohdr = (struct option_header *) nb->data;
|
||||
ohdr->type = OPTION_SOURCE_LINK_LAYER_ADDRESS;
|
||||
ohdr->len = 1;
|
||||
err = grub_netbuff_push (nb, sizeof (*sol));
|
||||
if (err)
|
||||
goto fail;
|
||||
|
||||
sol = (struct neighbour_solicit *) nb->data;
|
||||
sol->reserved = 0;
|
||||
grub_memcpy (&sol->target, &proto_addr->ipv6, 16);
|
||||
|
||||
err = grub_netbuff_push (nb, sizeof (*icmphr));
|
||||
if (err)
|
||||
goto fail;
|
||||
|
||||
icmphr = (struct icmp_header *) nb->data;
|
||||
icmphr->type = ICMP6_NEIGHBOUR_SOLICIT;
|
||||
icmphr->code = 0;
|
||||
icmphr->checksum = 0;
|
||||
icmphr->checksum = grub_net_ip_transport_checksum (nb,
|
||||
GRUB_NET_IP_ICMPV6,
|
||||
&inf->address,
|
||||
&multicast);
|
||||
nbd = nb->data;
|
||||
err = grub_net_send_ip_packet (inf, &multicast, &ll_multicast, nb,
|
||||
GRUB_NET_IP_ICMPV6);
|
||||
if (err)
|
||||
goto fail;
|
||||
|
||||
for (i = 0; i < GRUB_NET_TRIES; i++)
|
||||
{
|
||||
if (grub_net_link_layer_resolve_check (inf, proto_addr))
|
||||
break;
|
||||
grub_net_poll_cards (GRUB_NET_INTERVAL);
|
||||
if (grub_net_link_layer_resolve_check (inf, proto_addr))
|
||||
break;
|
||||
nb->data = nbd;
|
||||
err = grub_net_send_ip_packet (inf, &multicast, &ll_multicast, nb,
|
||||
GRUB_NET_IP_ICMPV6);
|
||||
if (err)
|
||||
break;
|
||||
}
|
||||
|
||||
fail:
|
||||
grub_netbuff_free (nb);
|
||||
return err;
|
||||
}
|
|
@ -24,6 +24,8 @@
|
|||
#include <grub/net.h>
|
||||
#include <grub/net/netbuff.h>
|
||||
#include <grub/mm.h>
|
||||
#include <grub/priority_queue.h>
|
||||
#include <grub/time.h>
|
||||
|
||||
struct iphdr {
|
||||
grub_uint8_t verhdrlen;
|
||||
|
@ -38,43 +40,162 @@ struct iphdr {
|
|||
grub_uint32_t dest;
|
||||
} __attribute__ ((packed)) ;
|
||||
|
||||
struct ip6hdr
|
||||
enum
|
||||
{
|
||||
grub_uint8_t version:4, priority:4;
|
||||
grub_uint8_t flow_lbl[3];
|
||||
grub_uint16_t payload_len;
|
||||
grub_uint8_t nexthdr;
|
||||
grub_uint8_t hop_limit;
|
||||
grub_uint8_t saddr[16];
|
||||
grub_uint8_t daddr[16];
|
||||
DONT_FRAGMENT = 0x4000,
|
||||
MORE_FRAGMENTS = 0x2000,
|
||||
OFFSET_MASK = 0x1fff
|
||||
};
|
||||
|
||||
typedef grub_uint64_t ip6addr[2];
|
||||
|
||||
struct ip6hdr {
|
||||
grub_uint32_t version_class_flow;
|
||||
grub_uint16_t len;
|
||||
grub_uint8_t protocol;
|
||||
grub_uint8_t ttl;
|
||||
ip6addr src;
|
||||
ip6addr dest;
|
||||
} __attribute__ ((packed)) ;
|
||||
|
||||
static int
|
||||
cmp (const void *a__, const void *b__)
|
||||
{
|
||||
struct grub_net_buff *a_ = *(struct grub_net_buff **) a__;
|
||||
struct grub_net_buff *b_ = *(struct grub_net_buff **) b__;
|
||||
struct iphdr *a = (struct iphdr *) a_->data;
|
||||
struct iphdr *b = (struct iphdr *) b_->data;
|
||||
/* We want the first elements to be on top. */
|
||||
if ((grub_be_to_cpu16 (a->frags) & OFFSET_MASK)
|
||||
< (grub_be_to_cpu16 (b->frags) & OFFSET_MASK))
|
||||
return +1;
|
||||
if ((grub_be_to_cpu16 (a->frags) & OFFSET_MASK)
|
||||
> (grub_be_to_cpu16 (b->frags) & OFFSET_MASK))
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct reassemble
|
||||
{
|
||||
struct reassemble *next;
|
||||
grub_uint32_t source;
|
||||
grub_uint32_t dest;
|
||||
grub_uint16_t id;
|
||||
grub_uint8_t proto;
|
||||
grub_uint64_t last_time;
|
||||
grub_priority_queue_t pq;
|
||||
grub_uint8_t *asm_buffer;
|
||||
grub_size_t total_len;
|
||||
grub_size_t cur_ptr;
|
||||
grub_uint8_t ttl;
|
||||
};
|
||||
|
||||
static struct reassemble *reassembles;
|
||||
|
||||
grub_uint16_t
|
||||
grub_net_ip_chksum (void *ipv, int len)
|
||||
grub_net_ip_chksum (void *ipv, grub_size_t len)
|
||||
{
|
||||
grub_uint16_t *ip = (grub_uint16_t *) ipv;
|
||||
grub_uint32_t sum = 0;
|
||||
|
||||
len >>= 1;
|
||||
while (len--)
|
||||
for (; len >= 2; len -= 2)
|
||||
{
|
||||
sum += grub_be_to_cpu16 (*(ip++));
|
||||
sum += grub_be_to_cpu16 (grub_get_unaligned16 (ip++));
|
||||
if (sum > 0xFFFF)
|
||||
sum -= 0xFFFF;
|
||||
}
|
||||
if (len)
|
||||
{
|
||||
sum += *((grub_uint8_t *) ip) << 8;
|
||||
if (sum > 0xFFFF)
|
||||
sum -= 0xFFFF;
|
||||
}
|
||||
|
||||
if (sum >= 0xFFFF)
|
||||
sum -= 0xFFFF;
|
||||
|
||||
return grub_cpu_to_be16 ((~sum) & 0x0000FFFF);
|
||||
}
|
||||
|
||||
grub_err_t
|
||||
grub_net_send_ip_packet (struct grub_net_network_level_interface * inf,
|
||||
static int id = 0x2400;
|
||||
|
||||
static grub_err_t
|
||||
send_fragmented (struct grub_net_network_level_interface * inf,
|
||||
const grub_net_network_level_address_t * target,
|
||||
struct grub_net_buff * nb)
|
||||
struct grub_net_buff * nb,
|
||||
grub_net_ip_protocol_t proto,
|
||||
grub_net_link_level_address_t ll_target_addr)
|
||||
{
|
||||
grub_size_t off = 0;
|
||||
grub_size_t fraglen;
|
||||
grub_err_t err;
|
||||
|
||||
fraglen = (inf->card->mtu - sizeof (struct iphdr)) & ~7;
|
||||
id++;
|
||||
|
||||
while (nb->tail - nb->data)
|
||||
{
|
||||
grub_size_t len = fraglen;
|
||||
struct grub_net_buff *nb2;
|
||||
struct iphdr *iph;
|
||||
|
||||
if ((grub_ssize_t) len > nb->tail - nb->data)
|
||||
len = nb->tail - nb->data;
|
||||
nb2 = grub_netbuff_alloc (fraglen + sizeof (struct iphdr)
|
||||
+ GRUB_NET_MAX_LINK_HEADER_SIZE);
|
||||
if (!nb2)
|
||||
return grub_errno;
|
||||
err = grub_netbuff_reserve (nb2, GRUB_NET_MAX_LINK_HEADER_SIZE);
|
||||
if (err)
|
||||
return err;
|
||||
err = grub_netbuff_put (nb2, sizeof (struct iphdr));
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
iph = (struct iphdr *) nb2->data;
|
||||
iph->verhdrlen = ((4 << 4) | 5);
|
||||
iph->service = 0;
|
||||
iph->len = grub_cpu_to_be16 (len + sizeof (struct iphdr));
|
||||
iph->ident = grub_cpu_to_be16 (id);
|
||||
iph->frags = grub_cpu_to_be16 (off | (((grub_ssize_t) len
|
||||
== nb->tail - nb->data)
|
||||
? 0 : MORE_FRAGMENTS));
|
||||
iph->ttl = 0xff;
|
||||
iph->protocol = proto;
|
||||
iph->src = inf->address.ipv4;
|
||||
iph->dest = target->ipv4;
|
||||
off += len / 8;
|
||||
|
||||
iph->chksum = 0;
|
||||
iph->chksum = grub_net_ip_chksum ((void *) nb2->data, sizeof (*iph));
|
||||
err = grub_netbuff_put (nb2, len);
|
||||
if (err)
|
||||
return err;
|
||||
grub_memcpy (iph + 1, nb->data, len);
|
||||
err = grub_netbuff_pull (nb, len);
|
||||
if (err)
|
||||
return err;
|
||||
err = send_ethernet_packet (inf, nb2, ll_target_addr,
|
||||
GRUB_NET_ETHERTYPE_IP);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_net_send_ip4_packet (struct grub_net_network_level_interface *inf,
|
||||
const grub_net_network_level_address_t *target,
|
||||
const grub_net_link_level_address_t *ll_target_addr,
|
||||
struct grub_net_buff *nb,
|
||||
grub_net_ip_protocol_t proto)
|
||||
{
|
||||
struct iphdr *iph;
|
||||
static int id = 0x2400;
|
||||
grub_net_link_level_address_t ll_target_addr;
|
||||
grub_err_t err;
|
||||
|
||||
COMPILE_TIME_ASSERT (GRUB_NET_OUR_IPV4_HEADER_SIZE == sizeof (*iph));
|
||||
|
||||
if (nb->tail - nb->data + sizeof (struct iphdr) > inf->card->mtu)
|
||||
return send_fragmented (inf, target, nb, proto, *ll_target_addr);
|
||||
|
||||
grub_netbuff_push (nb, sizeof (*iph));
|
||||
iph = (struct iphdr *) nb->data;
|
||||
|
@ -85,75 +206,495 @@ grub_net_send_ip_packet (struct grub_net_network_level_interface * inf,
|
|||
iph->ident = grub_cpu_to_be16 (++id);
|
||||
iph->frags = 0;
|
||||
iph->ttl = 0xff;
|
||||
iph->protocol = 0x11;
|
||||
iph->protocol = proto;
|
||||
iph->src = inf->address.ipv4;
|
||||
iph->dest = target->ipv4;
|
||||
|
||||
iph->chksum = 0;
|
||||
iph->chksum = grub_net_ip_chksum ((void *) nb->data, sizeof (*iph));
|
||||
|
||||
/* Determine link layer target address via ARP. */
|
||||
err = grub_net_arp_resolve (inf, target, &ll_target_addr);
|
||||
if (err)
|
||||
return err;
|
||||
return send_ethernet_packet (inf, nb, ll_target_addr,
|
||||
return send_ethernet_packet (inf, nb, *ll_target_addr,
|
||||
GRUB_NET_ETHERTYPE_IP);
|
||||
}
|
||||
|
||||
grub_err_t
|
||||
grub_net_recv_ip_packets (struct grub_net_buff * nb,
|
||||
const struct grub_net_card * card,
|
||||
const grub_net_link_level_address_t * hwaddress)
|
||||
static grub_err_t
|
||||
handle_dgram (struct grub_net_buff *nb,
|
||||
struct grub_net_card *card,
|
||||
const grub_net_link_level_address_t *source_hwaddress,
|
||||
const grub_net_link_level_address_t *hwaddress,
|
||||
grub_net_ip_protocol_t proto,
|
||||
const grub_net_network_level_address_t *source,
|
||||
const grub_net_network_level_address_t *dest,
|
||||
grub_uint8_t ttl)
|
||||
{
|
||||
struct iphdr *iph = (struct iphdr *) nb->data;
|
||||
grub_err_t err;
|
||||
struct grub_net_network_level_interface *inf = NULL;
|
||||
|
||||
err = grub_netbuff_pull (nb, sizeof (*iph));
|
||||
if (err)
|
||||
return err;
|
||||
grub_err_t err;
|
||||
int multicast = 0;
|
||||
|
||||
/* DHCP needs special treatment since we don't know IP yet. */
|
||||
{
|
||||
struct udphdr *udph;
|
||||
udph = (struct udphdr *) nb->data;
|
||||
if (iph->protocol == IP_UDP && grub_be_to_cpu16 (udph->dst) == 68)
|
||||
if (proto == GRUB_NET_IP_UDP && grub_be_to_cpu16 (udph->dst) == 68)
|
||||
{
|
||||
FOR_NET_NETWORK_LEVEL_INTERFACES (inf)
|
||||
if (inf->card == card
|
||||
&& inf->address.type == GRUB_NET_NETWORK_LEVEL_PROTOCOL_DHCP_RECV
|
||||
&& grub_net_hwaddr_cmp (&inf->hwaddress, hwaddress) == 0)
|
||||
{
|
||||
if (udph->chksum)
|
||||
{
|
||||
grub_uint16_t chk, expected;
|
||||
chk = udph->chksum;
|
||||
udph->chksum = 0;
|
||||
expected = grub_net_ip_transport_checksum (nb,
|
||||
GRUB_NET_IP_UDP,
|
||||
source,
|
||||
dest);
|
||||
if (expected != chk)
|
||||
{
|
||||
grub_dprintf ("net", "Invalid UDP checksum. "
|
||||
"Expected %x, got %x\n",
|
||||
grub_be_to_cpu16 (expected),
|
||||
grub_be_to_cpu16 (chk));
|
||||
grub_netbuff_free (nb);
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
udph->chksum = chk;
|
||||
}
|
||||
|
||||
err = grub_netbuff_pull (nb, sizeof (*udph));
|
||||
if (err)
|
||||
return err;
|
||||
grub_net_process_dhcp (nb, inf->card);
|
||||
grub_netbuff_free (nb);
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
grub_netbuff_free (nb);
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
if (!inf)
|
||||
{
|
||||
FOR_NET_NETWORK_LEVEL_INTERFACES (inf)
|
||||
{
|
||||
if (inf->card == card
|
||||
&& inf->address.type == GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4
|
||||
&& inf->address.ipv4 == iph->dest
|
||||
&& grub_net_addr_cmp (&inf->address, dest) == 0
|
||||
&& grub_net_hwaddr_cmp (&inf->hwaddress, hwaddress) == 0)
|
||||
break;
|
||||
/* Solicited node multicast. */
|
||||
if (inf->card == card
|
||||
&& inf->address.type == GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6
|
||||
&& dest->type == GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6
|
||||
&& dest->ipv6[0] == grub_be_to_cpu64_compile_time (0xff02ULL << 48)
|
||||
&& dest->ipv6[1] == (grub_be_to_cpu64_compile_time (0x01ff000000ULL)
|
||||
| (inf->address.ipv6[1]
|
||||
& grub_be_to_cpu64_compile_time (0xffffff)))
|
||||
&& hwaddress->type == GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET
|
||||
&& hwaddress->mac[0] == 0x33 && hwaddress->mac[1] == 0x33
|
||||
&& hwaddress->mac[2] == 0xff
|
||||
&& hwaddress->mac[3] == ((grub_be_to_cpu64 (inf->address.ipv6[1])
|
||||
>> 16) & 0xff)
|
||||
&& hwaddress->mac[4] == ((grub_be_to_cpu64 (inf->address.ipv6[1])
|
||||
>> 8) & 0xff)
|
||||
&& hwaddress->mac[5] == ((grub_be_to_cpu64 (inf->address.ipv6[1])
|
||||
>> 0) & 0xff))
|
||||
{
|
||||
multicast = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
switch (iph->protocol)
|
||||
if (!inf && !(dest->type == GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6
|
||||
&& dest->ipv6[0] == grub_be_to_cpu64_compile_time (0xff02ULL
|
||||
<< 48)
|
||||
&& dest->ipv6[1] == grub_be_to_cpu64_compile_time (1)))
|
||||
{
|
||||
case IP_UDP:
|
||||
return grub_net_recv_udp_packet (nb, inf);
|
||||
grub_netbuff_free (nb);
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
if (multicast)
|
||||
inf = NULL;
|
||||
|
||||
switch (proto)
|
||||
{
|
||||
case GRUB_NET_IP_UDP:
|
||||
return grub_net_recv_udp_packet (nb, inf, source);
|
||||
case GRUB_NET_IP_TCP:
|
||||
return grub_net_recv_tcp_packet (nb, inf, source);
|
||||
case GRUB_NET_IP_ICMP:
|
||||
return grub_net_recv_icmp_packet (nb, inf, source_hwaddress, source);
|
||||
case GRUB_NET_IP_ICMPV6:
|
||||
return grub_net_recv_icmp6_packet (nb, card, inf, source_hwaddress,
|
||||
source, dest, ttl);
|
||||
default:
|
||||
grub_netbuff_free (nb);
|
||||
break;
|
||||
}
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
static void
|
||||
free_rsm (struct reassemble *rsm)
|
||||
{
|
||||
struct grub_net_buff **nb;
|
||||
while ((nb = grub_priority_queue_top (rsm->pq)))
|
||||
{
|
||||
grub_netbuff_free (*nb);
|
||||
grub_priority_queue_pop (rsm->pq);
|
||||
}
|
||||
grub_free (rsm->asm_buffer);
|
||||
grub_priority_queue_destroy (rsm->pq);
|
||||
}
|
||||
|
||||
static void
|
||||
free_old_fragments (void)
|
||||
{
|
||||
struct reassemble *rsm, **prev;
|
||||
grub_uint64_t limit_time = grub_get_time_ms () - 90000;
|
||||
|
||||
for (prev = &reassembles, rsm = *prev; rsm; prev = &rsm->next, rsm = *prev)
|
||||
if (rsm->last_time < limit_time)
|
||||
{
|
||||
*prev = rsm->next;
|
||||
free_rsm (rsm);
|
||||
}
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_net_recv_ip4_packets (struct grub_net_buff *nb,
|
||||
struct grub_net_card *card,
|
||||
const grub_net_link_level_address_t *hwaddress,
|
||||
const grub_net_link_level_address_t *src_hwaddress)
|
||||
{
|
||||
struct iphdr *iph = (struct iphdr *) nb->data;
|
||||
grub_err_t err;
|
||||
struct reassemble *rsm, **prev;
|
||||
|
||||
if ((iph->verhdrlen >> 4) != 4)
|
||||
{
|
||||
grub_dprintf ("net", "Bad IP version: %d\n", (iph->verhdrlen >> 4));
|
||||
grub_netbuff_free (nb);
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
if ((iph->verhdrlen & 0xf) < 5)
|
||||
{
|
||||
grub_dprintf ("net", "IP header too short: %d\n",
|
||||
(iph->verhdrlen & 0xf));
|
||||
grub_netbuff_free (nb);
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
if (nb->tail - nb->data < (grub_ssize_t) ((iph->verhdrlen & 0xf)
|
||||
* sizeof (grub_uint32_t)))
|
||||
{
|
||||
grub_dprintf ("net", "IP packet too short: %" PRIdGRUB_SSIZE "\n",
|
||||
(nb->tail - nb->data));
|
||||
grub_netbuff_free (nb);
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
/* Check size. */
|
||||
{
|
||||
grub_size_t expected_size = grub_be_to_cpu16 (iph->len);
|
||||
grub_size_t actual_size = (nb->tail - nb->data);
|
||||
if (actual_size > expected_size)
|
||||
{
|
||||
err = grub_netbuff_unput (nb, actual_size - expected_size);
|
||||
if (err)
|
||||
{
|
||||
grub_netbuff_free (nb);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
if (actual_size < expected_size)
|
||||
{
|
||||
grub_dprintf ("net", "Cut IP packet actual: %" PRIuGRUB_SIZE
|
||||
", expected %" PRIuGRUB_SIZE "\n", actual_size,
|
||||
expected_size);
|
||||
grub_netbuff_free (nb);
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Unfragmented packet. Good. */
|
||||
if (((grub_be_to_cpu16 (iph->frags) & MORE_FRAGMENTS) == 0)
|
||||
&& (grub_be_to_cpu16 (iph->frags) & OFFSET_MASK) == 0)
|
||||
{
|
||||
grub_net_network_level_address_t source;
|
||||
grub_net_network_level_address_t dest;
|
||||
|
||||
err = grub_netbuff_pull (nb, ((iph->verhdrlen & 0xf)
|
||||
* sizeof (grub_uint32_t)));
|
||||
if (err)
|
||||
{
|
||||
grub_netbuff_free (nb);
|
||||
return err;
|
||||
}
|
||||
|
||||
source.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4;
|
||||
source.ipv4 = iph->src;
|
||||
|
||||
dest.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4;
|
||||
dest.ipv4 = iph->dest;
|
||||
|
||||
return handle_dgram (nb, card, src_hwaddress, hwaddress, iph->protocol,
|
||||
&source, &dest, iph->ttl);
|
||||
}
|
||||
|
||||
for (prev = &reassembles, rsm = *prev; rsm; prev = &rsm->next, rsm = *prev)
|
||||
if (rsm->source == iph->src && rsm->dest == iph->dest
|
||||
&& rsm->id == iph->ident && rsm->proto == iph->protocol)
|
||||
break;
|
||||
if (!rsm)
|
||||
{
|
||||
rsm = grub_malloc (sizeof (*rsm));
|
||||
if (!rsm)
|
||||
return grub_errno;
|
||||
rsm->source = iph->src;
|
||||
rsm->dest = iph->dest;
|
||||
rsm->id = iph->ident;
|
||||
rsm->proto = iph->protocol;
|
||||
rsm->next = reassembles;
|
||||
reassembles = rsm;
|
||||
prev = &reassembles;
|
||||
rsm->pq = grub_priority_queue_new (sizeof (struct grub_net_buff **), cmp);
|
||||
if (!rsm->pq)
|
||||
{
|
||||
grub_free (rsm);
|
||||
return grub_errno;
|
||||
}
|
||||
rsm->asm_buffer = 0;
|
||||
rsm->total_len = 0;
|
||||
rsm->cur_ptr = 0;
|
||||
rsm->ttl = 0xff;
|
||||
}
|
||||
if (rsm->ttl > iph->ttl)
|
||||
rsm->ttl = iph->ttl;
|
||||
rsm->last_time = grub_get_time_ms ();
|
||||
free_old_fragments ();
|
||||
|
||||
err = grub_priority_queue_push (rsm->pq, &nb);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (!(grub_be_to_cpu16 (iph->frags) & MORE_FRAGMENTS))
|
||||
{
|
||||
rsm->total_len = (8 * (grub_be_to_cpu16 (iph->frags) & OFFSET_MASK)
|
||||
+ (nb->tail - nb->data));
|
||||
rsm->total_len -= ((iph->verhdrlen & 0xf) * sizeof (grub_uint32_t));
|
||||
rsm->asm_buffer = grub_zalloc (rsm->total_len);
|
||||
if (!rsm->asm_buffer)
|
||||
{
|
||||
*prev = rsm->next;
|
||||
free_rsm (rsm);
|
||||
return grub_errno;
|
||||
}
|
||||
}
|
||||
if (!rsm->asm_buffer)
|
||||
return GRUB_ERR_NONE;
|
||||
|
||||
while (1)
|
||||
{
|
||||
struct grub_net_buff **nb_top_p, *nb_top;
|
||||
grub_size_t copy;
|
||||
grub_uint8_t *res;
|
||||
grub_size_t res_len;
|
||||
struct grub_net_buff *ret;
|
||||
grub_net_ip_protocol_t proto;
|
||||
grub_uint32_t src;
|
||||
grub_uint32_t dst;
|
||||
grub_net_network_level_address_t source;
|
||||
grub_net_network_level_address_t dest;
|
||||
grub_uint8_t ttl;
|
||||
|
||||
nb_top_p = grub_priority_queue_top (rsm->pq);
|
||||
if (!nb_top_p)
|
||||
return GRUB_ERR_NONE;
|
||||
nb_top = *nb_top_p;
|
||||
grub_priority_queue_pop (rsm->pq);
|
||||
iph = (struct iphdr *) nb_top->data;
|
||||
err = grub_netbuff_pull (nb_top, ((iph->verhdrlen & 0xf)
|
||||
* sizeof (grub_uint32_t)));
|
||||
if (err)
|
||||
{
|
||||
grub_netbuff_free (nb_top);
|
||||
return err;
|
||||
}
|
||||
if (rsm->cur_ptr < (grub_size_t) 8 * (grub_be_to_cpu16 (iph->frags)
|
||||
& OFFSET_MASK))
|
||||
return GRUB_ERR_NONE;
|
||||
|
||||
rsm->cur_ptr = (8 * (grub_be_to_cpu16 (iph->frags) & OFFSET_MASK)
|
||||
+ (nb_top->tail - nb_top->head));
|
||||
if ((grub_size_t) 8 * (grub_be_to_cpu16 (iph->frags) & OFFSET_MASK)
|
||||
>= rsm->total_len)
|
||||
{
|
||||
grub_netbuff_free (nb_top);
|
||||
continue;
|
||||
}
|
||||
copy = nb_top->tail - nb_top->data;
|
||||
if (rsm->total_len - 8 * (grub_be_to_cpu16 (iph->frags) & OFFSET_MASK)
|
||||
< copy)
|
||||
copy = rsm->total_len - 8 * (grub_be_to_cpu16 (iph->frags)
|
||||
& OFFSET_MASK);
|
||||
grub_memcpy (&rsm->asm_buffer[8 * (grub_be_to_cpu16 (iph->frags)
|
||||
& OFFSET_MASK)],
|
||||
nb_top->data, copy);
|
||||
|
||||
if ((grub_be_to_cpu16 (iph->frags) & MORE_FRAGMENTS))
|
||||
continue;
|
||||
|
||||
res = rsm->asm_buffer;
|
||||
proto = rsm->proto;
|
||||
src = rsm->source;
|
||||
dst = rsm->dest;
|
||||
ttl = rsm->ttl;
|
||||
|
||||
rsm->asm_buffer = 0;
|
||||
res_len = rsm->total_len;
|
||||
*prev = rsm->next;
|
||||
free_rsm (rsm);
|
||||
ret = grub_malloc (sizeof (*ret));
|
||||
if (!ret)
|
||||
{
|
||||
grub_free (res);
|
||||
return grub_errno;
|
||||
}
|
||||
ret->data = ret->head = res;
|
||||
ret->tail = ret->end = res + res_len;
|
||||
|
||||
source.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4;
|
||||
source.ipv4 = src;
|
||||
|
||||
dest.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4;
|
||||
dest.ipv4 = dst;
|
||||
|
||||
return handle_dgram (ret, card, src_hwaddress,
|
||||
hwaddress, proto, &source, &dest,
|
||||
ttl);
|
||||
}
|
||||
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_net_send_ip6_packet (struct grub_net_network_level_interface *inf,
|
||||
const grub_net_network_level_address_t *target,
|
||||
const grub_net_link_level_address_t *ll_target_addr,
|
||||
struct grub_net_buff *nb,
|
||||
grub_net_ip_protocol_t proto)
|
||||
{
|
||||
struct ip6hdr *iph;
|
||||
|
||||
COMPILE_TIME_ASSERT (GRUB_NET_OUR_IPV6_HEADER_SIZE == sizeof (*iph));
|
||||
|
||||
if (nb->tail - nb->data + sizeof (struct iphdr) > inf->card->mtu)
|
||||
return grub_error (GRUB_ERR_NET_PACKET_TOO_BIG, "packet too big");
|
||||
|
||||
grub_netbuff_push (nb, sizeof (*iph));
|
||||
iph = (struct ip6hdr *) nb->data;
|
||||
|
||||
iph->version_class_flow = grub_cpu_to_be32 ((6 << 28));
|
||||
iph->len = grub_cpu_to_be16 (nb->tail - nb->data - sizeof (*iph));
|
||||
iph->protocol = proto;
|
||||
iph->ttl = 0xff;
|
||||
grub_memcpy (&iph->src, inf->address.ipv6, sizeof (iph->src));
|
||||
grub_memcpy (&iph->dest, target->ipv6, sizeof (iph->dest));
|
||||
|
||||
return send_ethernet_packet (inf, nb, *ll_target_addr,
|
||||
GRUB_NET_ETHERTYPE_IP6);
|
||||
}
|
||||
|
||||
grub_err_t
|
||||
grub_net_send_ip_packet (struct grub_net_network_level_interface *inf,
|
||||
const grub_net_network_level_address_t *target,
|
||||
const grub_net_link_level_address_t *ll_target_addr,
|
||||
struct grub_net_buff *nb,
|
||||
grub_net_ip_protocol_t proto)
|
||||
{
|
||||
switch (target->type)
|
||||
{
|
||||
case GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4:
|
||||
return grub_net_send_ip4_packet (inf, target, ll_target_addr, nb, proto);
|
||||
case GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6:
|
||||
return grub_net_send_ip6_packet (inf, target, ll_target_addr, nb, proto);
|
||||
default:
|
||||
return grub_error (GRUB_ERR_BAD_ARGUMENT, "not an IP");
|
||||
}
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_net_recv_ip6_packets (struct grub_net_buff *nb,
|
||||
struct grub_net_card *card,
|
||||
const grub_net_link_level_address_t *hwaddress,
|
||||
const grub_net_link_level_address_t *src_hwaddress)
|
||||
{
|
||||
struct ip6hdr *iph = (struct ip6hdr *) nb->data;
|
||||
grub_err_t err;
|
||||
grub_net_network_level_address_t source;
|
||||
grub_net_network_level_address_t dest;
|
||||
|
||||
if (nb->tail - nb->data < (grub_ssize_t) sizeof (*iph))
|
||||
{
|
||||
grub_dprintf ("net", "IP packet too short: %" PRIdGRUB_SSIZE "\n",
|
||||
nb->tail - nb->data);
|
||||
grub_netbuff_free (nb);
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
err = grub_netbuff_pull (nb, sizeof (*iph));
|
||||
if (err)
|
||||
{
|
||||
grub_netbuff_free (nb);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Check size. */
|
||||
{
|
||||
grub_size_t expected_size = grub_be_to_cpu16 (iph->len);
|
||||
grub_size_t actual_size = (nb->tail - nb->data);
|
||||
if (actual_size > expected_size)
|
||||
{
|
||||
err = grub_netbuff_unput (nb, actual_size - expected_size);
|
||||
if (err)
|
||||
{
|
||||
grub_netbuff_free (nb);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
if (actual_size < expected_size)
|
||||
{
|
||||
grub_dprintf ("net", "Cut IP packet actual: %" PRIuGRUB_SIZE
|
||||
", expected %" PRIuGRUB_SIZE "\n", actual_size,
|
||||
expected_size);
|
||||
grub_netbuff_free (nb);
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
source.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6;
|
||||
dest.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6;
|
||||
grub_memcpy (source.ipv6, &iph->src, sizeof (source.ipv6));
|
||||
grub_memcpy (dest.ipv6, &iph->dest, sizeof (dest.ipv6));
|
||||
|
||||
return handle_dgram (nb, card, src_hwaddress, hwaddress, iph->protocol,
|
||||
&source, &dest, iph->ttl);
|
||||
}
|
||||
|
||||
grub_err_t
|
||||
grub_net_recv_ip_packets (struct grub_net_buff *nb,
|
||||
struct grub_net_card *card,
|
||||
const grub_net_link_level_address_t *hwaddress,
|
||||
const grub_net_link_level_address_t *src_hwaddress)
|
||||
{
|
||||
struct iphdr *iph = (struct iphdr *) nb->data;
|
||||
|
||||
if ((iph->verhdrlen >> 4) == 4)
|
||||
return grub_net_recv_ip4_packets (nb, card, hwaddress, src_hwaddress);
|
||||
if ((iph->verhdrlen >> 4) == 6)
|
||||
return grub_net_recv_ip6_packets (nb, card, hwaddress, src_hwaddress);
|
||||
grub_dprintf ("net", "Bad IP version: %d\n", (iph->verhdrlen >> 4));
|
||||
grub_netbuff_free (nb);
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
|
|
@ -27,6 +27,8 @@
|
|||
#include <grub/command.h>
|
||||
#include <grub/env.h>
|
||||
#include <grub/net/ethernet.h>
|
||||
#include <grub/net/arp.h>
|
||||
#include <grub/net/ip.h>
|
||||
#include <grub/loader.h>
|
||||
#include <grub/bufio.h>
|
||||
#include <grub/kernel.h>
|
||||
|
@ -55,6 +57,142 @@ struct grub_net_card *grub_net_cards = NULL;
|
|||
struct grub_net_network_level_protocol *grub_net_network_level_protocols = NULL;
|
||||
static struct grub_fs grub_net_fs;
|
||||
|
||||
struct grub_net_link_layer_entry {
|
||||
int avail;
|
||||
grub_net_network_level_address_t nl_address;
|
||||
grub_net_link_level_address_t ll_address;
|
||||
};
|
||||
|
||||
#define LINK_LAYER_CACHE_SIZE 256
|
||||
|
||||
static struct grub_net_link_layer_entry *
|
||||
link_layer_find_entry (const grub_net_network_level_address_t *proto,
|
||||
const struct grub_net_card *card)
|
||||
{
|
||||
unsigned i;
|
||||
if (!card->link_layer_table)
|
||||
return NULL;
|
||||
for (i = 0; i < LINK_LAYER_CACHE_SIZE; i++)
|
||||
{
|
||||
if (card->link_layer_table[i].avail == 1
|
||||
&& grub_net_addr_cmp (&card->link_layer_table[i].nl_address,
|
||||
proto) == 0)
|
||||
return &card->link_layer_table[i];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
grub_net_link_layer_add_address (struct grub_net_card *card,
|
||||
const grub_net_network_level_address_t *nl,
|
||||
const grub_net_link_level_address_t *ll,
|
||||
int override)
|
||||
{
|
||||
struct grub_net_link_layer_entry *entry;
|
||||
|
||||
/* Check if the sender is in the cache table. */
|
||||
entry = link_layer_find_entry (nl, card);
|
||||
/* Update sender hardware address. */
|
||||
if (entry && override)
|
||||
grub_memcpy (&entry->ll_address, ll, sizeof (entry->ll_address));
|
||||
if (entry)
|
||||
return;
|
||||
|
||||
/* Add sender to cache table. */
|
||||
if (card->link_layer_table == NULL)
|
||||
card->link_layer_table = grub_zalloc (LINK_LAYER_CACHE_SIZE
|
||||
* sizeof (card->link_layer_table[0]));
|
||||
entry = &(card->link_layer_table[card->new_ll_entry]);
|
||||
entry->avail = 1;
|
||||
grub_memcpy (&entry->ll_address, ll, sizeof (entry->ll_address));
|
||||
grub_memcpy (&entry->nl_address, nl, sizeof (entry->nl_address));
|
||||
card->new_ll_entry++;
|
||||
if (card->new_ll_entry == LINK_LAYER_CACHE_SIZE)
|
||||
card->new_ll_entry = 0;
|
||||
}
|
||||
|
||||
int
|
||||
grub_net_link_layer_resolve_check (struct grub_net_network_level_interface *inf,
|
||||
const grub_net_network_level_address_t *proto_addr)
|
||||
{
|
||||
struct grub_net_link_layer_entry *entry;
|
||||
|
||||
if (proto_addr->type == GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4
|
||||
&& proto_addr->ipv4 == 0xffffffff)
|
||||
return 1;
|
||||
entry = link_layer_find_entry (proto_addr, inf->card);
|
||||
if (entry)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
grub_err_t
|
||||
grub_net_link_layer_resolve (struct grub_net_network_level_interface *inf,
|
||||
const grub_net_network_level_address_t *proto_addr,
|
||||
grub_net_link_level_address_t *hw_addr)
|
||||
{
|
||||
struct grub_net_link_layer_entry *entry;
|
||||
grub_err_t err;
|
||||
|
||||
if ((proto_addr->type == GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4
|
||||
&& proto_addr->ipv4 == 0xffffffff)
|
||||
|| proto_addr->type == GRUB_NET_NETWORK_LEVEL_PROTOCOL_DHCP_RECV
|
||||
|| (proto_addr->type == GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6
|
||||
&& proto_addr->ipv6[0] == grub_be_to_cpu64_compile_time (0xff02ULL
|
||||
<< 48)
|
||||
&& proto_addr->ipv6[1] == (grub_be_to_cpu64_compile_time (1))))
|
||||
{
|
||||
hw_addr->type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET;
|
||||
grub_memset (hw_addr->mac, -1, 6);
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
if (proto_addr->type == GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6
|
||||
&& ((grub_be_to_cpu64 (proto_addr->ipv6[0]) >> 56) == 0xff))
|
||||
{
|
||||
hw_addr->type = GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET;
|
||||
hw_addr->mac[0] = 0x33;
|
||||
hw_addr->mac[1] = 0x33;
|
||||
hw_addr->mac[2] = ((grub_be_to_cpu64 (proto_addr->ipv6[1]) >> 24) & 0xff);
|
||||
hw_addr->mac[3] = ((grub_be_to_cpu64 (proto_addr->ipv6[1]) >> 16) & 0xff);
|
||||
hw_addr->mac[4] = ((grub_be_to_cpu64 (proto_addr->ipv6[1]) >> 8) & 0xff);
|
||||
hw_addr->mac[5] = ((grub_be_to_cpu64 (proto_addr->ipv6[1]) >> 0) & 0xff);
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
/* Check cache table. */
|
||||
entry = link_layer_find_entry (proto_addr, inf->card);
|
||||
if (entry)
|
||||
{
|
||||
*hw_addr = entry->ll_address;
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
switch (proto_addr->type)
|
||||
{
|
||||
case GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4:
|
||||
err = grub_net_arp_send_request (inf, proto_addr);
|
||||
break;
|
||||
case GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6:
|
||||
err = grub_net_icmp6_send_request (inf, proto_addr);
|
||||
break;
|
||||
case GRUB_NET_NETWORK_LEVEL_PROTOCOL_DHCP_RECV:
|
||||
return grub_error (GRUB_ERR_BUG, "shouldn't reach here");
|
||||
default:
|
||||
return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
|
||||
"unsupported address type %d", proto_addr->type);
|
||||
}
|
||||
if (err)
|
||||
return err;
|
||||
entry = link_layer_find_entry (proto_addr, inf->card);
|
||||
if (entry)
|
||||
{
|
||||
*hw_addr = entry->ll_address;
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
return grub_error (GRUB_ERR_TIMEOUT,
|
||||
"timeout: could not resolve hardware address");
|
||||
}
|
||||
|
||||
void
|
||||
grub_net_card_unregister (struct grub_net_card *card)
|
||||
{
|
||||
|
@ -72,6 +210,151 @@ grub_net_card_unregister (struct grub_net_card *card)
|
|||
GRUB_AS_LIST (card));
|
||||
}
|
||||
|
||||
static struct grub_net_slaac_mac_list *
|
||||
grub_net_ipv6_get_slaac (struct grub_net_card *card,
|
||||
const grub_net_link_level_address_t *hwaddr)
|
||||
{
|
||||
struct grub_net_slaac_mac_list *slaac;
|
||||
char *ptr;
|
||||
|
||||
for (slaac = card->slaac_list; slaac; slaac = slaac->next)
|
||||
if (grub_net_hwaddr_cmp (&slaac->address, hwaddr) == 0)
|
||||
return slaac;
|
||||
|
||||
slaac = grub_zalloc (sizeof (*slaac));
|
||||
if (!slaac)
|
||||
return NULL;
|
||||
|
||||
slaac->name = grub_malloc (grub_strlen (card->name)
|
||||
+ GRUB_NET_MAX_STR_HWADDR_LEN
|
||||
+ sizeof (":slaac"));
|
||||
ptr = grub_stpcpy (slaac->name, card->name);
|
||||
if (grub_net_hwaddr_cmp (&card->default_address, hwaddr) != 0)
|
||||
{
|
||||
ptr = grub_stpcpy (ptr, ":");
|
||||
grub_net_hwaddr_to_str (hwaddr, ptr);
|
||||
ptr += grub_strlen (ptr);
|
||||
}
|
||||
ptr = grub_stpcpy (ptr, ":slaac");
|
||||
|
||||
grub_memcpy (&slaac->address, hwaddr, sizeof (slaac->address));
|
||||
slaac->next = card->slaac_list;
|
||||
card->slaac_list = slaac;
|
||||
return slaac;
|
||||
}
|
||||
|
||||
struct grub_net_network_level_interface *
|
||||
grub_net_ipv6_get_link_local (struct grub_net_card *card,
|
||||
const grub_net_link_level_address_t *hwaddr)
|
||||
{
|
||||
struct grub_net_network_level_interface *inf;
|
||||
char name[grub_strlen (card->name)
|
||||
+ GRUB_NET_MAX_STR_HWADDR_LEN
|
||||
+ sizeof (":link")];
|
||||
char *ptr;
|
||||
grub_net_network_level_address_t addr;
|
||||
|
||||
addr.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6;
|
||||
addr.ipv6[0] = grub_cpu_to_be64 (0xfe80ULL << 48);
|
||||
addr.ipv6[1] = grub_net_ipv6_get_id (hwaddr);
|
||||
|
||||
FOR_NET_NETWORK_LEVEL_INTERFACES (inf)
|
||||
{
|
||||
if (inf->card == card
|
||||
&& grub_net_hwaddr_cmp (&inf->hwaddress, hwaddr) == 0
|
||||
&& grub_net_addr_cmp (&inf->address, &addr) == 0)
|
||||
return inf;
|
||||
}
|
||||
|
||||
ptr = grub_stpcpy (name, card->name);
|
||||
if (grub_net_hwaddr_cmp (&card->default_address, hwaddr) != 0)
|
||||
{
|
||||
ptr = grub_stpcpy (ptr, ":");
|
||||
grub_net_hwaddr_to_str (hwaddr, ptr);
|
||||
ptr += grub_strlen (ptr);
|
||||
}
|
||||
ptr = grub_stpcpy (ptr, ":link");
|
||||
return grub_net_add_addr (name, card, &addr, hwaddr, 0);
|
||||
}
|
||||
|
||||
/* FIXME: allow to specify mac address. */
|
||||
static grub_err_t
|
||||
grub_cmd_ipv6_autoconf (struct grub_command *cmd __attribute__ ((unused)),
|
||||
int argc, char **args)
|
||||
{
|
||||
struct grub_net_card *card;
|
||||
struct grub_net_network_level_interface **ifaces;
|
||||
grub_size_t ncards = 0;
|
||||
unsigned j = 0;
|
||||
int interval;
|
||||
grub_err_t err;
|
||||
struct grub_net_slaac_mac_list **slaacs;
|
||||
|
||||
FOR_NET_CARDS (card)
|
||||
{
|
||||
if (argc > 0 && grub_strcmp (card->name, args[0]) != 0)
|
||||
continue;
|
||||
ncards++;
|
||||
}
|
||||
|
||||
ifaces = grub_zalloc (ncards * sizeof (ifaces[0]));
|
||||
slaacs = grub_zalloc (ncards * sizeof (slaacs[0]));
|
||||
if (!ifaces || !slaacs)
|
||||
{
|
||||
grub_free (ifaces);
|
||||
grub_free (slaacs);
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
FOR_NET_CARDS (card)
|
||||
{
|
||||
if (argc > 0 && grub_strcmp (card->name, args[0]) != 0)
|
||||
continue;
|
||||
ifaces[j] = grub_net_ipv6_get_link_local (card, &card->default_address);
|
||||
if (!ifaces[j])
|
||||
{
|
||||
grub_free (ifaces);
|
||||
grub_free (slaacs);
|
||||
return grub_errno;
|
||||
}
|
||||
slaacs[j] = grub_net_ipv6_get_slaac (card, &card->default_address);
|
||||
if (!slaacs[j])
|
||||
{
|
||||
grub_free (ifaces);
|
||||
grub_free (slaacs);
|
||||
return grub_errno;
|
||||
}
|
||||
j++;
|
||||
}
|
||||
|
||||
for (interval = 200; interval < 10000; interval *= 2)
|
||||
{
|
||||
/* FIXME: send router solicitation. */
|
||||
int done = 1;
|
||||
for (j = 0; j < ncards; j++)
|
||||
{
|
||||
if (slaacs[j]->slaac_counter)
|
||||
continue;
|
||||
done = 0;
|
||||
}
|
||||
if (done)
|
||||
break;
|
||||
grub_net_poll_cards (interval);
|
||||
}
|
||||
|
||||
err = GRUB_ERR_NONE;
|
||||
for (j = 0; j < ncards; j++)
|
||||
{
|
||||
if (slaacs[j]->slaac_counter)
|
||||
continue;
|
||||
err = grub_error (GRUB_ERR_FILE_NOT_FOUND, "couldn't configure %s",
|
||||
ifaces[j]->card->name);
|
||||
}
|
||||
|
||||
grub_free (ifaces);
|
||||
grub_free (slaacs);
|
||||
return err;
|
||||
}
|
||||
|
||||
static inline void
|
||||
grub_net_route_register (struct grub_net_route *route)
|
||||
|
@ -93,18 +376,23 @@ static int
|
|||
parse_ip (const char *val, grub_uint32_t *ip, const char **rest)
|
||||
{
|
||||
grub_uint32_t newip = 0;
|
||||
unsigned long t;
|
||||
int i;
|
||||
const char *ptr = val;
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
unsigned long t;
|
||||
t = grub_strtoul (ptr, (char **) &ptr, 0);
|
||||
if (grub_errno)
|
||||
{
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
return 0;
|
||||
}
|
||||
if (*ptr != '.' && i == 0)
|
||||
{
|
||||
newip = t;
|
||||
break;
|
||||
}
|
||||
if (t & ~0xff)
|
||||
return 0;
|
||||
newip >>= 8;
|
||||
|
@ -115,7 +403,56 @@ parse_ip (const char *val, grub_uint32_t *ip, const char **rest)
|
|||
}
|
||||
*ip = grub_cpu_to_le32 (newip);
|
||||
if (rest)
|
||||
*rest = ptr - 1;
|
||||
*rest = (ptr - 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
parse_ip6 (const char *val, grub_uint64_t *ip, const char **rest)
|
||||
{
|
||||
grub_uint16_t newip[8];
|
||||
const char *ptr = val;
|
||||
int word, quaddot = -1;
|
||||
|
||||
if (ptr[0] == ':' && ptr[1] != ':')
|
||||
return 0;
|
||||
if (ptr[0] == ':')
|
||||
ptr++;
|
||||
|
||||
for (word = 0; word < 8; word++)
|
||||
{
|
||||
unsigned long t;
|
||||
if (*ptr == ':')
|
||||
{
|
||||
quaddot = word;
|
||||
word--;
|
||||
ptr++;
|
||||
continue;
|
||||
}
|
||||
t = grub_strtoul (ptr, (char **) &ptr, 16);
|
||||
if (grub_errno)
|
||||
{
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
break;
|
||||
}
|
||||
if (t & ~0xffff)
|
||||
return 0;
|
||||
newip[word] = grub_cpu_to_be16 (t);
|
||||
if (*ptr != ':')
|
||||
break;
|
||||
ptr++;
|
||||
}
|
||||
if (quaddot == -1 && word < 7)
|
||||
return 0;
|
||||
if (quaddot != -1)
|
||||
{
|
||||
grub_memmove (&newip[quaddot + 7 - word], &newip[quaddot],
|
||||
(word - quaddot + 1) * sizeof (newip[0]));
|
||||
grub_memset (&newip[quaddot], 0, (7 - word) * sizeof (newip[0]));
|
||||
}
|
||||
grub_memcpy (ip, newip, 16);
|
||||
if (rest)
|
||||
*rest = ptr;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -131,10 +468,30 @@ match_net (const grub_net_network_level_netaddress_t *net,
|
|||
return 0;
|
||||
case GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4:
|
||||
{
|
||||
grub_int32_t mask = ((1 << net->ipv4.masksize) - 1) << (32 - net->ipv4.masksize);
|
||||
grub_uint32_t mask = (0xffffffffU << (32 - net->ipv4.masksize));
|
||||
if (net->ipv4.masksize == 0)
|
||||
mask = 0;
|
||||
return ((grub_be_to_cpu32 (net->ipv4.base) & mask)
|
||||
== (grub_be_to_cpu32 (addr->ipv4) & mask));
|
||||
}
|
||||
case GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6:
|
||||
{
|
||||
grub_uint64_t mask[2];
|
||||
if (net->ipv6.masksize <= 64)
|
||||
{
|
||||
mask[0] = 0xffffffffffffffffULL << (64 - net->ipv6.masksize);
|
||||
mask[1] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
mask[0] = 0xffffffffffffffffULL;
|
||||
mask[1] = 0xffffffffffffffffULL << (128 - net->ipv6.masksize);
|
||||
}
|
||||
return (((grub_be_to_cpu64 (net->ipv6.base[0]) & mask[0])
|
||||
== (grub_be_to_cpu64 (addr->ipv6[0]) & mask[0]))
|
||||
&& ((grub_be_to_cpu64 (net->ipv6.base[1]) & mask[1])
|
||||
== (grub_be_to_cpu64 (addr->ipv6[1]) & mask[1])));
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -143,13 +500,31 @@ grub_err_t
|
|||
grub_net_resolve_address (const char *name,
|
||||
grub_net_network_level_address_t *addr)
|
||||
{
|
||||
if (parse_ip (name, &addr->ipv4, NULL))
|
||||
const char *rest;
|
||||
grub_err_t err;
|
||||
grub_size_t naddresses;
|
||||
struct grub_net_network_level_address *addresses;
|
||||
|
||||
if (parse_ip (name, &addr->ipv4, &rest) && *rest == 0)
|
||||
{
|
||||
addr->type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4;
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
return grub_error (GRUB_ERR_NET_BAD_ADDRESS, N_("unrecognised address %s"),
|
||||
if (parse_ip6 (name, addr->ipv6, &rest) && *rest == 0)
|
||||
{
|
||||
addr->type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6;
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
err = grub_net_dns_lookup (name, 0, 0, &naddresses, &addresses, 1);
|
||||
if (err)
|
||||
return err;
|
||||
if (!naddresses)
|
||||
grub_error (GRUB_ERR_NET_BAD_ADDRESS, N_("unresolvable address %s"),
|
||||
name);
|
||||
/* FIXME: use other results as well. */
|
||||
*addr = addresses[0];
|
||||
grub_free (addresses);
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
grub_err_t
|
||||
|
@ -162,17 +537,70 @@ grub_net_resolve_net_address (const char *name,
|
|||
addr->type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4;
|
||||
if (*rest == '/')
|
||||
{
|
||||
addr->ipv4.masksize = grub_strtoul (rest + 1, NULL, 0);
|
||||
if (!grub_errno)
|
||||
addr->ipv4.masksize = grub_strtoul (rest + 1, (char **) &rest, 0);
|
||||
if (!grub_errno && *rest == 0)
|
||||
return GRUB_ERR_NONE;
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
}
|
||||
else if (*rest == 0)
|
||||
{
|
||||
addr->ipv4.masksize = 32;
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
}
|
||||
if (parse_ip6 (name, addr->ipv6.base, &rest))
|
||||
{
|
||||
addr->type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6;
|
||||
if (*rest == '/')
|
||||
{
|
||||
addr->ipv6.masksize = grub_strtoul (rest + 1, (char **) &rest, 0);
|
||||
if (!grub_errno && *rest == 0)
|
||||
return GRUB_ERR_NONE;
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
}
|
||||
else if (*rest == 0)
|
||||
{
|
||||
addr->ipv6.masksize = 128;
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
}
|
||||
return grub_error (GRUB_ERR_NET_BAD_ADDRESS, N_("unrecognised address %s"),
|
||||
name);
|
||||
}
|
||||
|
||||
static int
|
||||
route_cmp (const struct grub_net_route *a, const struct grub_net_route *b)
|
||||
{
|
||||
if (a == NULL && b == NULL)
|
||||
return 0;
|
||||
if (b == NULL)
|
||||
return +1;
|
||||
if (a == NULL)
|
||||
return -1;
|
||||
if (a->target.type < b->target.type)
|
||||
return -1;
|
||||
if (a->target.type > b->target.type)
|
||||
return +1;
|
||||
switch (a->target.type)
|
||||
{
|
||||
case GRUB_NET_NETWORK_LEVEL_PROTOCOL_DHCP_RECV:
|
||||
break;
|
||||
case GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6:
|
||||
if (a->target.ipv6.masksize > b->target.ipv6.masksize)
|
||||
return +1;
|
||||
if (a->target.ipv6.masksize < b->target.ipv6.masksize)
|
||||
return -1;
|
||||
break;
|
||||
case GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4:
|
||||
if (a->target.ipv4.masksize > b->target.ipv4.masksize)
|
||||
return +1;
|
||||
if (a->target.ipv4.masksize < b->target.ipv4.masksize)
|
||||
return -1;
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
grub_err_t
|
||||
grub_net_route_address (grub_net_network_level_address_t addr,
|
||||
grub_net_network_level_address_t *gateway,
|
||||
|
@ -191,25 +619,27 @@ grub_net_route_address (grub_net_network_level_address_t addr,
|
|||
|
||||
for (depth = 0; depth < routecnt + 2; depth++)
|
||||
{
|
||||
struct grub_net_route *bestroute = NULL;
|
||||
FOR_NET_ROUTES(route)
|
||||
{
|
||||
if (depth && prot != route->prot)
|
||||
continue;
|
||||
if (!match_net (&route->target, &curtarget))
|
||||
continue;
|
||||
|
||||
if (route->is_gateway)
|
||||
{
|
||||
if (depth == 0)
|
||||
*gateway = route->gw;
|
||||
curtarget = route->gw;
|
||||
break;
|
||||
if (route_cmp (route, bestroute) > 0)
|
||||
bestroute = route;
|
||||
}
|
||||
*interf = route->interface;
|
||||
if (bestroute == NULL)
|
||||
return grub_error (GRUB_ERR_NET_NO_ROUTE, "destination unreachable");
|
||||
|
||||
if (!bestroute->is_gateway)
|
||||
{
|
||||
*interf = bestroute->interface;
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
if (route == NULL)
|
||||
return grub_error (GRUB_ERR_NET_NO_ROUTE, "destination unreachable");
|
||||
if (depth == 0)
|
||||
*gateway = bestroute->gw;
|
||||
curtarget = bestroute->gw;
|
||||
}
|
||||
|
||||
return grub_error (GRUB_ERR_NET_ROUTE_LOOP, "route loop detected");
|
||||
|
@ -249,6 +679,27 @@ grub_net_addr_to_str (const grub_net_network_level_address_t *target, char *buf)
|
|||
case GRUB_NET_NETWORK_LEVEL_PROTOCOL_DHCP_RECV:
|
||||
grub_strcpy (buf, "temporary");
|
||||
return;
|
||||
case GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6:
|
||||
{
|
||||
char *ptr = buf;
|
||||
grub_uint64_t n = grub_be_to_cpu64 (target->ipv6[0]);
|
||||
int i;
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
grub_snprintf (ptr, 6, "%" PRIxGRUB_UINT64_T ":",
|
||||
(n >> (48 - 16 * i)) & 0xffff);
|
||||
ptr += grub_strlen (ptr);
|
||||
}
|
||||
n = grub_be_to_cpu64 (target->ipv6[1]);
|
||||
for (i = 0; i < 3; i++)
|
||||
{
|
||||
grub_snprintf (ptr, 6, "%" PRIxGRUB_UINT64_T ":",
|
||||
(n >> (48 - 16 * i)) & 0xffff);
|
||||
ptr += grub_strlen (ptr);
|
||||
}
|
||||
grub_snprintf (ptr, 5, "%" PRIxGRUB_UINT64_T, n & 0xffff);
|
||||
return;
|
||||
}
|
||||
case GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4:
|
||||
{
|
||||
grub_uint32_t n = grub_be_to_cpu32 (target->ipv4);
|
||||
|
@ -258,18 +709,13 @@ grub_net_addr_to_str (const grub_net_network_level_address_t *target, char *buf)
|
|||
}
|
||||
return;
|
||||
}
|
||||
grub_printf ("Unknown address type %d\n", target->type);
|
||||
grub_snprintf (buf, GRUB_NET_MAX_STR_ADDR_LEN,
|
||||
"Unknown address type %d", target->type);
|
||||
}
|
||||
|
||||
/*
|
||||
Currently suppoerted adresses:
|
||||
ethernet: XX:XX:XX:XX:XX:XX
|
||||
*/
|
||||
|
||||
#define MAX_STR_HWADDR_LEN (sizeof ("XX:XX:XX:XX:XX:XX"))
|
||||
|
||||
static void
|
||||
hwaddr_to_str (const grub_net_link_level_address_t *addr, char *str)
|
||||
void
|
||||
grub_net_hwaddr_to_str (const grub_net_link_level_address_t *addr, char *str)
|
||||
{
|
||||
str[0] = 0;
|
||||
switch (addr->type)
|
||||
|
@ -280,7 +726,7 @@ hwaddr_to_str (const grub_net_link_level_address_t *addr, char *str)
|
|||
unsigned i;
|
||||
for (ptr = str, i = 0; i < ARRAY_SIZE (addr->mac); i++)
|
||||
{
|
||||
grub_snprintf (ptr, MAX_STR_HWADDR_LEN - (ptr - str),
|
||||
grub_snprintf (ptr, GRUB_NET_MAX_STR_HWADDR_LEN - (ptr - str),
|
||||
"%02x:", addr->mac[i] & 0xff);
|
||||
ptr += (sizeof ("XX:") - 1);
|
||||
}
|
||||
|
@ -307,6 +753,27 @@ grub_net_hwaddr_cmp (const grub_net_link_level_address_t *a,
|
|||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
grub_net_addr_cmp (const grub_net_network_level_address_t *a,
|
||||
const grub_net_network_level_address_t *b)
|
||||
{
|
||||
if (a->type < b->type)
|
||||
return -1;
|
||||
if (a->type > b->type)
|
||||
return +1;
|
||||
switch (a->type)
|
||||
{
|
||||
case GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4:
|
||||
return grub_memcmp (&a->ipv4, &b->ipv4, sizeof (a->ipv4));
|
||||
case GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6:
|
||||
return grub_memcmp (&a->ipv6, &b->ipv6, sizeof (a->ipv6));
|
||||
case GRUB_NET_NETWORK_LEVEL_PROTOCOL_DHCP_RECV:
|
||||
return 0;
|
||||
}
|
||||
grub_printf ("Unsupported address type %d\n", a->type);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* FIXME: implement this. */
|
||||
static char *
|
||||
hwaddr_set_env (struct grub_env_var *var __attribute__ ((unused)),
|
||||
|
@ -327,9 +794,9 @@ static void
|
|||
grub_net_network_level_interface_register (struct grub_net_network_level_interface *inter)
|
||||
{
|
||||
{
|
||||
char buf[MAX_STR_HWADDR_LEN];
|
||||
char buf[GRUB_NET_MAX_STR_HWADDR_LEN];
|
||||
char name[grub_strlen (inter->name) + sizeof ("net__mac")];
|
||||
hwaddr_to_str (&inter->hwaddress, buf);
|
||||
grub_net_hwaddr_to_str (&inter->hwaddress, buf);
|
||||
grub_snprintf (name, sizeof (name), "net_%s_mac", inter->name);
|
||||
grub_env_set (name, buf);
|
||||
grub_register_variable_hook (name, 0, hwaddr_set_env);
|
||||
|
@ -355,8 +822,8 @@ grub_net_network_level_interface_register (struct grub_net_network_level_interfa
|
|||
struct grub_net_network_level_interface *
|
||||
grub_net_add_addr (const char *name,
|
||||
struct grub_net_card *card,
|
||||
grub_net_network_level_address_t addr,
|
||||
grub_net_link_level_address_t hwaddress,
|
||||
const grub_net_network_level_address_t *addr,
|
||||
const grub_net_link_level_address_t *hwaddress,
|
||||
grub_net_interface_flags_t flags)
|
||||
{
|
||||
struct grub_net_network_level_interface *inter;
|
||||
|
@ -366,8 +833,8 @@ grub_net_add_addr (const char *name,
|
|||
return NULL;
|
||||
|
||||
inter->name = grub_strdup (name);
|
||||
grub_memcpy (&(inter->address), &addr, sizeof (inter->address));
|
||||
grub_memcpy (&(inter->hwaddress), &hwaddress, sizeof (inter->hwaddress));
|
||||
grub_memcpy (&(inter->address), addr, sizeof (inter->address));
|
||||
grub_memcpy (&(inter->hwaddress), hwaddress, sizeof (inter->hwaddress));
|
||||
inter->flags = flags;
|
||||
inter->card = card;
|
||||
inter->dhcp_ack = NULL;
|
||||
|
@ -375,6 +842,43 @@ grub_net_add_addr (const char *name,
|
|||
|
||||
grub_net_network_level_interface_register (inter);
|
||||
|
||||
if (addr->type == GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4)
|
||||
{
|
||||
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;
|
||||
|
||||
route = grub_zalloc (sizeof (*route));
|
||||
if (!route)
|
||||
return NULL;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
return inter;
|
||||
}
|
||||
|
||||
|
@ -408,7 +912,7 @@ 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,
|
||||
grub_net_add_addr (args[0], card, &addr, &card->default_address,
|
||||
flags);
|
||||
return grub_errno;
|
||||
}
|
||||
|
@ -532,7 +1036,7 @@ print_net_address (const grub_net_network_level_netaddress_t *target)
|
|||
{
|
||||
case GRUB_NET_NETWORK_LEVEL_PROTOCOL_DHCP_RECV:
|
||||
grub_printf ("temporary\n");
|
||||
break;
|
||||
return;
|
||||
case GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4:
|
||||
{
|
||||
grub_uint32_t n = grub_be_to_cpu32 (target->ipv4.base);
|
||||
|
@ -543,6 +1047,16 @@ print_net_address (const grub_net_network_level_netaddress_t *target)
|
|||
target->ipv4.masksize);
|
||||
}
|
||||
return;
|
||||
case GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6:
|
||||
{
|
||||
char buf[GRUB_NET_MAX_STR_ADDR_LEN];
|
||||
struct grub_net_network_level_address base;
|
||||
base.type = GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6;
|
||||
grub_memcpy (&base.ipv6, &target->ipv6, 16);
|
||||
grub_net_addr_to_str (&base, buf);
|
||||
grub_printf ("%s/%d ", buf, target->ipv6.masksize);
|
||||
}
|
||||
return;
|
||||
}
|
||||
grub_printf ("Unknown address type %d\n", target->type);
|
||||
}
|
||||
|
@ -585,8 +1099,8 @@ grub_cmd_listcards (struct grub_command *cmd __attribute__ ((unused)),
|
|||
struct grub_net_card *card;
|
||||
FOR_NET_CARDS(card)
|
||||
{
|
||||
char buf[MAX_STR_HWADDR_LEN];
|
||||
hwaddr_to_str (&card->default_address, buf);
|
||||
char buf[GRUB_NET_MAX_STR_HWADDR_LEN];
|
||||
grub_net_hwaddr_to_str (&card->default_address, buf);
|
||||
grub_printf ("%s %s\n", card->name, buf);
|
||||
}
|
||||
return GRUB_ERR_NONE;
|
||||
|
@ -600,9 +1114,9 @@ grub_cmd_listaddrs (struct grub_command *cmd __attribute__ ((unused)),
|
|||
struct grub_net_network_level_interface *inf;
|
||||
FOR_NET_NETWORK_LEVEL_INTERFACES (inf)
|
||||
{
|
||||
char bufh[MAX_STR_HWADDR_LEN];
|
||||
char bufh[GRUB_NET_MAX_STR_HWADDR_LEN];
|
||||
char bufn[GRUB_NET_MAX_STR_ADDR_LEN];
|
||||
hwaddr_to_str (&inf->hwaddress, bufh);
|
||||
grub_net_hwaddr_to_str (&inf->hwaddress, bufh);
|
||||
grub_net_addr_to_str (&inf->address, bufn);
|
||||
grub_printf ("%s %s %s\n", inf->name, bufh, bufn);
|
||||
}
|
||||
|
@ -764,23 +1278,20 @@ receive_packets (struct grub_net_card *card)
|
|||
/* Maybe should be better have a fixed number of packets for each card
|
||||
and just mark them as used and not used. */
|
||||
struct grub_net_buff *nb;
|
||||
grub_ssize_t actual;
|
||||
nb = grub_netbuff_alloc (1500);
|
||||
|
||||
nb = card->driver->recv (card);
|
||||
if (!nb)
|
||||
{
|
||||
grub_print_error ();
|
||||
card->last_poll = grub_get_time_ms ();
|
||||
return;
|
||||
}
|
||||
|
||||
actual = card->driver->recv (card, nb);
|
||||
if (actual < 0)
|
||||
{
|
||||
grub_netbuff_free (nb);
|
||||
card->last_poll = grub_get_time_ms ();
|
||||
break;
|
||||
}
|
||||
grub_net_recv_ethernet_packet (nb, card);
|
||||
if (grub_errno)
|
||||
{
|
||||
grub_dprintf ("net", "error receiving: %d: %s\n", grub_errno,
|
||||
grub_errmsg);
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
}
|
||||
}
|
||||
grub_print_error ();
|
||||
}
|
||||
|
@ -796,6 +1307,7 @@ grub_net_poll_cards (unsigned time)
|
|||
while ((grub_get_time_ms () - start_time) < time)
|
||||
receive_packets (card);
|
||||
}
|
||||
grub_net_tcp_retransmit ();
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -810,23 +1322,25 @@ grub_net_poll_cards_idle_real (void)
|
|||
|| ctime >= card->last_poll + card->idle_poll_delay_ms)
|
||||
receive_packets (card);
|
||||
}
|
||||
grub_net_tcp_retransmit ();
|
||||
}
|
||||
|
||||
/* Read from the packets list*/
|
||||
static grub_ssize_t
|
||||
grub_net_fs_read_real (grub_file_t file, char *buf, grub_size_t len)
|
||||
{
|
||||
grub_net_t sock = file->device->net;
|
||||
grub_net_t net = file->device->net;
|
||||
struct grub_net_buff *nb;
|
||||
char *ptr = buf;
|
||||
grub_size_t amount, total = 0;
|
||||
int try = 0;
|
||||
while (try <= 3)
|
||||
|
||||
while (try <= GRUB_NET_TRIES)
|
||||
{
|
||||
while (sock->packs.first)
|
||||
while (net->packs.first)
|
||||
{
|
||||
try = 0;
|
||||
nb = sock->packs.first->nb;
|
||||
nb = net->packs.first->nb;
|
||||
amount = nb->tail - nb->data;
|
||||
if (amount > len)
|
||||
amount = len;
|
||||
|
@ -841,7 +1355,7 @@ grub_net_fs_read_real (grub_file_t file, char *buf, grub_size_t len)
|
|||
if (amount == (grub_size_t) (nb->tail - nb->data))
|
||||
{
|
||||
grub_netbuff_free (nb);
|
||||
grub_net_remove_packet (sock->packs.first);
|
||||
grub_net_remove_packet (net->packs.first);
|
||||
}
|
||||
else
|
||||
nb->data += amount;
|
||||
|
@ -849,28 +1363,50 @@ grub_net_fs_read_real (grub_file_t file, char *buf, grub_size_t len)
|
|||
if (!len)
|
||||
return total;
|
||||
}
|
||||
if (!sock->eof)
|
||||
if (!net->eof)
|
||||
{
|
||||
try++;
|
||||
grub_net_poll_cards (200);
|
||||
grub_net_poll_cards (GRUB_NET_INTERVAL);
|
||||
}
|
||||
else
|
||||
return total;
|
||||
}
|
||||
return total;
|
||||
grub_error (GRUB_ERR_TIMEOUT, "timeout reading '%s'", net->name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static grub_off_t
|
||||
have_ahead (struct grub_file *file)
|
||||
{
|
||||
grub_net_t net = file->device->net;
|
||||
grub_off_t ret = net->offset;
|
||||
struct grub_net_packet *pack;
|
||||
for (pack = net->packs.first; pack; pack = pack->next)
|
||||
ret += pack->nb->tail - pack->nb->data;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
grub_net_seek_real (struct grub_file *file, grub_off_t offset)
|
||||
{
|
||||
grub_size_t len = offset - file->device->net->offset;
|
||||
|
||||
if (!len)
|
||||
if (offset == file->device->net->offset)
|
||||
return GRUB_ERR_NONE;
|
||||
|
||||
if (file->device->net->offset > offset)
|
||||
if (offset > file->device->net->offset)
|
||||
{
|
||||
if (!file->device->net->protocol->seek || have_ahead (file) >= offset)
|
||||
{
|
||||
grub_net_fs_read_real (file, NULL,
|
||||
offset - file->device->net->offset);
|
||||
return grub_errno;
|
||||
}
|
||||
return file->device->net->protocol->seek (file, offset);
|
||||
}
|
||||
|
||||
{
|
||||
grub_err_t err;
|
||||
if (file->device->net->protocol->seek)
|
||||
return file->device->net->protocol->seek (file, offset);
|
||||
while (file->device->net->packs.first)
|
||||
{
|
||||
grub_netbuff_free (file->device->net->packs.first->nb);
|
||||
|
@ -885,11 +1421,9 @@ grub_net_seek_real (struct grub_file *file, grub_off_t offset)
|
|||
err = file->device->net->protocol->open (file, file->device->net->name);
|
||||
if (err)
|
||||
return err;
|
||||
len = offset;
|
||||
grub_net_fs_read_real (file, NULL, offset);
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
grub_net_fs_read_real (file, NULL, len);
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
static grub_ssize_t
|
||||
|
@ -941,13 +1475,18 @@ static struct grub_preboot *fini_hnd;
|
|||
|
||||
static grub_command_t cmd_addaddr, cmd_deladdr, cmd_addroute, cmd_delroute;
|
||||
static grub_command_t cmd_lsroutes, cmd_lscards;
|
||||
static grub_command_t cmd_lsaddr;
|
||||
static grub_command_t cmd_lsaddr, cmd_slaac;
|
||||
|
||||
GRUB_MOD_INIT(net)
|
||||
{
|
||||
cmd_addaddr = grub_register_command ("net_add_addr", grub_cmd_addaddr,
|
||||
N_("SHORTNAME CARD ADDRESS [HWADDRESS]"),
|
||||
N_("Add a network address."));
|
||||
cmd_slaac = grub_register_command ("net_ipv6_autoconf",
|
||||
grub_cmd_ipv6_autoconf,
|
||||
"[CARD [HWADDRESS]]",
|
||||
N_("Perform an IPV6 autoconfiguration"));
|
||||
|
||||
cmd_deladdr = grub_register_command ("net_del_addr", grub_cmd_deladdr,
|
||||
N_("SHORTNAME"),
|
||||
N_("Delete a network address."));
|
||||
|
@ -964,6 +1503,7 @@ GRUB_MOD_INIT(net)
|
|||
cmd_lsaddr = grub_register_command ("net_ls_addr", grub_cmd_listaddrs,
|
||||
"", N_("list network addresses"));
|
||||
grub_bootp_init ();
|
||||
grub_dns_init ();
|
||||
|
||||
grub_fs_register (&grub_net_fs);
|
||||
grub_net_open = grub_net_open_real;
|
||||
|
@ -976,6 +1516,7 @@ GRUB_MOD_INIT(net)
|
|||
GRUB_MOD_FINI(net)
|
||||
{
|
||||
grub_bootp_fini ();
|
||||
grub_dns_fini ();
|
||||
grub_unregister_command (cmd_addaddr);
|
||||
grub_unregister_command (cmd_deladdr);
|
||||
grub_unregister_command (cmd_addroute);
|
||||
|
@ -983,6 +1524,7 @@ GRUB_MOD_FINI(net)
|
|||
grub_unregister_command (cmd_lsroutes);
|
||||
grub_unregister_command (cmd_lscards);
|
||||
grub_unregister_command (cmd_lsaddr);
|
||||
grub_unregister_command (cmd_slaac);
|
||||
grub_fs_unregister (&grub_net_fs);
|
||||
grub_net_open = NULL;
|
||||
grub_net_fini_hw (0);
|
||||
|
|
|
@ -21,7 +21,6 @@
|
|||
#include <grub/mm.h>
|
||||
#include <grub/net/netbuff.h>
|
||||
|
||||
|
||||
grub_err_t
|
||||
grub_netbuff_put (struct grub_net_buff *nb, grub_size_t len)
|
||||
{
|
||||
|
@ -90,7 +89,7 @@ grub_netbuff_alloc (grub_size_t len)
|
|||
nb = (struct grub_net_buff *) ((grub_properly_aligned_t *) data
|
||||
+ len / sizeof (grub_properly_aligned_t));
|
||||
nb->head = nb->data = nb->tail = data;
|
||||
nb->end = (char *) nb;
|
||||
nb->end = (grub_uint8_t *) nb;
|
||||
return nb;
|
||||
}
|
||||
|
||||
|
|
975
grub-core/net/tcp.c
Normal file
975
grub-core/net/tcp.c
Normal file
|
@ -0,0 +1,975 @@
|
|||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2010,2011 Free Software Foundation, Inc.
|
||||
*
|
||||
* GRUB is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GRUB is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <grub/net.h>
|
||||
#include <grub/net/ip.h>
|
||||
#include <grub/net/tcp.h>
|
||||
#include <grub/net/netbuff.h>
|
||||
#include <grub/time.h>
|
||||
#include <grub/priority_queue.h>
|
||||
|
||||
#define TCP_SYN_RETRANSMISSION_TIMEOUT GRUB_NET_INTERVAL
|
||||
#define TCP_SYN_RETRANSMISSION_COUNT GRUB_NET_TRIES
|
||||
#define TCP_RETRANSMISSION_TIMEOUT GRUB_NET_INTERVAL
|
||||
#define TCP_RETRANSMISSION_COUNT GRUB_NET_TRIES
|
||||
|
||||
struct unacked
|
||||
{
|
||||
struct unacked *next;
|
||||
struct grub_net_buff *nb;
|
||||
grub_uint64_t last_try;
|
||||
int try_count;
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
TCP_FIN = 0x1,
|
||||
TCP_SYN = 0x2,
|
||||
TCP_RST = 0x4,
|
||||
TCP_PUSH = 0x8,
|
||||
TCP_ACK = 0x10,
|
||||
TCP_URG = 0x20,
|
||||
};
|
||||
|
||||
struct grub_net_tcp_socket
|
||||
{
|
||||
struct grub_net_tcp_socket *next;
|
||||
|
||||
int established;
|
||||
int i_closed;
|
||||
int they_closed;
|
||||
int in_port;
|
||||
int out_port;
|
||||
int errors;
|
||||
int they_reseted;
|
||||
int i_reseted;
|
||||
grub_uint32_t my_start_seq;
|
||||
grub_uint32_t my_cur_seq;
|
||||
grub_uint32_t their_start_seq;
|
||||
grub_uint32_t their_cur_seq;
|
||||
grub_uint16_t my_window;
|
||||
struct unacked *unack_first;
|
||||
struct unacked *unack_last;
|
||||
grub_err_t (*recv_hook) (grub_net_tcp_socket_t sock, struct grub_net_buff *nb,
|
||||
void *recv);
|
||||
void (*error_hook) (grub_net_tcp_socket_t sock, void *recv);
|
||||
void (*fin_hook) (grub_net_tcp_socket_t sock, void *recv);
|
||||
void *hook_data;
|
||||
grub_net_network_level_address_t out_nla;
|
||||
grub_net_link_level_address_t ll_target_addr;
|
||||
struct grub_net_network_level_interface *inf;
|
||||
grub_net_packets_t packs;
|
||||
grub_priority_queue_t pq;
|
||||
};
|
||||
|
||||
struct grub_net_tcp_listen
|
||||
{
|
||||
struct grub_net_tcp_listen *next;
|
||||
|
||||
grub_uint16_t port;
|
||||
const struct grub_net_network_level_interface *inf;
|
||||
|
||||
grub_err_t (*listen_hook) (grub_net_tcp_listen_t listen,
|
||||
grub_net_tcp_socket_t sock,
|
||||
void *data);
|
||||
void *hook_data;
|
||||
};
|
||||
|
||||
struct tcphdr
|
||||
{
|
||||
grub_uint16_t src;
|
||||
grub_uint16_t dst;
|
||||
grub_uint32_t seqnr;
|
||||
grub_uint32_t ack;
|
||||
grub_uint16_t flags;
|
||||
grub_uint16_t window;
|
||||
grub_uint16_t checksum;
|
||||
grub_uint16_t urgent;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct tcp_pseudohdr
|
||||
{
|
||||
grub_uint32_t src;
|
||||
grub_uint32_t dst;
|
||||
grub_uint8_t zero;
|
||||
grub_uint8_t proto;
|
||||
grub_uint16_t tcp_length;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct tcp6_pseudohdr
|
||||
{
|
||||
grub_uint64_t src[2];
|
||||
grub_uint64_t dst[2];
|
||||
grub_uint32_t tcp_length;
|
||||
grub_uint8_t zero[3];
|
||||
grub_uint8_t proto;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
static struct grub_net_tcp_socket *tcp_sockets;
|
||||
static struct grub_net_tcp_listen *tcp_listens;
|
||||
|
||||
#define FOR_TCP_SOCKETS(var) FOR_LIST_ELEMENTS (var, tcp_sockets)
|
||||
#define FOR_TCP_LISTENS(var) FOR_LIST_ELEMENTS (var, tcp_listens)
|
||||
|
||||
grub_net_tcp_listen_t
|
||||
grub_net_tcp_listen (grub_uint16_t port,
|
||||
const struct grub_net_network_level_interface *inf,
|
||||
grub_err_t (*listen_hook) (grub_net_tcp_listen_t listen,
|
||||
grub_net_tcp_socket_t sock,
|
||||
void *data),
|
||||
void *hook_data)
|
||||
{
|
||||
grub_net_tcp_listen_t ret;
|
||||
ret = grub_malloc (sizeof (*ret));
|
||||
if (!ret)
|
||||
return NULL;
|
||||
ret->listen_hook = listen_hook;
|
||||
ret->hook_data = hook_data;
|
||||
ret->port = port;
|
||||
ret->inf = inf;
|
||||
grub_list_push (GRUB_AS_LIST_P (&tcp_listens), GRUB_AS_LIST (ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
void
|
||||
grub_net_tcp_stop_listen (grub_net_tcp_listen_t listen)
|
||||
{
|
||||
grub_list_remove (GRUB_AS_LIST_P (&tcp_listens),
|
||||
GRUB_AS_LIST (listen));
|
||||
}
|
||||
|
||||
static inline void
|
||||
tcp_socket_register (grub_net_tcp_socket_t sock)
|
||||
{
|
||||
grub_list_push (GRUB_AS_LIST_P (&tcp_sockets),
|
||||
GRUB_AS_LIST (sock));
|
||||
}
|
||||
|
||||
static void
|
||||
error (grub_net_tcp_socket_t sock)
|
||||
{
|
||||
struct unacked *unack, *next;
|
||||
|
||||
if (sock->error_hook)
|
||||
sock->error_hook (sock, sock->hook_data);
|
||||
|
||||
for (unack = sock->unack_first; unack; unack = next)
|
||||
{
|
||||
next = unack->next;
|
||||
grub_netbuff_free (unack->nb);
|
||||
grub_free (unack);
|
||||
}
|
||||
|
||||
sock->unack_first = NULL;
|
||||
sock->unack_last = NULL;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
tcp_send (struct grub_net_buff *nb, grub_net_tcp_socket_t socket)
|
||||
{
|
||||
grub_err_t err;
|
||||
grub_uint8_t *nbd;
|
||||
struct unacked *unack;
|
||||
struct tcphdr *tcph;
|
||||
grub_size_t size;
|
||||
|
||||
tcph = (struct tcphdr *) nb->data;
|
||||
|
||||
tcph->seqnr = grub_cpu_to_be32 (socket->my_cur_seq);
|
||||
size = (nb->tail - nb->data - (grub_be_to_cpu16 (tcph->flags) >> 12) * 4);
|
||||
if (grub_be_to_cpu16 (tcph->flags) & TCP_FIN)
|
||||
size++;
|
||||
socket->my_cur_seq += size;
|
||||
tcph->src = grub_cpu_to_be16 (socket->in_port);
|
||||
tcph->dst = grub_cpu_to_be16 (socket->out_port);
|
||||
tcph->checksum = 0;
|
||||
tcph->checksum = grub_net_ip_transport_checksum (nb, GRUB_NET_IP_TCP,
|
||||
&socket->inf->address,
|
||||
&socket->out_nla);
|
||||
nbd = nb->data;
|
||||
if (size)
|
||||
{
|
||||
unack = grub_malloc (sizeof (*unack));
|
||||
if (!unack)
|
||||
return grub_errno;
|
||||
|
||||
unack->next = NULL;
|
||||
unack->nb = nb;
|
||||
unack->try_count = 1;
|
||||
unack->last_try = grub_get_time_ms ();
|
||||
if (!socket->unack_last)
|
||||
socket->unack_first = socket->unack_last = unack;
|
||||
else
|
||||
socket->unack_last->next = unack;
|
||||
}
|
||||
|
||||
err = grub_net_send_ip_packet (socket->inf, &(socket->out_nla),
|
||||
&(socket->ll_target_addr), nb,
|
||||
GRUB_NET_IP_TCP);
|
||||
if (err)
|
||||
return err;
|
||||
nb->data = nbd;
|
||||
if (!size)
|
||||
grub_netbuff_free (nb);
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
void
|
||||
grub_net_tcp_close (grub_net_tcp_socket_t sock,
|
||||
int discard_received)
|
||||
{
|
||||
struct grub_net_buff *nb_fin;
|
||||
struct tcphdr *tcph_fin;
|
||||
grub_err_t err;
|
||||
|
||||
if (discard_received != GRUB_NET_TCP_CONTINUE_RECEIVING)
|
||||
{
|
||||
sock->recv_hook = NULL;
|
||||
sock->error_hook = NULL;
|
||||
sock->fin_hook = NULL;
|
||||
}
|
||||
|
||||
if (discard_received == GRUB_NET_TCP_ABORT)
|
||||
sock->i_reseted = 1;
|
||||
|
||||
if (sock->i_closed)
|
||||
return;
|
||||
|
||||
sock->i_closed = 1;
|
||||
|
||||
nb_fin = grub_netbuff_alloc (sizeof (*tcph_fin)
|
||||
+ GRUB_NET_OUR_MAX_IP_HEADER_SIZE
|
||||
+ GRUB_NET_MAX_LINK_HEADER_SIZE);
|
||||
if (!nb_fin)
|
||||
return;
|
||||
err = grub_netbuff_reserve (nb_fin, GRUB_NET_OUR_MAX_IP_HEADER_SIZE
|
||||
+ GRUB_NET_MAX_LINK_HEADER_SIZE);
|
||||
if (err)
|
||||
{
|
||||
grub_netbuff_free (nb_fin);
|
||||
grub_dprintf ("net", "error closing socket\n");
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
return;
|
||||
}
|
||||
|
||||
err = grub_netbuff_put (nb_fin, sizeof (*tcph_fin));
|
||||
if (err)
|
||||
{
|
||||
grub_netbuff_free (nb_fin);
|
||||
grub_dprintf ("net", "error closing socket\n");
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
return;
|
||||
}
|
||||
tcph_fin = (void *) nb_fin->data;
|
||||
tcph_fin->ack = grub_cpu_to_be32 (sock->their_cur_seq);
|
||||
tcph_fin->flags = grub_cpu_to_be16_compile_time ((5 << 12) | TCP_FIN
|
||||
| TCP_ACK);
|
||||
tcph_fin->window = grub_cpu_to_be16_compile_time (0);
|
||||
tcph_fin->urgent = 0;
|
||||
err = tcp_send (nb_fin, sock);
|
||||
if (err)
|
||||
{
|
||||
grub_netbuff_free (nb_fin);
|
||||
grub_dprintf ("net", "error closing socket\n");
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
static void
|
||||
ack_real (grub_net_tcp_socket_t sock, int res)
|
||||
{
|
||||
struct grub_net_buff *nb_ack;
|
||||
struct tcphdr *tcph_ack;
|
||||
grub_err_t err;
|
||||
|
||||
nb_ack = grub_netbuff_alloc (sizeof (*tcph_ack) + 128);
|
||||
if (!nb_ack)
|
||||
return;
|
||||
err = grub_netbuff_reserve (nb_ack, 128);
|
||||
if (err)
|
||||
{
|
||||
grub_netbuff_free (nb_ack);
|
||||
grub_dprintf ("net", "error closing socket\n");
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
return;
|
||||
}
|
||||
|
||||
err = grub_netbuff_put (nb_ack, sizeof (*tcph_ack));
|
||||
if (err)
|
||||
{
|
||||
grub_netbuff_free (nb_ack);
|
||||
grub_dprintf ("net", "error closing socket\n");
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
return;
|
||||
}
|
||||
tcph_ack = (void *) nb_ack->data;
|
||||
if (res)
|
||||
{
|
||||
tcph_ack->ack = grub_cpu_to_be32_compile_time (0);
|
||||
tcph_ack->flags = grub_cpu_to_be16_compile_time ((5 << 12) | TCP_RST);
|
||||
tcph_ack->window = grub_cpu_to_be16_compile_time (0);
|
||||
}
|
||||
else
|
||||
{
|
||||
tcph_ack->ack = grub_cpu_to_be32 (sock->their_cur_seq);
|
||||
tcph_ack->flags = grub_cpu_to_be16_compile_time ((5 << 12) | TCP_ACK);
|
||||
tcph_ack->window = grub_cpu_to_be16 (sock->my_window);
|
||||
}
|
||||
tcph_ack->urgent = 0;
|
||||
tcph_ack->src = grub_cpu_to_be16 (sock->in_port);
|
||||
tcph_ack->dst = grub_cpu_to_be16 (sock->out_port);
|
||||
err = tcp_send (nb_ack, sock);
|
||||
if (err)
|
||||
{
|
||||
grub_dprintf ("net", "error acking socket\n");
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
ack (grub_net_tcp_socket_t sock)
|
||||
{
|
||||
ack_real (sock, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
reset (grub_net_tcp_socket_t sock)
|
||||
{
|
||||
ack_real (sock, 1);
|
||||
}
|
||||
|
||||
void
|
||||
grub_net_tcp_retransmit (void)
|
||||
{
|
||||
grub_net_tcp_socket_t sock;
|
||||
grub_uint64_t ctime = grub_get_time_ms ();
|
||||
grub_uint64_t limit_time = ctime - TCP_RETRANSMISSION_TIMEOUT;
|
||||
|
||||
FOR_TCP_SOCKETS (sock)
|
||||
{
|
||||
struct unacked *unack;
|
||||
for (unack = sock->unack_first; unack; unack = unack->next)
|
||||
{
|
||||
struct tcphdr *tcph;
|
||||
grub_uint8_t *nbd;
|
||||
grub_err_t err;
|
||||
|
||||
if (unack->last_try > limit_time)
|
||||
continue;
|
||||
|
||||
if (unack->try_count > TCP_RETRANSMISSION_COUNT)
|
||||
{
|
||||
error (sock);
|
||||
break;
|
||||
}
|
||||
unack->try_count++;
|
||||
unack->last_try = ctime;
|
||||
nbd = unack->nb->data;
|
||||
tcph = (struct tcphdr *) nbd;
|
||||
|
||||
if ((tcph->flags & grub_cpu_to_be16_compile_time (TCP_ACK))
|
||||
&& tcph->ack != grub_cpu_to_be32 (sock->their_cur_seq))
|
||||
{
|
||||
tcph->checksum = 0;
|
||||
tcph->checksum = grub_net_ip_transport_checksum (unack->nb,
|
||||
GRUB_NET_IP_TCP,
|
||||
&sock->inf->address,
|
||||
&sock->out_nla);
|
||||
}
|
||||
|
||||
err = grub_net_send_ip_packet (sock->inf, &(sock->out_nla),
|
||||
&(sock->ll_target_addr), unack->nb,
|
||||
GRUB_NET_IP_TCP);
|
||||
unack->nb->data = nbd;
|
||||
if (err)
|
||||
{
|
||||
grub_dprintf ("net", "TCP retransmit failed: %s\n", grub_errmsg);
|
||||
grub_errno = GRUB_ERR_NONE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
grub_uint16_t
|
||||
grub_net_ip_transport_checksum (struct grub_net_buff *nb,
|
||||
grub_uint16_t proto,
|
||||
const grub_net_network_level_address_t *src,
|
||||
const grub_net_network_level_address_t *dst)
|
||||
{
|
||||
grub_uint16_t a, b = 0;
|
||||
grub_uint32_t c;
|
||||
a = ~grub_be_to_cpu16 (grub_net_ip_chksum ((void *) nb->data,
|
||||
nb->tail - nb->data));
|
||||
|
||||
switch (dst->type)
|
||||
{
|
||||
case GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4:
|
||||
{
|
||||
struct tcp_pseudohdr ph;
|
||||
ph.src = src->ipv4;
|
||||
ph.dst = dst->ipv4;
|
||||
ph.zero = 0;
|
||||
ph.tcp_length = grub_cpu_to_be16 (nb->tail - nb->data);
|
||||
ph.proto = proto;
|
||||
b = ~grub_be_to_cpu16 (grub_net_ip_chksum ((void *) &ph, sizeof (ph)));
|
||||
break;
|
||||
}
|
||||
case GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6:
|
||||
{
|
||||
struct tcp6_pseudohdr ph;
|
||||
grub_memcpy (ph.src, src->ipv6, sizeof (ph.src));
|
||||
grub_memcpy (ph.dst, dst->ipv6, sizeof (ph.dst));
|
||||
grub_memset (ph.zero, 0, sizeof (ph.zero));
|
||||
ph.tcp_length = grub_cpu_to_be32 (nb->tail - nb->data);
|
||||
ph.proto = proto;
|
||||
b = ~grub_be_to_cpu16 (grub_net_ip_chksum ((void *) &ph, sizeof (ph)));
|
||||
break;
|
||||
}
|
||||
case GRUB_NET_NETWORK_LEVEL_PROTOCOL_DHCP_RECV:
|
||||
b = 0;
|
||||
break;
|
||||
}
|
||||
c = (grub_uint32_t) a + (grub_uint32_t) b;
|
||||
if (c >= 0xffff)
|
||||
c -= 0xffff;
|
||||
return grub_cpu_to_be16 (~c);
|
||||
}
|
||||
|
||||
/* FIXME: overflow. */
|
||||
static int
|
||||
cmp (const void *a__, const void *b__)
|
||||
{
|
||||
struct grub_net_buff *a_ = *(struct grub_net_buff **) a__;
|
||||
struct grub_net_buff *b_ = *(struct grub_net_buff **) b__;
|
||||
struct tcphdr *a = (struct tcphdr *) a_->data;
|
||||
struct tcphdr *b = (struct tcphdr *) b_->data;
|
||||
/* We want the first elements to be on top. */
|
||||
if (grub_be_to_cpu32 (a->seqnr) < grub_be_to_cpu32 (b->seqnr))
|
||||
return +1;
|
||||
if (grub_be_to_cpu32 (a->seqnr) > grub_be_to_cpu32 (b->seqnr))
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
destroy_pq (grub_net_tcp_socket_t sock)
|
||||
{
|
||||
struct grub_net_buff **nb_p;
|
||||
while ((nb_p = grub_priority_queue_top (sock->pq)))
|
||||
{
|
||||
grub_netbuff_free (*nb_p);
|
||||
grub_priority_queue_pop (sock->pq);
|
||||
}
|
||||
|
||||
grub_priority_queue_destroy (sock->pq);
|
||||
}
|
||||
|
||||
grub_err_t
|
||||
grub_net_tcp_accept (grub_net_tcp_socket_t sock,
|
||||
grub_err_t (*recv_hook) (grub_net_tcp_socket_t sock,
|
||||
struct grub_net_buff *nb,
|
||||
void *data),
|
||||
void (*error_hook) (grub_net_tcp_socket_t sock,
|
||||
void *data),
|
||||
void (*fin_hook) (grub_net_tcp_socket_t sock,
|
||||
void *data),
|
||||
void *hook_data)
|
||||
{
|
||||
struct grub_net_buff *nb_ack;
|
||||
struct tcphdr *tcph;
|
||||
grub_err_t err;
|
||||
|
||||
sock->recv_hook = recv_hook;
|
||||
sock->error_hook = error_hook;
|
||||
sock->fin_hook = fin_hook;
|
||||
sock->hook_data = hook_data;
|
||||
nb_ack = grub_netbuff_alloc (sizeof (*tcph)
|
||||
+ GRUB_NET_OUR_MAX_IP_HEADER_SIZE
|
||||
+ GRUB_NET_MAX_LINK_HEADER_SIZE);
|
||||
if (!nb_ack)
|
||||
return grub_errno;
|
||||
err = grub_netbuff_reserve (nb_ack, GRUB_NET_OUR_MAX_IP_HEADER_SIZE
|
||||
+ GRUB_NET_MAX_LINK_HEADER_SIZE);
|
||||
if (err)
|
||||
{
|
||||
grub_netbuff_free (nb_ack);
|
||||
return err;
|
||||
}
|
||||
|
||||
err = grub_netbuff_put (nb_ack, sizeof (*tcph));
|
||||
if (err)
|
||||
{
|
||||
grub_netbuff_free (nb_ack);
|
||||
return err;
|
||||
}
|
||||
tcph = (void *) nb_ack->data;
|
||||
tcph->ack = grub_cpu_to_be32 (sock->their_cur_seq);
|
||||
tcph->flags = grub_cpu_to_be16_compile_time ((5 << 12) | TCP_SYN | TCP_ACK);
|
||||
tcph->window = grub_cpu_to_be16 (sock->my_window);
|
||||
tcph->urgent = 0;
|
||||
sock->established = 1;
|
||||
tcp_socket_register (sock);
|
||||
err = tcp_send (nb_ack, sock);
|
||||
if (err)
|
||||
return err;
|
||||
sock->my_cur_seq++;
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
grub_net_tcp_socket_t
|
||||
grub_net_tcp_open (char *server,
|
||||
grub_uint16_t out_port,
|
||||
grub_err_t (*recv_hook) (grub_net_tcp_socket_t sock,
|
||||
struct grub_net_buff *nb,
|
||||
void *data),
|
||||
void (*error_hook) (grub_net_tcp_socket_t sock,
|
||||
void *data),
|
||||
void (*fin_hook) (grub_net_tcp_socket_t sock,
|
||||
void *data),
|
||||
void *hook_data)
|
||||
{
|
||||
grub_err_t err;
|
||||
grub_net_network_level_address_t addr;
|
||||
struct grub_net_network_level_interface *inf;
|
||||
grub_net_network_level_address_t gateway;
|
||||
grub_net_tcp_socket_t socket;
|
||||
static grub_uint16_t in_port = 21550;
|
||||
struct grub_net_buff *nb;
|
||||
struct tcphdr *tcph;
|
||||
int i;
|
||||
grub_uint8_t *nbd;
|
||||
grub_net_link_level_address_t ll_target_addr;
|
||||
|
||||
err = grub_net_resolve_address (server, &addr);
|
||||
if (err)
|
||||
return NULL;
|
||||
|
||||
if (addr.type != GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4
|
||||
&& addr.type != GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6)
|
||||
{
|
||||
grub_error (GRUB_ERR_BAD_ARGUMENT, "not an IP address");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
err = grub_net_route_address (addr, &gateway, &inf);
|
||||
if (err)
|
||||
return NULL;
|
||||
|
||||
err = grub_net_link_layer_resolve (inf, &gateway, &ll_target_addr);
|
||||
if (err)
|
||||
return NULL;
|
||||
|
||||
socket = grub_zalloc (sizeof (*socket));
|
||||
if (socket == NULL)
|
||||
return NULL;
|
||||
|
||||
socket->out_port = out_port;
|
||||
socket->inf = inf;
|
||||
socket->out_nla = addr;
|
||||
socket->ll_target_addr = ll_target_addr;
|
||||
socket->in_port = in_port++;
|
||||
socket->recv_hook = recv_hook;
|
||||
socket->error_hook = error_hook;
|
||||
socket->fin_hook = fin_hook;
|
||||
socket->hook_data = hook_data;
|
||||
|
||||
nb = grub_netbuff_alloc (sizeof (*tcph) + 128);
|
||||
if (!nb)
|
||||
return NULL;
|
||||
err = grub_netbuff_reserve (nb, 128);
|
||||
if (err)
|
||||
{
|
||||
grub_netbuff_free (nb);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
err = grub_netbuff_put (nb, sizeof (*tcph));
|
||||
if (err)
|
||||
{
|
||||
grub_netbuff_free (nb);
|
||||
return NULL;
|
||||
}
|
||||
socket->pq = grub_priority_queue_new (sizeof (struct grub_net_buff *), cmp);
|
||||
if (!socket->pq)
|
||||
{
|
||||
grub_netbuff_free (nb);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
tcph = (void *) nb->data;
|
||||
socket->my_start_seq = grub_get_time_ms ();
|
||||
socket->my_cur_seq = socket->my_start_seq + 1;
|
||||
socket->my_window = 8192;
|
||||
tcph->seqnr = grub_cpu_to_be32 (socket->my_start_seq);
|
||||
tcph->ack = grub_cpu_to_be32_compile_time (0);
|
||||
tcph->flags = grub_cpu_to_be16_compile_time ((5 << 12) | TCP_SYN);
|
||||
tcph->window = grub_cpu_to_be16 (socket->my_window);
|
||||
tcph->urgent = 0;
|
||||
tcph->src = grub_cpu_to_be16 (socket->in_port);
|
||||
tcph->dst = grub_cpu_to_be16 (socket->out_port);
|
||||
tcph->checksum = 0;
|
||||
tcph->checksum = grub_net_ip_transport_checksum (nb, GRUB_NET_IP_TCP,
|
||||
&socket->inf->address,
|
||||
&socket->out_nla);
|
||||
|
||||
tcp_socket_register (socket);
|
||||
|
||||
nbd = nb->data;
|
||||
for (i = 0; i < TCP_SYN_RETRANSMISSION_COUNT; i++)
|
||||
{
|
||||
int j;
|
||||
nb->data = nbd;
|
||||
err = grub_net_send_ip_packet (socket->inf, &(socket->out_nla),
|
||||
&(socket->ll_target_addr), nb,
|
||||
GRUB_NET_IP_TCP);
|
||||
if (err)
|
||||
{
|
||||
grub_list_remove (GRUB_AS_LIST_P (&tcp_sockets),
|
||||
GRUB_AS_LIST (socket));
|
||||
grub_free (socket);
|
||||
grub_netbuff_free (nb);
|
||||
return NULL;
|
||||
}
|
||||
for (j = 0; (j < TCP_SYN_RETRANSMISSION_TIMEOUT / 50
|
||||
&& !socket->established); j++)
|
||||
grub_net_poll_cards (50);
|
||||
if (socket->established)
|
||||
break;
|
||||
}
|
||||
if (!socket->established)
|
||||
{
|
||||
grub_list_remove (GRUB_AS_LIST_P (&tcp_sockets),
|
||||
GRUB_AS_LIST (socket));
|
||||
if (socket->they_reseted)
|
||||
grub_error (GRUB_ERR_NET_PORT_CLOSED, "port closed");
|
||||
else
|
||||
grub_error (GRUB_ERR_NET_NO_ANSWER, "no answer");
|
||||
|
||||
grub_netbuff_free (nb);
|
||||
destroy_pq (socket);
|
||||
grub_free (socket);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
grub_netbuff_free (nb);
|
||||
return socket;
|
||||
}
|
||||
|
||||
grub_err_t
|
||||
grub_net_send_tcp_packet (const grub_net_tcp_socket_t socket,
|
||||
struct grub_net_buff *nb, int push)
|
||||
{
|
||||
struct tcphdr *tcph;
|
||||
grub_err_t err;
|
||||
grub_ssize_t fraglen;
|
||||
COMPILE_TIME_ASSERT (sizeof (struct tcphdr) == GRUB_NET_TCP_HEADER_SIZE);
|
||||
if (socket->out_nla.type == GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4)
|
||||
fraglen = (socket->inf->card->mtu - GRUB_NET_OUR_IPV4_HEADER_SIZE
|
||||
- sizeof (*tcph));
|
||||
else
|
||||
fraglen = 1280 - GRUB_NET_OUR_IPV6_HEADER_SIZE;
|
||||
|
||||
while (nb->tail - nb->data > fraglen)
|
||||
{
|
||||
struct grub_net_buff *nb2;
|
||||
|
||||
nb2 = grub_netbuff_alloc (fraglen + sizeof (*tcph)
|
||||
+ GRUB_NET_OUR_MAX_IP_HEADER_SIZE
|
||||
+ GRUB_NET_MAX_LINK_HEADER_SIZE);
|
||||
if (!nb2)
|
||||
return grub_errno;
|
||||
err = grub_netbuff_reserve (nb2, GRUB_NET_MAX_LINK_HEADER_SIZE
|
||||
+ GRUB_NET_OUR_MAX_IP_HEADER_SIZE);
|
||||
if (err)
|
||||
return err;
|
||||
err = grub_netbuff_put (nb2, sizeof (*tcph));
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
tcph = (struct tcphdr *) nb2->data;
|
||||
tcph->ack = grub_cpu_to_be32 (socket->their_cur_seq);
|
||||
tcph->flags = grub_cpu_to_be16_compile_time ((5 << 12) | TCP_ACK);
|
||||
tcph->window = grub_cpu_to_be16 (socket->my_window);
|
||||
tcph->urgent = 0;
|
||||
err = grub_netbuff_put (nb2, fraglen);
|
||||
if (err)
|
||||
return err;
|
||||
grub_memcpy (tcph + 1, nb->data, fraglen);
|
||||
err = grub_netbuff_pull (nb, fraglen);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = tcp_send (nb2, socket);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
err = grub_netbuff_push (nb, sizeof (*tcph));
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
tcph = (struct tcphdr *) nb->data;
|
||||
tcph->ack = grub_cpu_to_be32 (socket->their_cur_seq);
|
||||
tcph->flags = (grub_cpu_to_be16_compile_time ((5 << 12) | TCP_ACK)
|
||||
| (push ? grub_cpu_to_be16_compile_time (TCP_PUSH) : 0));
|
||||
tcph->window = grub_cpu_to_be16 (socket->my_window);
|
||||
tcph->urgent = 0;
|
||||
return tcp_send (nb, socket);
|
||||
}
|
||||
|
||||
grub_err_t
|
||||
grub_net_recv_tcp_packet (struct grub_net_buff *nb,
|
||||
struct grub_net_network_level_interface *inf,
|
||||
const grub_net_network_level_address_t *source)
|
||||
{
|
||||
struct tcphdr *tcph;
|
||||
grub_net_tcp_socket_t sock;
|
||||
grub_err_t err;
|
||||
|
||||
/* Ignore broadcast. */
|
||||
if (!inf)
|
||||
{
|
||||
grub_netbuff_free (nb);
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
tcph = (struct tcphdr *) nb->data;
|
||||
if ((grub_be_to_cpu16 (tcph->flags) >> 12) < 5)
|
||||
{
|
||||
grub_dprintf ("net", "TCP header too short: %u\n",
|
||||
grub_be_to_cpu16 (tcph->flags) >> 12);
|
||||
grub_netbuff_free (nb);
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
if (nb->tail - nb->data < (grub_ssize_t) ((grub_be_to_cpu16 (tcph->flags)
|
||||
>> 12) * sizeof (grub_uint32_t)))
|
||||
{
|
||||
grub_dprintf ("net", "TCP packet too short: %" PRIuGRUB_SIZE "\n",
|
||||
nb->tail - nb->data);
|
||||
grub_netbuff_free (nb);
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
FOR_TCP_SOCKETS (sock)
|
||||
{
|
||||
if (!(grub_be_to_cpu16 (tcph->dst) == sock->in_port
|
||||
&& grub_be_to_cpu16 (tcph->src) == sock->out_port
|
||||
&& inf == sock->inf
|
||||
&& grub_net_addr_cmp (source, &sock->out_nla) == 0))
|
||||
continue;
|
||||
if (tcph->checksum)
|
||||
{
|
||||
grub_uint16_t chk, expected;
|
||||
chk = tcph->checksum;
|
||||
tcph->checksum = 0;
|
||||
expected = grub_net_ip_transport_checksum (nb, GRUB_NET_IP_TCP,
|
||||
&sock->out_nla,
|
||||
&sock->inf->address);
|
||||
if (expected != chk)
|
||||
{
|
||||
grub_dprintf ("net", "Invalid TCP checksum. "
|
||||
"Expected %x, got %x\n",
|
||||
grub_be_to_cpu16 (expected),
|
||||
grub_be_to_cpu16 (chk));
|
||||
grub_netbuff_free (nb);
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
tcph->checksum = chk;
|
||||
}
|
||||
|
||||
if ((grub_be_to_cpu16 (tcph->flags) & TCP_SYN)
|
||||
&& (grub_be_to_cpu16 (tcph->flags) & TCP_ACK)
|
||||
&& !sock->established)
|
||||
{
|
||||
sock->their_start_seq = grub_be_to_cpu32 (tcph->seqnr);
|
||||
sock->their_cur_seq = sock->their_start_seq + 1;
|
||||
sock->established = 1;
|
||||
}
|
||||
|
||||
if (grub_be_to_cpu16 (tcph->flags) & TCP_RST)
|
||||
{
|
||||
sock->they_reseted = 1;
|
||||
|
||||
error (sock);
|
||||
|
||||
grub_netbuff_free (nb);
|
||||
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
if (grub_be_to_cpu16 (tcph->flags) & TCP_ACK)
|
||||
{
|
||||
struct unacked *unack, *next;
|
||||
grub_uint32_t acked = grub_be_to_cpu32 (tcph->ack);
|
||||
for (unack = sock->unack_first; unack; unack = next)
|
||||
{
|
||||
grub_uint32_t seqnr;
|
||||
struct tcphdr *unack_tcph;
|
||||
next = unack->next;
|
||||
seqnr = grub_be_to_cpu32 (((struct tcphdr *) unack->nb->data)
|
||||
->seqnr);
|
||||
unack_tcph = (struct tcphdr *) unack->nb->data;
|
||||
seqnr += (unack->nb->tail - unack->nb->data
|
||||
- (grub_be_to_cpu16 (unack_tcph->flags) >> 12) * 4);
|
||||
if (grub_be_to_cpu16 (unack_tcph->flags) & TCP_FIN)
|
||||
seqnr++;
|
||||
|
||||
if (seqnr > acked)
|
||||
break;
|
||||
grub_netbuff_free (unack->nb);
|
||||
grub_free (unack);
|
||||
}
|
||||
sock->unack_first = unack;
|
||||
if (!sock->unack_first)
|
||||
sock->unack_last = NULL;
|
||||
}
|
||||
|
||||
if (grub_be_to_cpu32 (tcph->seqnr) < sock->their_cur_seq)
|
||||
{
|
||||
ack (sock);
|
||||
grub_netbuff_free (nb);
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
if (sock->i_reseted && (nb->tail - nb->data
|
||||
- (grub_be_to_cpu16 (tcph->flags)
|
||||
>> 12) * sizeof (grub_uint32_t)) > 0)
|
||||
{
|
||||
reset (sock);
|
||||
}
|
||||
|
||||
err = grub_priority_queue_push (sock->pq, &nb);
|
||||
if (err)
|
||||
{
|
||||
grub_netbuff_free (nb);
|
||||
return err;
|
||||
}
|
||||
|
||||
{
|
||||
struct grub_net_buff **nb_top_p, *nb_top;
|
||||
int do_ack = 0;
|
||||
int just_closed = 0;
|
||||
while (1)
|
||||
{
|
||||
nb_top_p = grub_priority_queue_top (sock->pq);
|
||||
if (!nb_top_p)
|
||||
return GRUB_ERR_NONE;
|
||||
nb_top = *nb_top_p;
|
||||
tcph = (struct tcphdr *) nb_top->data;
|
||||
if (grub_be_to_cpu32 (tcph->seqnr) >= sock->their_cur_seq)
|
||||
break;
|
||||
grub_netbuff_free (nb_top);
|
||||
grub_priority_queue_pop (sock->pq);
|
||||
}
|
||||
if (grub_be_to_cpu32 (tcph->seqnr) != sock->their_cur_seq)
|
||||
return GRUB_ERR_NONE;
|
||||
while (1)
|
||||
{
|
||||
nb_top_p = grub_priority_queue_top (sock->pq);
|
||||
if (!nb_top_p)
|
||||
break;
|
||||
nb_top = *nb_top_p;
|
||||
tcph = (struct tcphdr *) nb_top->data;
|
||||
|
||||
if (grub_be_to_cpu32 (tcph->seqnr) != sock->their_cur_seq)
|
||||
break;
|
||||
grub_priority_queue_pop (sock->pq);
|
||||
|
||||
err = grub_netbuff_pull (nb_top, (grub_be_to_cpu16 (tcph->flags)
|
||||
>> 12) * sizeof (grub_uint32_t));
|
||||
if (err)
|
||||
{
|
||||
grub_netbuff_free (nb_top);
|
||||
return err;
|
||||
}
|
||||
|
||||
sock->their_cur_seq += (nb_top->tail - nb_top->data);
|
||||
if (grub_be_to_cpu16 (tcph->flags) & TCP_FIN)
|
||||
{
|
||||
sock->they_closed = 1;
|
||||
just_closed = 1;
|
||||
sock->their_cur_seq++;
|
||||
do_ack = 1;
|
||||
}
|
||||
/* If there is data, puts packet in socket list. */
|
||||
if ((nb_top->tail - nb_top->data) > 0)
|
||||
{
|
||||
grub_net_put_packet (&sock->packs, nb_top);
|
||||
do_ack = 1;
|
||||
}
|
||||
else
|
||||
grub_netbuff_free (nb);
|
||||
}
|
||||
if (do_ack)
|
||||
ack (sock);
|
||||
while (sock->packs.first)
|
||||
{
|
||||
nb = sock->packs.first->nb;
|
||||
if (sock->recv_hook)
|
||||
sock->recv_hook (sock, sock->packs.first->nb, sock->hook_data);
|
||||
else
|
||||
grub_netbuff_free (nb);
|
||||
grub_net_remove_packet (sock->packs.first);
|
||||
}
|
||||
|
||||
if (sock->fin_hook && just_closed)
|
||||
sock->fin_hook (sock, sock->hook_data);
|
||||
}
|
||||
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
if (grub_be_to_cpu16 (tcph->flags) & TCP_SYN)
|
||||
{
|
||||
grub_net_tcp_listen_t listen;
|
||||
|
||||
FOR_TCP_LISTENS (listen)
|
||||
{
|
||||
if (!(grub_be_to_cpu16 (tcph->dst) == listen->port
|
||||
&& (inf == listen->inf || listen->inf == NULL)))
|
||||
continue;
|
||||
sock = grub_zalloc (sizeof (*sock));
|
||||
if (sock == NULL)
|
||||
return grub_errno;
|
||||
|
||||
sock->out_port = grub_be_to_cpu16 (tcph->src);
|
||||
sock->in_port = grub_be_to_cpu16 (tcph->dst);
|
||||
sock->inf = inf;
|
||||
sock->out_nla = *source;
|
||||
sock->their_start_seq = grub_be_to_cpu32 (tcph->seqnr);
|
||||
sock->their_cur_seq = sock->their_start_seq + 1;
|
||||
sock->my_cur_seq = sock->my_start_seq = grub_get_time_ms ();
|
||||
sock->my_window = 8192;
|
||||
|
||||
sock->pq = grub_priority_queue_new (sizeof (struct grub_net_buff *),
|
||||
cmp);
|
||||
if (!sock->pq)
|
||||
{
|
||||
grub_netbuff_free (nb);
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
err = listen->listen_hook (listen, sock, listen->hook_data);
|
||||
|
||||
grub_netbuff_free (nb);
|
||||
return err;
|
||||
|
||||
}
|
||||
}
|
||||
grub_netbuff_free (nb);
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
|
@ -25,6 +25,7 @@
|
|||
#include <grub/mm.h>
|
||||
#include <grub/dl.h>
|
||||
#include <grub/file.h>
|
||||
#include <grub/priority_queue.h>
|
||||
|
||||
GRUB_MOD_LICENSE ("GPLv3+");
|
||||
|
||||
|
@ -102,24 +103,63 @@ typedef struct tftp_data
|
|||
grub_uint64_t block;
|
||||
grub_uint32_t block_size;
|
||||
int have_oack;
|
||||
grub_net_socket_t sock;
|
||||
grub_net_udp_socket_t sock;
|
||||
grub_priority_queue_t pq;
|
||||
} *tftp_data_t;
|
||||
|
||||
static int
|
||||
cmp (const void *a__, const void *b__)
|
||||
{
|
||||
struct grub_net_buff *a_ = *(struct grub_net_buff **) a__;
|
||||
struct grub_net_buff *b_ = *(struct grub_net_buff **) b__;
|
||||
struct tftphdr *a = (struct tftphdr *) a_->data;
|
||||
struct tftphdr *b = (struct tftphdr *) b_->data;
|
||||
/* We want the first elements to be on top. */
|
||||
if (grub_be_to_cpu16 (a->u.data.block) < grub_be_to_cpu16 (b->u.data.block))
|
||||
return +1;
|
||||
if (grub_be_to_cpu16 (a->u.data.block) > grub_be_to_cpu16 (b->u.data.block))
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
tftp_receive (grub_net_socket_t sock __attribute__ ((unused)),
|
||||
ack (grub_net_udp_socket_t sock, grub_uint16_t block)
|
||||
{
|
||||
struct tftphdr *tftph_ack;
|
||||
grub_uint8_t nbdata[512];
|
||||
struct grub_net_buff nb_ack;
|
||||
grub_err_t err;
|
||||
|
||||
nb_ack.head = nbdata;
|
||||
nb_ack.end = nbdata + sizeof (nbdata);
|
||||
grub_netbuff_clear (&nb_ack);
|
||||
grub_netbuff_reserve (&nb_ack, 512);
|
||||
err = grub_netbuff_push (&nb_ack, sizeof (tftph_ack->opcode)
|
||||
+ sizeof (tftph_ack->u.ack.block));
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
tftph_ack = (struct tftphdr *) nb_ack.data;
|
||||
tftph_ack->opcode = grub_cpu_to_be16 (TFTP_ACK);
|
||||
tftph_ack->u.ack.block = block;
|
||||
|
||||
err = grub_net_send_udp_packet (sock, &nb_ack);
|
||||
return err;
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
tftp_receive (grub_net_udp_socket_t sock __attribute__ ((unused)),
|
||||
struct grub_net_buff *nb,
|
||||
void *f)
|
||||
{
|
||||
grub_file_t file = f;
|
||||
struct tftphdr *tftph = (void *) nb->data;
|
||||
char nbdata[512];
|
||||
tftp_data_t data = file->data;
|
||||
grub_err_t err;
|
||||
char *ptr;
|
||||
struct grub_net_buff nb_ack;
|
||||
grub_uint8_t *ptr;
|
||||
|
||||
nb_ack.head = nbdata;
|
||||
nb_ack.end = nbdata + sizeof (nbdata);
|
||||
if (nb->tail - nb->data < (grub_ssize_t) sizeof (tftph->opcode))
|
||||
return grub_error (GRUB_ERR_OUT_OF_RANGE, "TFTP packet too small");
|
||||
|
||||
tftph = (struct tftphdr *) nb->data;
|
||||
switch (grub_be_to_cpu16 (tftph->opcode))
|
||||
|
@ -130,76 +170,99 @@ tftp_receive (grub_net_socket_t sock __attribute__ ((unused)),
|
|||
for (ptr = nb->data + sizeof (tftph->opcode); ptr < nb->tail;)
|
||||
{
|
||||
if (grub_memcmp (ptr, "tsize\0", sizeof ("tsize\0") - 1) == 0)
|
||||
{
|
||||
data->file_size = grub_strtoul (ptr + sizeof ("tsize\0") - 1,
|
||||
0, 0);
|
||||
}
|
||||
data->file_size = grub_strtoul ((char *) ptr + sizeof ("tsize\0")
|
||||
- 1, 0, 0);
|
||||
if (grub_memcmp (ptr, "blksize\0", sizeof ("blksize\0") - 1) == 0)
|
||||
{
|
||||
data->block_size = grub_strtoul (ptr + sizeof ("blksize\0") - 1,
|
||||
0, 0);
|
||||
}
|
||||
data->block_size = grub_strtoul ((char *) ptr + sizeof ("blksize\0")
|
||||
- 1, 0, 0);
|
||||
while (ptr < nb->tail && *ptr)
|
||||
ptr++;
|
||||
ptr++;
|
||||
}
|
||||
data->block = 0;
|
||||
grub_netbuff_free (nb);
|
||||
break;
|
||||
err = ack (data->sock, 0);
|
||||
if (err)
|
||||
return err;
|
||||
return GRUB_ERR_NONE;
|
||||
case TFTP_DATA:
|
||||
err = grub_netbuff_pull (nb, sizeof (tftph->opcode) +
|
||||
if (nb->tail - nb->data < (grub_ssize_t) (sizeof (tftph->opcode)
|
||||
+ sizeof (tftph->u.data.block)))
|
||||
return grub_error (GRUB_ERR_OUT_OF_RANGE, "TFTP packet too small");
|
||||
err = ack (data->sock, tftph->u.data.block);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = grub_priority_queue_push (data->pq, &nb);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
{
|
||||
struct grub_net_buff **nb_top_p, *nb_top;
|
||||
while (1)
|
||||
{
|
||||
nb_top_p = grub_priority_queue_top (data->pq);
|
||||
if (!nb_top_p)
|
||||
return GRUB_ERR_NONE;
|
||||
nb_top = *nb_top_p;
|
||||
tftph = (struct tftphdr *) nb_top->data;
|
||||
if (grub_be_to_cpu16 (tftph->u.data.block) >= data->block + 1)
|
||||
break;
|
||||
grub_priority_queue_pop (data->pq);
|
||||
}
|
||||
if (grub_be_to_cpu16 (tftph->u.data.block) == data->block + 1)
|
||||
{
|
||||
unsigned size;
|
||||
|
||||
grub_priority_queue_pop (data->pq);
|
||||
|
||||
err = grub_netbuff_pull (nb_top, sizeof (tftph->opcode) +
|
||||
sizeof (tftph->u.data.block));
|
||||
if (err)
|
||||
return err;
|
||||
if (grub_be_to_cpu16 (tftph->u.data.block) == data->block + 1)
|
||||
{
|
||||
unsigned size = nb->tail - nb->data;
|
||||
size = nb_top->tail - nb_top->data;
|
||||
|
||||
data->block++;
|
||||
if (size < data->block_size)
|
||||
{
|
||||
file->device->net->eof = 1;
|
||||
grub_net_udp_close (data->sock);
|
||||
data->sock = NULL;
|
||||
}
|
||||
/* Prevent garbage in broken cards. */
|
||||
/* Prevent garbage in broken cards. Is it still necessary
|
||||
given that IP implementation has been fixed?
|
||||
*/
|
||||
if (size > data->block_size)
|
||||
{
|
||||
err = grub_netbuff_unput (nb, size - data->block_size);
|
||||
err = grub_netbuff_unput (nb_top, size - data->block_size);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
/* If there is data, puts packet in socket list. */
|
||||
if ((nb->tail - nb->data) > 0)
|
||||
grub_net_put_packet (&file->device->net->packs, nb);
|
||||
if ((nb_top->tail - nb_top->data) > 0)
|
||||
grub_net_put_packet (&file->device->net->packs, nb_top);
|
||||
else
|
||||
grub_netbuff_free (nb);
|
||||
}
|
||||
else
|
||||
{
|
||||
grub_netbuff_free (nb);
|
||||
}
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
break;
|
||||
case TFTP_ERROR:
|
||||
grub_netbuff_free (nb);
|
||||
return grub_error (GRUB_ERR_IO, (char *) tftph->u.err.errmsg);
|
||||
default:
|
||||
grub_netbuff_free (nb);
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
}
|
||||
grub_netbuff_clear (&nb_ack);
|
||||
grub_netbuff_reserve (&nb_ack, 512);
|
||||
err = grub_netbuff_push (&nb_ack, sizeof (tftph->opcode)
|
||||
+ sizeof (tftph->u.ack.block));
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
tftph = (struct tftphdr *) nb_ack.data;
|
||||
tftph->opcode = grub_cpu_to_be16 (TFTP_ACK);
|
||||
tftph->u.ack.block = grub_cpu_to_be16 (data->block);
|
||||
|
||||
err = grub_net_send_udp_packet (data->sock, &nb_ack);
|
||||
if (file->device->net->eof)
|
||||
static void
|
||||
destroy_pq (tftp_data_t data)
|
||||
{
|
||||
grub_net_udp_close (data->sock);
|
||||
data->sock = NULL;
|
||||
}
|
||||
return err;
|
||||
struct grub_net_buff **nb_p;
|
||||
while ((nb_p = grub_priority_queue_top (data->pq)))
|
||||
grub_netbuff_free (*nb_p);
|
||||
|
||||
grub_priority_queue_destroy (data->pq);
|
||||
}
|
||||
|
||||
static grub_err_t
|
||||
|
@ -210,10 +273,12 @@ tftp_open (struct grub_file *file, const char *filename)
|
|||
int i;
|
||||
int rrqlen;
|
||||
int hdrlen;
|
||||
char open_data[1500];
|
||||
grub_uint8_t open_data[1500];
|
||||
struct grub_net_buff nb;
|
||||
tftp_data_t data;
|
||||
grub_err_t err;
|
||||
grub_uint8_t *nbd;
|
||||
grub_net_network_level_address_t addr;
|
||||
|
||||
data = grub_zalloc (sizeof (*data));
|
||||
if (!data)
|
||||
|
@ -265,39 +330,48 @@ tftp_open (struct grub_file *file, const char *filename)
|
|||
|
||||
file->not_easily_seekable = 1;
|
||||
file->data = data;
|
||||
data->sock = grub_net_udp_open (file->device->net->server,
|
||||
|
||||
data->pq = grub_priority_queue_new (sizeof (struct grub_net_buff *), cmp);
|
||||
if (!data->pq)
|
||||
return grub_errno;
|
||||
|
||||
err = grub_net_resolve_address (file->device->net->server, &addr);
|
||||
if (err)
|
||||
{
|
||||
destroy_pq (data);
|
||||
return err;
|
||||
}
|
||||
|
||||
data->sock = grub_net_udp_open (addr,
|
||||
TFTP_SERVER_PORT, tftp_receive,
|
||||
file);
|
||||
if (!data->sock)
|
||||
return grub_errno;
|
||||
|
||||
err = grub_net_send_udp_packet (data->sock, &nb);
|
||||
if (err)
|
||||
{
|
||||
grub_net_udp_close (data->sock);
|
||||
return err;
|
||||
destroy_pq (data);
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
/* Receive OACK packet. */
|
||||
for (i = 0; i < 3; i++)
|
||||
nbd = nb.data;
|
||||
for (i = 0; i < GRUB_NET_TRIES; i++)
|
||||
{
|
||||
grub_net_poll_cards (100);
|
||||
if (grub_errno)
|
||||
return grub_errno;
|
||||
if (data->have_oack)
|
||||
break;
|
||||
/* Retry. */
|
||||
nb.data = nbd;
|
||||
err = grub_net_send_udp_packet (data->sock, &nb);
|
||||
if (err)
|
||||
{
|
||||
grub_net_udp_close (data->sock);
|
||||
destroy_pq (data);
|
||||
return err;
|
||||
}
|
||||
grub_net_poll_cards (GRUB_NET_INTERVAL);
|
||||
if (data->have_oack)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!data->have_oack)
|
||||
{
|
||||
grub_net_udp_close (data->sock);
|
||||
destroy_pq (data);
|
||||
return grub_error (GRUB_ERR_TIMEOUT, "Time out opening tftp.");
|
||||
}
|
||||
file->size = data->file_size;
|
||||
|
@ -312,7 +386,7 @@ tftp_close (struct grub_file *file)
|
|||
|
||||
if (data->sock)
|
||||
{
|
||||
char nbdata[512];
|
||||
grub_uint8_t nbdata[512];
|
||||
grub_err_t err;
|
||||
struct grub_net_buff nb_err;
|
||||
struct tftphdr *tftph;
|
||||
|
@ -338,6 +412,7 @@ tftp_close (struct grub_file *file)
|
|||
grub_print_error ();
|
||||
grub_net_udp_close (data->sock);
|
||||
}
|
||||
destroy_pq (data);
|
||||
grub_free (data);
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
|
|
@ -1,29 +1,90 @@
|
|||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2010,2011 Free Software Foundation, Inc.
|
||||
*
|
||||
* GRUB is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GRUB is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <grub/net.h>
|
||||
#include <grub/net/udp.h>
|
||||
#include <grub/net/ip.h>
|
||||
#include <grub/net/netbuff.h>
|
||||
#include <grub/time.h>
|
||||
|
||||
grub_net_socket_t
|
||||
grub_net_udp_open (char *server,
|
||||
struct grub_net_udp_socket
|
||||
{
|
||||
struct grub_net_udp_socket *next;
|
||||
|
||||
enum { GRUB_NET_SOCKET_START,
|
||||
GRUB_NET_SOCKET_ESTABLISHED,
|
||||
GRUB_NET_SOCKET_CLOSED } status;
|
||||
int in_port;
|
||||
int out_port;
|
||||
grub_err_t (*recv_hook) (grub_net_udp_socket_t sock, struct grub_net_buff *nb,
|
||||
void *recv);
|
||||
void *recv_hook_data;
|
||||
grub_net_network_level_address_t out_nla;
|
||||
grub_net_link_level_address_t ll_target_addr;
|
||||
struct grub_net_network_level_interface *inf;
|
||||
};
|
||||
|
||||
static struct grub_net_udp_socket *udp_sockets;
|
||||
|
||||
#define FOR_UDP_SOCKETS(var) for (var = udp_sockets; var; var = var->next)
|
||||
|
||||
static inline void
|
||||
udp_socket_register (grub_net_udp_socket_t sock)
|
||||
{
|
||||
grub_list_push (GRUB_AS_LIST_P (&udp_sockets),
|
||||
GRUB_AS_LIST (sock));
|
||||
}
|
||||
|
||||
void
|
||||
grub_net_udp_close (grub_net_udp_socket_t sock)
|
||||
{
|
||||
grub_list_remove (GRUB_AS_LIST_P (&udp_sockets),
|
||||
GRUB_AS_LIST (sock));
|
||||
grub_free (sock);
|
||||
}
|
||||
|
||||
grub_net_udp_socket_t
|
||||
grub_net_udp_open (grub_net_network_level_address_t addr,
|
||||
grub_uint16_t out_port,
|
||||
grub_err_t (*recv_hook) (grub_net_socket_t sock,
|
||||
grub_err_t (*recv_hook) (grub_net_udp_socket_t sock,
|
||||
struct grub_net_buff *nb,
|
||||
void *data),
|
||||
void *recv_hook_data)
|
||||
{
|
||||
grub_err_t err;
|
||||
grub_net_network_level_address_t addr;
|
||||
struct grub_net_network_level_interface *inf;
|
||||
grub_net_network_level_address_t gateway;
|
||||
grub_net_socket_t socket;
|
||||
grub_net_udp_socket_t socket;
|
||||
static int in_port = 25300;
|
||||
grub_net_link_level_address_t ll_target_addr;
|
||||
|
||||
err = grub_net_resolve_address (server, &addr);
|
||||
if (addr.type != GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4
|
||||
&& addr.type != GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6)
|
||||
{
|
||||
grub_error (GRUB_ERR_BAD_ARGUMENT, "not an IP address");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
err = grub_net_route_address (addr, &gateway, &inf);
|
||||
if (err)
|
||||
return NULL;
|
||||
|
||||
err = grub_net_route_address (addr, &gateway, &inf);
|
||||
err = grub_net_link_layer_resolve (inf, &gateway, &ll_target_addr);
|
||||
if (err)
|
||||
return NULL;
|
||||
|
||||
|
@ -31,66 +92,117 @@ grub_net_udp_open (char *server,
|
|||
if (socket == NULL)
|
||||
return NULL;
|
||||
|
||||
socket->x_out_port = out_port;
|
||||
socket->x_inf = inf;
|
||||
socket->x_out_nla = addr;
|
||||
socket->x_in_port = in_port++;
|
||||
socket->x_status = GRUB_NET_SOCKET_START;
|
||||
socket->out_port = out_port;
|
||||
socket->inf = inf;
|
||||
socket->out_nla = addr;
|
||||
socket->ll_target_addr = ll_target_addr;
|
||||
socket->in_port = in_port++;
|
||||
socket->status = GRUB_NET_SOCKET_START;
|
||||
socket->recv_hook = recv_hook;
|
||||
socket->recv_hook_data = recv_hook_data;
|
||||
|
||||
grub_net_socket_register (socket);
|
||||
udp_socket_register (socket);
|
||||
|
||||
return socket;
|
||||
}
|
||||
|
||||
grub_err_t
|
||||
grub_net_send_udp_packet (const grub_net_socket_t socket,
|
||||
grub_net_send_udp_packet (const grub_net_udp_socket_t socket,
|
||||
struct grub_net_buff *nb)
|
||||
{
|
||||
struct udphdr *udph;
|
||||
grub_err_t err;
|
||||
|
||||
COMPILE_TIME_ASSERT (GRUB_NET_UDP_HEADER_SIZE == sizeof (*udph));
|
||||
|
||||
err = grub_netbuff_push (nb, sizeof (*udph));
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
udph = (struct udphdr *) nb->data;
|
||||
udph->src = grub_cpu_to_be16 (socket->x_in_port);
|
||||
udph->dst = grub_cpu_to_be16 (socket->x_out_port);
|
||||
udph->src = grub_cpu_to_be16 (socket->in_port);
|
||||
udph->dst = grub_cpu_to_be16 (socket->out_port);
|
||||
|
||||
/* No chechksum. */
|
||||
udph->chksum = 0;
|
||||
udph->len = grub_cpu_to_be16 (nb->tail - nb->data);
|
||||
|
||||
return grub_net_send_ip_packet (socket->x_inf, &(socket->x_out_nla), nb);
|
||||
udph->chksum = grub_net_ip_transport_checksum (nb, GRUB_NET_IP_UDP,
|
||||
&socket->inf->address,
|
||||
&socket->out_nla);
|
||||
|
||||
return grub_net_send_ip_packet (socket->inf, &(socket->out_nla),
|
||||
&(socket->ll_target_addr), nb,
|
||||
GRUB_NET_IP_UDP);
|
||||
}
|
||||
|
||||
grub_err_t
|
||||
grub_net_recv_udp_packet (struct grub_net_buff *nb,
|
||||
struct grub_net_network_level_interface * inf)
|
||||
struct grub_net_network_level_interface *inf,
|
||||
const grub_net_network_level_address_t *source)
|
||||
{
|
||||
struct udphdr *udph;
|
||||
grub_net_socket_t sock;
|
||||
grub_net_udp_socket_t sock;
|
||||
grub_err_t err;
|
||||
|
||||
/* Ignore broadcast. */
|
||||
if (!inf)
|
||||
{
|
||||
grub_netbuff_free (nb);
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
udph = (struct udphdr *) nb->data;
|
||||
if (nb->tail - nb->data < (grub_ssize_t) sizeof (*udph))
|
||||
{
|
||||
grub_dprintf ("net", "UDP packet too short: %" PRIuGRUB_SIZE "\n",
|
||||
nb->tail - nb->data);
|
||||
grub_netbuff_free (nb);
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
|
||||
FOR_UDP_SOCKETS (sock)
|
||||
{
|
||||
if (grub_be_to_cpu16 (udph->dst) == sock->in_port
|
||||
&& inf == sock->inf
|
||||
&& grub_net_addr_cmp (source, &sock->out_nla) == 0
|
||||
&& (sock->status == GRUB_NET_SOCKET_START
|
||||
|| grub_be_to_cpu16 (udph->src) == sock->out_port))
|
||||
{
|
||||
if (udph->chksum)
|
||||
{
|
||||
grub_uint16_t chk, expected;
|
||||
chk = udph->chksum;
|
||||
udph->chksum = 0;
|
||||
expected = grub_net_ip_transport_checksum (nb, GRUB_NET_IP_UDP,
|
||||
&sock->out_nla,
|
||||
&sock->inf->address);
|
||||
if (expected != chk)
|
||||
{
|
||||
grub_dprintf ("net", "Invalid UDP checksum. "
|
||||
"Expected %x, got %x\n",
|
||||
grub_be_to_cpu16 (expected),
|
||||
grub_be_to_cpu16 (chk));
|
||||
grub_netbuff_free (nb);
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
udph->chksum = chk;
|
||||
}
|
||||
|
||||
if (sock->status == GRUB_NET_SOCKET_START)
|
||||
{
|
||||
sock->out_port = grub_be_to_cpu16 (udph->src);
|
||||
sock->status = GRUB_NET_SOCKET_ESTABLISHED;
|
||||
}
|
||||
|
||||
err = grub_netbuff_pull (nb, sizeof (*udph));
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
FOR_NET_SOCKETS (sock)
|
||||
{
|
||||
if (grub_be_to_cpu16 (udph->dst) == sock->x_in_port
|
||||
&& inf == sock->x_inf && sock->recv_hook)
|
||||
{
|
||||
if (sock->x_status == GRUB_NET_SOCKET_START)
|
||||
{
|
||||
sock->x_out_port = grub_be_to_cpu16 (udph->src);
|
||||
sock->x_status = GRUB_NET_SOCKET_ESTABLISHED;
|
||||
}
|
||||
|
||||
/* App protocol remove its own reader. */
|
||||
if (sock->recv_hook)
|
||||
sock->recv_hook (sock, nb, sock->recv_hook_data);
|
||||
else
|
||||
grub_netbuff_free (nb);
|
||||
return GRUB_ERR_NONE;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1301,7 +1301,9 @@ struct grub_efi_simple_network
|
|||
void (*statistics) (void);
|
||||
void (*mcastiptomac) (void);
|
||||
void (*nvdata) (void);
|
||||
void (*getstatus) (void);
|
||||
grub_efi_status_t (*get_status) (struct grub_efi_simple_network *this,
|
||||
grub_uint32_t *int_status,
|
||||
void **txbuf);
|
||||
grub_efi_status_t (*transmit) (struct grub_efi_simple_network *this,
|
||||
grub_efi_uintn_t header_size,
|
||||
grub_efi_uintn_t buffer_size,
|
||||
|
|
|
@ -59,8 +59,14 @@ typedef enum
|
|||
GRUB_ERR_NET_BAD_ADDRESS,
|
||||
GRUB_ERR_NET_ROUTE_LOOP,
|
||||
GRUB_ERR_NET_NO_ROUTE,
|
||||
GRUB_ERR_NET_NO_ANSWER,
|
||||
GRUB_ERR_WAIT,
|
||||
GRUB_ERR_BUG
|
||||
GRUB_ERR_BUG,
|
||||
GRUB_ERR_NET_PORT_CLOSED,
|
||||
GRUB_ERR_NET_INVALID_RESPONSE,
|
||||
GRUB_ERR_NET_UNKNOWN_ERROR,
|
||||
GRUB_ERR_NET_PACKET_TOO_BIG,
|
||||
GRUB_ERR_NET_NO_DOMAIN
|
||||
}
|
||||
grub_err_t;
|
||||
|
||||
|
|
|
@ -370,6 +370,20 @@ void EXPORT_FUNC (__deregister_frame_info) (void);
|
|||
|
||||
/* Inline functions. */
|
||||
|
||||
static inline char *
|
||||
grub_memchr (const void *p, int c, grub_size_t len)
|
||||
{
|
||||
const char *s = p;
|
||||
const char *e = s + len;
|
||||
|
||||
for (; s < e; s++)
|
||||
if (*s == c)
|
||||
return (char *) s;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static inline unsigned int
|
||||
grub_abs (int x)
|
||||
{
|
||||
|
|
|
@ -27,6 +27,19 @@
|
|||
#include <grub/mm.h>
|
||||
#include <grub/net/netbuff.h>
|
||||
|
||||
enum
|
||||
{
|
||||
GRUB_NET_MAX_LINK_HEADER_SIZE = 64,
|
||||
GRUB_NET_UDP_HEADER_SIZE = 8,
|
||||
GRUB_NET_TCP_HEADER_SIZE = 20,
|
||||
GRUB_NET_OUR_IPV4_HEADER_SIZE = 20,
|
||||
GRUB_NET_OUR_IPV6_HEADER_SIZE = 40,
|
||||
GRUB_NET_OUR_MAX_IP_HEADER_SIZE = 40,
|
||||
GRUB_NET_TCP_RESERVE_SIZE = GRUB_NET_TCP_HEADER_SIZE
|
||||
+ GRUB_NET_OUR_IPV4_HEADER_SIZE
|
||||
+ GRUB_NET_MAX_LINK_HEADER_SIZE
|
||||
};
|
||||
|
||||
typedef enum grub_link_level_protocol_id
|
||||
{
|
||||
GRUB_NET_LINK_LEVEL_PROTOCOL_ETHERNET
|
||||
|
@ -64,8 +77,7 @@ struct grub_net_card_driver
|
|||
void (*close) (const struct grub_net_card *dev);
|
||||
grub_err_t (*send) (const struct grub_net_card *dev,
|
||||
struct grub_net_buff *buf);
|
||||
grub_ssize_t (*recv) (const struct grub_net_card *dev,
|
||||
struct grub_net_buff *buf);
|
||||
struct grub_net_buff * (*recv) (const struct grub_net_card *dev);
|
||||
};
|
||||
|
||||
typedef struct grub_net_packet
|
||||
|
@ -86,6 +98,16 @@ typedef struct grub_net_packets
|
|||
#include <grub/efi/api.h>
|
||||
#endif
|
||||
|
||||
struct grub_net_slaac_mac_list
|
||||
{
|
||||
struct grub_net_slaac_mac_list *next;
|
||||
grub_net_link_level_address_t address;
|
||||
int slaac_counter;
|
||||
char *name;
|
||||
};
|
||||
|
||||
struct grub_net_link_layer_entry;
|
||||
|
||||
struct grub_net_card
|
||||
{
|
||||
struct grub_net_card *next;
|
||||
|
@ -97,6 +119,10 @@ struct grub_net_card
|
|||
int opened;
|
||||
unsigned idle_poll_delay_ms;
|
||||
grub_uint64_t last_poll;
|
||||
grub_size_t mtu;
|
||||
struct grub_net_slaac_mac_list *slaac_list;
|
||||
grub_ssize_t new_ll_entry;
|
||||
struct grub_net_link_layer_entry *link_layer_table;
|
||||
union
|
||||
{
|
||||
#ifdef GRUB_MACHINE_EFI
|
||||
|
@ -116,7 +142,8 @@ struct grub_net_network_level_interface;
|
|||
typedef enum grub_network_level_protocol_id
|
||||
{
|
||||
GRUB_NET_NETWORK_LEVEL_PROTOCOL_DHCP_RECV,
|
||||
GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4
|
||||
GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4,
|
||||
GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV6
|
||||
} grub_network_level_protocol_id_t;
|
||||
|
||||
typedef struct grub_net_network_level_address
|
||||
|
@ -125,6 +152,7 @@ typedef struct grub_net_network_level_address
|
|||
union
|
||||
{
|
||||
grub_uint32_t ipv4;
|
||||
grub_uint64_t ipv6[2];
|
||||
};
|
||||
} grub_net_network_level_address_t;
|
||||
|
||||
|
@ -137,6 +165,10 @@ typedef struct grub_net_network_level_netaddress
|
|||
grub_uint32_t base;
|
||||
int masksize;
|
||||
} ipv4;
|
||||
struct {
|
||||
grub_uint64_t base[2];
|
||||
int masksize;
|
||||
} ipv6;
|
||||
};
|
||||
} grub_net_network_level_netaddress_t;
|
||||
|
||||
|
@ -193,43 +225,10 @@ struct grub_net_app_protocol
|
|||
int (*hook) (const char *filename,
|
||||
const struct grub_dirhook_info *info));
|
||||
grub_err_t (*open) (struct grub_file *file, const char *filename);
|
||||
grub_err_t (*seek) (struct grub_file *file, grub_off_t off);
|
||||
grub_err_t (*close) (struct grub_file *file);
|
||||
};
|
||||
|
||||
struct grub_net_socket
|
||||
{
|
||||
struct grub_net_socket *next;
|
||||
|
||||
enum { GRUB_NET_SOCKET_START,
|
||||
GRUB_NET_SOCKET_ESTABLISHED,
|
||||
GRUB_NET_SOCKET_CLOSED } x_status;
|
||||
int x_in_port;
|
||||
int x_out_port;
|
||||
grub_err_t (*recv_hook) (grub_net_socket_t sock, struct grub_net_buff *nb,
|
||||
void *recv);
|
||||
void *recv_hook_data;
|
||||
grub_net_network_level_address_t x_out_nla;
|
||||
struct grub_net_network_level_interface *x_inf;
|
||||
};
|
||||
|
||||
extern struct grub_net_socket *grub_net_sockets;
|
||||
|
||||
static inline void
|
||||
grub_net_socket_register (grub_net_socket_t sock)
|
||||
{
|
||||
grub_list_push (GRUB_AS_LIST_P (&grub_net_sockets),
|
||||
GRUB_AS_LIST (sock));
|
||||
}
|
||||
|
||||
static inline void
|
||||
grub_net_socket_unregister (grub_net_socket_t sock)
|
||||
{
|
||||
grub_list_remove (GRUB_AS_LIST_P (&grub_net_sockets),
|
||||
GRUB_AS_LIST (sock));
|
||||
}
|
||||
|
||||
#define FOR_NET_SOCKETS(var) for (var = grub_net_sockets; var; var = var->next)
|
||||
|
||||
typedef struct grub_net
|
||||
{
|
||||
char *server;
|
||||
|
@ -297,8 +296,8 @@ grub_net_session_recv (struct grub_net_session *session, void *buf,
|
|||
struct grub_net_network_level_interface *
|
||||
grub_net_add_addr (const char *name,
|
||||
struct grub_net_card *card,
|
||||
grub_net_network_level_address_t addr,
|
||||
grub_net_link_level_address_t hwaddress,
|
||||
const grub_net_network_level_address_t *addr,
|
||||
const grub_net_link_level_address_t *hwaddress,
|
||||
grub_net_interface_flags_t flags);
|
||||
|
||||
extern struct grub_net_network_level_interface *grub_net_network_level_interfaces;
|
||||
|
@ -338,7 +337,7 @@ void
|
|||
grub_net_card_unregister (struct grub_net_card *card);
|
||||
|
||||
#define FOR_NET_CARDS(var) for (var = grub_net_cards; var; var = var->next)
|
||||
#define FOR_NET_CARDS_SAFE(var, next) for (var = grub_net_cards, next = var->next; var; var = next, next = var->next)
|
||||
#define FOR_NET_CARDS_SAFE(var, next) for (var = grub_net_cards, next = (var ? var->next : 0); var; var = next, next = (var ? var->next : 0))
|
||||
|
||||
|
||||
struct grub_net_session *
|
||||
|
@ -397,6 +396,18 @@ struct grub_net_bootp_packet
|
|||
#define GRUB_NET_BOOTP_RFC1048_MAGIC_2 0x53
|
||||
#define GRUB_NET_BOOTP_RFC1048_MAGIC_3 0x63
|
||||
|
||||
enum
|
||||
{
|
||||
GRUB_NET_BOOTP_PAD = 0x00,
|
||||
GRUB_NET_BOOTP_ROUTER = 0x03,
|
||||
GRUB_NET_BOOTP_DNS = 0x06,
|
||||
GRUB_NET_BOOTP_HOSTNAME = 0x0c,
|
||||
GRUB_NET_BOOTP_DOMAIN = 0x0f,
|
||||
GRUB_NET_BOOTP_ROOT_PATH = 0x11,
|
||||
GRUB_NET_BOOTP_EXTENSIONS_PATH = 0x12,
|
||||
GRUB_NET_BOOTP_END = 0xff
|
||||
};
|
||||
|
||||
struct grub_net_network_level_interface *
|
||||
grub_net_configure_by_dhcp_ack (const char *name,
|
||||
struct grub_net_card *card,
|
||||
|
@ -412,19 +423,35 @@ grub_net_process_dhcp (struct grub_net_buff *nb,
|
|||
int
|
||||
grub_net_hwaddr_cmp (const grub_net_link_level_address_t *a,
|
||||
const grub_net_link_level_address_t *b);
|
||||
int
|
||||
grub_net_addr_cmp (const grub_net_network_level_address_t *a,
|
||||
const grub_net_network_level_address_t *b);
|
||||
|
||||
|
||||
/*
|
||||
Currently suppoerted adresses:
|
||||
Currently supported adresses:
|
||||
IPv4: XXX.XXX.XXX.XXX
|
||||
IPv6: XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX
|
||||
*/
|
||||
#define GRUB_NET_MAX_STR_ADDR_LEN sizeof ("XXX.XXX.XXX.XXX")
|
||||
#define GRUB_NET_MAX_STR_ADDR_LEN sizeof ("XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX")
|
||||
|
||||
/*
|
||||
Currently suppoerted adresses:
|
||||
ethernet: XX:XX:XX:XX:XX:XX
|
||||
*/
|
||||
|
||||
#define GRUB_NET_MAX_STR_HWADDR_LEN (sizeof ("XX:XX:XX:XX:XX:XX"))
|
||||
|
||||
void
|
||||
grub_net_addr_to_str (const grub_net_network_level_address_t *target,
|
||||
char *buf);
|
||||
void
|
||||
grub_net_hwaddr_to_str (const grub_net_link_level_address_t *addr, char *str);
|
||||
|
||||
#define FOR_NET_NETWORK_LEVEL_INTERFACES_SAFE(var,next) for (var = grub_net_network_level_interfaces, next = var->next; var; var = next, next = var->next)
|
||||
extern struct grub_net_network_level_interface *grub_net_network_level_interfaces;
|
||||
#define FOR_NET_NETWORK_LEVEL_INTERFACES(var) for (var = grub_net_network_level_interfaces; var; var = var->next)
|
||||
|
||||
#define FOR_NET_NETWORK_LEVEL_INTERFACES_SAFE(var,next) for (var = grub_net_network_level_interfaces, next = (var ? var->next : 0); var; var = next, next = (var ? var->next : 0))
|
||||
|
||||
void
|
||||
grub_net_poll_cards (unsigned time);
|
||||
|
@ -432,6 +459,9 @@ grub_net_poll_cards (unsigned time);
|
|||
void grub_bootp_init (void);
|
||||
void grub_bootp_fini (void);
|
||||
|
||||
void grub_dns_init (void);
|
||||
void grub_dns_fini (void);
|
||||
|
||||
static inline void
|
||||
grub_net_network_level_interface_unregister (struct grub_net_network_level_interface *inter)
|
||||
{
|
||||
|
@ -443,6 +473,37 @@ grub_net_network_level_interface_unregister (struct grub_net_network_level_inter
|
|||
inter->prev = 0;
|
||||
}
|
||||
|
||||
void
|
||||
grub_net_tcp_retransmit (void);
|
||||
|
||||
void
|
||||
grub_net_link_layer_add_address (struct grub_net_card *card,
|
||||
const grub_net_network_level_address_t *nl,
|
||||
const grub_net_link_level_address_t *ll,
|
||||
int override);
|
||||
int
|
||||
grub_net_link_layer_resolve_check (struct grub_net_network_level_interface *inf,
|
||||
const grub_net_network_level_address_t *proto_addr);
|
||||
grub_err_t
|
||||
grub_net_link_layer_resolve (struct grub_net_network_level_interface *inf,
|
||||
const grub_net_network_level_address_t *proto_addr,
|
||||
grub_net_link_level_address_t *hw_addr);
|
||||
grub_err_t
|
||||
grub_net_dns_lookup (const char *name,
|
||||
const struct grub_net_network_level_address *servers,
|
||||
grub_size_t n_servers,
|
||||
grub_size_t *naddresses,
|
||||
struct grub_net_network_level_address **addresses,
|
||||
int cache);
|
||||
grub_err_t
|
||||
grub_net_add_dns_server (const struct grub_net_network_level_address *s);
|
||||
void
|
||||
grub_net_remove_dns_server (const struct grub_net_network_level_address *s);
|
||||
|
||||
|
||||
extern char *grub_net_default_server;
|
||||
|
||||
#define GRUB_NET_TRIES 40
|
||||
#define GRUB_NET_INTERVAL 400
|
||||
|
||||
#endif /* ! GRUB_NET_HEADER */
|
||||
|
|
|
@ -1,36 +1,31 @@
|
|||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2010,2011 Free Software Foundation, Inc.
|
||||
*
|
||||
* GRUB is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GRUB is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef GRUB_NET_ARP_HEADER
|
||||
#define GRUB_NET_ARP_HEADER 1
|
||||
#include <grub/misc.h>
|
||||
#include <grub/net.h>
|
||||
|
||||
enum
|
||||
{
|
||||
/* IANA ARP constant to define hardware type as ethernet. */
|
||||
GRUB_NET_ARPHRD_ETHERNET = 1
|
||||
};
|
||||
extern grub_err_t grub_net_arp_receive (struct grub_net_buff *nb,
|
||||
struct grub_net_card *card);
|
||||
|
||||
/* ARP header operation codes */
|
||||
#define ARP_REQUEST 1
|
||||
#define ARP_REPLY 2
|
||||
|
||||
struct arp_entry {
|
||||
int avail;
|
||||
grub_net_network_level_address_t nl_address;
|
||||
grub_net_link_level_address_t ll_address;
|
||||
};
|
||||
|
||||
struct arphdr {
|
||||
grub_uint16_t hrd;
|
||||
grub_uint16_t pro;
|
||||
grub_uint8_t hln;
|
||||
grub_uint8_t pln;
|
||||
grub_uint16_t op;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
extern grub_err_t grub_net_arp_receive(struct grub_net_buff *nb);
|
||||
|
||||
extern grub_err_t grub_net_arp_resolve(struct grub_net_network_level_interface *inf,
|
||||
const grub_net_network_level_address_t *addr,
|
||||
grub_net_link_level_address_t *hw_addr);
|
||||
grub_err_t
|
||||
grub_net_arp_send_request (struct grub_net_network_level_interface *inf,
|
||||
const grub_net_network_level_address_t *proto_addr);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -22,19 +22,20 @@
|
|||
#include <grub/net.h>
|
||||
|
||||
/* IANA Ethertype */
|
||||
enum
|
||||
typedef enum
|
||||
{
|
||||
GRUB_NET_ETHERTYPE_IP = 0x0800,
|
||||
GRUB_NET_ETHERTYPE_ARP = 0x0806
|
||||
};
|
||||
GRUB_NET_ETHERTYPE_ARP = 0x0806,
|
||||
GRUB_NET_ETHERTYPE_IP6 = 0x86DD,
|
||||
} grub_net_ethertype_t;
|
||||
|
||||
grub_err_t
|
||||
send_ethernet_packet (struct grub_net_network_level_interface *inf,
|
||||
struct grub_net_buff *nb,
|
||||
grub_net_link_level_address_t target_addr,
|
||||
grub_uint16_t ethertype);
|
||||
grub_net_ethertype_t ethertype);
|
||||
grub_err_t
|
||||
grub_net_recv_ethernet_packet (struct grub_net_buff *nb,
|
||||
const struct grub_net_card *card);
|
||||
struct grub_net_card *card);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -21,22 +21,75 @@
|
|||
#include <grub/misc.h>
|
||||
#include <grub/net.h>
|
||||
|
||||
enum
|
||||
typedef enum grub_net_ip_protocol
|
||||
{
|
||||
IP_UDP = 0x11 /* UDP protocol */
|
||||
};
|
||||
#define IP_BROADCAST 0xFFFFFFFF
|
||||
GRUB_NET_IP_ICMP = 1,
|
||||
GRUB_NET_IP_TCP = 6,
|
||||
GRUB_NET_IP_UDP = 17,
|
||||
GRUB_NET_IP_ICMPV6 = 58
|
||||
} grub_net_ip_protocol_t;
|
||||
#define GRUB_NET_IP_BROADCAST 0xFFFFFFFF
|
||||
|
||||
grub_uint16_t grub_net_ip_chksum(void *ipv, int len);
|
||||
static inline grub_uint64_t
|
||||
grub_net_ipv6_get_id (const grub_net_link_level_address_t *addr)
|
||||
{
|
||||
return grub_cpu_to_be64 (((grub_uint64_t) (addr->mac[0] ^ 2) << 56)
|
||||
| ((grub_uint64_t) addr->mac[1] << 48)
|
||||
| ((grub_uint64_t) addr->mac[2] << 40)
|
||||
| 0xfffe000000ULL
|
||||
| ((grub_uint64_t) addr->mac[3] << 16)
|
||||
| ((grub_uint64_t) addr->mac[4] << 8)
|
||||
| ((grub_uint64_t) addr->mac[5]));
|
||||
}
|
||||
|
||||
grub_uint16_t grub_net_ip_chksum(void *ipv, grub_size_t len);
|
||||
|
||||
grub_err_t
|
||||
grub_net_recv_ip_packets (struct grub_net_buff *nb,
|
||||
const struct grub_net_card *card,
|
||||
const grub_net_link_level_address_t *hwaddress);
|
||||
struct grub_net_card *card,
|
||||
const grub_net_link_level_address_t *hwaddress,
|
||||
const grub_net_link_level_address_t *src_hwaddress);
|
||||
|
||||
grub_err_t
|
||||
grub_net_send_ip_packet (struct grub_net_network_level_interface *inf,
|
||||
const grub_net_network_level_address_t *target,
|
||||
struct grub_net_buff *nb);
|
||||
const grub_net_link_level_address_t *ll_target_addr,
|
||||
struct grub_net_buff *nb,
|
||||
grub_net_ip_protocol_t proto);
|
||||
|
||||
grub_err_t
|
||||
grub_net_recv_icmp_packet (struct grub_net_buff *nb,
|
||||
struct grub_net_network_level_interface *inf,
|
||||
const grub_net_link_level_address_t *ll_src,
|
||||
const grub_net_network_level_address_t *src);
|
||||
grub_err_t
|
||||
grub_net_recv_icmp6_packet (struct grub_net_buff *nb,
|
||||
struct grub_net_card *card,
|
||||
struct grub_net_network_level_interface *inf,
|
||||
const grub_net_link_level_address_t *ll_src,
|
||||
const grub_net_network_level_address_t *source,
|
||||
const grub_net_network_level_address_t *dest,
|
||||
grub_uint8_t ttl);
|
||||
grub_err_t
|
||||
grub_net_recv_udp_packet (struct grub_net_buff *nb,
|
||||
struct grub_net_network_level_interface *inf,
|
||||
const grub_net_network_level_address_t *src);
|
||||
grub_err_t
|
||||
grub_net_recv_tcp_packet (struct grub_net_buff *nb,
|
||||
struct grub_net_network_level_interface *inf,
|
||||
const grub_net_network_level_address_t *source);
|
||||
|
||||
grub_uint16_t
|
||||
grub_net_ip_transport_checksum (struct grub_net_buff *nb,
|
||||
grub_uint16_t proto,
|
||||
const grub_net_network_level_address_t *src,
|
||||
const grub_net_network_level_address_t *dst);
|
||||
|
||||
struct grub_net_network_level_interface *
|
||||
grub_net_ipv6_get_link_local (struct grub_net_card *card,
|
||||
const grub_net_link_level_address_t *hwaddr);
|
||||
grub_err_t
|
||||
grub_net_icmp6_send_request (struct grub_net_network_level_interface *inf,
|
||||
const grub_net_network_level_address_t *proto_addr);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -8,14 +8,14 @@
|
|||
|
||||
struct grub_net_buff
|
||||
{
|
||||
/*Pointer to the start of the buffer*/
|
||||
char *head;
|
||||
/*Pointer to the data */
|
||||
char *data;
|
||||
/*Pointer to the tail */
|
||||
char *tail;
|
||||
/*Pointer to the end of the buffer*/
|
||||
char *end;
|
||||
/* Pointer to the start of the buffer. */
|
||||
grub_uint8_t *head;
|
||||
/* Pointer to the data. */
|
||||
grub_uint8_t *data;
|
||||
/* Pointer to the tail. */
|
||||
grub_uint8_t *tail;
|
||||
/* Pointer to the end of the buffer. */
|
||||
grub_uint8_t *end;
|
||||
};
|
||||
|
||||
grub_err_t grub_netbuff_put (struct grub_net_buff *net_buff, grub_size_t len);
|
||||
|
|
79
include/grub/net/tcp.h
Normal file
79
include/grub/net/tcp.h
Normal file
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2010,2011 Free Software Foundation, Inc.
|
||||
*
|
||||
* GRUB is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GRUB is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef GRUB_NET_TCP_HEADER
|
||||
#define GRUB_NET_TCP_HEADER 1
|
||||
#include <grub/types.h>
|
||||
#include <grub/net.h>
|
||||
|
||||
struct grub_net_tcp_socket;
|
||||
typedef struct grub_net_tcp_socket *grub_net_tcp_socket_t;
|
||||
|
||||
struct grub_net_tcp_listen;
|
||||
typedef struct grub_net_tcp_listen *grub_net_tcp_listen_t;
|
||||
|
||||
grub_net_tcp_socket_t
|
||||
grub_net_tcp_open (char *server,
|
||||
grub_uint16_t out_port,
|
||||
grub_err_t (*recv_hook) (grub_net_tcp_socket_t sock,
|
||||
struct grub_net_buff *nb,
|
||||
void *data),
|
||||
void (*error_hook) (grub_net_tcp_socket_t sock,
|
||||
void *data),
|
||||
void (*fin_hook) (grub_net_tcp_socket_t sock,
|
||||
void *data),
|
||||
void *hook_data);
|
||||
|
||||
grub_net_tcp_listen_t
|
||||
grub_net_tcp_listen (grub_uint16_t port,
|
||||
const struct grub_net_network_level_interface *inf,
|
||||
grub_err_t (*listen_hook) (grub_net_tcp_listen_t listen,
|
||||
grub_net_tcp_socket_t sock,
|
||||
void *data),
|
||||
void *hook_data);
|
||||
|
||||
void
|
||||
grub_net_tcp_stop_listen (grub_net_tcp_listen_t listen);
|
||||
|
||||
grub_err_t
|
||||
grub_net_send_tcp_packet (const grub_net_tcp_socket_t socket,
|
||||
struct grub_net_buff *nb,
|
||||
int push);
|
||||
|
||||
enum
|
||||
{
|
||||
GRUB_NET_TCP_CONTINUE_RECEIVING,
|
||||
GRUB_NET_TCP_DISCARD,
|
||||
GRUB_NET_TCP_ABORT
|
||||
};
|
||||
|
||||
void
|
||||
grub_net_tcp_close (grub_net_tcp_socket_t sock, int discard_received);
|
||||
|
||||
grub_err_t
|
||||
grub_net_tcp_accept (grub_net_tcp_socket_t sock,
|
||||
grub_err_t (*recv_hook) (grub_net_tcp_socket_t sock,
|
||||
struct grub_net_buff *nb,
|
||||
void *data),
|
||||
void (*error_hook) (grub_net_tcp_socket_t sock,
|
||||
void *data),
|
||||
void (*fin_hook) (grub_net_tcp_socket_t sock,
|
||||
void *data),
|
||||
void *hook_data);
|
||||
|
||||
#endif
|
|
@ -1,3 +1,21 @@
|
|||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2010,2011 Free Software Foundation, Inc.
|
||||
*
|
||||
* GRUB is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GRUB is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef GRUB_NET_UDP_HEADER
|
||||
#define GRUB_NET_UDP_HEADER 1
|
||||
#include <grub/types.h>
|
||||
|
@ -11,28 +29,23 @@ struct udphdr
|
|||
grub_uint16_t chksum;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct grub_net_udp_socket;
|
||||
typedef struct grub_net_udp_socket *grub_net_udp_socket_t;
|
||||
|
||||
grub_net_socket_t
|
||||
grub_net_udp_open (char *server,
|
||||
grub_net_udp_socket_t
|
||||
grub_net_udp_open (grub_net_network_level_address_t addr,
|
||||
grub_uint16_t out_port,
|
||||
grub_err_t (*recv_hook) (grub_net_socket_t sock,
|
||||
grub_err_t (*recv_hook) (grub_net_udp_socket_t sock,
|
||||
struct grub_net_buff *nb,
|
||||
void *data),
|
||||
void *recv_hook_data);
|
||||
|
||||
static inline void
|
||||
grub_net_udp_close (grub_net_socket_t sock)
|
||||
{
|
||||
grub_net_socket_unregister (sock);
|
||||
grub_free (sock);
|
||||
}
|
||||
void
|
||||
grub_net_udp_close (grub_net_udp_socket_t sock);
|
||||
|
||||
grub_err_t
|
||||
grub_net_send_udp_packet (const grub_net_socket_t socket, struct grub_net_buff *nb);
|
||||
|
||||
grub_err_t
|
||||
grub_net_recv_udp_packet (struct grub_net_buff *nb,
|
||||
struct grub_net_network_level_interface *inf);
|
||||
grub_net_send_udp_packet (const grub_net_udp_socket_t socket,
|
||||
struct grub_net_buff *nb);
|
||||
|
||||
|
||||
#endif
|
||||
|
|
36
include/grub/priority_queue.h
Normal file
36
include/grub/priority_queue.h
Normal file
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* GRUB -- GRand Unified Bootloader
|
||||
* Copyright (C) 2011 Free Software Foundation, Inc.
|
||||
*
|
||||
* GRUB is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GRUB is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef GRUB_PRIORITY_QUEUE_HEADER
|
||||
#define GRUB_PRIORITY_QUEUE_HEADER 1
|
||||
|
||||
#include <grub/misc.h>
|
||||
#include <grub/err.h>
|
||||
|
||||
struct grub_priority_queue;
|
||||
typedef struct grub_priority_queue *grub_priority_queue_t;
|
||||
typedef int (*grub_comparator_t) (const void *a, const void *b);
|
||||
|
||||
grub_priority_queue_t grub_priority_queue_new (grub_size_t elsize,
|
||||
grub_comparator_t cmp);
|
||||
void grub_priority_queue_destroy (grub_priority_queue_t pq);
|
||||
void *grub_priority_queue_top (grub_priority_queue_t pq);
|
||||
void grub_priority_queue_pop (grub_priority_queue_t pq);
|
||||
grub_err_t grub_priority_queue_push (grub_priority_queue_t pq, const void *el);
|
||||
|
||||
#endif
|
|
@ -101,10 +101,12 @@ typedef grub_int64_t grub_ssize_t;
|
|||
# define PRIxGRUB_SIZE "lx"
|
||||
# define PRIxGRUB_ADDR "lx"
|
||||
# define PRIuGRUB_SIZE "lu"
|
||||
# define PRIdGRUB_SSIZE "ld"
|
||||
# else
|
||||
# define PRIxGRUB_SIZE "llx"
|
||||
# define PRIxGRUB_ADDR "llx"
|
||||
# define PRIuGRUB_SIZE "llu"
|
||||
# define PRIdGRUB_SSIZE "lld"
|
||||
# endif
|
||||
#else
|
||||
typedef grub_uint32_t grub_addr_t;
|
||||
|
@ -114,6 +116,7 @@ typedef grub_int32_t grub_ssize_t;
|
|||
# define PRIxGRUB_SIZE "x"
|
||||
# define PRIxGRUB_ADDR "x"
|
||||
# define PRIuGRUB_SIZE "u"
|
||||
# define PRIdGRUB_SSIZE "d"
|
||||
#endif
|
||||
|
||||
#define GRUB_UCHAR_MAX 0xFF
|
||||
|
@ -149,6 +152,18 @@ typedef grub_uint64_t grub_disk_addr_t;
|
|||
|
||||
#define grub_swap_bytes16_compile_time(x) ((((x) & 0xff) << 8) | (((x) & 0xff00) >> 8))
|
||||
#define grub_swap_bytes32_compile_time(x) ((((x) & 0xff) << 24) | (((x) & 0xff00) << 8) | (((x) & 0xff0000) >> 8) | (((x) & 0xff000000UL) >> 24))
|
||||
#define grub_swap_bytes64_compile_time(x) \
|
||||
({ \
|
||||
grub_uint64_t _x = (x); \
|
||||
(grub_uint64_t) ((_x << 56) \
|
||||
| ((_x & (grub_uint64_t) 0xFF00ULL) << 40) \
|
||||
| ((_x & (grub_uint64_t) 0xFF0000ULL) << 24) \
|
||||
| ((_x & (grub_uint64_t) 0xFF000000ULL) << 8) \
|
||||
| ((_x & (grub_uint64_t) 0xFF00000000ULL) >> 8) \
|
||||
| ((_x & (grub_uint64_t) 0xFF0000000000ULL) >> 24) \
|
||||
| ((_x & (grub_uint64_t) 0xFF000000000000ULL) >> 40) \
|
||||
| (_x >> 56)); \
|
||||
})
|
||||
|
||||
#if defined(__GNUC__) && (__GNUC__ > 3) && (__GNUC__ > 4 || __GNUC_MINOR__ >= 3)
|
||||
static inline grub_uint32_t grub_swap_bytes32(grub_uint32_t x)
|
||||
|
@ -197,6 +212,10 @@ static inline grub_uint64_t grub_swap_bytes64(grub_uint64_t x)
|
|||
# define grub_be_to_cpu16(x) ((grub_uint16_t) (x))
|
||||
# define grub_be_to_cpu32(x) ((grub_uint32_t) (x))
|
||||
# define grub_be_to_cpu64(x) ((grub_uint64_t) (x))
|
||||
# define grub_cpu_to_be16_compile_time(x) ((grub_uint16_t) (x))
|
||||
# define grub_cpu_to_be32_compile_time(x) ((grub_uint32_t) (x))
|
||||
# define grub_cpu_to_be64_compile_time(x) ((grub_uint64_t) (x))
|
||||
# define grub_be_to_cpu64_compile_time(x) ((grub_uint64_t) (x))
|
||||
# define grub_cpu_to_le32_compile_time(x) grub_swap_bytes32_compile_time(x)
|
||||
# define grub_cpu_to_le16_compile_time(x) grub_swap_bytes16_compile_time(x)
|
||||
#else /* ! WORDS_BIGENDIAN */
|
||||
|
@ -212,8 +231,13 @@ static inline grub_uint64_t grub_swap_bytes64(grub_uint64_t x)
|
|||
# define grub_be_to_cpu16(x) grub_swap_bytes16(x)
|
||||
# define grub_be_to_cpu32(x) grub_swap_bytes32(x)
|
||||
# define grub_be_to_cpu64(x) grub_swap_bytes64(x)
|
||||
# define grub_cpu_to_be16_compile_time(x) grub_swap_bytes16_compile_time(x)
|
||||
# define grub_cpu_to_be32_compile_time(x) grub_swap_bytes32_compile_time(x)
|
||||
# define grub_cpu_to_be64_compile_time(x) grub_swap_bytes64_compile_time(x)
|
||||
# define grub_be_to_cpu64_compile_time(x) grub_swap_bytes64_compile_time(x)
|
||||
# define grub_cpu_to_le16_compile_time(x) ((grub_uint16_t) (x))
|
||||
# define grub_cpu_to_le32_compile_time(x) ((grub_uint32_t) (x))
|
||||
|
||||
#endif /* ! WORDS_BIGENDIAN */
|
||||
|
||||
static inline grub_uint16_t grub_get_unaligned16 (const void *ptr)
|
||||
|
|
Loading…
Reference in a new issue