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 /*@}*/