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; tftp_data_t data = file->data; grub_err_t err; grub_uint8_t *ptr; if (nb->tail - nb->data < (grub_ssize_t) sizeof (tftph->opcode)) { grub_dprintf ("tftp", "TFTP packet too small\n"); return GRUB_ERR_NONE; } tftph = (struct tftphdr *) nb->data; switch (grub_be_to_cpu16 (tftph->opcode)) { case TFTP_OACK: data->block_size = TFTP_DEFAULTSIZE_PACKET; data->have_oack = 1; 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 ((char *) ptr + sizeof ("tsize\0") - 1, 0, 0); if (grub_memcmp (ptr, "blksize\0", sizeof ("blksize\0") - 1) == 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); err = ack (data, 0); grub_error_save (&data->save_err); return GRUB_ERR_NONE; case TFTP_DATA: if (nb->tail - nb->data < (grub_ssize_t) (sizeof (tftph->opcode) + sizeof (tftph->u.data.block))) { grub_dprintf ("tftp", "TFTP packet too small\n"); return GRUB_ERR_NONE; } 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 (cmp_block (grub_be_to_cpu16 (tftph->u.data.block), data->block + 1) >= 0) break; ack (data, grub_be_to_cpu16 (tftph->u.data.block)); grub_netbuff_free (nb_top); grub_priority_queue_pop (data->pq); } while (cmp_block (grub_be_to_cpu16 (tftph->u.data.block), data->block + 1) == 0) { unsigned size; grub_priority_queue_pop (data->pq); if (file->device->net->packs.count < 50) err = ack (data, data->block + 1); else { file->device->net->stall = 1; err = 0; } if (err) return err; err = grub_netbuff_pull (nb_top, sizeof (tftph->opcode) + sizeof (tftph->u.data.block)); if (err) return err; size = nb_top->tail - nb_top->data; data->block++; if (size < data->block_size) { if (data->ack_sent < data->block) ack (data, data->block); file->device->net->eof = 1; file->device->net->stall = 1; grub_net_udp_close (data->sock); data->sock = NULL; } /* 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_top, size - data->block_size); if (err) return err; } /* If there is data, puts packet in socket list. */ if ((nb_top->tail - nb_top->data) > 0) grub_net_put_packet (&file->device->net->packs, nb_top); else grub_netbuff_free (nb_top); } } return GRUB_ERR_NONE; case TFTP_ERROR: data->have_oack = 1; grub_netbuff_free (nb); grub_error (GRUB_ERR_IO, (char *) tftph->u.err.errmsg); grub_error_save (&data->save_err); return GRUB_ERR_NONE; default: grub_netbuff_free (nb); return GRUB_ERR_NONE; } }
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 (file->device->net->packs.count >= 20) file->device->net->stall = 1; if (file->device->net->packs.count >= 100) grub_net_tcp_stall (data->sock); 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); if (file->device->net->packs.count >= 20) { file->device->net->stall = 1; grub_net_tcp_stall (data->sock); } grub_net_put_packet (&file->device->net->packs, nb2); grub_netbuff_pull (nb, data->chunk_rem); } data->in_chunk_len = 1; } }