Exemple #1
0
/**
  * @brief  receive callback during tftp read operation (not on standard port 69)
  * @param  arg: pointer on argument passed to callback
  * @param  udp_pcb: pointer on the udp pcb
  * @param  pkt_buf: pointer on the received pbuf
  * @param  addr: pointer on remote IP address
  * @param  port: pointer on remote udp port
  * @retval None
  */
void rrq_recv_callback(void *arg, struct udp_pcb *upcb, struct pbuf *p,
                       struct ip_addr *addr, u16_t port)
{
  /* Get our connection state  */
  tftp_connection_args *args = (tftp_connection_args *)arg;

  if (tftp_is_correct_ack(p->payload, args->block))
  {
    /* increment block # */
    args->block++;
  }
  else
  {
    /* we did not receive the expected ACK, so
       do not update block #. This causes the current block to be resent. */
  }

  /* if the last read returned less than the requested number of bytes
   * (i.e. TFTP_DATA_LEN_MAX), then we've sent the whole file and we can quit
   */
  if (args->data_len < TFTP_DATA_LEN_MAX)
  {
    /* Clean the connection*/
    tftp_cleanup_rd(upcb, args);

    pbuf_free(p);
  }

  /* if the whole file has not yet been sent then continue  */
  tftp_send_next_block(upcb, args, addr, port);

  pbuf_free(p);
}
Exemple #2
0
static void tftp_handle_ack(Slirp *slirp, struct tftp_t *tp, int pktlen)
{
  int s;

  s = tftp_session_find(slirp, tp);

  if (s < 0) {
    return;
  }

  tftp_send_next_block(&slirp->tftp_sessions[s], tp);
}
Exemple #3
0
int tftp_process_read(struct udp_pcb *upcb, struct ip_addr *to, int to_port, char* FileName)
{
  tftp_connection_args *args = NULL;

  /* If Could not open the file which will be transmitted  */
  if (file_fopen(&file_SD, &efs1.myFs, FileName, 'r') != 0)
  {
    tftp_send_error_message(upcb, to, to_port, TFTP_ERR_FILE_NOT_FOUND);

    tftp_cleanup_rd(upcb, args);

    return 0;
  }

  /* This function is called from a callback,
   * therefore, interrupts are disabled,
   * therefore, we can use regular malloc. */

  args = mem_malloc(sizeof *args);
  /* If we aren't able to allocate memory for a "tftp_connection_args" */
  if (!args)
  {
    /* unable to allocate memory for tftp args  */
    tftp_send_error_message(upcb, to, to_port, TFTP_ERR_NOTDEFINED);

    /* no need to use tftp_cleanup_rd because no 
            "tftp_connection_args" struct has been malloc'd   */
    tftp_cleanup_rd(upcb, args);

    return 0;
  }

  /* initialize connection structure  */
  args->op = TFTP_RRQ;
  args->to_ip.addr = to->addr;
  args->to_port = to_port;
  args->block = 1; /* block number starts at 1 (not 0) according to RFC1350  */
  args->tot_bytes = 0;


  /* set callback for receives on this UDP PCB (Protocol Control Block) */
  udp_recv(upcb, rrq_recv_callback, args);

  /* initiate the transaction by sending the first block of data
   * further blocks will be sent when ACKs are received
   *   - the receive callbacks need to get the proper state    */

  tftp_send_next_block(upcb, args, to, to_port);

  return 1;
}
Exemple #4
0
/**
  * @brief  processes tftp read operation
  * @param  upcb: pointer on udp pcb 
  * @param  to: pointer on remote IP address
  * @param  to_port: pointer on remote udp port
  * @param  FileName: pointer on filename to be read
  * @retval error code
  */
int tftp_process_read(struct udp_pcb *upcb, const ip_addr_t *to, unsigned short to_port, char* FileName)
{
  tftp_connection_args *args = NULL;

  char *path = malloc(strlen(FileName) + sizeof(TFTPD_PATH) + 1);
  if(!path)
	  return 0;
  strcpy(path, TFTPD_PATH);
  strcat(path, FileName);
  /* If Could not open the file which will be transmitted  */
  if (f_open(&file_SD, (const TCHAR*)path, FA_READ) != FR_OK)
  {
    tftp_send_error_message(upcb, to, to_port, TFTP_ERR_FILE_NOT_FOUND);

    tftp_cleanup_rd(upcb, args);

    return 0;
  }
  
  args = mem_malloc(sizeof *args);
  /* If we aren't able to allocate memory for a "tftp_connection_args" */
  if (!args)
  {
    /* unable to allocate memory for tftp args  */
    tftp_send_error_message(upcb, to, to_port, TFTP_ERR_NOTDEFINED);

    /* no need to use tftp_cleanup_rd because no "tftp_connection_args" struct has been malloc'd   */
    tftp_cleanup_rd(upcb, args);

    return 0;
  }

  /* initialize connection structure  */
  args->op = TFTP_RRQ;
  args->to_ip.addr = to->addr;
  args->to_port = to_port;
  args->block = 1; /* block number starts at 1 (not 0) according to RFC1350  */
  args->tot_bytes = 0;


  /* set callback for receives on this UDP PCB  */
  udp_recv(upcb, rrq_recv_callback, args);

  /* initiate the transaction by sending the first block of data,
    further blocks will be sent when ACKs are received */

  tftp_send_next_block(upcb, args, to, to_port);

  return 1;
}
Exemple #5
0
static void tftp_handle_rrq(Slirp *slirp, struct tftp_t *tp, int pktlen)
{
  struct tftp_session *spt;
  int s, k;
  size_t prefix_len;
  char *req_fname;
  const char *option_name[2];
  uint32_t option_value[2];
  int nb_options = 0;

  /* check if a session already exists and if so terminate it */
  s = tftp_session_find(slirp, tp);
  if (s >= 0) {
    tftp_session_terminate(&slirp->tftp_sessions[s]);
  }

  s = tftp_session_allocate(slirp, tp);

  if (s < 0) {
    return;
  }

  spt = &slirp->tftp_sessions[s];

  /* unspecified prefix means service disabled */
  if (!slirp->tftp_prefix) {
      tftp_send_error(spt, 2, "Access violation", tp);
      return;
  }

  /* skip header fields */
  k = 0;
  pktlen -= offsetof(struct tftp_t, x.tp_buf);

  /* prepend tftp_prefix */
  prefix_len = strlen(slirp->tftp_prefix);
  spt->filename = g_malloc(prefix_len + TFTP_FILENAME_MAX + 2);
  memcpy(spt->filename, slirp->tftp_prefix, prefix_len);
  spt->filename[prefix_len] = '/';

  /* get name */
  req_fname = spt->filename + prefix_len + 1;

  while (1) {
    if (k >= TFTP_FILENAME_MAX || k >= pktlen) {
      tftp_send_error(spt, 2, "Access violation", tp);
      return;
    }
    req_fname[k] = tp->x.tp_buf[k];
    if (req_fname[k++] == '\0') {
      break;
    }
  }

  /* check mode */
  if ((pktlen - k) < 6) {
    tftp_send_error(spt, 2, "Access violation", tp);
    return;
  }

  if (strcasecmp(&tp->x.tp_buf[k], "octet") != 0) {
      tftp_send_error(spt, 4, "Unsupported transfer mode", tp);
      return;
  }

  k += 6; /* skipping octet */

  /* do sanity checks on the filename */
  if (!strncmp(req_fname, "../", 3) ||
      req_fname[strlen(req_fname) - 1] == '/' ||
      strstr(req_fname, "/../")) {
      tftp_send_error(spt, 2, "Access violation", tp);
      return;
  }

  /* check if the file exists */
  if (tftp_read_data(spt, 0, NULL, 0) < 0) {
      tftp_send_error(spt, 1, "File not found", tp);
      return;
  }

  if (tp->x.tp_buf[pktlen - 1] != 0) {
      tftp_send_error(spt, 2, "Access violation", tp);
      return;
  }

  while (k < pktlen && nb_options < ARRAY_SIZE(option_name)) {
      const char *key, *value;

      key = &tp->x.tp_buf[k];
      k += strlen(key) + 1;

      if (k >= pktlen) {
	  tftp_send_error(spt, 2, "Access violation", tp);
	  return;
      }

      value = &tp->x.tp_buf[k];
      k += strlen(value) + 1;

      if (strcasecmp(key, "tsize") == 0) {
	  int tsize = atoi(value);
	  struct stat stat_p;

	  if (tsize == 0) {
	      if (stat(spt->filename, &stat_p) == 0)
		  tsize = stat_p.st_size;
	      else {
		  tftp_send_error(spt, 1, "File not found", tp);
		  return;
	      }
	  }

          option_name[nb_options] = "tsize";
          option_value[nb_options] = tsize;
          nb_options++;
      } else if (strcasecmp(key, "blksize") == 0) {
          int blksize = atoi(value);

          /* If blksize option is bigger than what we will
           * emit, accept the option with our packet size.
           * Otherwise, simply do as we didn't see the option.
           */
          if (blksize >= 512) {
              option_name[nb_options] = "blksize";
              option_value[nb_options] = 512;
              nb_options++;
          }
      }
  }

  if (nb_options > 0) {
      assert(nb_options <= ARRAY_SIZE(option_name));
      tftp_send_oack(spt, option_name, option_value, nb_options, tp);
      return;
  }

  spt->block_nr = 0;
  tftp_send_next_block(spt, tp);
}