Index: atftp-0.7/tftpd_file.c
===================================================================
--- atftp-0.7.orig/tftpd_file.c	2012-10-10 12:01:49.082521984 +0200
+++ atftp-0.7/tftpd_file.c	2012-10-10 14:12:18.357696328 +0200
@@ -402,7 +402,6 @@ int tftpd_send_file(struct thread_data *
      int timeout_state = state;
      int result;
      long block_number = 0;
-     long last_requested_block = -1;
      long last_block = -1;
      int block_loops = 0;
      int data_size;
@@ -430,6 +429,11 @@ int tftpd_send_file(struct thread_data *
      long prev_file_pos = 0;
      int temp = 0;
 
+     long prev_sent_block = -1;
+     int prev_sent_count = 0;
+     int prev_ack_count = 0;
+     int curr_sent_count = 0;
+
      /* look for mode option */
      if (strcasecmp(data->tftp_options[OPT_MODE].value, "netascii") == 0)
      {
@@ -787,7 +791,7 @@ int tftpd_send_file(struct thread_data *
                                    sa = &client_info->client;
 
                                    /* rewind the last_requested_block counter */
-                                   last_requested_block = -1;
+                                   prev_sent_block = -1;
 
                                    state = S_SEND_OACK;
                                    break;
@@ -856,6 +860,7 @@ int tftpd_send_file(struct thread_data *
                                           "source port mismatch, check bypassed");
                          }
                     }
+
                     /* The ACK is from the current client */
                     number_of_timeout = 0;
                     block_number = (block_loops * 65536) + ntohs(tftphdr->th_block);
@@ -864,28 +869,88 @@ int tftpd_send_file(struct thread_data *
                          logger(LOG_DEBUG, "received ACK <block: %d>", block_number);
                     }
 
-		    /* if turned on, check whether the block request isn't already fulfilled */
-                    if (tftpd_prevent_sas) {
-                        /* multicast, block numbers could contain gaps */
-                        if (multicast) {
-                            if (last_requested_block >= block_number)
+                    /* Now check the ACK number and possibly ignore the request */
+
+                    /* multicast, block numbers could contain gaps */
+                    if (multicast) {
+		        /* if turned on, check whether the block request isn't already fulfilled */
+                        if (tftpd_prevent_sas) {
+                            if (prev_sent_block >= block_number)
                             {
                                 if (data->trace)
-                                    logger(LOG_DEBUG, "received duplicated ACK <block: %d >= %d>", last_requested_block, block_number);
+                                    logger(LOG_DEBUG, "received duplicated ACK <block: %d >= %d>", prev_sent_block, block_number);
                                 break;
                             }
                             else
-                                last_requested_block = block_number;
-                        /* unicast, blocks should be requested one after another */
-		        } else {
-                            if (last_requested_block + 1 != block_number && last_requested_block != -1)
+                                prev_sent_block = block_number;
+                        }
+                        /* don't prevent thes SAS */
+                        /* use a heuristic suggested by Vladimir Nadvornik */
+                        else {
+                            /* here comes the ACK again */
+                            if (prev_sent_block == block_number)
+                            {
+                                /* drop if number of ACKs == times of previous block sending */
+                                if (++prev_ack_count == prev_sent_count) {
+                                    logger(LOG_DEBUG, "ACK count (%d) == previous block transmission count -> dropping ACK", prev_ack_count);
+                                    break;
+                                }
+                                /* else resend the block */
+                                logger(LOG_DEBUG, "resending block %d", block_number + 1);
+                            }
+                            /* received ACK to sent block -> move on to next block */
+                            else if (prev_sent_block < block_number) {
+                                prev_sent_block = block_number;
+                                prev_sent_count = curr_sent_count;
+                                curr_sent_count = 0;
+                                prev_ack_count = 1;
+                            }
+                            /* block with low number -> ignore it completely */
+                            else {
+                                logger(LOG_DEBUG, "ignoring ACK %d", block_number);
+                                break;
+                            }
+                        }
+                    /* unicast, blocks should be requested one after another */
+		    } else {
+		        /* if turned on, check whether the block request isn't already fulfilled */
+                        if (tftpd_prevent_sas) {
+                            if (prev_sent_block + 1 != block_number)
                             {
+                                logger(LOG_WARNING, "timeout: retrying...");
                                 if (data->trace)
-                                    logger(LOG_DEBUG, "received out of order ACK <block: %d != %d>", last_requested_block + 1, block_number);
+                                    logger(LOG_DEBUG, "received out of order ACK <block: %d != %d>", prev_sent_block + 1, block_number);
+                                break;
+                            }
+                            else {
+                                prev_sent_block = block_number;
+                            }
+                        /* don't prevent thes SAS */
+                        /* use a heuristic suggested by Vladimir Nadvornik */
+                        } else {
+                            /* here comes the ACK again */
+                            if (prev_sent_block == block_number)
+                            {
+                                /* drop if number of ACKs == times of previous block sending */
+                                if (++prev_ack_count == prev_sent_count) {
+                                    logger(LOG_DEBUG, "ACK count (%d) == previous block transmission count -> dropping ACK", prev_ack_count);
+                                    break;
+                                }
+                                /* else resend the block */
+                                logger(LOG_DEBUG, "resending block %d", block_number + 1);
+                            }
+                            /* received ACK to sent block -> move on to next block */
+                            else if (prev_sent_block < block_number) {
+                                prev_sent_block = block_number;
+                                prev_sent_count = curr_sent_count;
+                                curr_sent_count = 0;
+                                prev_ack_count = 1;
+                            }
+                            /* nor previous nor current block number -> ignore it completely */
+                            else {
+                                logger(LOG_DEBUG, "ignoring ACK %d", block_number);
                                 break;
                             }
-                            else
-                                last_requested_block = block_number;
                         }
                     }
 
@@ -898,6 +963,8 @@ int tftpd_send_file(struct thread_data *
                          state = S_END;
                          break;
                     }
+
+                    curr_sent_count++;
                     state = S_SEND_DATA;
                     break;
                case GET_ERROR:
@@ -989,7 +1056,7 @@ int tftpd_send_file(struct thread_data *
                          state = S_SEND_OACK;                
                          fseek(fp, 0, SEEK_SET);
 			 /* reset the last block received counter */
-			 last_requested_block = -1;
+			 prev_sent_block = -1;
                     }
                     else
                     {
