Пример #1
0
grub_err_t
grub_net_recv_udp_packet (struct grub_net_buff * nb,
			  struct grub_net_network_level_interface * inf)
{
  struct udphdr *udph;
  grub_net_socket_t sock;
  grub_err_t err;
  udph = (struct udphdr *) nb->data;
  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.  */
	sock->recv_hook (sock, nb, sock->recv_hook_data);
	return GRUB_ERR_NONE;
      }
  }
  grub_netbuff_free (nb);
  return GRUB_ERR_NONE;
}
Пример #2
0
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;
    }
}
Пример #3
0
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;
    }
}
Пример #4
0
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_make_pkt (nb->tail - nb->data + sizeof (*icmphr));
	if (!nb_reply)
	  {
	    grub_netbuff_free (nb);
	    return grub_errno;
	  }
	grub_memcpy (nb_reply->data + sizeof (*icmphr), nb->data, nb->tail - nb->data);
	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);

	grub_netbuff_free (nb);
	grub_netbuff_free (nb_reply);
	return err;
      }
    };

  grub_netbuff_free (nb);
  return GRUB_ERR_NONE;
}