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

Committer:
andrewboyson
Date:
Fri Jan 25 17:37:51 2019 +0000
Revision:
116:60521b29e4c9
Parent:
115:5c003909bcf3
Child:
128:79052cb4a41c
Added backoff delay to DHCP

Who changed what in which revision?

UserRevisionLine numberNew contents of line
andrewboyson 115:5c003909bcf3 1 #include <stdint.h>
andrewboyson 115:5c003909bcf3 2 #include <stdbool.h>
andrewboyson 115:5c003909bcf3 3
andrewboyson 115:5c003909bcf3 4 #include "log.h"
andrewboyson 115:5c003909bcf3 5 #include "net.h"
andrewboyson 115:5c003909bcf3 6 #include "action.h"
andrewboyson 115:5c003909bcf3 7 #include "udp.h"
andrewboyson 115:5c003909bcf3 8 #include "dns.h"
andrewboyson 115:5c003909bcf3 9 #include "tftp.h"
andrewboyson 115:5c003909bcf3 10 #include "mstimer.h"
andrewboyson 116:60521b29e4c9 11 #include "resolve.h"
andrewboyson 115:5c003909bcf3 12
andrewboyson 115:5c003909bcf3 13 bool TftpTrace = false;
andrewboyson 115:5c003909bcf3 14
andrewboyson 116:60521b29e4c9 15 #define WRITE_TIMEOUT_MS 6000 //Make this longer than the resolve time which is up to 3 seconds
andrewboyson 115:5c003909bcf3 16
andrewboyson 115:5c003909bcf3 17 #define TFTP_RRQ 1
andrewboyson 115:5c003909bcf3 18 #define TFTP_WRQ 2
andrewboyson 115:5c003909bcf3 19 #define TFTP_DATA 3
andrewboyson 115:5c003909bcf3 20 #define TFTP_ACK 4
andrewboyson 115:5c003909bcf3 21 #define TFTP_ERROR 5
andrewboyson 115:5c003909bcf3 22
andrewboyson 115:5c003909bcf3 23 static void logOp(char* p)
andrewboyson 115:5c003909bcf3 24 {
andrewboyson 115:5c003909bcf3 25 if (*p)
andrewboyson 115:5c003909bcf3 26 {
andrewboyson 115:5c003909bcf3 27 LogF("Unknown op code %02x%02x", *p, *++p);
andrewboyson 115:5c003909bcf3 28 return;
andrewboyson 115:5c003909bcf3 29 }
andrewboyson 115:5c003909bcf3 30 p++;
andrewboyson 115:5c003909bcf3 31 switch (*p)
andrewboyson 115:5c003909bcf3 32 {
andrewboyson 115:5c003909bcf3 33 case TFTP_RRQ: Log ("RRQ") ; break;
andrewboyson 115:5c003909bcf3 34 case TFTP_WRQ: Log ("WRQ") ; break;
andrewboyson 115:5c003909bcf3 35 case TFTP_DATA: Log ("DATA") ; break;
andrewboyson 115:5c003909bcf3 36 case TFTP_ACK: Log ("ACK") ; break;
andrewboyson 115:5c003909bcf3 37 case TFTP_ERROR: Log ("ERROR") ; break;
andrewboyson 115:5c003909bcf3 38 default: LogF("Unknown op code 00%02x", *p); break;
andrewboyson 115:5c003909bcf3 39 }
andrewboyson 115:5c003909bcf3 40 }
andrewboyson 115:5c003909bcf3 41
andrewboyson 115:5c003909bcf3 42 static void logError(char* p)
andrewboyson 115:5c003909bcf3 43 {
andrewboyson 115:5c003909bcf3 44 if (*p)
andrewboyson 115:5c003909bcf3 45 {
andrewboyson 115:5c003909bcf3 46 LogF("Unknown error code %02x%02x", *p, *++p);
andrewboyson 115:5c003909bcf3 47 return;
andrewboyson 115:5c003909bcf3 48 }
andrewboyson 115:5c003909bcf3 49 p++;
andrewboyson 115:5c003909bcf3 50 switch (*p)
andrewboyson 115:5c003909bcf3 51 {
andrewboyson 115:5c003909bcf3 52 case 0: Log ("Not defined, see error message." ); break;
andrewboyson 115:5c003909bcf3 53 case 1: Log ("File not found." ); break;
andrewboyson 115:5c003909bcf3 54 case 2: Log ("Access violation." ); break;
andrewboyson 115:5c003909bcf3 55 case 3: Log ("Disk full or allocation exceeded."); break;
andrewboyson 115:5c003909bcf3 56 case 4: Log ("Illegal TFTP operation." ); break;
andrewboyson 115:5c003909bcf3 57 case 5: Log ("Unknown transfer ID." ); break;
andrewboyson 115:5c003909bcf3 58 case 6: Log ("File already exists." ); break;
andrewboyson 115:5c003909bcf3 59 case 7: Log ("No such user." ); break;
andrewboyson 115:5c003909bcf3 60 default: LogF("Unknown error code 00%02x", *p ); break;
andrewboyson 115:5c003909bcf3 61 }
andrewboyson 115:5c003909bcf3 62 }
andrewboyson 115:5c003909bcf3 63 bool TftpSendRequestsViaIp4 = false;
andrewboyson 115:5c003909bcf3 64 uint32_t TftpServerIp4;
andrewboyson 115:5c003909bcf3 65 char TftpServerIp6[16];
andrewboyson 115:5c003909bcf3 66 int TftpWriteStatus = TFTP_WRITE_STATUS_NONE;
andrewboyson 115:5c003909bcf3 67 char TftpServerName[DNS_MAX_LABEL_LENGTH+1];
andrewboyson 115:5c003909bcf3 68 char TftpFileName [DNS_MAX_LABEL_LENGTH+1];
andrewboyson 115:5c003909bcf3 69
andrewboyson 115:5c003909bcf3 70 int (*TftpGetNextByteFunction)();
andrewboyson 115:5c003909bcf3 71
andrewboyson 115:5c003909bcf3 72 static void logHeader(int size, char* p)
andrewboyson 115:5c003909bcf3 73 {
andrewboyson 115:5c003909bcf3 74 if (NetTraceVerbose)
andrewboyson 115:5c003909bcf3 75 {
andrewboyson 115:5c003909bcf3 76 Log ("TFTP header\r\n");
andrewboyson 115:5c003909bcf3 77 Log (" Op code "); logOp(p); Log("\r\n");
andrewboyson 115:5c003909bcf3 78 Log (" Size "); LogF("%d", size); Log("\r\n");
andrewboyson 115:5c003909bcf3 79 }
andrewboyson 115:5c003909bcf3 80 else
andrewboyson 115:5c003909bcf3 81 {
andrewboyson 115:5c003909bcf3 82 Log ("TFTP header");
andrewboyson 115:5c003909bcf3 83 Log (": Op "); logOp(p);
andrewboyson 115:5c003909bcf3 84 LogF(", %d bytes", size);
andrewboyson 115:5c003909bcf3 85 Log ("\r\n");
andrewboyson 115:5c003909bcf3 86 }
andrewboyson 115:5c003909bcf3 87 }
andrewboyson 115:5c003909bcf3 88 static int sendBlock(uint16_t block, int* pSize, char* pHeader)
andrewboyson 115:5c003909bcf3 89 {
andrewboyson 115:5c003909bcf3 90 /*2 bytes 2 bytes n bytes
andrewboyson 115:5c003909bcf3 91 ----------------------------------
andrewboyson 115:5c003909bcf3 92 | Opcode | Block # | Data |
andrewboyson 115:5c003909bcf3 93 ---------------------------------- */
andrewboyson 115:5c003909bcf3 94 char* p = pHeader;
andrewboyson 115:5c003909bcf3 95 *p++ = 0;
andrewboyson 115:5c003909bcf3 96 *p++ = TFTP_DATA;
andrewboyson 115:5c003909bcf3 97 *p++ = block >> 8;
andrewboyson 115:5c003909bcf3 98 *p++ = block & 0xFF;
andrewboyson 115:5c003909bcf3 99
andrewboyson 115:5c003909bcf3 100 int len = 0;
andrewboyson 115:5c003909bcf3 101 while (len < 512)
andrewboyson 115:5c003909bcf3 102 {
andrewboyson 115:5c003909bcf3 103 int c = TftpGetNextByteFunction();
andrewboyson 115:5c003909bcf3 104 if (c == -1) break;
andrewboyson 115:5c003909bcf3 105 *p++ = c;
andrewboyson 115:5c003909bcf3 106 len++;
andrewboyson 115:5c003909bcf3 107 }
andrewboyson 115:5c003909bcf3 108 if (len < 512) TftpWriteStatus = TFTP_WRITE_STATUS_NONE;
andrewboyson 115:5c003909bcf3 109 *pSize = p - pHeader;
andrewboyson 115:5c003909bcf3 110 return UNICAST_TFTP;
andrewboyson 115:5c003909bcf3 111 }
andrewboyson 115:5c003909bcf3 112 static void handleError(char* p)
andrewboyson 115:5c003909bcf3 113 {
andrewboyson 115:5c003909bcf3 114 /*2 bytes 2 bytes string 1 byte
andrewboyson 115:5c003909bcf3 115 -----------------------------------------
andrewboyson 115:5c003909bcf3 116 | ERROR | ErrorCode | ErrMsg | 0 |
andrewboyson 115:5c003909bcf3 117 ----------------------------------------- */
andrewboyson 115:5c003909bcf3 118 p += 2; //Skip the op code which we already know
andrewboyson 115:5c003909bcf3 119 if (NetTraceNewLine) Log("\r\n");
andrewboyson 115:5c003909bcf3 120 LogTime("TFTP error - ");
andrewboyson 115:5c003909bcf3 121 logError(p); p += 2;
andrewboyson 115:5c003909bcf3 122 Log(p);
andrewboyson 115:5c003909bcf3 123 Log("\r\n");
andrewboyson 115:5c003909bcf3 124 TftpWriteStatus = TFTP_WRITE_STATUS_NONE;
andrewboyson 115:5c003909bcf3 125 }
andrewboyson 115:5c003909bcf3 126 static int handleAck(char* pHeaderRx, int* pSizeTx, char* pHeaderTx)
andrewboyson 115:5c003909bcf3 127 {
andrewboyson 115:5c003909bcf3 128 /* 2 bytes 2 bytes
andrewboyson 115:5c003909bcf3 129 -----------------------
andrewboyson 115:5c003909bcf3 130 | ACK | Block # |
andrewboyson 115:5c003909bcf3 131 ----------------------- */
andrewboyson 115:5c003909bcf3 132 char* p = pHeaderRx;
andrewboyson 115:5c003909bcf3 133 p += 2; //Skip the op code which we already know
andrewboyson 115:5c003909bcf3 134 uint16_t block = *p++;
andrewboyson 115:5c003909bcf3 135 block <<= 8;
andrewboyson 115:5c003909bcf3 136 block += *p++;
andrewboyson 115:5c003909bcf3 137
andrewboyson 115:5c003909bcf3 138 return sendBlock(block + 1, pSizeTx, pHeaderTx);
andrewboyson 115:5c003909bcf3 139 }
andrewboyson 115:5c003909bcf3 140 static int sendRequest(int* pSize, char* pHeader)
andrewboyson 115:5c003909bcf3 141 {
andrewboyson 115:5c003909bcf3 142 /*2 bytes string 1 byte string 1 byte
andrewboyson 115:5c003909bcf3 143 -----------------------------------------------
andrewboyson 115:5c003909bcf3 144 | WRQ | Filename | 0 | Mode | 0 |
andrewboyson 115:5c003909bcf3 145 ----------------------------------------------- */
andrewboyson 115:5c003909bcf3 146 char* p = pHeader;
andrewboyson 115:5c003909bcf3 147 *p++ = 0;
andrewboyson 115:5c003909bcf3 148 *p++ = TFTP_WRQ;
andrewboyson 115:5c003909bcf3 149 char* pName = TftpFileName;
andrewboyson 115:5c003909bcf3 150 while (*pName) *p++ = *pName++;
andrewboyson 115:5c003909bcf3 151 *p++ = 0;
andrewboyson 115:5c003909bcf3 152 const char* pMode = "octet";
andrewboyson 115:5c003909bcf3 153 while (*pMode) *p++ = *pMode++;
andrewboyson 115:5c003909bcf3 154 *p++ = 0;
andrewboyson 115:5c003909bcf3 155 *pSize = p - pHeader;
andrewboyson 115:5c003909bcf3 156 return UNICAST_TFTP;
andrewboyson 115:5c003909bcf3 157 }
andrewboyson 115:5c003909bcf3 158 int TftpHandlePacketReceived(void (*traceback)(void), int sizeRx, void * pPacketRx, int* pSizeTx, void* pPacketTx)
andrewboyson 115:5c003909bcf3 159 {
andrewboyson 115:5c003909bcf3 160 char* pHeaderRx = (char*)pPacketRx;
andrewboyson 115:5c003909bcf3 161 char* pHeaderTx = (char*)pPacketTx;
andrewboyson 115:5c003909bcf3 162
andrewboyson 115:5c003909bcf3 163 char* p = pHeaderRx;
andrewboyson 115:5c003909bcf3 164
andrewboyson 115:5c003909bcf3 165 if (*p)
andrewboyson 115:5c003909bcf3 166 {
andrewboyson 115:5c003909bcf3 167 LogTimeF("Expected high byte of op code to be zero not %u\r\n", *p);
andrewboyson 115:5c003909bcf3 168 return DO_NOTHING;
andrewboyson 115:5c003909bcf3 169 }
andrewboyson 115:5c003909bcf3 170 if (TftpTrace)
andrewboyson 115:5c003909bcf3 171 {
andrewboyson 115:5c003909bcf3 172 if (NetTraceNewLine) Log("\r\n");
andrewboyson 115:5c003909bcf3 173 LogTimeF("TFTP received packet\r\n");
andrewboyson 115:5c003909bcf3 174 if (NetTraceStack) traceback();
andrewboyson 115:5c003909bcf3 175 logHeader(sizeRx, pHeaderRx);
andrewboyson 115:5c003909bcf3 176 }
andrewboyson 115:5c003909bcf3 177 p++;
andrewboyson 115:5c003909bcf3 178 int dest = DO_NOTHING;
andrewboyson 115:5c003909bcf3 179 switch (*p)
andrewboyson 115:5c003909bcf3 180 {
andrewboyson 115:5c003909bcf3 181 case TFTP_ACK:
andrewboyson 115:5c003909bcf3 182 if (TftpWriteStatus == TFTP_WRITE_STATUS_NONE) return DO_NOTHING;
andrewboyson 115:5c003909bcf3 183 dest = handleAck(pHeaderRx, pSizeTx, pHeaderTx);
andrewboyson 115:5c003909bcf3 184 break;
andrewboyson 115:5c003909bcf3 185 case TFTP_ERROR:
andrewboyson 115:5c003909bcf3 186 handleError(pHeaderRx);
andrewboyson 115:5c003909bcf3 187 return DO_NOTHING;
andrewboyson 115:5c003909bcf3 188 default:
andrewboyson 115:5c003909bcf3 189 LogTimeF("\r\nTFTP packet unknown mode %d\r\n", *p);
andrewboyson 115:5c003909bcf3 190 return DO_NOTHING;
andrewboyson 115:5c003909bcf3 191 }
andrewboyson 115:5c003909bcf3 192
andrewboyson 115:5c003909bcf3 193 if (TftpTrace) logHeader(*pSizeTx, pHeaderTx);
andrewboyson 115:5c003909bcf3 194
andrewboyson 115:5c003909bcf3 195 return ActionMakeFromDestAndTrace(dest, TftpTrace && NetTraceStack);
andrewboyson 115:5c003909bcf3 196 }
andrewboyson 115:5c003909bcf3 197 static bool isTimedOut()
andrewboyson 115:5c003909bcf3 198 {
andrewboyson 115:5c003909bcf3 199 static uint32_t writeStartMs = 0;
andrewboyson 115:5c003909bcf3 200
andrewboyson 115:5c003909bcf3 201 if (TftpWriteStatus == TFTP_WRITE_STATUS_NONE) writeStartMs = MsTimerCount;
andrewboyson 115:5c003909bcf3 202
andrewboyson 115:5c003909bcf3 203 if (MsTimerHasElapsed(writeStartMs, WRITE_TIMEOUT_MS))
andrewboyson 115:5c003909bcf3 204 {
andrewboyson 115:5c003909bcf3 205 LogTime("TFTP - write operation timed out so reset\r\n");
andrewboyson 115:5c003909bcf3 206 writeStartMs = MsTimerCount;
andrewboyson 115:5c003909bcf3 207 return true;
andrewboyson 115:5c003909bcf3 208 }
andrewboyson 115:5c003909bcf3 209 return false;
andrewboyson 115:5c003909bcf3 210 }
andrewboyson 115:5c003909bcf3 211 static bool isOkToGo()
andrewboyson 115:5c003909bcf3 212 {
andrewboyson 115:5c003909bcf3 213 if (!TftpServerName[0])
andrewboyson 115:5c003909bcf3 214 {
andrewboyson 115:5c003909bcf3 215 LogTimeF("TftpPollForRequestToSend - A request to send a client message has been made but no server name has been specified\r\n");
andrewboyson 115:5c003909bcf3 216 return false;
andrewboyson 115:5c003909bcf3 217 }
andrewboyson 115:5c003909bcf3 218
andrewboyson 115:5c003909bcf3 219 if (!TftpGetNextByteFunction)
andrewboyson 115:5c003909bcf3 220 {
andrewboyson 115:5c003909bcf3 221 LogTimeF("TftpPollForRequestToSend - A request to send a client message has been made but TFTP has not been plumbed into a file stream\r\n");
andrewboyson 115:5c003909bcf3 222 return false;
andrewboyson 115:5c003909bcf3 223 }
andrewboyson 115:5c003909bcf3 224 return true;
andrewboyson 115:5c003909bcf3 225 }
andrewboyson 115:5c003909bcf3 226 int TftpPollForPacketToSend(int type, void* pPacket, int* pSize)
andrewboyson 115:5c003909bcf3 227 {
andrewboyson 116:60521b29e4c9 228 if (isTimedOut() ) { TftpWriteStatus = TFTP_WRITE_STATUS_NONE; return DO_NOTHING; }
andrewboyson 116:60521b29e4c9 229 if (TftpWriteStatus != TFTP_WRITE_STATUS_REQUEST ) { return DO_NOTHING; }
andrewboyson 116:60521b29e4c9 230 if (!isOkToGo() ) { TftpWriteStatus = TFTP_WRITE_STATUS_NONE; return DO_NOTHING; }
andrewboyson 116:60521b29e4c9 231 if (!Resolve(TftpServerName, type, &TftpServerIp4, TftpServerIp6)) { return DO_NOTHING; }
andrewboyson 115:5c003909bcf3 232
andrewboyson 115:5c003909bcf3 233 //Have IP and MAC so send request
andrewboyson 115:5c003909bcf3 234 TftpWriteStatus = TFTP_WRITE_STATUS_IN_PROGRESS;
andrewboyson 115:5c003909bcf3 235 int dest = sendRequest(pSize, (char*)pPacket);
andrewboyson 115:5c003909bcf3 236 if (TftpTrace)
andrewboyson 115:5c003909bcf3 237 {
andrewboyson 115:5c003909bcf3 238 if (NetTraceNewLine) Log("\r\n");
andrewboyson 115:5c003909bcf3 239 LogTimeF("TFTP Sending request\r\n");
andrewboyson 115:5c003909bcf3 240 logHeader(*pSize, (char*)pPacket);
andrewboyson 115:5c003909bcf3 241 }
andrewboyson 115:5c003909bcf3 242 return ActionMakeFromDestAndTrace(dest, TftpTrace && NetTraceStack);
andrewboyson 115:5c003909bcf3 243 }