int last_pkt;
u16_t blknum;
u16_t blksize;
+ u32_t tsize;
u8_t retries;
u8_t mode_write;
u8_t tftp_mode;
{
size_t fname_length = strlen(fname)+1;
size_t mode_length = strlen(mode)+1;
+ size_t tsize_length = strlen("tsize")+3; /* "tsize\0\0\0" */
size_t blksize_length = 0;
int blksize = tftp_state.blksize;
struct pbuf* p;
}
}
- p = init_packet(opcode, 0, fname_length + mode_length + blksize_length - 2);
+ p = init_packet(opcode, 0, fname_length + mode_length + blksize_length + tsize_length - 2);
if (p == NULL) {
return ERR_MEM;
}
payload = (char*) p->payload;
MEMCPY(payload+2, fname, fname_length);
MEMCPY(payload+2+fname_length, mode, mode_length);
+ sprintf(payload+2+fname_length+mode_length, "tsize%c%u%c", 0, 0, 0);
if (tftp_state.blksize)
- sprintf(payload+2+fname_length+mode_length, "blksize%c%d", 0, tftp_state.blksize);
+ sprintf(payload+2+fname_length+mode_length+tsize_length, "blksize%c%d", 0, tftp_state.blksize);
tftp_state.wait_oack = true;
ret = udp_sendto(tftp_state.upcb, p, addr, port);
}
blknum = lwip_ntohs(sbuf[1]);
- if (tftp_state.blksize && tftp_state.wait_oack) {
+ if (tftp_state.wait_oack) {
/*
- * Data received while we are expecting an OACK for our blksize option.
+ * Data received while we are expecting an OACK for our tsize option.
* This means the server doesn't support it, let's switch back to the
* default block size.
*/
- tftp_state.blksize = 0;
- tftp_state.wait_oack = false;
+ tftp_state.tsize = 0;
+ tftp_state.wait_oack = false;
+
+ if (tftp_state.blksize) {
+ /*
+ * Data received while we are expecting an OACK for our blksize option.
+ * This means the server doesn't support it, let's switch back to the
+ * default block size.
+ */
+ tftp_state.blksize = 0;
+ tftp_state.wait_oack = false;
+ }
}
if (blknum == tftp_state.blknum) {
pbuf_remove_header(p, TFTP_HEADER_LENGTH);
}
break;
case PP_HTONS(TFTP_OACK): {
- const char *optval = find_option(p, "blksize");
+ const char *blksizeoptval = find_option(p, "blksize");
+ const char *tsizeoptval = find_option(p, "tsize");
u16_t srv_blksize = 0;
+ u32_t srv_tsize = 0;
tftp_state.wait_oack = false;
- if (optval) {
+ if (blksizeoptval) {
if (!tftp_state.blksize) {
/* We did not request this option */
send_error(addr, port, TFTP_ERROR_ILLEGAL_OPERATION, "blksize unexpected");
}
- srv_blksize = atoi(optval);
+ srv_blksize = atoi(blksizeoptval);
if (srv_blksize <= 0 || srv_blksize > tftp_state.blksize) {
send_error(addr, port, TFTP_ERROR_ILLEGAL_OPERATION, "Invalid blksize");
}
LWIP_DEBUGF(TFTP_DEBUG | LWIP_DBG_STATE, ("tftp: accepting blksize=%d\n", srv_blksize));
tftp_state.blksize = srv_blksize;
}
+ if (tsizeoptval) {
+ srv_tsize = atoi(tsizeoptval);
+ if (srv_tsize <= 0) {
+ srv_tsize = 0; /* tsize is optional */
+ }
+ LWIP_DEBUGF(TFTP_DEBUG | LWIP_DBG_STATE, ("tftp: accepting tsize=%d\n", srv_tsize));
+ tftp_state.tsize = srv_tsize;
+ }
send_ack(addr, port, 0);
break;
}
return tftp_init_common(LWIP_TFTP_MODE_CLIENT, ctx);
}
+/** @ingroup tftp
+ * Get the transfer size used by the TFTP client. The server may
+ * report zero in case this is unsupported.
+ */
+u32_t
+tftp_client_get_tsize(void)
+{
+ return tftp_state.tsize;
+}
+
/** @ingroup tftp
* Set the block size to be used by the TFTP client. The server may choose to
* accept a lower value.
ulong daddr;
ulong size;
ulong block_count;
+ ulong hash_count;
ulong start_time;
enum done_state done;
};
static int store_block(struct tftp_ctx *ctx, void *src, u16_t len)
{
ulong store_addr = ctx->daddr;
+ ulong tftp_tsize;
+ ulong pos;
void *ptr;
if (CONFIG_IS_ENABLED(LMB)) {
ctx->daddr += len;
ctx->size += len;
ctx->block_count++;
- if (ctx->block_count % 10 == 0) {
- putc('#');
- if (ctx->block_count % (65 * 10) == 0)
- puts("\n\t ");
+
+ tftp_tsize = tftp_client_get_tsize();
+ if (tftp_tsize) {
+ pos = clamp(ctx->size, 0UL, tftp_tsize);
+
+ while (ctx->hash_count < pos * 50 / tftp_tsize) {
+ putc('#');
+ ctx->hash_count++;
+ }
+ } else {
+ if (ctx->block_count % 10 == 0) {
+ putc('#');
+ if (ctx->block_count % (65 * 10) == 0)
+ puts("\n\t ");
+ }
}
return 0;
static void tftp_close(void *handle)
{
struct tftp_ctx *ctx = handle;
+ ulong tftp_tsize;
ulong elapsed;
if (ctx->done == FAILURE || ctx->done == ABORTED) {
}
ctx->done = SUCCESS;
+ tftp_tsize = tftp_client_get_tsize();
+ if (tftp_tsize) {
+ /* Print hash marks for the last packet received */
+ while (ctx->hash_count < 49) {
+ putc('#');
+ ctx->hash_count++;
+ }
+ puts(" ");
+ print_size(tftp_tsize, "");
+ }
+
elapsed = get_timer(ctx->start_time);
if (elapsed > 0) {
puts("\n\t "); /* Line up with "Loading: " */
ctx.done = NOT_DONE;
ctx.size = 0;
ctx.block_count = 0;
+ ctx.hash_count = 0;
ctx.daddr = addr;
printf("Using %s device\n", udev->name);