Andrew Boyson / net

Dependents:   oldheating gps motorhome heating

Committer:
andrewboyson
Date:
Tue Nov 28 17:05:46 2017 +0000
Revision:
57:e0fb648acf48
Child:
59:e0e556c8bd46
Added TFTP

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 char* pHeader;
andrewboyson 57:e0fb648acf48 78 static int size;
andrewboyson 57:e0fb648acf48 79
andrewboyson 57:e0fb648acf48 80 static void logHeader()
andrewboyson 57:e0fb648acf48 81 {
andrewboyson 57:e0fb648acf48 82 char* p = pHeader;
andrewboyson 57:e0fb648acf48 83 if (NetTraceVerbose)
andrewboyson 57:e0fb648acf48 84 {
andrewboyson 57:e0fb648acf48 85 Log ("TFTP header\r\n");
andrewboyson 57:e0fb648acf48 86 Log (" Op code "); logOp(p); Log("\r\n");
andrewboyson 57:e0fb648acf48 87 Log (" Size "); LogF("%d", size); Log("\r\n");
andrewboyson 57:e0fb648acf48 88 }
andrewboyson 57:e0fb648acf48 89 else
andrewboyson 57:e0fb648acf48 90 {
andrewboyson 57:e0fb648acf48 91 Log ("TFTP header");
andrewboyson 57:e0fb648acf48 92 Log (": Op "); logOp(p);
andrewboyson 57:e0fb648acf48 93 LogF(", %d bytes", size);
andrewboyson 57:e0fb648acf48 94 Log ("\r\n");
andrewboyson 57:e0fb648acf48 95 }
andrewboyson 57:e0fb648acf48 96 }
andrewboyson 57:e0fb648acf48 97 static int sendBlock(uint16_t block)
andrewboyson 57:e0fb648acf48 98 {
andrewboyson 57:e0fb648acf48 99 /*2 bytes 2 bytes n bytes
andrewboyson 57:e0fb648acf48 100 ----------------------------------
andrewboyson 57:e0fb648acf48 101 | Opcode | Block # | Data |
andrewboyson 57:e0fb648acf48 102 ---------------------------------- */
andrewboyson 57:e0fb648acf48 103 char* p = pHeader;
andrewboyson 57:e0fb648acf48 104 *p++ = 0;
andrewboyson 57:e0fb648acf48 105 *p++ = TFTP_DATA;
andrewboyson 57:e0fb648acf48 106 *p++ = block >> 8;
andrewboyson 57:e0fb648acf48 107 *p++ = block & 0xFF;
andrewboyson 57:e0fb648acf48 108
andrewboyson 57:e0fb648acf48 109 int len = 0;
andrewboyson 57:e0fb648acf48 110 while (len < 512)
andrewboyson 57:e0fb648acf48 111 {
andrewboyson 57:e0fb648acf48 112 int c = TftpGetNextByteFunction();
andrewboyson 57:e0fb648acf48 113 if (c == -1) break;
andrewboyson 57:e0fb648acf48 114 *p++ = c;
andrewboyson 57:e0fb648acf48 115 len++;
andrewboyson 57:e0fb648acf48 116 }
andrewboyson 57:e0fb648acf48 117 if (len < 512) TftpWriteStatus = TFTP_WRITE_STATUS_NONE;
andrewboyson 57:e0fb648acf48 118 size = p - pHeader;
andrewboyson 57:e0fb648acf48 119 return UNICAST_TFTP;
andrewboyson 57:e0fb648acf48 120 }
andrewboyson 57:e0fb648acf48 121 static void handleError()
andrewboyson 57:e0fb648acf48 122 {
andrewboyson 57:e0fb648acf48 123 /*2 bytes 2 bytes string 1 byte
andrewboyson 57:e0fb648acf48 124 -----------------------------------------
andrewboyson 57:e0fb648acf48 125 | ERROR | ErrorCode | ErrMsg | 0 |
andrewboyson 57:e0fb648acf48 126 ----------------------------------------- */
andrewboyson 57:e0fb648acf48 127 char* p = pHeader + 2; //Skip the op code which we already know
andrewboyson 57:e0fb648acf48 128 if (NetTraceNewLine) Log("\r\n");
andrewboyson 57:e0fb648acf48 129 LogTime("TFTP error - ");
andrewboyson 57:e0fb648acf48 130 logError(p); p += 2;
andrewboyson 57:e0fb648acf48 131 Log(p);
andrewboyson 57:e0fb648acf48 132 Log("\r\n");
andrewboyson 57:e0fb648acf48 133 TftpWriteStatus = TFTP_WRITE_STATUS_NONE;
andrewboyson 57:e0fb648acf48 134 }
andrewboyson 57:e0fb648acf48 135 static int handleAck()
andrewboyson 57:e0fb648acf48 136 {
andrewboyson 57:e0fb648acf48 137 /*2 bytes 2 bytes
andrewboyson 57:e0fb648acf48 138 ---------------------
andrewboyson 57:e0fb648acf48 139 | ACK | Block # |
andrewboyson 57:e0fb648acf48 140 --------------------- */
andrewboyson 57:e0fb648acf48 141
andrewboyson 57:e0fb648acf48 142 char* p = pHeader + 2; //Skip the op code which we already know
andrewboyson 57:e0fb648acf48 143 uint16_t block = *p++;
andrewboyson 57:e0fb648acf48 144 block <<= 8;
andrewboyson 57:e0fb648acf48 145 block += *p++;
andrewboyson 57:e0fb648acf48 146
andrewboyson 57:e0fb648acf48 147 return sendBlock(block + 1);
andrewboyson 57:e0fb648acf48 148 }
andrewboyson 57:e0fb648acf48 149 static int sendRequest()
andrewboyson 57:e0fb648acf48 150 {
andrewboyson 57:e0fb648acf48 151 /*2 bytes string 1 byte string 1 byte
andrewboyson 57:e0fb648acf48 152 -----------------------------------------------
andrewboyson 57:e0fb648acf48 153 | WRQ | Filename | 0 | Mode | 0 |
andrewboyson 57:e0fb648acf48 154 ----------------------------------------------- */
andrewboyson 57:e0fb648acf48 155 char* p = pHeader;
andrewboyson 57:e0fb648acf48 156 *p++ = 0;
andrewboyson 57:e0fb648acf48 157 *p++ = TFTP_WRQ;
andrewboyson 57:e0fb648acf48 158 char* pName = TftpFileName;
andrewboyson 57:e0fb648acf48 159 while (*pName) *p++ = *pName++;
andrewboyson 57:e0fb648acf48 160 *p++ = 0;
andrewboyson 57:e0fb648acf48 161 const char* pMode = "octet";
andrewboyson 57:e0fb648acf48 162 while (*pMode) *p++ = *pMode++;
andrewboyson 57:e0fb648acf48 163 *p++ = 0;
andrewboyson 57:e0fb648acf48 164 size = p - pHeader;
andrewboyson 57:e0fb648acf48 165 return UNICAST_TFTP;
andrewboyson 57:e0fb648acf48 166 }
andrewboyson 57:e0fb648acf48 167 static void (*pTraceBack)(void);
andrewboyson 57:e0fb648acf48 168 int TftpHandlePacketReceived(void (*traceback)(void), int* pSize, void * pPacket)
andrewboyson 57:e0fb648acf48 169 {
andrewboyson 57:e0fb648acf48 170 pTraceBack = traceback;
andrewboyson 57:e0fb648acf48 171 pHeader = (char*)pPacket;
andrewboyson 57:e0fb648acf48 172 size = *pSize;
andrewboyson 57:e0fb648acf48 173
andrewboyson 57:e0fb648acf48 174 char* p = pHeader;
andrewboyson 57:e0fb648acf48 175
andrewboyson 57:e0fb648acf48 176 if (*p)
andrewboyson 57:e0fb648acf48 177 {
andrewboyson 57:e0fb648acf48 178 LogTimeF("Expected high byte of op code to be zero not %u\r\n", *p);
andrewboyson 57:e0fb648acf48 179 return DO_NOTHING;
andrewboyson 57:e0fb648acf48 180 }
andrewboyson 57:e0fb648acf48 181 if (TftpTrace)
andrewboyson 57:e0fb648acf48 182 {
andrewboyson 57:e0fb648acf48 183 if (NetTraceNewLine) Log("\r\n");
andrewboyson 57:e0fb648acf48 184 LogTimeF("TFTP received packet\r\n");
andrewboyson 57:e0fb648acf48 185 if (NetTraceStack) pTraceBack();
andrewboyson 57:e0fb648acf48 186 logHeader();
andrewboyson 57:e0fb648acf48 187 }
andrewboyson 57:e0fb648acf48 188 p++;
andrewboyson 57:e0fb648acf48 189 int dest = DO_NOTHING;
andrewboyson 57:e0fb648acf48 190 switch (*p)
andrewboyson 57:e0fb648acf48 191 {
andrewboyson 57:e0fb648acf48 192 case TFTP_ACK:
andrewboyson 57:e0fb648acf48 193 if (TftpWriteStatus == TFTP_WRITE_STATUS_NONE) return DO_NOTHING;
andrewboyson 57:e0fb648acf48 194 dest = handleAck();
andrewboyson 57:e0fb648acf48 195 break;
andrewboyson 57:e0fb648acf48 196 case TFTP_ERROR:
andrewboyson 57:e0fb648acf48 197 handleError();
andrewboyson 57:e0fb648acf48 198 return DO_NOTHING;
andrewboyson 57:e0fb648acf48 199 default:
andrewboyson 57:e0fb648acf48 200 LogTimeF("\r\nTFTP packet unknown mode %d\r\n", *p);
andrewboyson 57:e0fb648acf48 201 return DO_NOTHING;
andrewboyson 57:e0fb648acf48 202 }
andrewboyson 57:e0fb648acf48 203
andrewboyson 57:e0fb648acf48 204 if (TftpTrace) logHeader();
andrewboyson 57:e0fb648acf48 205
andrewboyson 57:e0fb648acf48 206 *pSize = size;
andrewboyson 57:e0fb648acf48 207 return ActionMakeFromDestAndTrace(dest, TftpTrace && NetTraceStack);
andrewboyson 57:e0fb648acf48 208 }
andrewboyson 57:e0fb648acf48 209 static bool resolve4(char* server, uint32_t* pIp)
andrewboyson 57:e0fb648acf48 210 {
andrewboyson 57:e0fb648acf48 211 //Check if have IP, if not, then request it and stop
andrewboyson 57:e0fb648acf48 212 Nr4NameToIp(server, pIp);
andrewboyson 57:e0fb648acf48 213 if (!*pIp)
andrewboyson 57:e0fb648acf48 214 {
andrewboyson 57:e0fb648acf48 215 Nr4MakeRequestForIpFromName(server); //The request is only repeated if made after a freeze time - call as often as you want.
andrewboyson 57:e0fb648acf48 216 return false;
andrewboyson 57:e0fb648acf48 217 }
andrewboyson 57:e0fb648acf48 218
andrewboyson 57:e0fb648acf48 219 //Check if have MAC and, if not, request it and stop
andrewboyson 57:e0fb648acf48 220 char mac[6];
andrewboyson 57:e0fb648acf48 221 Ar4IpToMac(*pIp, mac);
andrewboyson 57:e0fb648acf48 222 if (MacIsEmpty(mac))
andrewboyson 57:e0fb648acf48 223 {
andrewboyson 57:e0fb648acf48 224 Ar4MakeRequestForMacFromIp(*pIp); //The request is only repeated if made after a freeze time - call as often as you want.
andrewboyson 57:e0fb648acf48 225 return false;
andrewboyson 57:e0fb648acf48 226 }
andrewboyson 57:e0fb648acf48 227
andrewboyson 57:e0fb648acf48 228 return true;
andrewboyson 57:e0fb648acf48 229 }
andrewboyson 57:e0fb648acf48 230 static bool resolve6(char* server, char* ip)
andrewboyson 57:e0fb648acf48 231 {
andrewboyson 57:e0fb648acf48 232 //Check if have IP, if not, then request it and stop
andrewboyson 57:e0fb648acf48 233 Nr6NameToIp(server, ip);
andrewboyson 57:e0fb648acf48 234 if (Ip6AddressIsEmpty(ip))
andrewboyson 57:e0fb648acf48 235 {
andrewboyson 57:e0fb648acf48 236 Nr6MakeRequestForIpFromName(server); //The request is only repeated if made after a freeze time - call as often as you want.
andrewboyson 57:e0fb648acf48 237 return false;
andrewboyson 57:e0fb648acf48 238 }
andrewboyson 57:e0fb648acf48 239
andrewboyson 57:e0fb648acf48 240 //Check if have MAC and, if not, request it and stop
andrewboyson 57:e0fb648acf48 241 char mac[6];
andrewboyson 57:e0fb648acf48 242 Ar6IpToMac(ip, mac);
andrewboyson 57:e0fb648acf48 243 if (MacIsEmpty(mac))
andrewboyson 57:e0fb648acf48 244 {
andrewboyson 57:e0fb648acf48 245 Ar6MakeRequestForMacFromIp(ip); //The request is only repeated if made after a freeze time - call as often as you want.
andrewboyson 57:e0fb648acf48 246 return false;
andrewboyson 57:e0fb648acf48 247 }
andrewboyson 57:e0fb648acf48 248
andrewboyson 57:e0fb648acf48 249 return true;
andrewboyson 57:e0fb648acf48 250 }
andrewboyson 57:e0fb648acf48 251 int TftpPollForPacketToSend(int type, void* pPacket, int* pSize)
andrewboyson 57:e0fb648acf48 252 {
andrewboyson 57:e0fb648acf48 253 if (TftpWriteStatus != TFTP_WRITE_STATUS_REQUEST) return DO_NOTHING; //Wait until a request to send a file
andrewboyson 57:e0fb648acf48 254
andrewboyson 57:e0fb648acf48 255 pHeader = (char*)pPacket;
andrewboyson 57:e0fb648acf48 256 size = *pSize;
andrewboyson 57:e0fb648acf48 257
andrewboyson 57:e0fb648acf48 258 if (!TftpServerName[0])
andrewboyson 57:e0fb648acf48 259 {
andrewboyson 57:e0fb648acf48 260 LogTimeF("TftpPollForRequestToSend - A request to send a client message has been made but no server name has been specified\r\n");
andrewboyson 57:e0fb648acf48 261 TftpWriteStatus = TFTP_WRITE_STATUS_NONE;
andrewboyson 57:e0fb648acf48 262 return DO_NOTHING;
andrewboyson 57:e0fb648acf48 263 }
andrewboyson 57:e0fb648acf48 264
andrewboyson 57:e0fb648acf48 265 if (!TftpGetNextByteFunction)
andrewboyson 57:e0fb648acf48 266 {
andrewboyson 57:e0fb648acf48 267 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 268 TftpWriteStatus = TFTP_WRITE_STATUS_NONE;
andrewboyson 57:e0fb648acf48 269 return DO_NOTHING;
andrewboyson 57:e0fb648acf48 270 }
andrewboyson 57:e0fb648acf48 271
andrewboyson 57:e0fb648acf48 272 if (type == IPV4)
andrewboyson 57:e0fb648acf48 273 {
andrewboyson 57:e0fb648acf48 274 if (!resolve4(TftpServerName, &TftpServerIp4)) return DO_NOTHING;
andrewboyson 57:e0fb648acf48 275 }
andrewboyson 57:e0fb648acf48 276 else if (type == IPV6)
andrewboyson 57:e0fb648acf48 277 {
andrewboyson 57:e0fb648acf48 278 if (!resolve6(TftpServerName, TftpServerIp6)) return DO_NOTHING;
andrewboyson 57:e0fb648acf48 279 }
andrewboyson 57:e0fb648acf48 280 else
andrewboyson 57:e0fb648acf48 281 {
andrewboyson 57:e0fb648acf48 282 return DO_NOTHING;
andrewboyson 57:e0fb648acf48 283 }
andrewboyson 57:e0fb648acf48 284
andrewboyson 57:e0fb648acf48 285 //Have IP and MAC so send request
andrewboyson 57:e0fb648acf48 286 TftpWriteStatus = TFTP_WRITE_STATUS_IN_PROGRESS;
andrewboyson 57:e0fb648acf48 287 int dest = sendRequest();
andrewboyson 57:e0fb648acf48 288 if (TftpTrace)
andrewboyson 57:e0fb648acf48 289 {
andrewboyson 57:e0fb648acf48 290 if (NetTraceNewLine) Log("\r\n");
andrewboyson 57:e0fb648acf48 291 LogTimeF("TFTP Sending request\r\n");
andrewboyson 57:e0fb648acf48 292 logHeader();
andrewboyson 57:e0fb648acf48 293 }
andrewboyson 57:e0fb648acf48 294 *pSize = size;
andrewboyson 57:e0fb648acf48 295 return ActionMakeFromDestAndTrace(dest, TftpTrace && NetTraceStack);
andrewboyson 57:e0fb648acf48 296 }
andrewboyson 57:e0fb648acf48 297 int elapsed = 0;
andrewboyson 57:e0fb648acf48 298 void TftpMain()
andrewboyson 57:e0fb648acf48 299 {
andrewboyson 57:e0fb648acf48 300 if (TftpWriteStatus == TFTP_WRITE_STATUS_IN_PROGRESS)
andrewboyson 57:e0fb648acf48 301 {
andrewboyson 57:e0fb648acf48 302 if (ClockTicked) elapsed++;
andrewboyson 57:e0fb648acf48 303 if (elapsed > WRITE_TIMEOUT_SECS)
andrewboyson 57:e0fb648acf48 304 {
andrewboyson 57:e0fb648acf48 305 TftpWriteStatus = TFTP_WRITE_STATUS_NONE;
andrewboyson 57:e0fb648acf48 306 LogTime("TFTP - write operation timed out so reset\r\n");
andrewboyson 57:e0fb648acf48 307 }
andrewboyson 57:e0fb648acf48 308 }
andrewboyson 57:e0fb648acf48 309 else
andrewboyson 57:e0fb648acf48 310 {
andrewboyson 57:e0fb648acf48 311 elapsed = 0;
andrewboyson 57:e0fb648acf48 312 }
andrewboyson 57:e0fb648acf48 313 }