예제 #1
0
파일: tftp.c 프로젝트: k0059/yard-ice
int tftp_recv_netascii(struct udp_pcb * udp, struct sockaddr_in * sin, 
					   int block, char * buf, int len)
{
	char * line;
	FILE * f;
	int ret;
	int n;
	int i;


	f = null_fopen(NULL);
	DCC_LOG1(LOG_TRACE, "1. f=%p", f);

	i = 0;
	n = 1;
	ret = 0;
	while (i < len) {
		for (line = &buf[i]; i < len; i++) {
			/* CR or [CR, LF] */
			if (buf[i] == '\r') {
				buf[i++] = '\0';
				if (buf[i] == '\n')
					i++;
				break;
			}
			/* LF or [LF, CR] */
			if (buf[i] == '\n') {
				buf[i++] = '\0';
				if (buf[i] == '\r')
					i++;
				break;
			}
		}

		if (i == len)
			buf[i] = '\0';


		if ((ret = exec(f, yard_ice_cmd_tab, line)) < 0) {
			DCC_LOG1(LOG_ERROR, "shell_exec(): %d", ret);
			break;
		}
		n++;
		DCC_LOG1(LOG_TRACE, "line %d", n);
	}

	if (ret < 0) {
		sprintf(buf, "ERROR %d on line %d: %s", -ret, n, target_strerror(ret));
		DCC_LOG1(LOG_TRACE, "2. f=%p", f);
		ret = tftp_error(udp, sin, TFTP_EACCESS, buf);
		DCC_LOG1(LOG_TRACE, "3. f=%p", f);
	} else {
		ret = tftp_ack(udp, block, sin);
	}

	DCC_LOG1(LOG_TRACE, "f=%p", f);
	fclose(f);

	return ret;
}
예제 #2
0
파일: tftp.c 프로젝트: k0059/yard-ice
void __attribute__((noreturn)) tftp_daemon_task(struct debugger * dbg)
{
	uint8_t buf[MAX_TFTP_MSG];
	struct tftphdr * hdr = (struct tftphdr *)buf;
	char * msg = (char *)buf;
	struct sockaddr_in sin;
	struct udp_pcb * udp;
	struct tftp_req req;
	int state = TFTPD_IDLE;
	unsigned int addr_start = 0;
	unsigned int addr_end = 0;
	int block = 0;
	int opc;
	int len;
	int blksize = TFTP_SEGSIZE; 

	DCC_LOG1(LOG_TRACE, "thread: %d", __os_thread_self());

	if ((udp = udp_alloc()) == NULL) {
		DCC_LOG(LOG_WARNING, "udp_alloc() fail!");
		abort();
	}

	if (udp_bind(udp, INADDR_ANY, htons(IPPORT_TFTP)) < 0) {
		DCC_LOG(LOG_WARNING, "udp_bind() fail!");
		abort();
	}

	for (;;) {
		if ((len = udp_recv(udp, buf, MAX_TFTP_MSG, &sin)) < 0) {
			if (len == -ECONNREFUSED) {
				DCC_LOG(LOG_WARNING, "udp_rcv ICMP error: ECONNREFUSED");
			}
			if (len == -EFAULT) {
				DCC_LOG(LOG_WARNING, "udp_rcv error: EFAULT");
			}
			if (len == -ENOTCONN) {
				DCC_LOG(LOG_WARNING, "udp_rcv error: ENOTCONN");
			}
			continue;
		}


		opc = htons(hdr->th_opcode);
		if ((opc != TFTP_RRQ) && (opc != TFTP_WRQ)) {
			DCC_LOG1(LOG_WARNING, "invalid opc: %d", opc);
			WARN("TFTP: invalid opc: %d", opc);
			continue;
		}

		if (udp_connect(udp, sin.sin_addr.s_addr, sin.sin_port) < 0) {
			DCC_LOG(LOG_WARNING, "udp_connect() error");
			WARN("TFTP: UDP connect failed!");
			continue;
		}

		DCC_LOG2(LOG_TRACE, "Connected to: %I.%d", sin.sin_addr.s_addr, 
				 ntohs(sin.sin_port));

//		INF("Connected to: %08x.%d", sin.sin_addr.s_addr, 
//			ntohs(sin.sin_port));

		for (;;) {
			DCC_LOG3(LOG_INFO, "%I.%d %d", 
					 sin.sin_addr.s_addr, ntohs(sin.sin_port), len);

			DCC_LOG2(LOG_INFO, "len=%d, opc=%s", len, tftp_opc[opc]);

			switch (opc) {
			case TFTP_RRQ:
				DCC_LOG(LOG_TRACE, "read request: ...");

				tftp_req_parse((char *)&(hdr->th_stuff), &req);
				blksize = req.blksize;

				INF("TFTP: RRQ '%s' '%s' blksize=%d", req.fname, 
					   tftp_mode[req.mode], req.blksize);

				if (tftp_decode_fname(dbg, req.fname) < 0) {
					ERR("TFTP: bad address.");
					tftp_error(udp, &sin, TFTP_ENOTFOUND, "BAD ADDR.");
					break;
				}

				/* set the transfer info */
				addr_start = dbg->transf.base;
				addr_end = addr_start + dbg->transf.size;
				block = 0;

				DCC_LOG2(LOG_TRACE, "start=0x%08x end=0x%08x", 
						 addr_start, addr_end);

				DBG("TFTP: start=0x%08x end=0x%08x", 
						 addr_start, addr_end);

				if (req.mode == TFTP_NETASCII) {
					state = TFTPD_SEND_NETASCII;
				} else if (req.mode == TFTP_OCTET) {
					state = TFTPD_SEND_OCTET;
				} else {
					tftp_error(udp, &sin, TFTP_EUNDEF, NULL);
					break;
				}

				if (req.opt_len) {
					tftp_oack(udp, &sin, req.opt, req.opt_len);
					break;
				}

				if (req.mode == TFTP_NETASCII)
					goto send_netascii;

				if (req.mode == TFTP_OCTET)
					goto send_octet;

				break;

			case TFTP_WRQ:
				/* Write Request */
				DCC_LOG(LOG_TRACE, "write request...");

				tftp_req_parse((char *)&(hdr->th_stuff), &req);
				blksize = req.blksize;

				INF("WRQ '%s' '%s' blksize=%d", req.fname, 
					   tftp_mode[req.mode], req.blksize);

				if (tftp_decode_fname(dbg, req.fname) < 0) {
					tftp_error(udp, &sin, TFTP_ENOTFOUND, "BAD ADDR.");
					break;
				}

				/* set the transfer info */
				addr_start = dbg->transf.base;
				addr_end = addr_start + dbg->transf.size;
				block = 0;

				DCC_LOG2(LOG_TRACE, "start=0x%08x end=0x%08x", 
						 addr_start, addr_end);

				DBG("TFTP: start=0x%08x end=0x%08x", 
						 addr_start, addr_end);

				if ((req.mode == TFTP_NETASCII) || (req.mode == TFTP_OCTET)) {
					state = (req.mode == TFTP_NETASCII) ? 
						TFTPD_RECV_NETASCII : TFTPD_RECV_OCTET;

					if (req.opt_len) 
						tftp_oack(udp, &sin, req.opt, req.opt_len);
					else
						tftp_ack(udp, block, &sin);

					break;
				} 

				tftp_error(udp, &sin, TFTP_EUNDEF, NULL);
				break;

			case TFTP_ACK:
				block = htons(hdr->th_block);
				DCC_LOG1(LOG_TRACE, "ACK: %d.", block);

				if (state == TFTPD_SEND_NETASCII) {
					unsigned int addr;
					int rem;
					int n;

send_netascii:
					addr = addr_start + (block * 256);
					rem = addr_end - addr;
					if (rem < 0) {
						state = TFTPD_IDLE;
						DCC_LOG1(LOG_TRACE, "eot: %d bytes sent.", 
								 addr_end - addr_start);
						break;
					}

					n = (rem < 256) ? rem : 256;

					DCC_LOG2(LOG_TRACE, "send netascii: addr=0x%08x n=%d", 
							 addr, n);

					/* build the packet */
					len = tftp_hex(addr, hdr->th_data, n);

					goto send_data;
				}

				if (state == TFTPD_SEND_OCTET) {
					unsigned int addr;
					int rem;
					int n;

send_octet:
					addr = addr_start + (block * blksize);
					rem = addr_end - addr;
					if (rem < 0) {
						state = TFTPD_IDLE;
						DCC_LOG1(LOG_TRACE, "eot: %d bytes sent.", 
								 addr_end - addr_start);
						break;
					}
					n = (rem < blksize) ? rem : blksize;

					DCC_LOG2(LOG_TRACE, "send octet: addr=0x%08x n=%d", 
							 addr, n);

					/* build the packet */
					len = target_mem_read(addr, hdr->th_data, n);

					if (len < 0) {
						DCC_LOG(LOG_WARNING, "target memory read error.");
						len = 0;
					}

send_data:
					hdr->th_opcode = htons(TFTP_DATA);
					hdr->th_block = htons(block + 1);

					DCC_LOG2(LOG_TRACE, "block %d: %d bytes.", 
							 block + 1,  len);

					if (udp_sendto(udp, hdr, 
								   sizeof(struct tftphdr) + len, &sin) < 0) {
						DCC_LOG(LOG_WARNING, "udp_sendto() fail");
						state = TFTPD_IDLE;
						break;
					}

					break;
				}

				DCC_LOG(LOG_WARNING, "state invalid!");
				break;

			case TFTP_DATA:
				/* skip the header */
				len -= 4;
				DCC_LOG2(LOG_TRACE, "block=%d len=%d", 
						 htons(hdr->th_block), len);

				DBG("TFTP: DATA block=%d len=%d", htons(hdr->th_block), len);

				if (htons(hdr->th_block) != (block + 1)) {
					/* retransmission, just ack */
					DCC_LOG2(LOG_WARNING, "retransmission, block=%d len=%d", 
							 block, len);
					tftp_ack(udp, block, &sin);
					break;
				}

				if (state == TFTPD_RECV_OCTET) {
					unsigned int addr;
					int n;

					addr = addr_start + (block * blksize);

					block++;

					if (len != blksize) {
						DCC_LOG(LOG_TRACE, "last packet...");
						state = TFTPD_IDLE;
						if (len == 0) {
							tftp_ack(udp, block, &sin);
							break;
						}
					} else {
						DCC_LOG2(LOG_TRACE, "rcvd octet: addr=0x%08x n=%d", 
								 addr, len);
						/* ACK the packet before writing to
						   speed up the transfer, errors are postponed... */
						tftp_ack(udp, block, &sin);
					}

					n = target_mem_write(addr, hdr->th_data, len);

					if (n < len) {
						if (n < 0) {
							DCC_LOG(LOG_ERROR, "target_mem_write()!");
							sprintf(msg, "TARGET WRITE FAIL: %08x", addr);
							WARN("memory write failed at "
								   "addr=0x%08x, code %d", addr, n);
						} else {
							DCC_LOG2(LOG_WARNING, "short writ: "
									 "ret(%d) < len(%d)!", n, len);
							sprintf(msg, "TARGET SHORT WRITE: %08x", 
									addr + n);
						}
						tftp_error(udp, &sin, TFTP_EUNDEF, msg);
						state = TFTPD_RECV_ERROR;
					} else {
						if (n > len) {
							DCC_LOG2(LOG_WARNING, "long write: "
									 "ret(%d) < len(%d)!", n, len);
						}
						if (state == TFTPD_IDLE) {
							/* ack the last packet ... */
							tftp_ack(udp, block, &sin);
						}
					}
					break;
				}

				if (state == TFTPD_RECV_ERROR) {
//					tftp_error(udp, &sin, TFTP_EUNDEF, "TARGET WRITE FAIL.");
					state = TFTPD_IDLE;
					break;
				}

				if (state == TFTPD_RECV_NETASCII) {
					block++;
					if (len != blksize) {
						state = TFTPD_IDLE;
						if (len == 0) {
							tftp_ack(udp, block, &sin);
							break;
						}
					}
					DCC_LOG1(LOG_TRACE, "ASCII recv %d...", len);
					tftp_recv_netascii(udp, &sin, block, 
									   (char *)hdr->th_data, len);
					break;
				}

				tftp_error(udp, &sin, TFTP_EUNDEF, NULL);
				break;

			case TFTP_ERROR:
				DCC_LOG2(LOG_TRACE, "error: %d: %s.", 
						 htons(hdr->th_code), hdr->th_data);
				break;

			}

			if (state == TFTPD_IDLE) {
				DCC_LOG(LOG_TRACE, "[IDLE]");
				break;
			}

			DBG("TFTP: UDP receive ...");

			if ((len = udp_recv_tmo(udp, buf, MAX_TFTP_MSG, &sin, 5000)) < 0) {
				if (len == -ETIMEDOUT) {
					DCC_LOG(LOG_WARNING, "udp_recv_tmo() timeout!");
					WARN("TFTP: UDP receive timeout!");
				} else {
					if (len == -ECONNREFUSED) {
						DCC_LOG(LOG_WARNING, "udp_recv_tmo() lost peer!");
						WARN("TFTP: UDP peer lost!");
					} else {
						DCC_LOG(LOG_WARNING, "udp_recv_tmo() failed!");
						WARN("TFTP: UDP receive failed!");
					}
				}
				/* break the inner loop */
				break;
			}

			opc = htons(hdr->th_opcode);
		}

		/* disconnect */
		DCC_LOG(LOG_TRACE, "disconnecting.");
		udp_connect(udp, INADDR_ANY, 0);
	}
}
예제 #3
0
파일: tftp_client.c 프로젝트: cilynx/dd-wrt
void
tftp_stream_close(int *err)
{
    tftp_ack(err);
    tftp_stream.open = false;
}
예제 #4
0
파일: tftp_client.c 프로젝트: cilynx/dd-wrt
int
tftp_stream_read(char *buf,
                 int len,
                 int *err)
{
    int total_bytes = 0;
    int size, recv_len, data_len;
    struct timeval timeout;
    struct tftphdr *hdr = (struct tftphdr *)tftp_stream.data;

    while (total_bytes < len) {
        // Move any bytes which we've already read/buffered
        if (tftp_stream.avail > 0) {
            size = tftp_stream.avail;
            if (size > (len - total_bytes)) size = len - total_bytes;
            memcpy(buf, tftp_stream.bufp, size);
            buf += size;
            tftp_stream.bufp += size;
            tftp_stream.avail -= size;
            total_bytes += size;
        } else {
            if (tftp_ack(err) < 0) {
                return -1;
            }
            if ((tftp_stream.actual_len >= 0) && (tftp_stream.actual_len < SEGSIZE)) {
                // Out of data
                break;
            }
            timeout.tv_sec = (tftp_stream.last_good_block == 0) ? 10*TFTP_TIMEOUT_PERIOD : TFTP_TIMEOUT_PERIOD;
            timeout.tv_usec = 0;
            recv_len = sizeof(tftp_stream.data);
            if ((data_len = __udp_recvfrom(&tftp_stream.data[0], recv_len, &tftp_stream.from_addr, 
                                           &tftp_stream.local_addr,  &timeout)) < 0) {
                // No data, try again
                diag_printf("TFTP timed out %d/%d\n", tftp_stream.total_timeouts+1, TFTP_TIMEOUT_MAX);
                if ((++tftp_stream.total_timeouts > TFTP_TIMEOUT_MAX) || 
                    (tftp_stream.last_good_block == 0)) {
                    // Timeout - no data received
                    *err = TFTP_TIMEOUT;
                    return -1;
                }
                // Send out the ACK for the last block - maybe server will retry
                if (tftp_ack(err) < 0) {
                    return -1;
                }
            } else {
                tftp_stream.packets_received++;
                if (ntohs(hdr->th_opcode) == DATA) {
                    if (ntohs(hdr->th_block) == (cyg_uint16)((tftp_stream.last_good_block+1) & 0xFFFF)) {
                        // Consume this data
                        data_len -= 4;  /* Sizeof TFTP header */
                        tftp_stream.avail = tftp_stream.actual_len = data_len;
                        tftp_stream.bufp = hdr->th_data;
                        tftp_stream.last_good_block++;
                    }
                } else {
                    if (ntohs(hdr->th_opcode) == ERROR) {
                        *err = ntohs(hdr->th_code);
                        return -1;
                    } else {
                        // What kind of packet is this?
                        *err = TFTP_PROTOCOL;
                        return -1;
                    }
                }
            }
        }
    }
    return total_bytes;
}
예제 #5
0
static void upd_flash(tftp *tftp)
{
  char str[17];
  int tftp_block;
  u32 waddr;
  u32 sector, last_sector;
  int len;
  
  tftp_init(tftp);
  tftp->filename = upd_mem;
  
  waddr = 0;
  last_sector= 0xFFFFFFFF;
  
  while(1)
  {
    tftp_run(tftp);
    if ( (tftp->state == 2) ||
         (tftp->state == 3))
    {
        if (tftp->lastblock != tftp_block)
        {
          tftp_block = tftp->lastblock;
          
          strcpy(str, "Load flash      ");
          b2ds(&str[11], tftp_block);
          oled_pos(0, 0);
          oled_puts(str);

          sector = (tftp_block << 9) & 0xFFFF0000;
          if (sector != last_sector)
          {
            flash_erase(sector);
            last_sector = sector;
          }
          uart_puts(str); uart_putc('\r');
          
          len = 0;
          if (tftp->length > 4)
          {
            u8 *dat;
            dat = (u8 *)&tftp->data[4];
            
            len = tftp->length - 4;
            if (len > 256)
            {
              flash_write(waddr, dat, 256);
              len   -= 256; /* Update remaining data length */
              dat   += 256; /* Move the source pointer      */
              waddr += 256; /* Update the dest address      */

              /* Wait for the write transfer ends */
              while(flash_status() & 1)
                ;
            }
            flash_write(waddr, dat, len);
            /* Wait for the write transfer ends */
            while(flash_status() & 1)
              ;
            /* Update write address for next packet */
            waddr += len;
          }
        }
        tftp_ack(tftp);
    }
    if (tftp->state == 3)
    {
      uart_crlf();
      break;
    }
    if (tftp->state == 98)
    {
      uart_puts("TFTP timeout, restart\r\n");
      oled_pos(0, 0);
      oled_puts("TFTP: timeout!");
      tftp->timestamp = 0x3000;
      tftp->state = 0;
    }
    if (tftp->state == 99)
    {
      uart_puts("upd_firmware() TFTP error 99\r\n");
      break;
    }
  }
}