Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: oldheating gps motorhome heating
tcp/tcp.c
- Committer:
- andrewboyson
- Date:
- 2018-10-23
- Revision:
- 73:43e3d7fb3d60
- Parent:
- 72:19457bba58d0
- Child:
- 74:c3756bfa960e
File content as of revision 73:43e3d7fb3d60:
#include <stdint.h>
#include <stdbool.h>
#include "log.h"
#include "net.h"
#include "action.h"
#include "tcp.h"
#include "tcphdr.h"
#include "tcb.h"
#include "ip4.h"
#include "dhcp.h"
#include "http.h"
#include "led.h"
//Payload variables
static int dataLength;
static int maxMss = 0;
bool TcpTrace = false;
static bool doTrace = false;
static struct tcb* pTcb;
static void resetConnectionOut(char* message)
{
if (TcpTrace)
{
LogTime("TCP ");
Log(message);
Log("\r\n");
}
dataLength = 0;
TcpHdrClearOptions();
TcpHdrACK = false;
TcpHdrPSH = false;
TcpHdrRST = true;
TcpHdrSYN = false;
TcpHdrFIN = false;
pTcb->state = TCB_EMPTY;
}
static void startConnectionIn(void *pPacket, void* pCachedRemIp)
{
TcpHdrReadOptions(pPacket); //Get the MSS
if (TcpHdrMss > maxMss) TcpHdrMss = maxMss;
pTcb->mss = TcpHdrMss;
pTcb->state = TCB_SYN_RECEIVED;
pTcb->elapsed = TcbElapsed;
pTcb->pIp = pCachedRemIp;
pTcb->port = TcpHdrSrcPort;
pTcb->hadFin = false;
}
static void startConnectionOut(void* pPacket)
{
TcpHdrMss = maxMss; //Ethernet 1500 - 20 - 20; or, in our case 768 - 20 - 20
TcpHdrWriteOptions(pPacket);
dataLength = 0;
TcpHdrACK = true; //Send ACK and SYN
TcpHdrPSH = false;
TcpHdrRST = false;
TcpHdrSYN = true;
TcpHdrFIN = false;
}
static void establishConnectionIn()
{
pTcb->state = TCB_ESTABLISHED;
pTcb->elapsed = TcbElapsed;
pTcb->todo = 0;
}
static void handleEstablishedConnectionIn(void* pPacket)
{
char* pData = (char*)pPacket + TcpHdrSize;
HttpHandleRequest(dataLength, pData, pTcb->recdBytes - 1, &pTcb->todo);
}
static void handleEstablishedConnectionOut(void* pPacket)
{
TcpHdrClearOptions();
char* pData = (char*)pPacket + TcpHdrSize;
HttpSendReply(&dataLength, pData, pTcb->sentBytes - 1, TcpHdrMss, pTcb->todo);
TcpHdrACK = true; //Send ACK
TcpHdrRST = false;
TcpHdrSYN = false;
TcpHdrPSH = false;
if (dataLength < TcpHdrMss) //If a part packet then there can be no more to send
{
TcpHdrFIN = true; //Inform the client that we have no more to send after this
if (pTcb->hadFin) pTcb->state = TCB_ACK_WAIT; //Passive close
else pTcb->state = TCB_FIN_WAIT; //Active close
}
else
{
TcpHdrFIN = false;
}
pTcb->elapsed = TcbElapsed;
}
static void closeConnectionOut()
{
TcpHdrACK = true; //Send ACK
TcpHdrPSH = false;
TcpHdrRST = false;
TcpHdrSYN = false;
TcpHdrFIN = false;
TcpHdrClearOptions();
dataLength = 0;
pTcb->state = TCB_EMPTY;
}
int TcpHandleReceivedPacket(void (*traceback)(void), int sizeRx, void* pPacketRx, int* pSizeTx, void* pPacketTx, int type, void* pCachedRemIp)
{
TcpHdrRead(pPacketRx);
dataLength = sizeRx - TcpHdrSize;
maxMss = *pSizeTx - TcpHdrSize;
doTrace = false;
//Filter out unwanted links
switch (TcpHdrDstPort)
{
case 80:
if (HttpTrace)
{
if (NetTraceNewLine) Log("\r\n");
LogTime("HTTP server request\r\n");
doTrace = true;
}
break;
default:
if (TcpTrace)
{
if (NetTraceNewLine) Log("\r\n");
LogTimeF("TCP unknown port %d\r\n", TcpHdrDstPort);
if (NetTraceStack) traceback();
}
return DO_NOTHING; //Ignore unknown ports
}
//Get the Transmission Control Block
pTcb = TcbGetExisting(TcpHdrSrcPort);
if (!pTcb) pTcb = TcbGetEmpty();
if (!pTcb)
{
if (TcpTrace)
{
if (NetTraceNewLine) Log("\r\n");
LogTime("TCP no more tcbs are available\r\n");
if (NetTraceStack) traceback();
}
return DO_NOTHING; //Bomb out if no more tcbs are available
}
//Handle request to reset
if (TcpHdrRST)
{
if (TcpTrace)
{
if (NetTraceNewLine) Log("\r\n");
LogTime("TCP received reset - resetting TCB\r\n");
if (NetTraceStack) traceback();
}
pTcb->state = TCB_EMPTY; //Reset connection
return DO_NOTHING; //Don't reply
}
//Handle request to synchronise
if (TcpHdrSYN)
{
pTcb->recvIsn = TcpHdrSeqNum;
pTcb->sendIsn = TcbGetIsn();
pTcb->recdBytes = 0;
pTcb->sentBytes = 0;
}
else
{
pTcb->recdBytes = TcpHdrSeqNum - pTcb->recvIsn;
pTcb->sentBytes = TcpHdrAckNum - pTcb->sendIsn;
}
if (doTrace && NetTraceStack) traceback(); //This will already include the TCP header
if (TcpHdrSYN) pTcb->recdBytes += 1; //Add one to acknowledge the SYN
pTcb->recdBytes += dataLength; //Add the number of bytes received
if (TcpHdrFIN) pTcb->recdBytes += 1; //Add one to acknowledge the FIN
switch (pTcb->state)
{
case TCB_EMPTY:
if (!TcpHdrSYN) { resetConnectionOut("received other than a SYN when connection closed"); break; }
startConnectionIn(pPacketRx, pCachedRemIp);
startConnectionOut(pPacketTx);
break;
case TCB_SYN_RECEIVED:
if (dataLength) { resetConnectionOut("data received before connection established"); break; }
if (!TcpHdrACK) { resetConnectionOut("received other than an ACK before connection established"); break; }
establishConnectionIn();
return DO_NOTHING;
case TCB_ESTABLISHED:
if (!TcpHdrACK) { resetConnectionOut("received other than an ACK during established conection"); break; }
if (TcpHdrFIN) pTcb->hadFin = true; //When reply is all sent only a passive close is needed
handleEstablishedConnectionIn (pPacketRx);
handleEstablishedConnectionOut(pPacketTx);
break;
case TCB_FIN_WAIT: //End of active close
if (!TcpHdrFIN) return DO_NOTHING; //Ignore ACK to our FIN. Wait for FIN then close.
closeConnectionOut();
break;
case TCB_ACK_WAIT: //End of passive close
if (!TcpHdrACK) { resetConnectionOut("received other than an ACK when closing half open connection"); break; }
pTcb->state = TCB_EMPTY;
return DO_NOTHING;
}
//Specify the start of the data being sent and acknowledge the data received
TcpHdrAckNum = pTcb->recdBytes + pTcb->recvIsn; //Set up the acknowledgement field ready to send
TcpHdrSeqNum = pTcb->sentBytes + pTcb->sendIsn; //Set up the start of the message before adding the bytes sent
//Keep a record of where we expect the next packet send to start
if (TcpHdrSYN) pTcb->sentBytes += 1; //Add one to acknowledge the SYN
pTcb->sentBytes += dataLength; //Record the next sequence number
if (TcpHdrFIN) pTcb->sentBytes += 1; //Add one to acknowledge the FIN
//Swap the ports for the reply
TcpHdrSrcPort = TcpHdrDstPort;
TcpHdrDstPort = pTcb->port;
//Specify the receive window size to not throttle
TcpHdrWindow = 4000;
//Calculate the size of the reply
*pSizeTx = TcpHdrSize + dataLength;
return ActionMakeFromDestAndTrace(UNICAST, doTrace && NetTraceStack);
}
int TcpPollForPacketToSend(int* pSize, void* pPacket, int type, void* pCachedRemIp)
{
int dataLength = *pSize - TcpHdrSize;
int action = DO_NOTHING;
TcpHdrSrcPort = TcpHdrDstPort;
TcpHdrDstPort = pTcb->port;
*pSize = TcpHdrSize + dataLength;
return action;
}