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;
bufio->file = io;
bufio->block_size = size;
bufio->buffer_len = 0;
+ bufio->buffer_at = 0;
file->device = io->device;
file->offset = 0;
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;
- }
- else
- {
- bufio->file->offset = grub_divmod64 (file->offset, bufio->block_size,
- &pos);
- bufio->file->offset *= bufio->block_size;
}
+ 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;
- if (pos + len >= bufio->block_size)
+ /* Now read between file->offset + res and bufio->buffer_at. */
+ if (file->offset + res < bufio->buffer_at)
{
- 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;
- }
+ 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;
+ }
}
- 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);
+ /* 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;
- grub_memcpy (buf, &bufio->buffer[pos], len);
+ if (len < bufio->buffer_len)
+ {
+ grub_memcpy (buf, &bufio->buffer[0], len);
+ res += len;
+ }
+ else
+ {
+ grub_memcpy (buf, &bufio->buffer[0], bufio->buffer_len);
+ res += bufio->buffer_len;
+ }
return res;
}
}
}
+ grub_free (tmp_buf);
grub_errno = GRUB_ERR_NONE;
{
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;
}
}
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;
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;
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;
}
== 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;
}
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
{
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
- {
- have_line = 0;
- ptr = (char *) nb->tail;
- }
- t = grub_realloc (data->current_line,
- data->current_line_len + (ptr - (char *) nb->data));
- if (!t)
+ char *ptr = (char *) nb->data;
+ if ((!data->headers_recv || data->in_chunk_len) && data->current_line)
{
- grub_netbuff_free (nb);
- grub_net_tcp_close (data->sock, GRUB_NET_TCP_ABORT);
- return grub_errno;
- }
+ 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 (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;
+ 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)
- {
- char *ptr2;
- ptr2 = grub_memchr (ptr, '\n', (char *) nb->tail - ptr);
- if (!ptr2)
+ while (ptr < (char *) nb->tail && (!data->headers_recv
+ || data->in_chunk_len))
{
- data->current_line = grub_malloc ((char *) nb->tail - ptr);
- if (!data->current_line)
+ 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);
- return grub_errno;
+ grub_netbuff_free (nb);
+ return err;
}
- 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;
+ ptr = ptr2 + 1;
}
- err = parse_line (data, ptr, ptr2 - ptr);
- if (err)
+
+ if (((char *) nb->tail - ptr) <= 0)
{
- 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);
+ 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;
- }
- 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
"\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;
data->sock = grub_net_tcp_open (file->device->net->server,
HTTP_PORT, http_receive,
- http_err,
+ http_err, http_err,
file);
if (!data->sock)
{
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)
}
grub_free (old_data);
+ file->data = data;
err = http_establish (file, off, 0);
if (err)
{
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 err;
}
- file->size = data->file_size;
return GRUB_ERR_NONE;
}
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));
}
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,
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");
char *ptr = buf;
grub_size_t amount, total = 0;
int try = 0;
+
while (try <= GRUB_NET_TRIES)
{
while (net->packs.first)
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;
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
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);
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;
struct unacked *unack;
for (unack = sock->unack_first; unack; unack = unack->next)
{
+ struct tcphdr *tcph;
grub_uint8_t *nbd;
grub_err_t err;
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);
{
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);
}
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;
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
}
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;
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;
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);
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);
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);
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);
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);
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)
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;
}
}
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;
}
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
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
# 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_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)