📄 tcp.c
字号:
/*********************************************************************
*
* TCP Module for Microchip TCP/IP Stack
*
*********************************************************************
* FileName: TCP.C
* Dependencies: string.h
* StackTsk.h
* Helpers.h
* IP.h
* MAC.h
* ARP.h
* Tick.h
* TCP.h
* Processor: PIC18
* Complier: MCC18 v1.00.50 or higher
* HITECH PICC-18 V8.10PL1 or higher
* Company: Microchip Technology, Inc.
*
* Software License Agreement
*
* This software is owned by Microchip Technology Inc. ("Microchip")
* and is supplied to you for use exclusively as described in the
* associated software agreement. This software is protected by
* software and other intellectual property laws. Any use in
* violation of the software license may subject the user to criminal
* sanctions as well as civil liability. Copyright 2006 Microchip
* Technology Inc. All rights reserved.
*
* This software is provided "AS IS." MICROCHIP DISCLAIMS ALL
* WARRANTIES, EXPRESS, IMPLIED, STATUTORY OR OTHERWISE, NOT LIMITED
* TO MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND
* INFRINGEMENT. Microchip shall in no event be liable for special,
* incidental, or consequential damages.
*
*
* Author Date Comment
*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Nilesh Rajbharti 5/8/01 Original (Rev 1.0)
* Nilesh Rajbharti 5/22/02 Rev 2.0 (See version.log for detail)
* Nilesh Rajbharti 11/1/02 Fixed TCPTick() SYN Retry bug.
* Nilesh Rajbharti 12/5/02 Modified TCPProcess()
* to include localIP as third param.
* This was done to allow this function
* to calculate checksum correctly.
* Roy Schofield 10/1/04 TCPConnect() startTick bug fix.
* Howard Schlunder 1/3/05 Fixed HandleTCPSeg() unexpected
* discard problem identified by Richard
* Shelquist.
* Howard Schlunder 1/16/06 Fixed an imporbable RX checksum bug
* when using a Microchip Ethernet controller)
********************************************************************/
#define THIS_IS_TCP
#include <string.h>
#include "StackTsk.h"
#include "Helpers.h"
#include "IP.h"
#include "MAC.h"
#include "Tick.h"
#include "TCP.h"
/*
* Max TCP data length is MAC_TX_BUFFER_SIZE - sizeof(TCP_HEADER) -
* sizeof(IP_HEADER) - sizeof(ETHER_HEADER)
*/
#define MAX_TCP_DATA_LEN (MAC_TX_BUFFER_SIZE - 54)
/*
* TCP Timeout value to begin with.
*/
#define TCP_START_TIMEOUT_VAL ((TICK)TICK_SECOND * (TICK)60)
/*
* TCP Flags as defined by rfc793
*/
#define FIN (0x01)
#define SYN (0x02)
#define RST (0x04)
#define PSH (0x08)
#define ACK (0x10)
#define URG (0x20)
/*
* TCP Header def. as per rfc 793.
*/
typedef struct _TCP_HEADER
{
WORD SourcePort;
WORD DestPort;
DWORD SeqNumber;
DWORD AckNumber;
struct
{
unsigned int Reserved3 : 4;
unsigned int Val : 4;
}__attribute__ ((packed)) DataOffset;
union
{
struct
{
unsigned int flagFIN : 1;
unsigned int flagSYN : 1;
unsigned int flagRST : 1;
unsigned int flagPSH : 1;
unsigned int flagACK : 1;
unsigned int flagURG : 1;
unsigned int Reserved2 : 2;
}__attribute__ ((packed)) bits;
BYTE byte;
}__attribute__ ((packed)) Flags;
WORD Window;
WORD Checksum;
WORD UrgentPointer;
}__attribute__ ((packed)) TCP_HEADER;
/*
* TCP Options as defined by rfc 793
*/
#define TCP_OPTIONS_END_OF_LIST (0x00)
#define TCP_OPTIONS_NO_OP (0x01)
#define TCP_OPTIONS_MAX_SEG_SIZE (0x02)
typedef struct _TCP_OPTIONS
{
BYTE Kind;
BYTE Length;
WORD_VAL MaxSegSize;
}__attribute__ ((packed)) TCP_OPTIONS;
#define SwapPseudoTCPHeader(h) (h.TCPLength = swaps(h.TCPLength))
/*
* Pseudo header as defined by rfc 793.
*/
typedef struct _PSEUDO_HEADER
{
IP_ADDR SourceAddress;
IP_ADDR DestAddress;
BYTE Zero;
BYTE Protocol;
WORD TCPLength;
}__attribute__ ((packed)) PSEUDO_HEADER;
/*
* Local temp port numbers.
*/
static WORD _NextPort;
/*
* Starting segment sequence number for each new connection.
*/
static DWORD ISS;
/*
* These are all sockets supported by this TCP.
*/
#ifdef MCHP_C18
// Allow the linker to place the next TCB array into a separate
// memory bank. This is needed because the TCB array is very
// large.
#pragma udata SocketMemory
#endif
SOCKET_INFO TCB[MAX_SOCKETS];
static void HandleTCPSeg(TCP_SOCKET s,
NODE_INFO *remote,
TCP_HEADER *h,
WORD len);
static void TransmitTCP(NODE_INFO *remote,
TCP_PORT localPort,
TCP_PORT remotePort,
DWORD seq,
DWORD ack,
BYTE flags,
BUFFER buffer,
WORD len);
static TCP_SOCKET FindMatchingSocket(TCP_HEADER *h,
NODE_INFO *remote);
static void SwapTCPHeader(TCP_HEADER* header);
static void CloseSocket(SOCKET_INFO* ps);
#define SendTCP(remote, localPort, remotePort, seq, ack, flags) \
TransmitTCP(remote, localPort, remotePort, seq, ack, flags, \
INVALID_BUFFER, 0)
#define LOCAL_PORT_START_NUMBER (1024)
#define LOCAL_PORT_END_NUMBER (5000)
/*********************************************************************
* Function: void TCPInit(void)
*
* PreCondition: None
*
* Input: None
*
* Output: TCP is initialized.
*
* Side Effects: None
*
* Overview: Initialize all socket info.
*
* Note: This function is called only one during lifetime
* of the application.
********************************************************************/
void TCPInit(void)
{
TCP_SOCKET s;
SOCKET_INFO* ps;
// Initialize all sockets.
for ( s = 0; s < MAX_SOCKETS; s++ )
{
ps = &TCB[s];
ps->smState = TCP_CLOSED;
ps->Flags.bServer = FALSE;
ps->Flags.bIsPutReady = TRUE;
ps->Flags.bFirstRead = TRUE;
ps->Flags.bIsTxInProgress = FALSE;
ps->Flags.bIsGetReady = FALSE;
ps->Flags.bACKValid = FALSE;
ps->TxBuffer = INVALID_BUFFER;
ps->TimeOut = TCP_START_TIMEOUT_VAL;
}
_NextPort = LOCAL_PORT_START_NUMBER;
ISS = 0;
}
/*********************************************************************
* Function: TCP_SOCKET TCPListen(TCP_PORT port)
*
* PreCondition: TCPInit() is already called.
*
* Input: port - A TCP port to be opened.
*
* Output: Given port is opened and returned on success
* INVALID_SOCKET if no more sockets left.
*
* Side Effects: None
*
* Overview: None
*
* Note: None
********************************************************************/
TCP_SOCKET TCPListen(TCP_PORT port)
{
TCP_SOCKET s;
SOCKET_INFO* ps;
for ( s = 0; s < MAX_SOCKETS; s++ )
{
ps = &TCB[s];
if ( ps->smState == TCP_CLOSED )
{
/*
* We have a CLOSED socket.
* Initialize it with LISTENing state info.
*/
ps->smState = TCP_LISTEN;
ps->localPort = port;
ps->remotePort = 0;
/*
* There is no remote node IP address info yet.
*/
ps->remote.IPAddr.Val = 0x00;
/*
* If a socket is listened on, it is a SERVER.
*/
ps->Flags.bServer = TRUE;
ps->Flags.bIsGetReady = FALSE;
ps->TxBuffer = INVALID_BUFFER;
ps->Flags.bIsPutReady = TRUE;
return s;
}
}
return INVALID_SOCKET;
}
/*********************************************************************
* Function: TCP_SOCKET TCPConnect(NODE_INFO* remote,
* TCP_PORT remotePort)
*
* PreCondition: TCPInit() is already called.
*
* Input: remote - Remote node address info
* remotePort - remote port to be connected.
*
* Output: A new socket is created, connection request is
* sent and socket handle is returned.
*
* Side Effects: None
*
* Overview: None
*
* Note: By default this function is not included in
* source. You must define STACK_CLIENT_MODE to
* be able to use this function.
********************************************************************/
#ifdef STACK_CLIENT_MODE
TCP_SOCKET TCPConnect(NODE_INFO *remote, TCP_PORT remotePort)
{
TCP_SOCKET s;
SOCKET_INFO* ps;
BOOL lbFound;
lbFound = FALSE;
/*
* Find an available socket
*/
for ( s = 0; s < MAX_SOCKETS; s++ )
{
ps = &TCB[s];
if ( ps->smState == TCP_CLOSED )
{
lbFound = TRUE;
break;
}
}
/*
* If there is no socket available, return error.
*/
if ( lbFound == FALSE )
return INVALID_SOCKET;
/*
* Each new socket that is opened by this node, gets
* next sequential port number.
*/
ps->localPort = ++_NextPort;
if ( _NextPort > LOCAL_PORT_END_NUMBER )
_NextPort = LOCAL_PORT_START_NUMBER;
/*
* This is a client socket.
*/
ps->Flags.bServer = FALSE;
/*
* This is the port, we are trying to connect to.
*/
ps->remotePort = remotePort;
/*
* Each new socket that is opened by this node, will
* start with next segment seqeuence number.
*/
ps->SND_SEQ = ++ISS;
ps->SND_ACK = 0;
memcpy((BYTE*)&ps->remote, (const void*)remote, sizeof(ps->remote));
/*
* Send SYN message.
*/
SendTCP(&ps->remote,
ps->localPort,
ps->remotePort,
ps->SND_SEQ,
ps->SND_ACK,
SYN);
ps->smState = TCP_SYN_SENT;
ps->SND_SEQ++;
// Allow TCPTick() to operate properly
ps->startTick = TickGet();
return s;
}
#endif
/*********************************************************************
* Function: BOOL TCPIsConnected(TCP_SOCKET s)
*
* PreCondition: TCPInit() is already called.
*
* Input: s - Socket to be checked for connection.
*
* Output: TRUE if given socket is connected
* FALSE if given socket is not connected.
*
* Side Effects: None
*
* Overview: None
*
* Note: A socket is said to be connected if it is not
* in LISTEN and CLOSED mode. Socket may be in
* SYN_RCVD or FIN_WAIT_1 and may contain socket
* data.
********************************************************************/
BOOL TCPIsConnected(TCP_SOCKET s)
{
return ( TCB[s].smState == TCP_EST );
}
/*********************************************************************
* Function: void TCPDisconnect(TCP_SOCKET s)
*
* PreCondition: TCPInit() is already called AND
* TCPIsPutReady(s) == TRUE
*
* Input: s - Socket to be disconnected.
*
* Output: A disconnect request is sent for given socket.
*
* Side Effects: None
*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -