/* Check if the received acknowledgement is correct */ u32_t tftp_is_correct_ack(char *buf, int block) { /* first make sure this is a data ACK packet */ if (tftp_decode_op(buf) != TFTP_ACK) return 0; /* then compare block numbers */ if (block != tftp_extract_block(buf)) return 0; return 1; }
/** * @brief receive callback during tftp write operation (not on standard port 69) * @param arg: pointer on argument passed to callback * @param udp_pcb: pointer on the udp pcb * @param pkt_buf: pointer on the received pbuf * @param addr: pointer on remote IP address * @param port: pointer on remote port * @retval None */ void wrq_recv_callback(void *arg, struct udp_pcb *upcb, struct pbuf *pkt_buf, struct ip_addr *addr, u16_t port) { tftp_connection_args *args = (tftp_connection_args *)arg; int n = 0; /* we expect to receive only one pbuf (pbuf size should be configured > max TFTP frame size */ if (pkt_buf->len != pkt_buf->tot_len) { return; } /* Does this packet have any valid data to write? */ if ((pkt_buf->len > TFTP_DATA_PKT_HDR_LEN) && (tftp_extract_block(pkt_buf->payload) == (args->block + 1))) { /* write the received data to the file */ memcpy((char*)TempBuffer, (char*)pkt_buf->payload + TFTP_DATA_PKT_HDR_LEN, pkt_buf->len - TFTP_DATA_PKT_HDR_LEN); f_write(&file_CR, (char*)TempBuffer, pkt_buf->len - TFTP_DATA_PKT_HDR_LEN, (UINT*)&n); if (n <= 0) { tftp_send_error_message(upcb, addr, port, TFTP_ERR_FILE_NOT_FOUND); /* close the connection */ tftp_cleanup_wr(upcb, args); /* close the connection */ } /* update our block number to match the block number just received */ args->block++; /* update total bytes */ (args->tot_bytes) += (pkt_buf->len - TFTP_DATA_PKT_HDR_LEN); } else if (tftp_extract_block(pkt_buf->payload) == (args->block + 1)) { /* update our block number to match the block number just received */ args->block++; } /* Send the appropriate ACK pkt (the block number sent in the ACK pkt echoes * the block number of the DATA pkt we just received - see RFC1350) * NOTE!: If the DATA pkt we received did not have the appropriate block * number, then the args->block (our block number) is never updated and * we simply send "duplicate ACK" which has the same block number as the * last ACK pkt we sent. This lets the host know that we are still waiting * on block number args->block+1. */ tftp_send_ack_packet(upcb, addr, port, args->block); /* If the last write returned less than the maximum TFTP data pkt length, * then we've received the whole file and so we can quit (this is how TFTP * signals the end of a transfer!) */ if (pkt_buf->len < TFTP_DATA_PKT_LEN_MAX) { tftp_cleanup_wr(upcb, args); pbuf_free(pkt_buf); } else { pbuf_free(pkt_buf); return; } }
void wrq_recv_callback(void *_args, struct udp_pcb *upcb, struct pbuf *pkt_buf, struct ip_addr *addr, u16_t port) { tftp_connection_args *args = (tftp_connection_args *)_args; int n = 0; if (pkt_buf->len != pkt_buf->tot_len) { return; } /* Does this packet have any valid data to write? */ if ((pkt_buf->len > TFTP_DATA_PKT_HDR_LEN) && (tftp_extract_block(pkt_buf->payload) == (args->block + 1))) { /* write the received data to the file */ n = file_write(&file_CR, pkt_buf->len - TFTP_DATA_PKT_HDR_LEN, (euint8*)pkt_buf->payload + TFTP_DATA_PKT_HDR_LEN); if (n <= 0) { tftp_send_error_message(upcb, addr, port, TFTP_ERR_FILE_NOT_FOUND); /* close the connection */ tftp_cleanup_wr(upcb, args); /* close the connection */ } /* update our block number to match the block number just received */ args->block++; /* update total bytes */ (args->tot_bytes) += (pkt_buf->len - TFTP_DATA_PKT_HDR_LEN); /* This is a valid pkt but it has no data. This would occur if the file being written is an exact multiple of 512 bytes. In this case, the args->block value must still be updated, but we can skip everything else. */ } else if (tftp_extract_block(pkt_buf->payload) == (args->block + 1)) { /* update our block number to match the block number just received */ args->block++; } /* SEndTransferthe appropriate ACK pkt (the block number sent in the ACK pkt echoes * the block number of the DATA pkt we just received - see RFC1350) * NOTE!: If the DATA pkt we received did not have the appropriate block * number, then the args->block (our block number) is never updated and * we simply sEndTransfera "duplicate ACK" which has the same block number as the * last ACK pkt we sent. This lets the host know that we are still waiting * on block number args->block+1. */ tftp_send_ack_packet(upcb, addr, port, args->block); /* If the last write returned less than the maximum TFTP data pkt length, * then we've received the whole file and so we can quit (this is how TFTP * signals the EndTransferof a transfer!) */ if (pkt_buf->len < TFTP_DATA_PKT_LEN_MAX) { tftp_cleanup_wr(upcb, args); pbuf_free(pkt_buf); } else { pbuf_free(pkt_buf); return; } }