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:
Wed Oct 31 19:41:04 2018 +0000
Revision:
76:17534bde28d3
Parent:
75:603b10404183
Child:
77:6cb7d92c37f3
Tidied up the TCB to ensure there always was one even for a closed connection

Who changed what in which revision?

UserRevisionLine numberNew contents of line
andrewboyson 74:c3756bfa960e 1 #include <stdint.h>
andrewboyson 74:c3756bfa960e 2 #include <stdbool.h>
andrewboyson 75:603b10404183 3 #include <stdarg.h>
andrewboyson 74:c3756bfa960e 4
andrewboyson 74:c3756bfa960e 5 #include "log.h"
andrewboyson 74:c3756bfa960e 6 #include "net.h"
andrewboyson 74:c3756bfa960e 7 #include "action.h"
andrewboyson 74:c3756bfa960e 8 #include "tcp.h"
andrewboyson 74:c3756bfa960e 9 #include "tcphdr.h"
andrewboyson 74:c3756bfa960e 10 #include "tcpsend.h"
andrewboyson 74:c3756bfa960e 11 #include "tcb.h"
andrewboyson 74:c3756bfa960e 12 #include "ip4.h"
andrewboyson 74:c3756bfa960e 13 #include "dhcp.h"
andrewboyson 74:c3756bfa960e 14 #include "http.h"
andrewboyson 74:c3756bfa960e 15 #include "led.h"
andrewboyson 74:c3756bfa960e 16
andrewboyson 74:c3756bfa960e 17 //Payload variables
andrewboyson 74:c3756bfa960e 18 static struct tcb* pTcb;
andrewboyson 74:c3756bfa960e 19
andrewboyson 74:c3756bfa960e 20 static void logReset(char* message)
andrewboyson 74:c3756bfa960e 21 {
andrewboyson 74:c3756bfa960e 22 if (TcpTrace) { LogTime("TCP sent RST - "); Log(message); Log("\r\n"); }
andrewboyson 74:c3756bfa960e 23 }
andrewboyson 74:c3756bfa960e 24
andrewboyson 75:603b10404183 25 static void logTraceBack(void (*traceback)(void), char* fmt, ...)
andrewboyson 75:603b10404183 26 {
andrewboyson 75:603b10404183 27 if (TcpTrace)
andrewboyson 75:603b10404183 28 {
andrewboyson 75:603b10404183 29 if (NetTraceNewLine) Log("\r\n");
andrewboyson 75:603b10404183 30 va_list argptr;
andrewboyson 75:603b10404183 31 va_start(argptr, fmt);
andrewboyson 75:603b10404183 32 LogV(fmt, argptr);
andrewboyson 75:603b10404183 33 va_end(argptr);
andrewboyson 75:603b10404183 34 Log("\r\n");
andrewboyson 75:603b10404183 35 if (NetTraceStack) traceback();
andrewboyson 75:603b10404183 36 }
andrewboyson 75:603b10404183 37 }
andrewboyson 75:603b10404183 38
andrewboyson 74:c3756bfa960e 39 static void startConnection(void *pPacket, int ipType, int remArIndex, int locMss)
andrewboyson 74:c3756bfa960e 40 {
andrewboyson 74:c3756bfa960e 41 //Get the MSS to use for sends - it is the lower of the MSS advertised by the remote host and our local MSS
andrewboyson 74:c3756bfa960e 42 int remMss = TcpHdrMssGet();
andrewboyson 74:c3756bfa960e 43 pTcb->remMss = remMss ? remMss : 536; //default MSS for IPv4 [576 - 20(TCP) - 20(IP)];
andrewboyson 74:c3756bfa960e 44 if (pTcb->remMss > locMss) pTcb->remMss = locMss;
andrewboyson 74:c3756bfa960e 45
andrewboyson 75:603b10404183 46 pTcb->lastSendTime = TcbElapsed;
andrewboyson 75:603b10404183 47 pTcb->rcvdFin = false;
andrewboyson 75:603b10404183 48 pTcb->sentFin = false;
andrewboyson 75:603b10404183 49 pTcb->todo = 0;
andrewboyson 75:603b10404183 50 pTcb->remIsn = TcpHdrSeqNum;
andrewboyson 75:603b10404183 51 pTcb->locIsn = TcbGetIsn();
andrewboyson 75:603b10404183 52 pTcb->bytesRcvdFromRem = 0;
andrewboyson 75:603b10404183 53 pTcb->bytesAckdByRem = 0;
andrewboyson 75:603b10404183 54 pTcb->bytesAckdToRem = 0;
andrewboyson 75:603b10404183 55 pTcb->bytesSentToRem = 0;
andrewboyson 74:c3756bfa960e 56 }
andrewboyson 75:603b10404183 57 static void handleReceivedData(void* pPacket, int dataLength, uint32_t position)
andrewboyson 74:c3756bfa960e 58 {
andrewboyson 74:c3756bfa960e 59 pTcb->window = TcpHdrWindow;
andrewboyson 74:c3756bfa960e 60 char* pData = (char*)pPacket + TcpHdrSizeGet();
andrewboyson 74:c3756bfa960e 61 switch (pTcb->locPort)
andrewboyson 74:c3756bfa960e 62 {
andrewboyson 74:c3756bfa960e 63 case 80:
andrewboyson 75:603b10404183 64 HttpHandleRequest(dataLength, pData, position, &pTcb->todo);
andrewboyson 74:c3756bfa960e 65 break;
andrewboyson 74:c3756bfa960e 66 default:
andrewboyson 74:c3756bfa960e 67 break;
andrewboyson 74:c3756bfa960e 68 }
andrewboyson 74:c3756bfa960e 69 }
andrewboyson 74:c3756bfa960e 70
andrewboyson 74:c3756bfa960e 71 int TcpHandleReceivedPacket(void (*traceback)(void), int sizeRx, void* pPacketRx, int* pSizeTx, void* pPacketTx, int ipType, int remArIndex)
andrewboyson 74:c3756bfa960e 72 {
andrewboyson 74:c3756bfa960e 73 TcpHdrReadFromPacket(pPacketRx);
andrewboyson 74:c3756bfa960e 74
andrewboyson 74:c3756bfa960e 75 int dataLength = sizeRx - TcpHdrSizeGet();
andrewboyson 74:c3756bfa960e 76 int locMss = *pSizeTx - TcpHdrSizeGet();
andrewboyson 74:c3756bfa960e 77
andrewboyson 74:c3756bfa960e 78 TcpDoTrace = false;
andrewboyson 74:c3756bfa960e 79
andrewboyson 74:c3756bfa960e 80 //Filter out unwanted links
andrewboyson 74:c3756bfa960e 81 switch (TcpHdrDstPort)
andrewboyson 74:c3756bfa960e 82 {
andrewboyson 74:c3756bfa960e 83 case 80:
andrewboyson 74:c3756bfa960e 84 if (HttpTrace)
andrewboyson 74:c3756bfa960e 85 {
andrewboyson 74:c3756bfa960e 86 if (NetTraceNewLine) Log("\r\n");
andrewboyson 74:c3756bfa960e 87 LogTime("HTTP server request\r\n");
andrewboyson 74:c3756bfa960e 88 TcpDoTrace = true;
andrewboyson 74:c3756bfa960e 89 }
andrewboyson 74:c3756bfa960e 90 break;
andrewboyson 74:c3756bfa960e 91
andrewboyson 74:c3756bfa960e 92 default:
andrewboyson 75:603b10404183 93 logTraceBack(traceback, "TCP - unknown port %d\r\n", TcpHdrDstPort);
andrewboyson 74:c3756bfa960e 94 return DO_NOTHING; //Ignore unknown ports
andrewboyson 74:c3756bfa960e 95 }
andrewboyson 74:c3756bfa960e 96
andrewboyson 76:17534bde28d3 97 //Get the Transmission Control Block
andrewboyson 74:c3756bfa960e 98 pTcb = TcbGetExisting(TcpHdrSrcPort);
andrewboyson 76:17534bde28d3 99 if (!pTcb) pTcb = TcbGetEmpty();
andrewboyson 76:17534bde28d3 100 if (!pTcb) //Bomb out if no more tcbs are available
andrewboyson 76:17534bde28d3 101 {
andrewboyson 76:17534bde28d3 102 logTraceBack(traceback, "TCP - no more tcbs are available\r\n");
andrewboyson 76:17534bde28d3 103 return DO_NOTHING;
andrewboyson 76:17534bde28d3 104 }
andrewboyson 76:17534bde28d3 105 pTcb->remArIndex = remArIndex;
andrewboyson 76:17534bde28d3 106 pTcb->ipType = ipType;
andrewboyson 76:17534bde28d3 107 pTcb->remPort = TcpHdrSrcPort;
andrewboyson 76:17534bde28d3 108 pTcb->locPort = TcpHdrDstPort;
andrewboyson 76:17534bde28d3 109 pTcb->window = TcpHdrWindow;
andrewboyson 75:603b10404183 110
andrewboyson 74:c3756bfa960e 111 //Handle request to reset
andrewboyson 74:c3756bfa960e 112 if (TcpHdrRST)
andrewboyson 74:c3756bfa960e 113 {
andrewboyson 76:17534bde28d3 114 if (pTcb->state)
andrewboyson 74:c3756bfa960e 115 {
andrewboyson 75:603b10404183 116 logTraceBack(traceback, "TCP - received reset - resetting TCB\r\n");
andrewboyson 75:603b10404183 117 pTcb->state = TCB_EMPTY;
andrewboyson 74:c3756bfa960e 118 }
andrewboyson 74:c3756bfa960e 119 return DO_NOTHING; //Don't reply
andrewboyson 74:c3756bfa960e 120 }
andrewboyson 74:c3756bfa960e 121
andrewboyson 74:c3756bfa960e 122 //Handle request to synchronise
andrewboyson 74:c3756bfa960e 123 if (TcpHdrSYN)
andrewboyson 74:c3756bfa960e 124 {
andrewboyson 76:17534bde28d3 125 if (pTcb->state)
andrewboyson 75:603b10404183 126 {
andrewboyson 75:603b10404183 127 logReset("received a SYN when connection open");
andrewboyson 75:603b10404183 128 pTcb->state = TCB_EMPTY;
andrewboyson 75:603b10404183 129 return TcpSendReset(pSizeTx, pPacketTx, pTcb);
andrewboyson 75:603b10404183 130 }
andrewboyson 76:17534bde28d3 131 else
andrewboyson 75:603b10404183 132 {
andrewboyson 76:17534bde28d3 133 startConnection(pPacketRx, ipType, remArIndex, locMss);
andrewboyson 75:603b10404183 134 }
andrewboyson 74:c3756bfa960e 135 }
andrewboyson 74:c3756bfa960e 136
andrewboyson 76:17534bde28d3 137 //Calculate the sequence length of the received packet
andrewboyson 76:17534bde28d3 138 int seqLengthRcvd = 0;
andrewboyson 76:17534bde28d3 139 if (TcpHdrSYN) seqLengthRcvd += 1; //Add one to acknowledge the SYN
andrewboyson 76:17534bde28d3 140 seqLengthRcvd += dataLength; //Add the number of bytes received
andrewboyson 76:17534bde28d3 141 if (TcpHdrFIN) seqLengthRcvd += 1; //Add one to acknowledge the FIN
andrewboyson 76:17534bde28d3 142
andrewboyson 76:17534bde28d3 143 /*RFC793 p36 If the connection does not exist (CLOSED) then a reset is sent
andrewboyson 76:17534bde28d3 144 in response to any incoming segment except another reset.
andrewboyson 76:17534bde28d3 145 If the incoming segment has an ACK field, the reset takes its sequence number from the ACK field of the segment,
andrewboyson 76:17534bde28d3 146 otherwise the reset has sequence number zero
andrewboyson 76:17534bde28d3 147 and
andrewboyson 76:17534bde28d3 148 the ACK field is set to the sum of the sequence number and segment length of the incoming segment.
andrewboyson 76:17534bde28d3 149 The connection remains in the CLOSED state.
andrewboyson 76:17534bde28d3 150 In TcpSendReset TcpHdrAckNum = pTcb->bytesAckdToRem + pTcb->remIsn; //Set up the acknowledgement field ready to send
andrewboyson 76:17534bde28d3 151 TcpHdrSeqNum = pTcb->bytesSentToRem + pTcb->locIsn; //Set up the start of the message before adding the bytes sent
andrewboyson 76:17534bde28d3 152 */
andrewboyson 76:17534bde28d3 153 if (!TcpHdrSYN && !pTcb->state)
andrewboyson 76:17534bde28d3 154 {
andrewboyson 76:17534bde28d3 155 pTcb->remIsn = 0;
andrewboyson 76:17534bde28d3 156 pTcb->locIsn = 0;
andrewboyson 76:17534bde28d3 157 pTcb->bytesRcvdFromRem = 0;
andrewboyson 76:17534bde28d3 158 pTcb->bytesAckdByRem = 0;
andrewboyson 76:17534bde28d3 159
andrewboyson 76:17534bde28d3 160 pTcb->bytesSentToRem = TcpHdrACK ? TcpHdrAckNum : 0; //Seq number
andrewboyson 76:17534bde28d3 161 pTcb->bytesAckdToRem = TcpHdrSeqNum + seqLengthRcvd; //Ack number
andrewboyson 76:17534bde28d3 162 logReset("TCP - non SYN packet received on a closed connection");
andrewboyson 76:17534bde28d3 163 return TcpSendReset(pSizeTx, pPacketTx, pTcb);
andrewboyson 76:17534bde28d3 164 }
andrewboyson 76:17534bde28d3 165
andrewboyson 76:17534bde28d3 166 /* If the connection is in a synchronized state
andrewboyson 76:17534bde28d3 167 any unacceptable segment (out of window sequence number or
andrewboyson 76:17534bde28d3 168 unacceptible acknowledgment number) must elicit only an empty
andrewboyson 76:17534bde28d3 169 acknowledgment segment containing the current send-sequence number
andrewboyson 76:17534bde28d3 170 and an acknowledgment indicating the next sequence number expected
andrewboyson 76:17534bde28d3 171 to be received, and the connection remains in the same state.*/
andrewboyson 74:c3756bfa960e 172 uint32_t seqRcvdFromRem = TcpHdrSeqNum - pTcb->remIsn;
andrewboyson 74:c3756bfa960e 173 bool resendAck = seqRcvdFromRem != pTcb->bytesAckdToRem;
andrewboyson 75:603b10404183 174 if (resendAck) return TcpResendLastAck(pSizeTx, pPacketTx, pTcb);
andrewboyson 74:c3756bfa960e 175
andrewboyson 75:603b10404183 176 //Record the number of bytes acked by the remote host
andrewboyson 75:603b10404183 177 pTcb->bytesAckdByRem = TcpHdrAckNum - pTcb->locIsn;
andrewboyson 74:c3756bfa960e 178
andrewboyson 74:c3756bfa960e 179 //Handle FIN
andrewboyson 74:c3756bfa960e 180 if (TcpHdrFIN) pTcb->rcvdFin = true; //When reply is all sent only a passive close is needed
andrewboyson 74:c3756bfa960e 181
andrewboyson 74:c3756bfa960e 182 if (TcpDoTrace && NetTraceStack) traceback(); //This will already include the TCP header
andrewboyson 74:c3756bfa960e 183
andrewboyson 75:603b10404183 184 //Record the number of bytes received from the remote host
andrewboyson 76:17534bde28d3 185 pTcb->bytesRcvdFromRem += seqLengthRcvd;
andrewboyson 74:c3756bfa960e 186
andrewboyson 76:17534bde28d3 187 switch (pTcb->state) //This is the state of the connection BEFORE this packet arrived
andrewboyson 74:c3756bfa960e 188 {
andrewboyson 74:c3756bfa960e 189 case TCB_EMPTY:
andrewboyson 74:c3756bfa960e 190 pTcb->state = TCB_SYN_RECEIVED;
andrewboyson 74:c3756bfa960e 191 break;
andrewboyson 74:c3756bfa960e 192
andrewboyson 74:c3756bfa960e 193 case TCB_SYN_RECEIVED:
andrewboyson 74:c3756bfa960e 194 if (dataLength)
andrewboyson 74:c3756bfa960e 195 {
andrewboyson 74:c3756bfa960e 196 logReset("data received before connection established");
andrewboyson 74:c3756bfa960e 197 pTcb->state = TCB_EMPTY;
andrewboyson 75:603b10404183 198 return TcpSendReset(pSizeTx, pPacketTx, pTcb);
andrewboyson 74:c3756bfa960e 199 }
andrewboyson 74:c3756bfa960e 200 pTcb->state = TCB_ESTABLISHED;
andrewboyson 74:c3756bfa960e 201 break;
andrewboyson 74:c3756bfa960e 202
andrewboyson 74:c3756bfa960e 203 case TCB_ESTABLISHED:
andrewboyson 75:603b10404183 204 if (dataLength) handleReceivedData (pPacketRx, dataLength, seqRcvdFromRem - 1);
andrewboyson 74:c3756bfa960e 205 if (pTcb->sentFin)
andrewboyson 74:c3756bfa960e 206 {
andrewboyson 74:c3756bfa960e 207 pTcb->state = pTcb->rcvdFin ? TCB_CLOSE_ACK_WAIT : TCB_CLOSE_FIN_WAIT;
andrewboyson 74:c3756bfa960e 208 }
andrewboyson 74:c3756bfa960e 209 break;
andrewboyson 74:c3756bfa960e 210
andrewboyson 74:c3756bfa960e 211 case TCB_CLOSE_FIN_WAIT: //End of active close
andrewboyson 74:c3756bfa960e 212 if (TcpHdrFIN)
andrewboyson 74:c3756bfa960e 213 {
andrewboyson 74:c3756bfa960e 214 pTcb->state = TCB_EMPTY;//Ignore ACK to our FIN. Wait for FIN then close.
andrewboyson 74:c3756bfa960e 215 }
andrewboyson 74:c3756bfa960e 216 break;
andrewboyson 74:c3756bfa960e 217
andrewboyson 74:c3756bfa960e 218 case TCB_CLOSE_ACK_WAIT: //End of passive close
andrewboyson 74:c3756bfa960e 219 pTcb->state = TCB_EMPTY;
andrewboyson 74:c3756bfa960e 220 break;
andrewboyson 74:c3756bfa960e 221 }
andrewboyson 74:c3756bfa960e 222
andrewboyson 75:603b10404183 223 return TcpSend(pSizeTx, pPacketTx, pTcb);
andrewboyson 74:c3756bfa960e 224 }