A stack which works with or without an Mbed os library. Provides IPv4 or IPv6 with a full 1500 byte buffer.
Dependents: oldheating gps motorhome heating
tftp.c
00001 #include <stdint.h> 00002 #include <stdbool.h> 00003 00004 #include "log.h" 00005 #include "net.h" 00006 #include "action.h" 00007 #include "eth.h" 00008 #include "dhcp.h" 00009 #include "udp.h" 00010 #include "dns.h" 00011 #include "tftp.h" 00012 #include "mstimer.h" 00013 #include "resolve.h" 00014 #include "dnslabel.h" 00015 00016 bool TftpTrace = false; 00017 00018 #define WRITE_TIMEOUT_MS 7000 //Make this longer than the resolve time which is up to 3 seconds 00019 00020 #define TFTP_RRQ 1 00021 #define TFTP_WRQ 2 00022 #define TFTP_DATA 3 00023 #define TFTP_ACK 4 00024 #define TFTP_ERROR 5 00025 00026 static void logOp(char* p) 00027 { 00028 if (*p) 00029 { 00030 LogF("Unknown op code %02x", *p); LogF("%02x", *++p); 00031 return; 00032 } 00033 p++; 00034 switch (*p) 00035 { 00036 case TFTP_RRQ: Log ("RRQ") ; break; 00037 case TFTP_WRQ: Log ("WRQ") ; break; 00038 case TFTP_DATA: Log ("DATA") ; break; 00039 case TFTP_ACK: Log ("ACK") ; break; 00040 case TFTP_ERROR: Log ("ERROR") ; break; 00041 default: LogF("Unknown op code 00%02x", *p); break; 00042 } 00043 } 00044 00045 static void logError(char* p) 00046 { 00047 if (*p) 00048 { 00049 LogF("Unknown error code %02x", *p); 00050 LogF("%02x", *++p); 00051 return; 00052 } 00053 p++; 00054 switch (*p) 00055 { 00056 case 0: Log ("Not defined, see error message." ); break; 00057 case 1: Log ("File not found." ); break; 00058 case 2: Log ("Access violation." ); break; 00059 case 3: Log ("Disk full or allocation exceeded."); break; 00060 case 4: Log ("Illegal TFTP operation." ); break; 00061 case 5: Log ("Unknown transfer ID." ); break; 00062 case 6: Log ("File already exists." ); break; 00063 case 7: Log ("No such user." ); break; 00064 default: LogF("Unknown error code 00%02x", *p ); break; 00065 } 00066 } 00067 bool TftpSendRequestsViaIp4 = false; 00068 uint32_t TftpServerIp4; 00069 char TftpServerIp6[16]; 00070 int TftpWriteStatus = TFTP_WRITE_STATUS_UNAVAILABLE; 00071 char TftpServerName[DNS_MAX_LABEL_LENGTH+1]; 00072 char TftpFileName [DNS_MAX_LABEL_LENGTH+1]; 00073 00074 int (*TftpGetNextByteFunction)(); 00075 00076 static void logHeader(int size, char* p) 00077 { 00078 if (NetTraceVerbose) 00079 { 00080 Log ("TFTP header\r\n"); 00081 Log (" Op code "); logOp(p); Log("\r\n"); 00082 Log (" Size "); LogF("%d", size); Log("\r\n"); 00083 } 00084 else 00085 { 00086 Log ("TFTP header"); 00087 Log (": Op "); logOp(p); 00088 LogF(", %d bytes", size); 00089 Log ("\r\n"); 00090 } 00091 } 00092 static int sendBlock(uint16_t block, int* pSize, char* pHeader) 00093 { 00094 /*2 bytes 2 bytes n bytes 00095 ---------------------------------- 00096 | Opcode | Block # | Data | 00097 ---------------------------------- */ 00098 char* p = pHeader; 00099 *p++ = 0; 00100 *p++ = TFTP_DATA; 00101 *p++ = block >> 8; 00102 *p++ = block & 0xFF; 00103 00104 int len = 0; 00105 while (len < 512) 00106 { 00107 int c = TftpGetNextByteFunction(); 00108 if (c == -1) break; 00109 *p++ = c; 00110 len++; 00111 } 00112 if (len < 512) TftpWriteStatus = TFTP_WRITE_STATUS_NONE; 00113 *pSize = p - pHeader; 00114 return UNICAST_TFTP; 00115 } 00116 static void handleError(char* p) 00117 { 00118 /*2 bytes 2 bytes string 1 byte 00119 ----------------------------------------- 00120 | ERROR | ErrorCode | ErrMsg | 0 | 00121 ----------------------------------------- */ 00122 p += 2; //Skip the op code which we already know 00123 if (NetTraceNewLine) Log("\r\n"); 00124 LogTime("TFTP error - "); 00125 logError(p); p += 2; 00126 Log(p); 00127 Log("\r\n"); 00128 TftpWriteStatus = TFTP_WRITE_STATUS_NONE; 00129 } 00130 static int handleAck(char* pHeaderRx, int* pSizeTx, char* pHeaderTx) 00131 { 00132 /* 2 bytes 2 bytes 00133 ----------------------- 00134 | ACK | Block # | 00135 ----------------------- */ 00136 char* p = pHeaderRx; 00137 p += 2; //Skip the op code which we already know 00138 uint16_t block = *p++; 00139 block <<= 8; 00140 block += *p++; 00141 00142 return sendBlock(block + 1, pSizeTx, pHeaderTx); 00143 } 00144 static int sendRequest(int* pSize, char* pHeader) 00145 { 00146 /*2 bytes string 1 byte string 1 byte 00147 ----------------------------------------------- 00148 | WRQ | Filename | 0 | Mode | 0 | 00149 ----------------------------------------------- */ 00150 char* p = pHeader; 00151 *p++ = 0; 00152 *p++ = TFTP_WRQ; 00153 char* pName = TftpFileName; 00154 while (*pName) *p++ = *pName++; 00155 *p++ = 0; 00156 const char* pMode = "octet"; 00157 while (*pMode) *p++ = *pMode++; 00158 *p++ = 0; 00159 *pSize = p - pHeader; 00160 return UNICAST_TFTP; 00161 } 00162 int TftpHandlePacketReceived(void (*traceback)(void), int sizeRx, void * pPacketRx, int* pSizeTx, void* pPacketTx) 00163 { 00164 char* pHeaderRx = (char*)pPacketRx; 00165 char* pHeaderTx = (char*)pPacketTx; 00166 00167 char* p = pHeaderRx; 00168 00169 if (*p) 00170 { 00171 LogTimeF("Expected high byte of op code to be zero not %u\r\n", *p); 00172 return DO_NOTHING; 00173 } 00174 if (TftpTrace) 00175 { 00176 if (NetTraceNewLine) Log("\r\n"); 00177 LogTimeF("TFTP received packet\r\n"); 00178 if (NetTraceStack) traceback(); 00179 logHeader(sizeRx, pHeaderRx); 00180 } 00181 p++; 00182 int dest = DO_NOTHING; 00183 switch (*p) 00184 { 00185 case TFTP_ACK: 00186 if (TftpWriteStatus == TFTP_WRITE_STATUS_NONE) return DO_NOTHING; 00187 dest = handleAck(pHeaderRx, pSizeTx, pHeaderTx); 00188 break; 00189 case TFTP_ERROR: 00190 handleError(pHeaderRx); 00191 return DO_NOTHING; 00192 default: 00193 LogTimeF("\r\nTFTP packet unknown mode %d\r\n", *p); 00194 return DO_NOTHING; 00195 } 00196 00197 if (TftpTrace) logHeader(*pSizeTx, pHeaderTx); 00198 00199 return ActionMakeFromDestAndTrace(dest, TftpTrace && NetTraceStack); 00200 } 00201 static bool isTimedOut() 00202 { 00203 static uint32_t writeStartMs = 0; 00204 00205 if (TftpWriteStatus == TFTP_WRITE_STATUS_NONE || TftpWriteStatus == TFTP_WRITE_STATUS_UNAVAILABLE) writeStartMs = MsTimerCount; 00206 00207 if (MsTimerRelative(writeStartMs, WRITE_TIMEOUT_MS)) 00208 { 00209 LogTime("TFTP - write operation timed out so reset\r\n"); 00210 writeStartMs = MsTimerCount; 00211 return true; 00212 } 00213 return false; 00214 } 00215 static bool isOkToGo() 00216 { 00217 if (!TftpServerName[0]) 00218 { 00219 LogTimeF("TftpPollForRequestToSend - A request to send a client message has been made but no server name has been specified\r\n"); 00220 return false; 00221 } 00222 00223 if (!TftpGetNextByteFunction) 00224 { 00225 LogTimeF("TftpPollForRequestToSend - A request to send a client message has been made but TFTP has not been plumbed into a file stream\r\n"); 00226 return false; 00227 } 00228 return true; 00229 } 00230 int TftpPollForPacketToSend(int type, void* pPacket, int* pSize) 00231 { 00232 if (type == ETH_IPV4) 00233 { 00234 if (!DhcpLocalIp) 00235 { 00236 TftpWriteStatus = TFTP_WRITE_STATUS_UNAVAILABLE; 00237 } 00238 else 00239 { 00240 if (TftpWriteStatus == TFTP_WRITE_STATUS_UNAVAILABLE) TftpWriteStatus = TFTP_WRITE_STATUS_NONE; 00241 } 00242 } 00243 if (isTimedOut() ) { TftpWriteStatus = TFTP_WRITE_STATUS_NONE; return DO_NOTHING; } 00244 if (TftpWriteStatus != TFTP_WRITE_STATUS_REQUEST ) { return DO_NOTHING; } 00245 if (!isOkToGo() ) { TftpWriteStatus = TFTP_WRITE_STATUS_NONE; return DO_NOTHING; } 00246 if (!Resolve(TftpServerName, type, &TftpServerIp4, TftpServerIp6)) { return DO_NOTHING; } 00247 00248 //Have IP and MAC so send request 00249 TftpWriteStatus = TFTP_WRITE_STATUS_IN_PROGRESS; 00250 int dest = sendRequest(pSize, (char*)pPacket); 00251 if (TftpTrace) 00252 { 00253 if (NetTraceNewLine) Log("\r\n"); 00254 LogTimeF("TFTP Sending request\r\n"); 00255 logHeader(*pSize, (char*)pPacket); 00256 } 00257 return ActionMakeFromDestAndTrace(dest, TftpTrace && NetTraceStack); 00258 }
Generated on Tue Jul 12 2022 18:53:40 by 1.7.2