Andrew Boyson / net

Dependents:   oldheating gps motorhome heating

Committer:
andrewboyson
Date:
Tue Oct 23 06:46:50 2018 +0000
Revision:
73:43e3d7fb3d60
Parent:
72:19457bba58d0
Child:
74:c3756bfa960e
Separated the TCP header into its own module

Who changed what in which revision?

UserRevisionLine numberNew contents of line
andrewboyson 61:aad055f1b0d1 1 #include <stdint.h>
andrewboyson 61:aad055f1b0d1 2 #include <stdbool.h>
andrewboyson 61:aad055f1b0d1 3
andrewboyson 37:793b39683406 4 #include "log.h"
andrewboyson 37:793b39683406 5 #include "net.h"
andrewboyson 37:793b39683406 6 #include "action.h"
andrewboyson 37:793b39683406 7 #include "tcp.h"
andrewboyson 73:43e3d7fb3d60 8 #include "tcphdr.h"
andrewboyson 37:793b39683406 9 #include "tcb.h"
andrewboyson 37:793b39683406 10 #include "ip4.h"
andrewboyson 37:793b39683406 11 #include "dhcp.h"
andrewboyson 49:1a6336f2b3f9 12 #include "http.h"
andrewboyson 71:736a5747ade1 13 #include "led.h"
andrewboyson 10:f0854784e960 14
andrewboyson 73:43e3d7fb3d60 15
andrewboyson 73:43e3d7fb3d60 16 //Payload variables
andrewboyson 73:43e3d7fb3d60 17 static int dataLength;
andrewboyson 59:e0e556c8bd46 18 static int maxMss = 0;
andrewboyson 10:f0854784e960 19
andrewboyson 52:fbc5a46b5e16 20 bool TcpTrace = false;
andrewboyson 55:e64b8b47a2b6 21 static bool doTrace = false;
andrewboyson 52:fbc5a46b5e16 22
andrewboyson 54:84ef2b29cf7e 23 static struct tcb* pTcb;
andrewboyson 54:84ef2b29cf7e 24
andrewboyson 73:43e3d7fb3d60 25 static void resetConnectionOut(char* message)
andrewboyson 55:e64b8b47a2b6 26 {
andrewboyson 56:35117a8b5c65 27 if (TcpTrace)
andrewboyson 56:35117a8b5c65 28 {
andrewboyson 56:35117a8b5c65 29 LogTime("TCP ");
andrewboyson 56:35117a8b5c65 30 Log(message);
andrewboyson 56:35117a8b5c65 31 Log("\r\n");
andrewboyson 56:35117a8b5c65 32 }
andrewboyson 55:e64b8b47a2b6 33 dataLength = 0;
andrewboyson 73:43e3d7fb3d60 34 TcpHdrClearOptions();
andrewboyson 73:43e3d7fb3d60 35 TcpHdrACK = false;
andrewboyson 73:43e3d7fb3d60 36 TcpHdrPSH = false;
andrewboyson 73:43e3d7fb3d60 37 TcpHdrRST = true;
andrewboyson 73:43e3d7fb3d60 38 TcpHdrSYN = false;
andrewboyson 73:43e3d7fb3d60 39 TcpHdrFIN = false;
andrewboyson 61:aad055f1b0d1 40
andrewboyson 61:aad055f1b0d1 41 pTcb->state = TCB_EMPTY;
andrewboyson 55:e64b8b47a2b6 42 }
andrewboyson 73:43e3d7fb3d60 43 static void startConnectionIn(void *pPacket, void* pCachedRemIp)
andrewboyson 10:f0854784e960 44 {
andrewboyson 73:43e3d7fb3d60 45 TcpHdrReadOptions(pPacket); //Get the MSS
andrewboyson 73:43e3d7fb3d60 46 if (TcpHdrMss > maxMss) TcpHdrMss = maxMss;
andrewboyson 73:43e3d7fb3d60 47
andrewboyson 73:43e3d7fb3d60 48 pTcb->mss = TcpHdrMss;
andrewboyson 52:fbc5a46b5e16 49 pTcb->state = TCB_SYN_RECEIVED;
andrewboyson 52:fbc5a46b5e16 50 pTcb->elapsed = TcbElapsed;
andrewboyson 71:736a5747ade1 51 pTcb->pIp = pCachedRemIp;
andrewboyson 73:43e3d7fb3d60 52 pTcb->port = TcpHdrSrcPort;
andrewboyson 57:e0fb648acf48 53 pTcb->hadFin = false;
andrewboyson 71:736a5747ade1 54 }
andrewboyson 73:43e3d7fb3d60 55 static void startConnectionOut(void* pPacket)
andrewboyson 71:736a5747ade1 56 {
andrewboyson 73:43e3d7fb3d60 57 TcpHdrMss = maxMss; //Ethernet 1500 - 20 - 20; or, in our case 768 - 20 - 20
andrewboyson 73:43e3d7fb3d60 58 TcpHdrWriteOptions(pPacket);
andrewboyson 10:f0854784e960 59 dataLength = 0;
andrewboyson 10:f0854784e960 60
andrewboyson 73:43e3d7fb3d60 61 TcpHdrACK = true; //Send ACK and SYN
andrewboyson 73:43e3d7fb3d60 62 TcpHdrPSH = false;
andrewboyson 73:43e3d7fb3d60 63 TcpHdrRST = false;
andrewboyson 73:43e3d7fb3d60 64 TcpHdrSYN = true;
andrewboyson 73:43e3d7fb3d60 65 TcpHdrFIN = false;
andrewboyson 10:f0854784e960 66 }
andrewboyson 71:736a5747ade1 67 static void establishConnectionIn()
andrewboyson 10:f0854784e960 68 {
andrewboyson 56:35117a8b5c65 69 pTcb->state = TCB_ESTABLISHED;
andrewboyson 56:35117a8b5c65 70 pTcb->elapsed = TcbElapsed;
andrewboyson 57:e0fb648acf48 71 pTcb->todo = 0;
andrewboyson 10:f0854784e960 72 }
andrewboyson 73:43e3d7fb3d60 73 static void handleEstablishedConnectionIn(void* pPacket)
andrewboyson 73:43e3d7fb3d60 74 {
andrewboyson 73:43e3d7fb3d60 75 char* pData = (char*)pPacket + TcpHdrSize;
andrewboyson 73:43e3d7fb3d60 76 HttpHandleRequest(dataLength, pData, pTcb->recdBytes - 1, &pTcb->todo);
andrewboyson 71:736a5747ade1 77 }
andrewboyson 73:43e3d7fb3d60 78 static void handleEstablishedConnectionOut(void* pPacket)
andrewboyson 71:736a5747ade1 79 {
andrewboyson 73:43e3d7fb3d60 80 TcpHdrClearOptions();
andrewboyson 73:43e3d7fb3d60 81 char* pData = (char*)pPacket + TcpHdrSize;
andrewboyson 73:43e3d7fb3d60 82 HttpSendReply(&dataLength, pData, pTcb->sentBytes - 1, TcpHdrMss, pTcb->todo);
andrewboyson 10:f0854784e960 83
andrewboyson 73:43e3d7fb3d60 84 TcpHdrACK = true; //Send ACK
andrewboyson 73:43e3d7fb3d60 85 TcpHdrRST = false;
andrewboyson 73:43e3d7fb3d60 86 TcpHdrSYN = false;
andrewboyson 73:43e3d7fb3d60 87 TcpHdrPSH = false;
andrewboyson 10:f0854784e960 88
andrewboyson 73:43e3d7fb3d60 89 if (dataLength < TcpHdrMss) //If a part packet then there can be no more to send
andrewboyson 10:f0854784e960 90 {
andrewboyson 73:43e3d7fb3d60 91 TcpHdrFIN = true; //Inform the client that we have no more to send after this
andrewboyson 57:e0fb648acf48 92 if (pTcb->hadFin) pTcb->state = TCB_ACK_WAIT; //Passive close
andrewboyson 57:e0fb648acf48 93 else pTcb->state = TCB_FIN_WAIT; //Active close
andrewboyson 10:f0854784e960 94 }
andrewboyson 56:35117a8b5c65 95 else
andrewboyson 56:35117a8b5c65 96 {
andrewboyson 73:43e3d7fb3d60 97 TcpHdrFIN = false;
andrewboyson 56:35117a8b5c65 98 }
andrewboyson 22:914b970356f0 99
andrewboyson 52:fbc5a46b5e16 100 pTcb->elapsed = TcbElapsed;
andrewboyson 10:f0854784e960 101 }
andrewboyson 71:736a5747ade1 102 static void closeConnectionOut()
andrewboyson 56:35117a8b5c65 103 {
andrewboyson 73:43e3d7fb3d60 104 TcpHdrACK = true; //Send ACK
andrewboyson 73:43e3d7fb3d60 105 TcpHdrPSH = false;
andrewboyson 73:43e3d7fb3d60 106 TcpHdrRST = false;
andrewboyson 73:43e3d7fb3d60 107 TcpHdrSYN = false;
andrewboyson 73:43e3d7fb3d60 108 TcpHdrFIN = false;
andrewboyson 10:f0854784e960 109
andrewboyson 73:43e3d7fb3d60 110 TcpHdrClearOptions();
andrewboyson 10:f0854784e960 111 dataLength = 0;
andrewboyson 10:f0854784e960 112
andrewboyson 57:e0fb648acf48 113 pTcb->state = TCB_EMPTY;
andrewboyson 10:f0854784e960 114 }
andrewboyson 10:f0854784e960 115
andrewboyson 71:736a5747ade1 116 int TcpHandleReceivedPacket(void (*traceback)(void), int sizeRx, void* pPacketRx, int* pSizeTx, void* pPacketTx, int type, void* pCachedRemIp)
andrewboyson 10:f0854784e960 117 {
andrewboyson 73:43e3d7fb3d60 118 TcpHdrRead(pPacketRx);
andrewboyson 59:e0e556c8bd46 119
andrewboyson 73:43e3d7fb3d60 120 dataLength = sizeRx - TcpHdrSize;
andrewboyson 73:43e3d7fb3d60 121 maxMss = *pSizeTx - TcpHdrSize;
andrewboyson 73:43e3d7fb3d60 122
andrewboyson 57:e0fb648acf48 123 doTrace = false;
andrewboyson 57:e0fb648acf48 124
andrewboyson 57:e0fb648acf48 125 //Filter out unwanted links
andrewboyson 73:43e3d7fb3d60 126 switch (TcpHdrDstPort)
andrewboyson 57:e0fb648acf48 127 {
andrewboyson 57:e0fb648acf48 128 case 80:
andrewboyson 57:e0fb648acf48 129 if (HttpTrace)
andrewboyson 57:e0fb648acf48 130 {
andrewboyson 57:e0fb648acf48 131 if (NetTraceNewLine) Log("\r\n");
andrewboyson 57:e0fb648acf48 132 LogTime("HTTP server request\r\n");
andrewboyson 57:e0fb648acf48 133 doTrace = true;
andrewboyson 57:e0fb648acf48 134 }
andrewboyson 57:e0fb648acf48 135 break;
andrewboyson 57:e0fb648acf48 136
andrewboyson 57:e0fb648acf48 137 default:
andrewboyson 57:e0fb648acf48 138 if (TcpTrace)
andrewboyson 57:e0fb648acf48 139 {
andrewboyson 57:e0fb648acf48 140 if (NetTraceNewLine) Log("\r\n");
andrewboyson 73:43e3d7fb3d60 141 LogTimeF("TCP unknown port %d\r\n", TcpHdrDstPort);
andrewboyson 59:e0e556c8bd46 142 if (NetTraceStack) traceback();
andrewboyson 57:e0fb648acf48 143 }
andrewboyson 57:e0fb648acf48 144 return DO_NOTHING; //Ignore unknown ports
andrewboyson 57:e0fb648acf48 145 }
andrewboyson 55:e64b8b47a2b6 146
andrewboyson 55:e64b8b47a2b6 147 //Get the Transmission Control Block
andrewboyson 73:43e3d7fb3d60 148 pTcb = TcbGetExisting(TcpHdrSrcPort);
andrewboyson 10:f0854784e960 149 if (!pTcb) pTcb = TcbGetEmpty();
andrewboyson 52:fbc5a46b5e16 150 if (!pTcb)
andrewboyson 52:fbc5a46b5e16 151 {
andrewboyson 52:fbc5a46b5e16 152 if (TcpTrace)
andrewboyson 52:fbc5a46b5e16 153 {
andrewboyson 57:e0fb648acf48 154 if (NetTraceNewLine) Log("\r\n");
andrewboyson 52:fbc5a46b5e16 155 LogTime("TCP no more tcbs are available\r\n");
andrewboyson 59:e0e556c8bd46 156 if (NetTraceStack) traceback();
andrewboyson 52:fbc5a46b5e16 157 }
andrewboyson 52:fbc5a46b5e16 158 return DO_NOTHING; //Bomb out if no more tcbs are available
andrewboyson 52:fbc5a46b5e16 159 }
andrewboyson 10:f0854784e960 160
andrewboyson 55:e64b8b47a2b6 161 //Handle request to reset
andrewboyson 73:43e3d7fb3d60 162 if (TcpHdrRST)
andrewboyson 10:f0854784e960 163 {
andrewboyson 57:e0fb648acf48 164 if (TcpTrace)
andrewboyson 57:e0fb648acf48 165 {
andrewboyson 57:e0fb648acf48 166 if (NetTraceNewLine) Log("\r\n");
andrewboyson 57:e0fb648acf48 167 LogTime("TCP received reset - resetting TCB\r\n");
andrewboyson 59:e0e556c8bd46 168 if (NetTraceStack) traceback();
andrewboyson 57:e0fb648acf48 169 }
andrewboyson 57:e0fb648acf48 170 pTcb->state = TCB_EMPTY; //Reset connection
andrewboyson 57:e0fb648acf48 171 return DO_NOTHING; //Don't reply
andrewboyson 10:f0854784e960 172 }
andrewboyson 55:e64b8b47a2b6 173
andrewboyson 55:e64b8b47a2b6 174 //Handle request to synchronise
andrewboyson 73:43e3d7fb3d60 175 if (TcpHdrSYN)
andrewboyson 55:e64b8b47a2b6 176 {
andrewboyson 73:43e3d7fb3d60 177 pTcb->recvIsn = TcpHdrSeqNum;
andrewboyson 72:19457bba58d0 178 pTcb->sendIsn = TcbGetIsn();
andrewboyson 57:e0fb648acf48 179 pTcb->recdBytes = 0;
andrewboyson 57:e0fb648acf48 180 pTcb->sentBytes = 0;
andrewboyson 55:e64b8b47a2b6 181 }
andrewboyson 72:19457bba58d0 182 else
andrewboyson 10:f0854784e960 183 {
andrewboyson 73:43e3d7fb3d60 184 pTcb->recdBytes = TcpHdrSeqNum - pTcb->recvIsn;
andrewboyson 73:43e3d7fb3d60 185 pTcb->sentBytes = TcpHdrAckNum - pTcb->sendIsn;
andrewboyson 52:fbc5a46b5e16 186 }
andrewboyson 72:19457bba58d0 187
andrewboyson 59:e0e556c8bd46 188 if (doTrace && NetTraceStack) traceback(); //This will already include the TCP header
andrewboyson 55:e64b8b47a2b6 189
andrewboyson 73:43e3d7fb3d60 190 if (TcpHdrSYN) pTcb->recdBytes += 1; //Add one to acknowledge the SYN
andrewboyson 73:43e3d7fb3d60 191 pTcb->recdBytes += dataLength; //Add the number of bytes received
andrewboyson 73:43e3d7fb3d60 192 if (TcpHdrFIN) pTcb->recdBytes += 1; //Add one to acknowledge the FIN
andrewboyson 10:f0854784e960 193
andrewboyson 10:f0854784e960 194 switch (pTcb->state)
andrewboyson 10:f0854784e960 195 {
andrewboyson 57:e0fb648acf48 196 case TCB_EMPTY:
andrewboyson 73:43e3d7fb3d60 197 if (!TcpHdrSYN) { resetConnectionOut("received other than a SYN when connection closed"); break; }
andrewboyson 73:43e3d7fb3d60 198 startConnectionIn(pPacketRx, pCachedRemIp);
andrewboyson 73:43e3d7fb3d60 199 startConnectionOut(pPacketTx);
andrewboyson 56:35117a8b5c65 200 break;
andrewboyson 56:35117a8b5c65 201
andrewboyson 56:35117a8b5c65 202 case TCB_SYN_RECEIVED:
andrewboyson 73:43e3d7fb3d60 203 if (dataLength) { resetConnectionOut("data received before connection established"); break; }
andrewboyson 73:43e3d7fb3d60 204 if (!TcpHdrACK) { resetConnectionOut("received other than an ACK before connection established"); break; }
andrewboyson 71:736a5747ade1 205 establishConnectionIn();
andrewboyson 56:35117a8b5c65 206 return DO_NOTHING;
andrewboyson 56:35117a8b5c65 207
andrewboyson 56:35117a8b5c65 208 case TCB_ESTABLISHED:
andrewboyson 73:43e3d7fb3d60 209 if (!TcpHdrACK) { resetConnectionOut("received other than an ACK during established conection"); break; }
andrewboyson 73:43e3d7fb3d60 210 if (TcpHdrFIN) pTcb->hadFin = true; //When reply is all sent only a passive close is needed
andrewboyson 73:43e3d7fb3d60 211 handleEstablishedConnectionIn (pPacketRx);
andrewboyson 73:43e3d7fb3d60 212 handleEstablishedConnectionOut(pPacketTx);
andrewboyson 56:35117a8b5c65 213 break;
andrewboyson 56:35117a8b5c65 214
andrewboyson 57:e0fb648acf48 215 case TCB_FIN_WAIT: //End of active close
andrewboyson 73:43e3d7fb3d60 216 if (!TcpHdrFIN) return DO_NOTHING; //Ignore ACK to our FIN. Wait for FIN then close.
andrewboyson 71:736a5747ade1 217 closeConnectionOut();
andrewboyson 56:35117a8b5c65 218 break;
andrewboyson 57:e0fb648acf48 219
andrewboyson 57:e0fb648acf48 220 case TCB_ACK_WAIT: //End of passive close
andrewboyson 73:43e3d7fb3d60 221 if (!TcpHdrACK) { resetConnectionOut("received other than an ACK when closing half open connection"); break; }
andrewboyson 57:e0fb648acf48 222 pTcb->state = TCB_EMPTY;
andrewboyson 57:e0fb648acf48 223 return DO_NOTHING;
andrewboyson 10:f0854784e960 224 }
andrewboyson 10:f0854784e960 225
andrewboyson 72:19457bba58d0 226 //Specify the start of the data being sent and acknowledge the data received
andrewboyson 73:43e3d7fb3d60 227 TcpHdrAckNum = pTcb->recdBytes + pTcb->recvIsn; //Set up the acknowledgement field ready to send
andrewboyson 73:43e3d7fb3d60 228 TcpHdrSeqNum = pTcb->sentBytes + pTcb->sendIsn; //Set up the start of the message before adding the bytes sent
andrewboyson 57:e0fb648acf48 229
andrewboyson 57:e0fb648acf48 230 //Keep a record of where we expect the next packet send to start
andrewboyson 73:43e3d7fb3d60 231 if (TcpHdrSYN) pTcb->sentBytes += 1; //Add one to acknowledge the SYN
andrewboyson 73:43e3d7fb3d60 232 pTcb->sentBytes += dataLength; //Record the next sequence number
andrewboyson 73:43e3d7fb3d60 233 if (TcpHdrFIN) pTcb->sentBytes += 1; //Add one to acknowledge the FIN
andrewboyson 55:e64b8b47a2b6 234
andrewboyson 57:e0fb648acf48 235 //Swap the ports for the reply
andrewboyson 73:43e3d7fb3d60 236 TcpHdrSrcPort = TcpHdrDstPort;
andrewboyson 73:43e3d7fb3d60 237 TcpHdrDstPort = pTcb->port;
andrewboyson 10:f0854784e960 238
andrewboyson 62:9b8c1e1761b6 239 //Specify the receive window size to not throttle
andrewboyson 73:43e3d7fb3d60 240 TcpHdrWindow = 4000;
andrewboyson 62:9b8c1e1761b6 241
andrewboyson 57:e0fb648acf48 242 //Calculate the size of the reply
andrewboyson 73:43e3d7fb3d60 243 *pSizeTx = TcpHdrSize + dataLength;
andrewboyson 54:84ef2b29cf7e 244
andrewboyson 55:e64b8b47a2b6 245 return ActionMakeFromDestAndTrace(UNICAST, doTrace && NetTraceStack);
andrewboyson 71:736a5747ade1 246 }
andrewboyson 10:f0854784e960 247
andrewboyson 71:736a5747ade1 248 int TcpPollForPacketToSend(int* pSize, void* pPacket, int type, void* pCachedRemIp)
andrewboyson 71:736a5747ade1 249 {
andrewboyson 73:43e3d7fb3d60 250 int dataLength = *pSize - TcpHdrSize;
andrewboyson 71:736a5747ade1 251
andrewboyson 71:736a5747ade1 252 int action = DO_NOTHING;
andrewboyson 71:736a5747ade1 253
andrewboyson 73:43e3d7fb3d60 254 TcpHdrSrcPort = TcpHdrDstPort;
andrewboyson 73:43e3d7fb3d60 255 TcpHdrDstPort = pTcb->port;
andrewboyson 71:736a5747ade1 256
andrewboyson 73:43e3d7fb3d60 257 *pSize = TcpHdrSize + dataLength;
andrewboyson 71:736a5747ade1 258 return action;
andrewboyson 10:f0854784e960 259 }
andrewboyson 71:736a5747ade1 260