?? tcp.c
字號:
/*********************************************************************
*
* Transmission Control Protocol (TCP) Communications Layer
* Module for Microchip TCP/IP Stack
* -Provides reliable, handshaked transport of application stream
* oriented data with flow control
* -Reference: RFC 793
*
*********************************************************************
* FileName: TCP.c
* Dependencies: string.h
* StackTsk.h
* Helpers.h
* IP.h
* MAC.h
* ARP.h
* Tick.h
* TCP.h
* Processor: PIC18, PIC24F, PIC24H, dsPIC30F, dsPIC33F
* Complier: Microchip C18 v3.02 or higher
* Microchip C30 v2.01 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)
* Howard Schlunder 12/11/06 Changed almost everything to
* better meet RFC 793.
********************************************************************/
#define __TCP_C
#include "mchp_tcp_ip\tcpip.h"
#if defined(STACK_USE_TCP)
#define MAX_TCP_DATA_LEN (MAC_TX_BUFFER_SIZE - sizeof(TCP_HEADER) - sizeof(IP_HEADER) - sizeof(ETHER_HEADER))
// TCP Timeout and retransmit numbers
#define TCP_START_TIMEOUT_VAL ((TICK)TICK_SECOND * (TICK)1)
#define TCP_TIME_WAIT_TIMEOUT_VAL ((TICK)TICK_SECOND * (TICK)0)
#define MAX_RETRY_COUNTS (5u)
// TCP Flags defined in RFC
#define FIN (0x01)
#define SYN (0x02)
#define RST (0x04)
#define PSH (0x08)
#define ACK (0x10)
#define URG (0x20)
// TCP Header
typedef struct _TCP_HEADER
{
WORD SourcePort;
WORD DestPort;
DWORD SeqNumber;
DWORD AckNumber;
struct
{
unsigned char Reserved3 : 4;
unsigned char Val : 4;
} DataOffset;
union
{
struct
{
unsigned char flagFIN : 1;
unsigned char flagSYN : 1;
unsigned char flagRST : 1;
unsigned char flagPSH : 1;
unsigned char flagACK : 1;
unsigned char flagURG : 1;
unsigned char Reserved2 : 2;
} bits;
BYTE byte;
} Flags;
WORD Window;
WORD Checksum;
WORD UrgentPointer;
} __attribute__((packed)) TCP_HEADER;
// TCP Options as defined by RFC
#define TCP_OPTIONS_END_OF_LIST (0x00u)
#define TCP_OPTIONS_NO_OP (0x01u)
#define TCP_OPTIONS_MAX_SEG_SIZE (0x02u)
typedef struct _TCP_OPTIONS
{
BYTE Kind;
BYTE Length;
WORD_VAL MaxSegSize;
} __attribute__((packed)) TCP_OPTIONS;
#define SwapPseudoTCPHeader(h) (h.TCPLength = swaps(h.TCPLength))
// IP 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;
#define LOCAL_PORT_START_NUMBER (1024u)
#define LOCAL_PORT_END_NUMBER (5000u)
// Local temp port numbers.
#ifdef STACK_CLIENT_MODE
#ifdef __PIC32MX__
static WORD NextPort;
#else
static WORD NextPort __attribute__((persistent));
#endif
#endif
// The TCB array is very large. With the C18 compiler, one must
// modify the linker script to make an array that spans more than
// one memory bank. To do this, make the necessary changes to your
// processor's linker script (.lkr). Here is an example showing
// gpr11 and 128 bytes of gpr12 being combined into one 384 byte
// block used exclusively by the TCB_MEM data section:
// ...
// //DATABANK NAME=gpr11 START=0xB00 END=0xBFF
// //DATABANK NAME=gpr12 START=0xC00 END=0xCFF
// DATABANK NAME=gpr11b START=0xB00 END=0xC7F PROTECTED
// DATABANK NAME=gpr12 START=0xC80 END=0xCFF
// ...
// SECTION NAME=TCP_TCB_RAM RAM=gpr11b
// ...
#pragma udata TCB_uRAM
TCB_STUB TCBStubs[MAX_TCP_SOCKETS];
#pragma udata // Return to any other RAM section
static TCB MyTCB;
static TCP_SOCKET hCurrentTCB = 0;
static void HandleTCPSeg(TCP_SOCKET hTCP, TCP_HEADER *h, WORD len);
static void SendTCP(TCP_SOCKET hTCP, BYTE flags);
static TCP_SOCKET FindMatchingSocket(TCP_HEADER *h, NODE_INFO *remote);
static void SwapTCPHeader(TCP_HEADER* header);
static void CloseSocket(TCP_SOCKET hTCP);
static void LoadTCB(TCP_SOCKET hTCP);
static void SaveTCB(TCP_SOCKET hTCP);
static void LoadTCB(TCP_SOCKET hTCP)
{
WORD PtrSave;
// if(hCurrentTCB == hTCP)
// return;
// Load up the new TCB
hCurrentTCB = hTCP;
PtrSave = MACSetReadPtr(TCBStubs[hTCP].bufferTxStart - sizeof(MyTCB));
MACGetArray((BYTE*)&MyTCB, sizeof(MyTCB));
MACSetReadPtr(PtrSave);
}
static void SaveTCB(TCP_SOCKET hTCP)
{
WORD PtrSave;
hCurrentTCB = hTCP;
// Save the current TCB
PtrSave = MACSetWritePtr(TCBStubs[hTCP].bufferTxStart - sizeof(MyTCB));
MACPutArray((BYTE*)&MyTCB, sizeof(MyTCB));
MACSetWritePtr(PtrSave);
}
/*********************************************************************
* Function: void TCPInit(void)
*
* PreCondition: None
*
* Input: None
*
* Output: TCP is initialized.
*
* Side Effects: None
*
* Overview: Initialize all socket states
*
* Note: This function is called only once during lifetime
* of the application.
********************************************************************/
void TCPInit(void)
{
TCP_SOCKET hTCP;
TCB_STUB *ps;
// Initialize all sockets.
for(hTCP = 0; hTCP < MAX_TCP_SOCKETS; hTCP++)
{
ps = &TCBStubs[hTCP];
ps->smState = TCP_CLOSED;
ps->bufferTxStart = BASE_TCB_ADDR + sizeof(TCB) + hTCP*(sizeof(TCB) + (TCP_TX_FIFO_SIZE+1) + (TCP_RX_FIFO_SIZE + 1));
ps->bufferRxStart = ps->bufferTxStart + TCP_TX_FIFO_SIZE+1;
ps->bufferEnd = ps->bufferRxStart + TCP_RX_FIFO_SIZE;
ps->Flags.bServer = FALSE;
ps->Flags.bTimerEnabled = FALSE;
}
// Initialize random number generator
srand((WORD)TickGet());
}
/*********************************************************************
* Function: TCP_SOCKET TCPListen(WORD 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(WORD port)
{
TCP_SOCKET hTCP;
TCB_STUB *ps;
for(hTCP = 0; hTCP < MAX_TCP_SOCKETS; hTCP++)
{
ps = &TCBStubs[hTCP];
if(ps->smState == TCP_CLOSED)
{
ps->Flags.bServer = TRUE;
ps->smState = TCP_LISTEN;
ps->remoteHash.Val = port;
ps->txTail = ps->bufferTxStart;
ps->txHead = ps->bufferTxStart;
ps->rxTail = ps->bufferRxStart;
ps->rxHead = ps->bufferRxStart;
MyTCB.localPort.Val = port;
MyTCB.txUnackedTail = ps->bufferTxStart;
((DWORD_VAL*)(&MyTCB.MySEQ))->w[0] = rand();
((DWORD_VAL*)(&MyTCB.MySEQ))->w[1] = rand();
SaveTCB(hTCP);
return hTCP;
}
}
return INVALID_SOCKET;
}
/*********************************************************************
* FunctionL BOOL TCPGetRemoteInfo(TCP_SOCKET hTCP, SOCKET_INFO *RemoteInfo)
*
* PreCondition: TCPInit() is already called.
*
* Input: hTCP - Handle of socket to read
*
* Output: A new socket is created, connection request is
* sent and socket handle is returned.
*
* Side Effects: None
*
* Overview: None
*
* Note: None
*
********************************************************************/
SOCKET_INFO* TCPGetRemoteInfo(TCP_SOCKET hTCP)
{
static SOCKET_INFO RemoteInfo;
LoadTCB(hTCP);
memcpy((void*)&RemoteInfo.remote, (void*)&MyTCB.remote, sizeof(NODE_INFO));
RemoteInfo.remotePort.Val = MyTCB.remotePort.Val;
return &RemoteInfo;
}
/*********************************************************************
* Function: TCP_SOCKET TCPConnect(NODE_INFO* remote,
* WORD 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, WORD remotePort)
{
TCP_SOCKET hTCP;
TCB_STUB *ps;
// Find an available socket
for(hTCP = 0; hTCP < MAX_TCP_SOCKETS; hTCP++)
{
ps = &TCBStubs[hTCP];
if(ps->smState != TCP_CLOSED)
continue;
// Zero out the TCB
memset((BYTE*)&MyTCB, 0x00, sizeof(MyTCB));
// Each new socket that is opened by this node, gets the
// next sequential port number.
if(NextPort < LOCAL_PORT_START_NUMBER || NextPort > LOCAL_PORT_END_NUMBER)
NextPort = LOCAL_PORT_START_NUMBER;
// Set the non-zero TCB fields
MyTCB.localPort.Val = NextPort++;
MyTCB.remotePort.Val = remotePort;
memcpy((void*)&MyTCB.remote, (void*)remote, sizeof(NODE_INFO));
((DWORD_VAL*)(&MyTCB.MySEQ))->w[0] = rand();
((DWORD_VAL*)(&MyTCB.MySEQ))->w[1] = rand();
MyTCB.retryCount = 0;
MyTCB.retryInterval = TCP_START_TIMEOUT_VAL;
// Zero out the buffer contents
MyTCB.txUnackedTail = ps->bufferTxStart;
ps->txHead = ps->bufferTxStart;
ps->txTail = ps->bufferTxStart;
ps->rxHead = ps->bufferRxStart;
ps->rxTail = ps->bufferRxStart;
// Update the TCB Stub
ps->remoteHash.Val = (remote->IPAddr.w[1]+remote->IPAddr.w[0] + remotePort) ^ MyTCB.localPort.Val;
ps->smState = TCP_SYN_SENT;
ps->eventTime = TickGet() + TCP_START_TIMEOUT_VAL;
ps->Flags.bTimerEnabled = TRUE;
// Save the TCB
SaveTCB(hTCP);
// Send TCP SYNchronize (connect) request
SendTCP(hTCP, SYN);
return hTCP;
}
// If there is no socket available, return error.
return INVALID_SOCKET;
}
#endif
/*********************************************************************
* Function: BOOL TCPIsConnected(TCP_SOCKET hTCP)
*
* PreCondition: TCPInit() is already called.
*
* Input: hTCP - 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 only if it is in
* the TCP_ESTABLISHED state
********************************************************************/
BOOL TCPIsConnected(TCP_SOCKET hTCP)
{
return TCBStubs[hTCP].smState == TCP_ESTABLISHED;
}
/*********************************************************************
* Function: void TCPDisconnect(TCP_SOCKET hTCP)
*
* PreCondition: TCPInit() is already called
*
* Input: hTCP - Socket to be disconnected.
*
* Output: A disconnect request is sent for given socket.
* This function does nothing if the socket isn't
* currently connected.
*
* Side Effects: None
*
* Overview: None
*
* Note: None
********************************************************************/
void TCPDisconnect(TCP_SOCKET hTCP)
{
TCB_STUB *ps;
ps = &TCBStubs[hTCP];
LoadTCB(hTCP);
switch(ps->smState)
{
//case TCP_CLOSED:
//case TCP_LISTEN:
//case TCP_LAST_ACK:
//case TCP_FIN_WAIT_1:
//case TCP_FIN_WAIT_2:
//case TCP_CLOSING:
//case TCP_TIME_WAIT:
// return;
case TCP_SYN_SENT:
CloseSocket(hTCP);
break;
case TCP_SYN_RECEIVED:
case TCP_ESTABLISHED:
MyTCB.MySEQ++;
SendTCP(hTCP, FIN | ACK);
ps->smState = TCP_FIN_WAIT_1;
// Clear timeout info
MyTCB.retryCount = 0;
MyTCB.retryInterval = TCP_START_TIMEOUT_VAL;
ps->eventTime = TickGet() + TCP_START_TIMEOUT_VAL;
ps->Flags.bTimerEnabled = TRUE;
break;
case TCP_CLOSE_WAIT:
MyTCB.MySEQ++;
SendTCP(hTCP, FIN | ACK);
ps->smState = TCP_LAST_ACK;
// Clear timeout info
MyTCB.retryCount = 0;
MyTCB.retryInterval = TCP_START_TIMEOUT_VAL;
ps->eventTime = TickGet() + TCP_START_TIMEOUT_VAL;
ps->Flags.bTimerEnabled = TRUE;
break;
}
SaveTCB(hTCP);
}
/*********************************************************************
* Function: void TCPFlush(TCP_SOCKET hTCP)
*
* PreCondition: TCPInit() is already called.
*
* Input: s - Socket whose data is to be transmitted.
*
* Output: None
*
* Side Effects: None
*
* Overview: None
*
* Note: None
********************************************************************/
void TCPFlush(TCP_SOCKET hTCP)
{
TCB_STUB *ps;
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -