00001 /*
00002 * Copyright (C) 2002 by egnite Software GmbH. All rights reserved.
00003 *
00004 * Redistribution and use in source and binary forms, with or without
00005 * modification, are permitted provided that the following conditions
00006 * are met:
00007 *
00008 * 1. Redistributions of source code must retain the above copyright
00009 * notice, this list of conditions and the following disclaimer.
00010 * 2. Redistributions in binary form must reproduce the above copyright
00011 * notice, this list of conditions and the following disclaimer in the
00012 * documentation and/or other materials provided with the distribution.
00013 * 3. All advertising materials mentioning features or use of this
00014 * software must display the following acknowledgement:
00015 *
00016 * This product includes software developed by egnite Software GmbH
00017 * and its contributors.
00018 *
00019 * THIS SOFTWARE IS PROVIDED BY EGNITE SOFTWARE GMBH AND CONTRIBUTORS
00020 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00021 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00022 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL EGNITE
00023 * SOFTWARE GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00024 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00025 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
00026 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
00027 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
00028 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
00029 * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00030 * SUCH DAMAGE.
00031 *
00032 * For additional information see http://www.ethernut.de/
00033 */
00034
00035 /*
00036 * $Log: tftp.c,v $
00037 * Revision 1.1 2002/08/01 17:34:30 harald
00038 * First check in
00039 *
00040 */
00041
00042 #include <io.h>
00043 #include <string.h>
00044
00045 #include "flash.h"
00046 #include "eboot.h"
00047 #include "tftp.h"
00048
00049 /*!
00050 * \addtogroup xgTftp
00051 */
00052 /*@{*/
00053
00054 /*!
00055 * \brief Erase and program a page in the flash ROM.
00056 *
00057 * \param page The page number to program, 0..479.
00058 * \param data Pointer to the new page contents.
00059 * \param len Number of bytes to program. If this is
00060 * less than 256, then the remaining bytes
00061 * will be filled with 0xFF.
00062 */
00063 static void FlashPage(u_short page, void *data, u_short len)
00064 {
00065 u_short i;
00066 u_short *wp = data;
00067
00068 if(len > 256)
00069 len = 256;
00070
00071 if(page >= 256) {
00072 if(page >= 480)
00073 return;
00074 outp(1, RAMPZ);
00075 }
00076 else
00077 outp(0, RAMPZ);
00078 page <<= 8;
00079
00080 SpmCommand(page, (1 << PGERS) | (1 << SPMEN));
00081 SpmCommand(0, (1 << RWWSRE) | (1 << SPMEN));
00082
00083 for(i = 0; i < len; i += 2, wp++)
00084 SpmBufferFill(i, *wp);
00085 for(; i < 256; i += 2)
00086 SpmBufferFill(i, 0xFFFF);
00087
00088 SpmCommand(page, (1 << PGWRT) | (1 << SPMEN));
00089 SpmCommand(0, (1 << RWWSRE) | (1 << SPMEN));
00090 }
00091
00092 /*!
00093 * \brief Set up a TFTP header for a file request.
00094 *
00095 * \param th Points to the TFTP header structure.
00096 * \param request Type of the request, either TFTP_RRQ or TFTP_WRQ.
00097 * \param name Name of the files.
00098 * \param mode Transfer mode.
00099 */
00100 static int MakeRequest(TFTPHDR *th, u_short request, u_char *name, u_char *mode)
00101 {
00102 u_char *cp;
00103
00104 th->th_opcode = htons(request);
00105 cp = th->th_u.tu_stuff;
00106 while(*name)
00107 *cp++ = *name++;
00108 *cp++ = 0;
00109 while(*mode)
00110 *cp++ = *mode++;
00111 *cp++ = 0;
00112 return (u_short)cp - (u_short)th;
00113 }
00114
00115 /*!
00116 * \brief Download a file from a TFTP server and burn it into the flash ROM.
00117 *
00118 * \return 0 on success, -1 otherwise.
00119 */
00120 int TftpRecv(void)
00121 {
00122 u_char retry;
00123 int rlen = 0;
00124 int slen;
00125 u_short sport = 1024;
00126 u_short tport = 69;
00127 u_short block = 0;
00128
00129 /*
00130 * Prepare the transmit buffer for a file request.
00131 */
00132 slen = MakeRequest(&sframe.u.tftp, TFTP_RRQ, bootfile, "octet");
00133
00134 /*
00135 * Lopp until we receive a packet with less than 512 bytes of data.
00136 */
00137 do {
00138
00139 /*
00140 * Send file request or acknowledge and receive
00141 * a data block.
00142 */
00143 for(retry = 0; retry < 3; retry++) {
00144 if(UdpOutput(server_ip, tport, sport, slen) >= 0) {
00145 if((rlen = UdpInput(sport, 5000)) >= 4)
00146 break;
00147 }
00148 }
00149
00150 /*
00151 * Can't reach the TFTP server or got a malformed
00152 * repsonse.
00153 */
00154 if(rlen < 4)
00155 return -1;
00156
00157
00158 /*
00159 * Accept data blocks only. Anything else will stop
00160 * the transfer with an error.
00161 */
00162 if(ntohs(rframe.u.tftp.th_opcode) != TFTP_DATA)
00163 return -1;
00164
00165 /*
00166 * If this was the first block we received, prepare
00167 * the send buffer for sending ACKs.
00168 */
00169 if(block == 0) {
00170 tport = ntohs(rframe.udp_hdr.uh_sport);
00171 sframe.u.tftp.th_opcode = htons(TFTP_ACK);
00172 slen = 4;
00173 }
00174
00175 /*
00176 * If this block is out of sequence, we ignore it.
00177 * However, if we missed the first block, return
00178 * with an error.
00179 */
00180 if(ntohs(rframe.u.tftp.th_u.tu_block) != block + 1) {
00181 if(block == 0)
00182 return -1;
00183 continue;
00184 }
00185
00186 /*
00187 * Burn the received data into the flash ROM.
00188 */
00189 if(rlen > 4) {
00190 FlashPage(block << 1, rframe.u.tftp.th_data, rlen - 4);
00191 if(rlen > 260)
00192 FlashPage((block << 1) + 1, &rframe.u.tftp.th_data[256], rlen - 260);
00193 }
00194
00195 /*
00196 * Update our block counter.
00197 */
00198 block++;
00199 sframe.u.tftp.th_u.tu_block = htons(block);
00200
00201 } while(rlen >= 516);
00202
00203 /*
00204 * Send the last ACK.
00205 */
00206 UdpOutput(server_ip, tport, sport, slen);
00207
00208 return 0;
00209 }
00210
00211 /*@}*/