📄 tcp.c
字号:
/*************************************************************************
*
* Copyright (c) 1993 - 2001 Accelerated Technology, Inc.
*
* PROPRIETARY RIGHTS of Accelerated Technology are involved in the
* subject matter of this material. All manufacturing, reproduction,
* use, and sales rights pertaining to this subject matter are governed
* by the license agreement. The recipient of this software implicitly
* accepts the terms of the license.
*
*************************************************************************/
/* Portions of this program were written by: */
/*************************************************************************
*
* part of:
* TCP/UDP/ICMP/IP Network kernel for NCSA Telnet
* by Tim Krauskopf
*
* National Center for Supercomputing Applications
* 152 Computing Applications Building
* 605 E. Springfield Ave.
* Champaign, IL 61820
*
*
************************************************************************/
/*************************************************************************
*
* FILENAME VERSION
*
* TCP.C 4.4
*
* DESCRIPTION
*
* TCP level routines
*
* DATA STRUCTURES
*
* int TCP_Backoff[MAX_RETRANSMITS + 1]
* struct _TCP_Port *TCP_Ports[TCP_MAX_PORTS]
* INT16 tasks_waiting_to_send
* UINT32 TCP_Ack_Timeout
*
* FUNCTIONS
*
* TCP_ACK_Check
* TCP_ACK_It
* TCP_Check_FIN
* TCP_Check_MSS
* TCP_Check_OOO_List
* TCP_Cleanup
* TCP_Do
* TCP_Estab1986
* TCP_Find_Empty_Port
* TCP_Get_Opt
* TCP_Interpret
* TCP_Make_Port
* TCP_OOO_Packet
* TCP_Reset_FIN
* TCP_Retransmit
* TCP_Send
* TCP_Send_ACK
* TCP_Set_Opt
* TCP_Update_Headers
* TCP_Valid_Seq
* TCP_Xmit
* TCP_Xmit_Timer
*
* DEPENDENCIES
*
* nucleus.h
* net_extr.h
* tcpdefs.h
* socketd.h
* externs.h
* target.h
* netevent.h
* nerrs.h
* tcp.h
* arp.h
*
*************************************************************************/
#include "plus/nucleus.h"
#include "net/target.h"
#include "net/inc/externs.h"
#include "net/inc/ip.h"
#include "net/inc/net_extr.h"
#include "net/inc/tcpdefs.h"
#include "net/inc/socketd.h"
#include "net/inc/netevent.h"
#include "net/inc/nerrs.h"
#include "net/inc/tcp.h"
#if (INCLUDE_SNMP == NU_TRUE)
#include SNMP_GLUE
#endif
/* This back off arrary is used by more than just TCP, therefore it
needs to be complied in even when TCP is not being used. */
int TCP_Backoff[TCP_MAX_BACKOFFS + 1];
/* Should this module even be built? */
#if (INCLUDE_TCP == NU_TRUE)
/* Local Prototypes */
static void TCP_Check_FIN (TCP_PORT *, TCPLAYER *);
static void TCP_Check_MSS (TCP_PORT *, TCPLAYER *, UINT16);
static INT16 TCP_Estab1986 (TCP_PORT *, NET_BUFFER *, UINT16, UINT16);
static INT16 TCP_ACK_Check (TCP_PORT *, TCPLAYER *);
static INT16 TCP_Reset_FIN (TCPLAYER *, struct pseudotcp *, INT16);
static INT16 TCP_Do(VOID *, NET_BUFFER *, UINT16, struct pseudotcp *, INT16);
static INT16 TCP_Find_Empty_Port (struct TASK_TABLE_STRUCT *);
static INT TCP_Valid_Seq(INT32 seq, UINT16 dlen, INT32 expected, INT32 wsize);
VOID TCP_Check_OOO_List(TCP_PORT *);
VOID TCP_Xmit_Timer(TCP_PORT *, UINT32);
INT16 TCP_OOO_Packet(TCP_PORT *, INT32);
extern NU_TASK NU_EventsDispatcher_ptr;
extern NU_TASK timer_task_ptr;
/*
* Define the TCP_Ports table. This is a critical structure in Nucleus NET
* as it maintains information about all open connections.
*/
struct _TCP_Port *TCP_Ports[TCP_MAX_PORTS];
/* A global counter of the number of tasks waiting for buffers to be freed
* so that data can be sent via TCP. Initialized in tcpinit. */
INT16 tasks_waiting_to_send;
/* This is the number of ticks to delay sending an ACK. A value of
approximately a 1/5 of a second (200ms) is recommended. This variable will
be initialized by the TCP init routine in PROTINIT.C. */
UINT32 TCP_ACK_Timeout;
/*************************************************************************
*
* FUNCTION
*
* TCP_Interpret
*
* DESCRIPTION
*
* Called when a packet comes in and passes the IP checksum and is
* of TCP protocol type. Check to see if we have an open connection
* on the appropriate port and stuff it in the right buffer
*
* INPUTS
*
* *buf_ptr
* *tcp_chk
*
* OUTPUTS
*
* INT16 0, 1, or 2
*
*************************************************************************/
INT16 TCP_Interpret (NET_BUFFER *buf_ptr, struct pseudotcp *tcp_chk)
{
TCP_PORT *prt;
UINT16 i, myport, hlen, hisport;
TCPLAYER *p;
INT socketd;
/* Increment the number of TCP segments received. */
SNMP_tcpInSegs_Inc;
/* Grab a pointer to the tcp layer */
p = (TCPLAYER *)buf_ptr->data_ptr;
/*
* checksum
* First, fill the pseudo header with its fields, then run our
* checksum to confirm it.
*
*/
if(GET16(p, TCP_CHECK_OFFSET))
{
/* compute the checksum */
if (TLS_TCP_Check( (UINT16 *) tcp_chk, buf_ptr))
{
NERRS_Log_Error (NERR_RECOVERABLE, __FILE__, __LINE__);
/* Drop the packet by placing it back on the buffer_freelist. */
MEM_Buffer_Chain_Free (&MEM_Buffer_List, &MEM_Buffer_Freelist);
/* Increment the number of TCP packets received with errors. */
SNMP_tcpInErrs_Inc;
return (2);
} /* end if, for compute of the checksum */
} /* end if, we need to do the checksum */
/*
* find the port which is associated with the incoming packet
* First try open connections, then try listeners
*/
myport = GET16(p, TCP_DEST_OFFSET);
hisport = GET16(p, TCP_SRC_OFFSET);
/* bytes offset to data */
hlen = (UINT16)(GET8(p, TCP_HLEN_OFFSET) >> 2);
/* Set the option len for this packet. */
buf_ptr->mem_option_len = (UINT16)(hlen - sizeof (TCPLAYER));
for (i = 0; i < TCP_MAX_PORTS; i++)
{
prt=TCP_Ports[i];
if((prt != NU_NULL) && (prt->in.port == myport) &&
(prt->out.port == hisport) &&
(prt->tcp_faddr == LONGSWAP(tcp_chk->source)) )
{
return (TCP_Do (prt, buf_ptr, hlen, tcp_chk, (INT16)prt->state));
} /* end if, this is the port that we want */
} /* end for, i < TCP_MAX_PORTS */
/*
* If we got this far, then the current state is either SLISTEN or SCLOSED.
* First check for listeners.
*/
if ((socketd = SCK_Check_Listeners(myport)) != -1)
{
return( TCP_Do (SCK_Sockets[socketd], buf_ptr, hlen, tcp_chk, SLISTEN));
}
/*
* no matching port was found to handle this packet, reject it
*/
/* Send a reset. */
TCP_Reset_FIN (p, tcp_chk, (INT16)(buf_ptr->mem_total_data_len - hlen));
/* If we have reached this point, nobody processed the packet. Therefore
we need to drop it by placing it back on the buffer_freelist. */
MEM_Buffer_Chain_Free (&MEM_Buffer_List, &MEM_Buffer_Freelist);
/* no error message if it is a SYN */
if(!(GET8(p, TCP_FLAGS_OFFSET) & TSYN))
{
/* Increment the number of TCP packets received with errors. */
SNMP_tcpInErrs_Inc;
NERRS_Log_Error (NERR_RECOVERABLE, __FILE__, __LINE__);
} /* end if t.flags & TSYN */
/* return on port matches */
return (1);
} /* TCP_Interpret() */
/*************************************************************************
*
* FUNCTION
*
* TCP_Do
*
* DESCRIPTION
*
* Deliver the incoming packet.
*
* INPUTS
*
* *input
* *buf_ptr
* hlen
* *tcp_chk
* state
*
* OUTPUTS
*
* INT16 0 or 1
*
*************************************************************************/
static INT16 TCP_Do(VOID *input, NET_BUFFER *buf_ptr, UINT16 hlen,
struct pseudotcp *tcp_chk, INT16 state)
{
struct TASK_TABLE_STRUCT *task_entry;
UINT16 myport;
INT tasklist_num;
INT portlist_num;
TCPLAYER *p;
UINT16 tlen;
UINT8 flags;
NET_BUFFER *nxtPkt;
TCP_PORT *prt;
SOCKET *listen_socket;
SOCKET *new_socket;
#if (INCLUDE_SNMP == NU_TRUE)
UINT8 tcp_laddr[4];
UINT8 tcp_faddr[4];
#endif
if (state == SLISTEN)
{
prt = NU_NULL;
listen_socket = input;
}
else
{
prt = input;
listen_socket = NU_NULL;
}
/* Get the total length on the packet. Including the TCP header. */
tlen = (INT16) buf_ptr->mem_total_data_len;
/* Get a pointer to the TCP header. */
p = (TCPLAYER *)buf_ptr->data_ptr;
/* Strip off the TCP header from the data sizes and data ptr. */
buf_ptr->data_ptr += (sizeof (TCPLAYER) + buf_ptr->mem_option_len);
buf_ptr->data_len -= (sizeof (TCPLAYER) + buf_ptr->mem_option_len);
buf_ptr->mem_total_data_len -= (sizeof (TCPLAYER) + buf_ptr->mem_option_len);
/* Enter the state machine. Determine the current state and perform
the appropriate function. Completed I/O will invoke this
routine and consequently advance the state. */
flags = GET8(p, TCP_FLAGS_OFFSET);
switch (state)
{
case SLISTEN: /* Waiting for a remote connection. */
/* If a reset is received, ignore it since we have not
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -