tftp.c 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. /*
  2. * Copyright (C) 2008 by Thermotemp GmbH. All rights reserved.
  3. * Copyright (C) 2002-2007 by egnite Software GmbH. All rights reserved.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions
  7. * are met:
  8. *
  9. * 1. Redistributions of source code must retain the above copyright
  10. * notice, this list of conditions and the following disclaimer.
  11. * 2. Redistributions in binary form must reproduce the above copyright
  12. * notice, this list of conditions and the following disclaimer in the
  13. * documentation and/or other materials provided with the distribution.
  14. * 3. Neither the name of the copyright holders nor the names of
  15. * contributors may be used to endorse or promote products derived
  16. * from this software without specific prior written permission.
  17. *
  18. * THIS SOFTWARE IS PROVIDED BY EGNITE SOFTWARE GMBH AND CONTRIBUTORS
  19. * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  20. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  21. * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL EGNITE
  22. * SOFTWARE GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  23. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  24. * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
  25. * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
  26. * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  27. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
  28. * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  29. * SUCH DAMAGE.
  30. *
  31. * For additional information see http://www.ethernut.de/
  32. */
  33. #include <stdio.h>
  34. #include <string.h>
  35. #include <sys/socket.h>
  36. #include <sys/heap.h>
  37. #include "default.h"
  38. #include "debug.h"
  39. #include "tftp.h"
  40. tftp_header tx_frame;
  41. tftp_header rx_frame;
  42. int tftp_receive(char *filename, u_long tftp_ip, int (*callback)(u_char *buffer, u_short block_size, u_long offset, void* user_data), void* user_data)
  43. {
  44. unsigned char retry;
  45. int len = 0;
  46. int rx_len = 0;
  47. int tx_len = 0;
  48. unsigned short block = 0;
  49. char *cp;
  50. UDPSOCKET *tftp_socket;
  51. u_long remote_ip;
  52. u_short remote_port = TFTP_PORT;
  53. u_long offset = 0;
  54. int total_bytes = 0;
  55. /*
  56. * Do nothing if there's no TFTP host configured.
  57. */
  58. tftp_socket = NutUdpCreateSocket(TFTP_PORT);
  59. if (tftp_socket == 0) {
  60. ERROR("Could not create TFTP UDP socket\r\n");
  61. goto error;
  62. }
  63. /*
  64. * Prepare the transmit buffer for a file request.
  65. */
  66. tx_frame.th_opcode = htons(TFTP_RRQ);
  67. tx_len = 2;
  68. cp = tx_frame.th_u.tu_stuff;
  69. INFO("TFTP Loading %s\r\n", filename);
  70. strcpy(cp, filename);
  71. len = strlen(filename) + 1;
  72. tx_len += len;
  73. cp += len;
  74. strcpy(cp, "octet");
  75. tx_len += 6;
  76. /*
  77. * Loop until we receive a packet with less than 512 bytes of data.
  78. */
  79. do {
  80. /*
  81. * Send file request or acknowledge and receive
  82. * a data block. Maximum 3 retries on timeout or error
  83. */
  84. for (retry = 0; retry < 3; retry++) {
  85. if (NutUdpSendTo(tftp_socket, tftp_ip, remote_port, &tx_frame, tx_len) == 0) {
  86. rx_len = NutUdpReceiveFrom(tftp_socket, &remote_ip, &remote_port, &rx_frame, sizeof(tftp_header), 5000);
  87. if (rx_len >= 4) break;
  88. }
  89. }
  90. /*
  91. * Can't reach the TFTP server or got a malformed
  92. * repsonse.
  93. */
  94. if (retry >= 3 || rx_len < 4) {
  95. goto error;
  96. }
  97. /*
  98. * Accept data blocks only. Anything else will stop
  99. * the transfer with an error.
  100. */
  101. if (ntohs(rx_frame.th_opcode) != TFTP_DATA) {
  102. goto error;
  103. }
  104. /*
  105. * If this was the first block we received, prepare
  106. * the send buffer for sending ACKs.
  107. */
  108. if (block == 0) {
  109. tx_frame.th_opcode = htons(TFTP_ACK);
  110. tx_len = 4;
  111. }
  112. /*
  113. * If this block is out of sequence, we ignore it.
  114. * However, if we missed the first block, return
  115. * with an error.
  116. */
  117. if (ntohs(rx_frame.th_u.tu_block) != block + 1) {
  118. if (block == 0) {
  119. goto error;
  120. }
  121. continue;
  122. }
  123. /*
  124. * Burn the received data into the flash ROM.
  125. */
  126. if (rx_len > 4) {
  127. //INFO("TFTP received block %d\r\n", block);
  128. INFO(".");
  129. callback(rx_frame.th_data, rx_len-4, offset, user_data);
  130. total_bytes += rx_len-4;
  131. offset += MIN(rx_len - 4, 512);
  132. }
  133. /*
  134. * Update our block counter.
  135. */
  136. block++;
  137. tx_frame.th_u.tu_block = htons(block);
  138. } while (rx_len >= 516);
  139. /*
  140. * Send the last ACK.
  141. */
  142. NutUdpSendTo(tftp_socket, tftp_ip, remote_port, &tx_frame, tx_len);
  143. return total_bytes;
  144. error:
  145. return -1;
  146. }