several net bugfixes and improvements and fix some memory leaks

This commit is contained in:
Vladimir 'phcoder' Serbinenko 2011-10-13 18:31:53 +02:00
parent da1b289afc
commit bd40efbf0b
8 changed files with 365 additions and 180 deletions

View file

@ -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,83 +106,87 @@ 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;
if (! len)
return res;
res += n;
buf += n;
bufio->file->offset += bufio->buffer_len;
pos = 0;
}
if (! len)
return res;
/* 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)
{
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;
}
}
/* 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;
if (len < bufio->buffer_len)
{
grub_memcpy (buf, &bufio->buffer[0], len);
res += len;
}
else
{
bufio->file->offset = grub_divmod64 (file->offset, bufio->block_size,
&pos);
bufio->file->offset *= bufio->block_size;
grub_memcpy (buf, &bufio->buffer[0], bufio->buffer_len);
res += bufio->buffer_len;
}
if (pos + len >= bufio->block_size)
{
if (pos)
{
grub_size_t n;
bufio->file->fs->read (bufio->file, bufio->buffer,
bufio->block_size);
if (grub_errno)
return -1;
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)
{
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;
}
if (! len)
{
bufio->buffer_len = 0;
return res;
}
}
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;
}

View file

@ -442,6 +442,7 @@ grub_disk_read_small (grub_disk_t disk, grub_disk_addr_t sector,
}
}
grub_free (tmp_buf);
grub_errno = GRUB_ERR_NONE;
{
@ -468,9 +469,11 @@ grub_disk_read_small (grub_disk_t disk, grub_disk_addr_t sector,
grub_error_push ();
grub_dprintf ("disk", "%s read failed\n", disk->name);
grub_error_pop ();
grub_free (tmp_buf);
return grub_errno;
}
grub_memcpy (buf, tmp_buf + offset, size);
grub_free (tmp_buf);
return GRUB_ERR_NONE;
}
}

View file

@ -79,6 +79,22 @@ parse_dhcp_vendor (const char *name, void *vend, int limit)
switch (tagtype)
{
case 3:
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 12:
set_env_limn_ro (name, "hostname", (char *) ptr, taglength);
break;

View file

@ -36,8 +36,6 @@ enum
typedef struct http_data
{
grub_uint64_t file_size;
grub_uint64_t position;
char *current_line;
grub_size_t current_line_len;
int headers_recv;
@ -47,18 +45,53 @@ typedef struct http_data
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 (http_data_t data, char *ptr, grub_size_t len)
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;
}
@ -93,10 +126,17 @@ parse_line (http_data_t data, char *ptr, grub_size_t len)
== 0 && !data->size_recv)
{
ptr += sizeof ("Content-Length: ") - 1;
data->file_size = grub_strtoull (ptr, &ptr, 10);
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;
}
@ -113,6 +153,8 @@ http_err (grub_net_tcp_socket_t sock __attribute__ ((unused)),
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
@ -122,94 +164,116 @@ http_receive (grub_net_tcp_socket_t sock __attribute__ ((unused)),
{
grub_file_t file = f;
http_data_t data = file->data;
char *ptr = (char *) nb->data;
grub_err_t err;
if (!data->headers_recv && data->current_line)
while (1)
{
int have_line = 1;
char *t;
ptr = grub_memchr (nb->data, '\n', nb->tail - nb->data);
if (ptr)
ptr++;
else
char *ptr = (char *) nb->data;
if ((!data->headers_recv || data->in_chunk_len) && data->current_line)
{
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 (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)
{
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)
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_len = (char *) nb->tail - ptr;
grub_memcpy (data->current_line, ptr, data->current_line_len);
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 = parse_line (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)
{
data->position += ((char *) nb->tail - ptr);
}
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;
}
grub_net_put_packet (&file->device->net->packs, nb);
}
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;
}
else
grub_netbuff_free (nb);
return GRUB_ERR_NONE;
}
static grub_err_t
@ -294,7 +358,7 @@ http_establish (struct grub_file *file, grub_off_t offset, int initial)
"\r\n"),
"Content-Range: bytes %" PRIuGRUB_UINT64_T "-%"
PRIuGRUB_UINT64_T "/%" PRIuGRUB_UINT64_T "\r\n\r\n",
offset, data->file_size - 1, data->file_size);
offset, file->size - 1, file->size);
grub_netbuff_put (nb, grub_strlen ((char *) ptr));
}
ptr = nb->tail;
@ -303,7 +367,7 @@ http_establish (struct grub_file *file, grub_off_t offset, int initial)
data->sock = grub_net_tcp_open (file->device->net->server,
HTTP_PORT, http_receive,
http_err,
http_err, http_err,
file);
if (!data->sock)
{
@ -351,13 +415,17 @@ http_seek (struct grub_file *file, grub_off_t off)
grub_net_tcp_close (old_data->sock, GRUB_NET_TCP_ABORT);
while (file->device->net->packs.first)
grub_net_remove_packet (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->file_size = old_data->file_size;
data->size_recv = 1;
data->filename = old_data->filename;
if (!data->filename)
@ -367,6 +435,7 @@ http_seek (struct grub_file *file, grub_off_t off)
}
grub_free (old_data);
file->data = data;
err = http_establish (file, off, 0);
if (err)
{
@ -386,6 +455,7 @@ http_open (struct grub_file *file, const char *filename)
data = grub_zalloc (sizeof (*data));
if (!data)
return grub_errno;
file->size = GRUB_FILE_SIZE_UNKNOWN;
data->filename = grub_strdup (filename);
if (!data->filename)
@ -404,7 +474,6 @@ http_open (struct grub_file *file, const char *filename)
grub_free (data);
return err;
}
file->size = data->file_size;
return GRUB_ERR_NONE;
}

View file

@ -469,6 +469,8 @@ match_net (const grub_net_network_level_netaddress_t *net,
case GRUB_NET_NETWORK_LEVEL_PROTOCOL_IPV4:
{
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));
}
@ -554,6 +556,39 @@ grub_net_resolve_net_address (const char *name,
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,
@ -572,25 +607,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;
}
*interf = route->interface;
return GRUB_ERR_NONE;
if (route_cmp (route, bestroute) > 0)
bestroute = route;
}
if (route == NULL)
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 (depth == 0)
*gateway = bestroute->gw;
curtarget = bestroute->gw;
}
return grub_error (GRUB_ERR_NET_ROUTE_LOOP, "route loop detected");
@ -1285,6 +1322,7 @@ grub_net_fs_read_real (grub_file_t file, char *buf, grub_size_t len)
char *ptr = buf;
grub_size_t amount, total = 0;
int try = 0;
while (try <= GRUB_NET_TRIES)
{
while (net->packs.first)

View file

@ -68,6 +68,7 @@ struct grub_net_tcp_socket
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, gw;
struct grub_net_network_level_interface *inf;
@ -234,10 +235,20 @@ grub_net_tcp_close (grub_net_tcp_socket_t sock,
struct tcphdr *tcph_fin;
grub_err_t err;
sock->i_closed = 1;
if (discard_received != GRUB_NET_TCP_CONTINUE_RECEIVING)
sock->recv_hook = NULL;
{
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
@ -263,13 +274,12 @@ grub_net_tcp_close (grub_net_tcp_socket_t sock,
return;
}
tcph_fin = (void *) nb_fin->data;
tcph_fin->ack = grub_cpu_to_be32 (0);
tcph_fin->flags = grub_cpu_to_be16 ((5 << 12) | TCP_FIN);
tcph_fin->window = grub_cpu_to_be16 (0);
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 (discard_received == GRUB_NET_TCP_ABORT)
sock->i_reseted = 1;
if (err)
{
grub_netbuff_free (nb_fin);
@ -309,14 +319,14 @@ ack_real (grub_net_tcp_socket_t sock, int res)
tcph_ack = (void *) nb_ack->data;
if (res)
{
tcph_ack->ack = grub_cpu_to_be32 (0);
tcph_ack->flags = grub_cpu_to_be16 ((5 << 12) | TCP_RST);
tcph_ack->window = grub_cpu_to_be16 (0);
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 ((5 << 12) | TCP_ACK);
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;
@ -354,6 +364,7 @@ grub_net_tcp_retransmit (void)
struct unacked *unack;
for (unack = sock->unack_first; unack; unack = unack->next)
{
struct tcphdr *tcph;
grub_uint8_t *nbd;
grub_err_t err;
@ -368,6 +379,18 @@ grub_net_tcp_retransmit (void)
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->gw), unack->nb,
GRUB_NET_IP_TCP);
@ -447,7 +470,10 @@ 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_netbuff_free (*nb_p);
grub_priority_queue_pop (sock->pq);
}
grub_priority_queue_destroy (sock->pq);
}
@ -459,6 +485,8 @@ grub_net_tcp_accept (grub_net_tcp_socket_t sock,
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;
@ -467,6 +495,7 @@ grub_net_tcp_accept (grub_net_tcp_socket_t sock,
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
@ -489,7 +518,7 @@ grub_net_tcp_accept (grub_net_tcp_socket_t sock,
}
tcph = (void *) nb_ack->data;
tcph->ack = grub_cpu_to_be32 (sock->their_cur_seq);
tcph->flags = grub_cpu_to_be16 ((5 << 12) | TCP_SYN | TCP_ACK);
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;
@ -509,6 +538,8 @@ grub_net_tcp_open (char *server,
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;
@ -548,6 +579,7 @@ grub_net_tcp_open (char *server,
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);
@ -578,8 +610,8 @@ grub_net_tcp_open (char *server,
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 (0);
tcph->flags = grub_cpu_to_be16 ((5 << 12) | TCP_SYN);
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);
@ -664,8 +696,8 @@ grub_net_send_tcp_packet (const grub_net_tcp_socket_t socket,
return err;
tcph = (struct tcphdr *) nb2->data;
tcph->ack = grub_cpu_to_be32 (0);
tcph->flags = grub_cpu_to_be16 ((5 << 12));
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);
@ -686,8 +718,9 @@ grub_net_send_tcp_packet (const grub_net_tcp_socket_t socket,
return err;
tcph = (struct tcphdr *) nb->data;
tcph->ack = grub_cpu_to_be32 (0);
tcph->flags = grub_cpu_to_be16 ((5 << 12) | (push ? TCP_PUSH : 0));
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);
@ -815,11 +848,15 @@ grub_net_recv_tcp_packet (struct grub_net_buff *nb,
err = grub_priority_queue_push (sock->pq, &nb);
if (err)
return 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);
@ -829,6 +866,7 @@ grub_net_recv_tcp_packet (struct grub_net_buff *nb,
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)
@ -845,15 +883,19 @@ grub_net_recv_tcp_packet (struct grub_net_buff *nb,
break;
grub_priority_queue_pop (sock->pq);
err = grub_netbuff_pull (nb, (grub_be_to_cpu16 (tcph->flags)
>> 12) * sizeof (grub_uint32_t));
err = grub_netbuff_pull (nb_top, (grub_be_to_cpu16 (tcph->flags)
>> 12) * sizeof (grub_uint32_t));
if (err)
return 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;
}
@ -868,14 +910,19 @@ grub_net_recv_tcp_packet (struct grub_net_buff *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);
}
while (sock->packs.first)
{
nb = sock->packs.first->nb;
if (sock->recv_hook)
sock->recv_hook (sock, sock->packs.first->nb, sock->hook_data);
grub_net_remove_packet (sock->packs.first);
}
return GRUB_ERR_NONE;
}

View file

@ -35,6 +35,8 @@ grub_net_tcp_open (char *server,
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
@ -70,6 +72,8 @@ grub_net_tcp_accept (grub_net_tcp_socket_t sock,
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

View file

@ -214,6 +214,7 @@ 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))
@ -232,6 +233,7 @@ 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)