void TFTPSRV_service_transaction ( TFTPSRV_STATE_STRUCT_PTR tftpsrv_ptr, /* [IN/OUT] The TFTP Server state */ TFTP_TRANS_STRUCT_PTR trans_ptr /* [IN/OUT] The transaction state */ ) { /* Body */ sockaddr_in sockaddr_tftp; uint32_t block_num; int32_t pkt_len, write_len; uint16_t sockaddrlen, pkt_op; /* receive the datagram */ sockaddrlen = sizeof(sockaddr_tftp); pkt_len = recvfrom(trans_ptr->SOCK, tftpsrv_ptr->BUFFER, TFTP_MAX_MESSAGE_SIZE, 0,(sockaddr *)&sockaddr_tftp, &sockaddrlen); if (pkt_len == RTCS_ERROR) { return; } /* Endif */ /* verify the sender's address and port */ if ((trans_ptr->ADDR.sin_port != sockaddr_tftp.sin_port) || (trans_ptr->ADDR.sin_addr.s_addr != sockaddr_tftp.sin_addr.s_addr)) { TFTP_SEND(tftpsrv_ptr->SRV_SOCK, _tftp_error_tid, sockaddr_tftp); return; } /* Endif */ /* get op and block number */ if (pkt_len < sizeof(TFTP_HEADER)) { TFTP_SEND(trans_ptr->SOCK, _tftp_error_tid, sockaddr_tftp); return; } /* Endif */ pkt_op = mqx_ntohs(tftpsrv_ptr->BUFFER); block_num = mqx_ntohs(tftpsrv_ptr->BUFFER + 2); /* verify the requested operation */ if (pkt_op != trans_ptr->RECV_OP) { if (pkt_op != TFTPOP_ERROR) { TFTP_SEND(trans_ptr->SOCK, _tftp_error_op, sockaddr_tftp); } /* Endif */ TFTPSRV_close_transaction(tftpsrv_ptr, trans_ptr); return; } /* Endif */ switch (pkt_op) { case TFTPOP_DATA: /* We are servicing a write request from a TFTP Client here */ if (block_num == trans_ptr->BLOCK) { pkt_len -= sizeof(TFTP_HEADER); write_len = RTCS_io_write(trans_ptr->TRANS_FILE_PTR, tftpsrv_ptr->BUFFER + sizeof(TFTP_HEADER), pkt_len); fflush(trans_ptr->TRANS_FILE_PTR); if (write_len != pkt_len) { TFTP_SEND(trans_ptr->SOCK, _tftp_error_srv, trans_ptr->ADDR); TFTPSRV_close_transaction(tftpsrv_ptr, trans_ptr); return; } /* Endif */ TFTPSRV_build_ACK(trans_ptr); trans_ptr->EXIT = (write_len < sizeof(TFTP_PACKET) - sizeof(TFTP_HEADER)); TFTPSRV_timer_cancel(tftpsrv_ptr, trans_ptr); TFTPSRV_timer_start(tftpsrv_ptr, trans_ptr, TFTP_timeout_update(&trans_ptr->XMIT_TIMER)); TFTPSRV_send(trans_ptr); } else if (block_num == trans_ptr->BLOCK - 1) { TFTPSRV_timer_cancel(tftpsrv_ptr, trans_ptr); TFTPSRV_timer_start(tftpsrv_ptr, trans_ptr, TFTP_timeout_restart(&trans_ptr->XMIT_TIMER)); TFTPSRV_send(trans_ptr); } /* Endif */ break; case TFTPOP_ACK: /* We are servicing a read request */ if (block_num == trans_ptr->BLOCK) { if (trans_ptr->EXIT) { /* We've received the last ACK, exit */ TFTPSRV_close_transaction(tftpsrv_ptr, trans_ptr); return; } /* Endif */ TFTPSRV_build_DATA(trans_ptr); if (trans_ptr->SEND_SIZE < sizeof(TFTP_HEADER)) { TFTP_SEND(trans_ptr->SOCK, _tftp_error_srv, sockaddr_tftp); TFTPSRV_close_transaction(tftpsrv_ptr, trans_ptr); return; } /* Endif */ TFTPSRV_timer_cancel(tftpsrv_ptr, trans_ptr); TFTPSRV_timer_start(tftpsrv_ptr, trans_ptr, TFTP_timeout_update(&trans_ptr->XMIT_TIMER)); TFTPSRV_send(trans_ptr); } /* Endif */ break; } /* Endswitch */ } /* Endbody */
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 */