uchar_ptr TFTP_read ( uint_32_ptr size /* [OUT] number of bytes read, or error code */ ) { /* Body */ uint_32 sock; sockaddr_in remote_addr; uint_16 remote_size; uint_16 ack_block; uint_16 pkt_op, pkt_block; uint_32 pkt_size; uint_32 time_left; boolean expired; #if TFTP_TIMEOUT_RETRIES uint_32 retries = 0; #endif ack_block = ntohs(TFTP_config.ACK.BLOCK); TFTP_timeout_restart(&TFTP_config.TIMEOUT); for (;;) { /* Check for timeout */ time_left = TFTP_timeout_left(&TFTP_config.TIMEOUT, &expired); if (expired) { #if TFTP_TIMEOUT_RETRIES retries++; if (retries > TFTP_TIMEOUT_RETRIES) { *size = RTCSERR_TFTP_TIMEOUT; TFTP_close(); return NULL; } /* Endif */ #endif /* Retransmit the last packet */ TFTP_RESEND(); } /* Endif */ /* Wait for a packet */ sock = TFTP_WAIT(time_left); /* Timeout -- retransmit last packet */ if (sock != TFTP_config.SOCK) { continue; } /* Endif */ remote_size = sizeof(remote_addr); pkt_size = TFTP_RECV(TFTP_config.PACKET); pkt_op = ntohs(TFTP_config.PACKET.HEAD.OP); pkt_block = ntohs(TFTP_config.PACKET.HEAD.BLOCK); /* Check source address of received packet */ if (remote_addr.sin_addr.s_addr != TFTP_config.SADDR.sin_addr.s_addr) { continue; } /* Endif */ /* Validate source port */ if (ack_block && remote_addr.sin_port != TFTP_config.SADDR.sin_port) { TFTP_SEND(TFTP_config.SOCK, _tftp_error_tid, remote_addr); continue; } /* Endif */ /* Check size of received packet */ if (pkt_size < sizeof(TFTP_HEADER)) { TFTP_SEND(TFTP_config.SOCK, _tftp_error_op, remote_addr); *size = RTCSERR_TFTP_ERROR + TFTPERR_ILLEGAL_OP; TFTP_close(); return NULL; } /* Endif */ /* Check for error packet */ if (pkt_op == TFTPOP_ERROR) { *size = RTCSERR_TFTP_ERROR + pkt_block; TFTP_close(); return NULL; } /* Endif */ /* Check for data packet */ if ((pkt_op != TFTPOP_DATA) || (pkt_size > sizeof(TFTP_PACKET)) || (pkt_block < ack_block) || (pkt_block > ack_block+1)) { TFTP_SEND(TFTP_config.SOCK, _tftp_error_op, remote_addr); *size = RTCSERR_TFTP_ERROR + TFTPERR_ILLEGAL_OP; TFTP_close(); return NULL; } /* Endif */ /* Check for retransmitted packet */ if (pkt_block == ack_block) { TFTP_timeout_restart(&TFTP_config.TIMEOUT); TFTP_SEND(TFTP_config.SOCK, TFTP_config.ACK, TFTP_config.SADDR); continue; } /* Endif */ /* We have the next packet */ break; } /* Endfor */ /* Update the adaptive timeout */ TFTP_timeout_update(&TFTP_config.TIMEOUT); /* Free the original RRQ */ if (!ack_block) { TFTP_config.SADDR.sin_port = remote_addr.sin_port; _mem_free(TFTP_config.RRQ_PTR); TFTP_config.RRQ_PTR = NULL; } /* Endif */ /* ACK it */ ack_block++; htons(TFTP_config.ACK.BLOCK, ack_block); TFTP_SEND(TFTP_config.SOCK, TFTP_config.ACK, TFTP_config.SADDR); TFTP_config.LAST = (pkt_size < sizeof(TFTP_PACKET)); /* Return the data */ *size = pkt_size - sizeof(TFTP_HEADER); return TFTP_config.PACKET.DATA; } /* Endbody */
unsigned char *TFTP_read ( uint32_t *size /* [OUT] number of bytes read, or error code */ ) { /* Body */ uint32_t sock; sockaddr_in remote_addr; uint16_t remote_size; uint16_t ack_block; uint16_t pkt_op, pkt_block; uint32_t pkt_size; uint32_t time_left; bool expired; #if TFTP_TIMEOUT_RETRIES uint32_t retries = 0; #endif ack_block = mqx_ntohs(TFTP_config.ACK.BLOCK); TFTP_timeout_restart(&TFTP_config.TIMEOUT); for (;;) { /* Check for timeout */ time_left = TFTP_timeout_left(&TFTP_config.TIMEOUT, &expired); if (expired) { #if TFTP_TIMEOUT_RETRIES retries++; if (retries > TFTP_TIMEOUT_RETRIES) { *size = RTCSERR_TFTP_TIMEOUT; TFTP_close(); return NULL; } /* Endif */ #endif /* Retransmit the last packet */ TFTP_RESEND(); } /* Endif */ /* Wait for a packet */ sock = TFTP_WAIT(time_left); /* Timeout -- retransmit last packet */ if (sock != TFTP_config.SOCK) { continue; } /* Endif */ remote_size = sizeof(remote_addr); pkt_size = TFTP_RECV(TFTP_config.PACKET); pkt_op = mqx_ntohs(TFTP_config.PACKET.HEAD.OP); pkt_block = mqx_ntohs(TFTP_config.PACKET.HEAD.BLOCK); /* Check source address of received packet */ if (remote_addr.sin_addr.s_addr != TFTP_config.SADDR.sin_addr.s_addr) { continue; } /* Endif */ /* Validate source port */ if (ack_block && remote_addr.sin_port != TFTP_config.SADDR.sin_port) { TFTP_SEND(TFTP_config.SOCK, _tftp_error_tid, remote_addr); continue; } /* Endif */ /* Check size of received packet */ if (pkt_size < sizeof(TFTP_HEADER)) { TFTP_SEND(TFTP_config.SOCK, _tftp_error_op, remote_addr); *size = RTCSERR_TFTP_ERROR + TFTPERR_ILLEGAL_OP; TFTP_close(); return NULL; } /* Endif */ /* Check for error packet */ if (pkt_op == TFTPOP_ERROR) { *size = RTCSERR_TFTP_ERROR + pkt_block; TFTP_close(); return NULL; } /* Endif */ /* Check for data packet */ if ((pkt_op != TFTPOP_DATA) || (pkt_size > sizeof(TFTP_PACKET))) { TFTP_SEND(TFTP_config.SOCK, _tftp_error_op, remote_addr); *size = RTCSERR_TFTP_ERROR + TFTPERR_ILLEGAL_OP; TFTP_close(); return NULL; } /* Endif */ /* Check for retransmitted packet */ if (pkt_block == ack_block) { TFTP_timeout_restart(&TFTP_config.TIMEOUT); TFTP_SEND(TFTP_config.SOCK, TFTP_config.ACK, TFTP_config.SADDR); continue; } /* Endif */ /* Aknowledge also packets with lower id, some servers do retransmit them until they get an ack */ if (pkt_block < ack_block) { TFTP_timeout_restart(&TFTP_config.TIMEOUT); mqx_htons(TFTP_config.ACK.BLOCK, pkt_block); TFTP_SEND(TFTP_config.SOCK, TFTP_config.ACK, TFTP_config.SADDR); mqx_htons(TFTP_config.ACK.BLOCK, ack_block); /* Restore id of last acknowledged packet */ continue; } /* Endif */ /* Drop unexpected packets */ if (pkt_block > ack_block+1) { /* Some server do send more than one packet at a time, these will eventually retransmitted */ continue; } /* We have the next packet */ break; } /* Endfor */ /* Update the adaptive timeout */ TFTP_timeout_update(&TFTP_config.TIMEOUT); /* Free the original RRQ */ if (!ack_block) { TFTP_config.SADDR.sin_port = remote_addr.sin_port; _mem_free(TFTP_config.RRQ_PTR); TFTP_config.RRQ_PTR = NULL; } /* Endif */ /* ACK it */ ack_block++; mqx_htons(TFTP_config.ACK.BLOCK, ack_block); TFTP_SEND(TFTP_config.SOCK, TFTP_config.ACK, TFTP_config.SADDR); TFTP_config.LAST = (pkt_size < sizeof(TFTP_PACKET)); /* Return the data */ *size = pkt_size - sizeof(TFTP_HEADER); return TFTP_config.PACKET.DATA; } /* Endbody */