Andrew Boyson / net

Dependents:   oldheating gps motorhome heating

Committer:
andrewboyson
Date:
Thu Dec 14 20:55:40 2017 +0000
Revision:
59:e0e556c8bd46
Parent:
57:e0fb648acf48
Added buffer length to help avoid over runs

Who changed what in which revision?

UserRevisionLine numberNew contents of line
andrewboyson 57:e0fb648acf48 1 #include "mbed.h"
andrewboyson 57:e0fb648acf48 2 #include "log.h"
andrewboyson 57:e0fb648acf48 3 #include "net.h"
andrewboyson 57:e0fb648acf48 4 #include "action.h"
andrewboyson 57:e0fb648acf48 5 #include "ip6addr.h"
andrewboyson 57:e0fb648acf48 6 #include "udp.h"
andrewboyson 57:e0fb648acf48 7 #include "ar4.h"
andrewboyson 57:e0fb648acf48 8 #include "ar6.h"
andrewboyson 57:e0fb648acf48 9 #include "arp.h"
andrewboyson 57:e0fb648acf48 10 #include "io.h"
andrewboyson 57:e0fb648acf48 11 #include "eth.h"
andrewboyson 57:e0fb648acf48 12 #include "nr4.h"
andrewboyson 57:e0fb648acf48 13 #include "nr6.h"
andrewboyson 57:e0fb648acf48 14 #include "dns.h"
andrewboyson 57:e0fb648acf48 15 #include "mac.h"
andrewboyson 57:e0fb648acf48 16 #include "tftp.h"
andrewboyson 57:e0fb648acf48 17 #include "clock.h"
andrewboyson 57:e0fb648acf48 18
andrewboyson 57:e0fb648acf48 19 bool TftpTrace = false;
andrewboyson 57:e0fb648acf48 20
andrewboyson 57:e0fb648acf48 21 #define WRITE_TIMEOUT_SECS 5
andrewboyson 57:e0fb648acf48 22
andrewboyson 57:e0fb648acf48 23 #define TFTP_RRQ 1
andrewboyson 57:e0fb648acf48 24 #define TFTP_WRQ 2
andrewboyson 57:e0fb648acf48 25 #define TFTP_DATA 3
andrewboyson 57:e0fb648acf48 26 #define TFTP_ACK 4
andrewboyson 57:e0fb648acf48 27 #define TFTP_ERROR 5
andrewboyson 57:e0fb648acf48 28
andrewboyson 57:e0fb648acf48 29 static void logOp(char* p)
andrewboyson 57:e0fb648acf48 30 {
andrewboyson 57:e0fb648acf48 31 if (*p)
andrewboyson 57:e0fb648acf48 32 {
andrewboyson 57:e0fb648acf48 33 LogF("Unknown op code %02x%02x", *p, *++p);
andrewboyson 57:e0fb648acf48 34 return;
andrewboyson 57:e0fb648acf48 35 }
andrewboyson 57:e0fb648acf48 36 p++;
andrewboyson 57:e0fb648acf48 37 switch (*p)
andrewboyson 57:e0fb648acf48 38 {
andrewboyson 57:e0fb648acf48 39 case TFTP_RRQ: Log ("RRQ") ; break;
andrewboyson 57:e0fb648acf48 40 case TFTP_WRQ: Log ("WRQ") ; break;
andrewboyson 57:e0fb648acf48 41 case TFTP_DATA: Log ("DATA") ; break;
andrewboyson 57:e0fb648acf48 42 case TFTP_ACK: Log ("ACK") ; break;
andrewboyson 57:e0fb648acf48 43 case TFTP_ERROR: Log ("ERROR") ; break;
andrewboyson 57:e0fb648acf48 44 default: LogF("Unknown op code 00%02x", *p); break;
andrewboyson 57:e0fb648acf48 45 }
andrewboyson 57:e0fb648acf48 46 }
andrewboyson 57:e0fb648acf48 47
andrewboyson 57:e0fb648acf48 48 static void logError(char* p)
andrewboyson 57:e0fb648acf48 49 {
andrewboyson 57:e0fb648acf48 50 if (*p)
andrewboyson 57:e0fb648acf48 51 {
andrewboyson 57:e0fb648acf48 52 LogF("Unknown error code %02x%02x", *p, *++p);
andrewboyson 57:e0fb648acf48 53 return;
andrewboyson 57:e0fb648acf48 54 }
andrewboyson 57:e0fb648acf48 55 p++;
andrewboyson 57:e0fb648acf48 56 switch (*p)
andrewboyson 57:e0fb648acf48 57 {
andrewboyson 57:e0fb648acf48 58 case 0: Log ("Not defined, see error message." ); break;
andrewboyson 57:e0fb648acf48 59 case 1: Log ("File not found." ); break;
andrewboyson 57:e0fb648acf48 60 case 2: Log ("Access violation." ); break;
andrewboyson 57:e0fb648acf48 61 case 3: Log ("Disk full or allocation exceeded."); break;
andrewboyson 57:e0fb648acf48 62 case 4: Log ("Illegal TFTP operation." ); break;
andrewboyson 57:e0fb648acf48 63 case 5: Log ("Unknown transfer ID." ); break;
andrewboyson 57:e0fb648acf48 64 case 6: Log ("File already exists." ); break;
andrewboyson 57:e0fb648acf48 65 case 7: Log ("No such user." ); break;
andrewboyson 57:e0fb648acf48 66 default: LogF("Unknown error code 00%02x", *p ); break;
andrewboyson 57:e0fb648acf48 67 }
andrewboyson 57:e0fb648acf48 68 }
andrewboyson 57:e0fb648acf48 69 uint32_t TftpServerIp4;
andrewboyson 57:e0fb648acf48 70 char TftpServerIp6[16];
andrewboyson 57:e0fb648acf48 71 int TftpWriteStatus = TFTP_WRITE_STATUS_NONE;
andrewboyson 57:e0fb648acf48 72 char TftpServerName[DNS_MAX_LABEL_LENGTH+1];
andrewboyson 57:e0fb648acf48 73 char TftpFileName [DNS_MAX_LABEL_LENGTH+1];
andrewboyson 57:e0fb648acf48 74
andrewboyson 57:e0fb648acf48 75 int (*TftpGetNextByteFunction)();
andrewboyson 57:e0fb648acf48 76
andrewboyson 57:e0fb648acf48 77 static int size;
andrewboyson 57:e0fb648acf48 78
andrewboyson 59:e0e556c8bd46 79 static void logHeader(char* p)
andrewboyson 57:e0fb648acf48 80 {
andrewboyson 57:e0fb648acf48 81 if (NetTraceVerbose)
andrewboyson 57:e0fb648acf48 82 {
andrewboyson 57:e0fb648acf48 83 Log ("TFTP header\r\n");
andrewboyson 57:e0fb648acf48 84 Log (" Op code "); logOp(p); Log("\r\n");
andrewboyson 57:e0fb648acf48 85 Log (" Size "); LogF("%d", size); Log("\r\n");
andrewboyson 57:e0fb648acf48 86 }
andrewboyson 57:e0fb648acf48 87 else
andrewboyson 57:e0fb648acf48 88 {
andrewboyson 57:e0fb648acf48 89 Log ("TFTP header");
andrewboyson 57:e0fb648acf48 90 Log (": Op "); logOp(p);
andrewboyson 57:e0fb648acf48 91 LogF(", %d bytes", size);
andrewboyson 57:e0fb648acf48 92 Log ("\r\n");
andrewboyson 57:e0fb648acf48 93 }
andrewboyson 57:e0fb648acf48 94 }
andrewboyson 59:e0e556c8bd46 95 static int sendBlock(uint16_t block, char* pHeader)
andrewboyson 57:e0fb648acf48 96 {
andrewboyson 57:e0fb648acf48 97 /*2 bytes 2 bytes n bytes
andrewboyson 57:e0fb648acf48 98 ----------------------------------
andrewboyson 57:e0fb648acf48 99 | Opcode | Block # | Data |
andrewboyson 57:e0fb648acf48 100 ---------------------------------- */
andrewboyson 59:e0e556c8bd46 101 char* p = pHeader;
andrewboyson 57:e0fb648acf48 102 *p++ = 0;
andrewboyson 57:e0fb648acf48 103 *p++ = TFTP_DATA;
andrewboyson 57:e0fb648acf48 104 *p++ = block >> 8;
andrewboyson 57:e0fb648acf48 105 *p++ = block & 0xFF;
andrewboyson 57:e0fb648acf48 106
andrewboyson 57:e0fb648acf48 107 int len = 0;
andrewboyson 57:e0fb648acf48 108 while (len < 512)
andrewboyson 57:e0fb648acf48 109 {
andrewboyson 57:e0fb648acf48 110 int c = TftpGetNextByteFunction();
andrewboyson 57:e0fb648acf48 111 if (c == -1) break;
andrewboyson 57:e0fb648acf48 112 *p++ = c;
andrewboyson 57:e0fb648acf48 113 len++;
andrewboyson 57:e0fb648acf48 114 }
andrewboyson 57:e0fb648acf48 115 if (len < 512) TftpWriteStatus = TFTP_WRITE_STATUS_NONE;
andrewboyson 57:e0fb648acf48 116 size = p - pHeader;
andrewboyson 57:e0fb648acf48 117 return UNICAST_TFTP;
andrewboyson 57:e0fb648acf48 118 }
andrewboyson 59:e0e556c8bd46 119 static void handleError(char* p)
andrewboyson 57:e0fb648acf48 120 {
andrewboyson 57:e0fb648acf48 121 /*2 bytes 2 bytes string 1 byte
andrewboyson 57:e0fb648acf48 122 -----------------------------------------
andrewboyson 57:e0fb648acf48 123 | ERROR | ErrorCode | ErrMsg | 0 |
andrewboyson 57:e0fb648acf48 124 ----------------------------------------- */
andrewboyson 59:e0e556c8bd46 125 p += 2; //Skip the op code which we already know
andrewboyson 57:e0fb648acf48 126 if (NetTraceNewLine) Log("\r\n");
andrewboyson 57:e0fb648acf48 127 LogTime("TFTP error - ");
andrewboyson 57:e0fb648acf48 128 logError(p); p += 2;
andrewboyson 57:e0fb648acf48 129 Log(p);
andrewboyson 57:e0fb648acf48 130 Log("\r\n");
andrewboyson 57:e0fb648acf48 131 TftpWriteStatus = TFTP_WRITE_STATUS_NONE;
andrewboyson 57:e0fb648acf48 132 }
andrewboyson 59:e0e556c8bd46 133 static int handleAck(char* pHeaderRx, char* pHeaderTx)
andrewboyson 57:e0fb648acf48 134 {
andrewboyson 59:e0e556c8bd46 135 /* 2 bytes 2 bytes
andrewboyson 59:e0e556c8bd46 136 -----------------------
andrewboyson 59:e0e556c8bd46 137 | ACK | Block # |
andrewboyson 59:e0e556c8bd46 138 ----------------------- */
andrewboyson 59:e0e556c8bd46 139 char* p = pHeaderRx;
andrewboyson 59:e0e556c8bd46 140 p += 2; //Skip the op code which we already know
andrewboyson 57:e0fb648acf48 141 uint16_t block = *p++;
andrewboyson 57:e0fb648acf48 142 block <<= 8;
andrewboyson 57:e0fb648acf48 143 block += *p++;
andrewboyson 57:e0fb648acf48 144
andrewboyson 59:e0e556c8bd46 145 return sendBlock(block + 1, pHeaderTx);
andrewboyson 57:e0fb648acf48 146 }
andrewboyson 59:e0e556c8bd46 147 static int sendRequest(char* pHeader)
andrewboyson 57:e0fb648acf48 148 {
andrewboyson 57:e0fb648acf48 149 /*2 bytes string 1 byte string 1 byte
andrewboyson 57:e0fb648acf48 150 -----------------------------------------------
andrewboyson 57:e0fb648acf48 151 | WRQ | Filename | 0 | Mode | 0 |
andrewboyson 57:e0fb648acf48 152 ----------------------------------------------- */
andrewboyson 59:e0e556c8bd46 153 char* p = pHeader;
andrewboyson 57:e0fb648acf48 154 *p++ = 0;
andrewboyson 57:e0fb648acf48 155 *p++ = TFTP_WRQ;
andrewboyson 57:e0fb648acf48 156 char* pName = TftpFileName;
andrewboyson 57:e0fb648acf48 157 while (*pName) *p++ = *pName++;
andrewboyson 57:e0fb648acf48 158 *p++ = 0;
andrewboyson 57:e0fb648acf48 159 const char* pMode = "octet";
andrewboyson 57:e0fb648acf48 160 while (*pMode) *p++ = *pMode++;
andrewboyson 57:e0fb648acf48 161 *p++ = 0;
andrewboyson 57:e0fb648acf48 162 size = p - pHeader;
andrewboyson 57:e0fb648acf48 163 return UNICAST_TFTP;
andrewboyson 57:e0fb648acf48 164 }
andrewboyson 57:e0fb648acf48 165 static void (*pTraceBack)(void);
andrewboyson 59:e0e556c8bd46 166 int TftpHandlePacketReceived(void (*traceback)(void), int sizeRx, void * pPacketRx, int* pSizeTx, void* pPacketTx)
andrewboyson 57:e0fb648acf48 167 {
andrewboyson 57:e0fb648acf48 168 pTraceBack = traceback;
andrewboyson 59:e0e556c8bd46 169 char* pHeaderRx = (char*)pPacketRx;
andrewboyson 59:e0e556c8bd46 170 char* pHeaderTx = (char*)pPacketTx;
andrewboyson 59:e0e556c8bd46 171 size = sizeRx;
andrewboyson 57:e0fb648acf48 172
andrewboyson 59:e0e556c8bd46 173 char* p = pHeaderRx;
andrewboyson 57:e0fb648acf48 174
andrewboyson 57:e0fb648acf48 175 if (*p)
andrewboyson 57:e0fb648acf48 176 {
andrewboyson 57:e0fb648acf48 177 LogTimeF("Expected high byte of op code to be zero not %u\r\n", *p);
andrewboyson 57:e0fb648acf48 178 return DO_NOTHING;
andrewboyson 57:e0fb648acf48 179 }
andrewboyson 57:e0fb648acf48 180 if (TftpTrace)
andrewboyson 57:e0fb648acf48 181 {
andrewboyson 57:e0fb648acf48 182 if (NetTraceNewLine) Log("\r\n");
andrewboyson 57:e0fb648acf48 183 LogTimeF("TFTP received packet\r\n");
andrewboyson 57:e0fb648acf48 184 if (NetTraceStack) pTraceBack();
andrewboyson 59:e0e556c8bd46 185 logHeader(pHeaderRx);
andrewboyson 57:e0fb648acf48 186 }
andrewboyson 57:e0fb648acf48 187 p++;
andrewboyson 57:e0fb648acf48 188 int dest = DO_NOTHING;
andrewboyson 57:e0fb648acf48 189 switch (*p)
andrewboyson 57:e0fb648acf48 190 {
andrewboyson 57:e0fb648acf48 191 case TFTP_ACK:
andrewboyson 57:e0fb648acf48 192 if (TftpWriteStatus == TFTP_WRITE_STATUS_NONE) return DO_NOTHING;
andrewboyson 59:e0e556c8bd46 193 dest = handleAck(pHeaderRx, pHeaderTx);
andrewboyson 57:e0fb648acf48 194 break;
andrewboyson 57:e0fb648acf48 195 case TFTP_ERROR:
andrewboyson 59:e0e556c8bd46 196 handleError(pHeaderRx);
andrewboyson 57:e0fb648acf48 197 return DO_NOTHING;
andrewboyson 57:e0fb648acf48 198 default:
andrewboyson 57:e0fb648acf48 199 LogTimeF("\r\nTFTP packet unknown mode %d\r\n", *p);
andrewboyson 57:e0fb648acf48 200 return DO_NOTHING;
andrewboyson 57:e0fb648acf48 201 }
andrewboyson 57:e0fb648acf48 202
andrewboyson 59:e0e556c8bd46 203 if (TftpTrace) logHeader(pHeaderTx);
andrewboyson 57:e0fb648acf48 204
andrewboyson 59:e0e556c8bd46 205 *pSizeTx = size;
andrewboyson 57:e0fb648acf48 206 return ActionMakeFromDestAndTrace(dest, TftpTrace && NetTraceStack);
andrewboyson 57:e0fb648acf48 207 }
andrewboyson 57:e0fb648acf48 208 static bool resolve4(char* server, uint32_t* pIp)
andrewboyson 57:e0fb648acf48 209 {
andrewboyson 57:e0fb648acf48 210 //Check if have IP, if not, then request it and stop
andrewboyson 57:e0fb648acf48 211 Nr4NameToIp(server, pIp);
andrewboyson 57:e0fb648acf48 212 if (!*pIp)
andrewboyson 57:e0fb648acf48 213 {
andrewboyson 57:e0fb648acf48 214 Nr4MakeRequestForIpFromName(server); //The request is only repeated if made after a freeze time - call as often as you want.
andrewboyson 57:e0fb648acf48 215 return false;
andrewboyson 57:e0fb648acf48 216 }
andrewboyson 57:e0fb648acf48 217
andrewboyson 57:e0fb648acf48 218 //Check if have MAC and, if not, request it and stop
andrewboyson 57:e0fb648acf48 219 char mac[6];
andrewboyson 57:e0fb648acf48 220 Ar4IpToMac(*pIp, mac);
andrewboyson 57:e0fb648acf48 221 if (MacIsEmpty(mac))
andrewboyson 57:e0fb648acf48 222 {
andrewboyson 57:e0fb648acf48 223 Ar4MakeRequestForMacFromIp(*pIp); //The request is only repeated if made after a freeze time - call as often as you want.
andrewboyson 57:e0fb648acf48 224 return false;
andrewboyson 57:e0fb648acf48 225 }
andrewboyson 57:e0fb648acf48 226
andrewboyson 57:e0fb648acf48 227 return true;
andrewboyson 57:e0fb648acf48 228 }
andrewboyson 57:e0fb648acf48 229 static bool resolve6(char* server, char* ip)
andrewboyson 57:e0fb648acf48 230 {
andrewboyson 57:e0fb648acf48 231 //Check if have IP, if not, then request it and stop
andrewboyson 57:e0fb648acf48 232 Nr6NameToIp(server, ip);
andrewboyson 57:e0fb648acf48 233 if (Ip6AddressIsEmpty(ip))
andrewboyson 57:e0fb648acf48 234 {
andrewboyson 57:e0fb648acf48 235 Nr6MakeRequestForIpFromName(server); //The request is only repeated if made after a freeze time - call as often as you want.
andrewboyson 57:e0fb648acf48 236 return false;
andrewboyson 57:e0fb648acf48 237 }
andrewboyson 57:e0fb648acf48 238
andrewboyson 57:e0fb648acf48 239 //Check if have MAC and, if not, request it and stop
andrewboyson 57:e0fb648acf48 240 char mac[6];
andrewboyson 57:e0fb648acf48 241 Ar6IpToMac(ip, mac);
andrewboyson 57:e0fb648acf48 242 if (MacIsEmpty(mac))
andrewboyson 57:e0fb648acf48 243 {
andrewboyson 57:e0fb648acf48 244 Ar6MakeRequestForMacFromIp(ip); //The request is only repeated if made after a freeze time - call as often as you want.
andrewboyson 57:e0fb648acf48 245 return false;
andrewboyson 57:e0fb648acf48 246 }
andrewboyson 57:e0fb648acf48 247
andrewboyson 57:e0fb648acf48 248 return true;
andrewboyson 57:e0fb648acf48 249 }
andrewboyson 57:e0fb648acf48 250 int TftpPollForPacketToSend(int type, void* pPacket, int* pSize)
andrewboyson 57:e0fb648acf48 251 {
andrewboyson 57:e0fb648acf48 252 if (TftpWriteStatus != TFTP_WRITE_STATUS_REQUEST) return DO_NOTHING; //Wait until a request to send a file
andrewboyson 57:e0fb648acf48 253
andrewboyson 59:e0e556c8bd46 254 char* pHeader = (char*)pPacket;
andrewboyson 57:e0fb648acf48 255 size = *pSize;
andrewboyson 57:e0fb648acf48 256
andrewboyson 57:e0fb648acf48 257 if (!TftpServerName[0])
andrewboyson 57:e0fb648acf48 258 {
andrewboyson 57:e0fb648acf48 259 LogTimeF("TftpPollForRequestToSend - A request to send a client message has been made but no server name has been specified\r\n");
andrewboyson 57:e0fb648acf48 260 TftpWriteStatus = TFTP_WRITE_STATUS_NONE;
andrewboyson 57:e0fb648acf48 261 return DO_NOTHING;
andrewboyson 57:e0fb648acf48 262 }
andrewboyson 57:e0fb648acf48 263
andrewboyson 57:e0fb648acf48 264 if (!TftpGetNextByteFunction)
andrewboyson 57:e0fb648acf48 265 {
andrewboyson 57:e0fb648acf48 266 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 57:e0fb648acf48 267 TftpWriteStatus = TFTP_WRITE_STATUS_NONE;
andrewboyson 57:e0fb648acf48 268 return DO_NOTHING;
andrewboyson 57:e0fb648acf48 269 }
andrewboyson 57:e0fb648acf48 270
andrewboyson 57:e0fb648acf48 271 if (type == IPV4)
andrewboyson 57:e0fb648acf48 272 {
andrewboyson 57:e0fb648acf48 273 if (!resolve4(TftpServerName, &TftpServerIp4)) return DO_NOTHING;
andrewboyson 57:e0fb648acf48 274 }
andrewboyson 57:e0fb648acf48 275 else if (type == IPV6)
andrewboyson 57:e0fb648acf48 276 {
andrewboyson 57:e0fb648acf48 277 if (!resolve6(TftpServerName, TftpServerIp6)) return DO_NOTHING;
andrewboyson 57:e0fb648acf48 278 }
andrewboyson 57:e0fb648acf48 279 else
andrewboyson 57:e0fb648acf48 280 {
andrewboyson 57:e0fb648acf48 281 return DO_NOTHING;
andrewboyson 57:e0fb648acf48 282 }
andrewboyson 57:e0fb648acf48 283
andrewboyson 57:e0fb648acf48 284 //Have IP and MAC so send request
andrewboyson 57:e0fb648acf48 285 TftpWriteStatus = TFTP_WRITE_STATUS_IN_PROGRESS;
andrewboyson 59:e0e556c8bd46 286 int dest = sendRequest(pHeader);
andrewboyson 57:e0fb648acf48 287 if (TftpTrace)
andrewboyson 57:e0fb648acf48 288 {
andrewboyson 57:e0fb648acf48 289 if (NetTraceNewLine) Log("\r\n");
andrewboyson 57:e0fb648acf48 290 LogTimeF("TFTP Sending request\r\n");
andrewboyson 59:e0e556c8bd46 291 logHeader(pHeader);
andrewboyson 57:e0fb648acf48 292 }
andrewboyson 57:e0fb648acf48 293 *pSize = size;
andrewboyson 57:e0fb648acf48 294 return ActionMakeFromDestAndTrace(dest, TftpTrace && NetTraceStack);
andrewboyson 57:e0fb648acf48 295 }
andrewboyson 57:e0fb648acf48 296 int elapsed = 0;
andrewboyson 57:e0fb648acf48 297 void TftpMain()
andrewboyson 57:e0fb648acf48 298 {
andrewboyson 57:e0fb648acf48 299 if (TftpWriteStatus == TFTP_WRITE_STATUS_IN_PROGRESS)
andrewboyson 57:e0fb648acf48 300 {
andrewboyson 57:e0fb648acf48 301 if (ClockTicked) elapsed++;
andrewboyson 57:e0fb648acf48 302 if (elapsed > WRITE_TIMEOUT_SECS)
andrewboyson 57:e0fb648acf48 303 {
andrewboyson 57:e0fb648acf48 304 TftpWriteStatus = TFTP_WRITE_STATUS_NONE;
andrewboyson 57:e0fb648acf48 305 LogTime("TFTP - write operation timed out so reset\r\n");
andrewboyson 57:e0fb648acf48 306 }
andrewboyson 57:e0fb648acf48 307 }
andrewboyson 57:e0fb648acf48 308 else
andrewboyson 57:e0fb648acf48 309 {
andrewboyson 57:e0fb648acf48 310 elapsed = 0;
andrewboyson 57:e0fb648acf48 311 }
andrewboyson 57:e0fb648acf48 312 }