Add .gitignore
[oweals/nmrpflash.git] / tftp.c
diff --git a/tftp.c b/tftp.c
index 89d98c0c154a1a16539f627a970183cc78cda4cd..ec15c4b1d6f422c59b50541f55df14c249ed38f6 100644 (file)
--- a/tftp.c
+++ b/tftp.c
@@ -149,12 +149,12 @@ static ssize_t tftp_recvfrom(int sock, char *pkt, uint16_t* port,
                 * at offset 0. The limit of 32 chars is arbitrary.
                 */
                fprintf(stderr, "Error: %.32s\n", pkt);
-               return -3;
+               return -2;
        } else if (!opcode || opcode > ERR) {
                fprintf(stderr, "Received invalid packet: ");
                pkt_print(pkt, stderr);
                fprintf(stderr, ".\n");
-               return -2;
+               return -1;
        }
 
        if (verbosity > 2) {
@@ -224,7 +224,7 @@ int tftp_put(struct nmrpd_args *args)
        struct sockaddr_in addr;
        uint16_t block, port;
        ssize_t len, last_len;
-       int fd, sock, ret, timeout;
+       int fd, sock, ret, timeout, errors, ackblock;
        char rx[TFTP_PKT_SIZE], tx[TFTP_PKT_SIZE];
 
        sock = -1;
@@ -255,13 +255,16 @@ int tftp_put(struct nmrpd_args *args)
        block = 0;
        last_len = -1;
        len = 0;
+       errors = 0;
        /* Not really, but this way the loop sends our WRQ before receiving */
        timeout = 1;
 
        pkt_mkwrq(tx, args->filename);
 
        do {
-               if (timeout || (pkt_num(rx) == ACK && pkt_num(rx + 2) == block)) {
+               ackblock = pkt_num(rx) == ACK ? pkt_num(rx + 2) : -1;
+
+               if (timeout || ackblock == block) {
                        if (!timeout) {
                                ++block;
                                pkt_mknum(tx, DATA);
@@ -272,7 +275,7 @@ int tftp_put(struct nmrpd_args *args)
                                        ret = len;
                                        goto cleanup;
                                } else if (!len) {
-                                       if (last_len != 512) {
+                                       if (last_len != 512 && last_len != -1) {
                                                break;
                                        }
                                }
@@ -284,10 +287,18 @@ int tftp_put(struct nmrpd_args *args)
                        if (ret < 0) {
                                goto cleanup;
                        }
-               } else if (pkt_num(rx) != ACK) {
-                       fprintf(stderr, "Expected ACK(%d), got ", block);
-                       pkt_print(rx, stderr);
-                       fprintf(stderr, "!\n");
+               } else if (pkt_num(rx) != ACK || ackblock > block) {
+                       if (verbosity) {
+                               fprintf(stderr, "Expected ACK(%d), got ", block);
+                               pkt_print(rx, stderr);
+                               fprintf(stderr, ".\n");
+                       }
+
+                       if (ackblock != -1 && ++errors > 5) {
+                               fprintf(stderr, "Protocol error; bailing out.\n");
+                               ret = -1;
+                               goto cleanup;
+                       }
                }
 
                ret = tftp_recvfrom(sock, rx, &port, args->rx_timeout);
@@ -296,8 +307,12 @@ int tftp_put(struct nmrpd_args *args)
                } else if (!ret) {
                        if (++timeout < 5) {
                                continue;
+                       } else if (block) {
+                               fprintf(stderr, "Timeout while waiting for ACK(%d).\n", block);
+                       } else {
+                               fprintf(stderr, "Timeout while waiting for initial reply.\n");
                        }
-                       fprintf(stderr, "Timeout while waiting for ACK(%d).\n", block);
+                       ret = -1;
                        goto cleanup;
                } else {
                        timeout = 0;