summaryrefslogtreecommitdiff
path: root/net/lwip/tftp.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/lwip/tftp.c')
-rw-r--r--net/lwip/tftp.c71
1 files changed, 60 insertions, 11 deletions
diff --git a/net/lwip/tftp.c b/net/lwip/tftp.c
index 4f9b2049187..fae701bad2e 100644
--- a/net/lwip/tftp.c
+++ b/net/lwip/tftp.c
@@ -8,6 +8,7 @@
#include <efi_loader.h>
#include <image.h>
#include <linux/delay.h>
+#include <linux/kconfig.h>
#include <lwip/apps/tftp_client.h>
#include <lwip/timeouts.h>
#include <mapmem.h>
@@ -15,6 +16,8 @@
#include <time.h>
#define PROGRESS_PRINT_STEP_BYTES (10 * 1024)
+/* Max time to wait for first data packet from server */
+#define NO_RSP_TIMEOUT_MS 10000
enum done_state {
NOT_DONE = 0,
@@ -31,6 +34,47 @@ struct tftp_ctx {
enum done_state done;
};
+/**
+ * store_block() - copy received data
+ *
+ * This function is called by the receive callback to copy a block of data
+ * into its final location (ctx->daddr). Before doing so, it checks if the copy
+ * is allowed.
+ *
+ * @ctx: the context for the current transfer
+ * @src: the data received from the TCP stack
+ * @len: the length of the data
+ */
+static int store_block(struct tftp_ctx *ctx, void *src, u16_t len)
+{
+ ulong store_addr = ctx->daddr;
+ void *ptr;
+
+ if (CONFIG_IS_ENABLED(LMB)) {
+ if (store_addr + len < store_addr ||
+ lmb_read_check(store_addr, len)) {
+ puts("\nTFTP error: ");
+ puts("trying to overwrite reserved memory...\n");
+ return -1;
+ }
+ }
+
+ ptr = map_sysmem(store_addr, len);
+ memcpy(ptr, src, len);
+ unmap_sysmem(ptr);
+
+ 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 ");
+ }
+
+ return 0;
+}
+
static void *tftp_open(const char *fname, const char *mode, u8_t is_write)
{
return NULL;
@@ -71,17 +115,9 @@ static int tftp_write(void *handle, struct pbuf *p)
struct tftp_ctx *ctx = handle;
struct pbuf *q;
- for (q = p; q; q = q->next) {
- memcpy((void *)ctx->daddr, q->payload, q->len);
- ctx->daddr += q->len;
- ctx->size += q->len;
- ctx->block_count++;
- if (ctx->block_count % 10 == 0) {
- putc('#');
- if (ctx->block_count % (65 * 10) == 0)
- puts("\n\t ");
- }
- }
+ for (q = p; q; q = q->next)
+ if (store_block(ctx, q->payload, q->len) < 0)
+ return -1;
return 0;
}
@@ -106,6 +142,17 @@ static const struct tftp_context tftp_context = {
tftp_error
};
+static void no_response(void *arg)
+{
+ struct tftp_ctx *ctx = (struct tftp_ctx *)arg;
+
+ if (ctx->size)
+ return;
+
+ printf("Timeout!\n");
+ ctx->done = FAILURE;
+}
+
static int tftp_loop(struct udevice *udev, ulong addr, char *fname,
ip_addr_t srvip, uint16_t srvport)
{
@@ -150,6 +197,7 @@ static int tftp_loop(struct udevice *udev, ulong addr, char *fname,
return -1;
}
+ sys_timeout(NO_RSP_TIMEOUT_MS, no_response, &ctx);
while (!ctx.done) {
net_lwip_rx(udev, netif);
sys_check_timeouts();
@@ -159,6 +207,7 @@ static int tftp_loop(struct udevice *udev, ulong addr, char *fname,
break;
}
}
+ sys_untimeout(no_response, (void *)&ctx);
tftp_cleanup();