tcpin.c

来自「代码在ti的c67系列单片机上实现了完整的TCPIP协议栈」· C语言 代码 · 共 1,084 行 · 第 1/3 页

C
1,084
字号
//--------------------------------------------------------------------------
// Ip Stack
//--------------------------------------------------------------------------
// TCPIN.C
//
// TCP In Functions
//
// Author: Michael A. Denio
// Copyright 1999 by Texas Instruments Inc.
//-------------------------------------------------------------------------
#include <stkmain.h>
#include "tcp.h"

//--------------------------------------------------------------------
// TcpAssembly()
//
// Assembled TCP Packets into the SB
//--------------------------------------------------------------------
static int TcpAssembly( TCPPROT *pt, HANDLE hFrag, UINT8 *pb )
{
    UINT32 seq,eseq,off,len,seqT,eatseq,eatflag;
    UINT8  *pbT;
    HANDLE hFragT,hFragB;

    seq     = *(UINT32 *)pb;
    eseq    = *(UINT32 *)(pb+4);
    off     = *(UINT32 *)(pb+8);
    eatflag = *(UINT32 *)(pb+12);
    eatseq  = *(UINT32 *)(pb+16);
    len     = eseq - seq;

    // We shouldn't get here if the data is old, but check anyway.
    if( SEQ_GEQ(pt->rcv_nxt, eseq) )
    {
        tcps.dwRcvDupPack++;
        tcps.dwRcvDupByte += (eseq - seq);
        // We don't want this Frag
        return( 0 );
    }

    // If the seq is beyond us, we KNOW we can't assemble
    // anything!
    if( SEQ_GT(seq, pt->rcv_nxt) )
    {
        // Track out of order packets
        tcps.dwRcvOOPack++;
        tcps.dwRcvOOByte += len;

        // We'll put it in order so we can reassemble accurately
        if( !(hFragT = pt->hFrag) )
        {
            // Easy case - no other frags
            pt->hFrag = hFrag;
        }
        else
        {
            hFragB = 0;
            for(;;)
            {
                pbT    = FragGetBufParams( hFrag, 0, 0, 0 );
                seqT   = *(UINT32 *)pbT;
                if( SEQ_LT( seq, seqT ) )
                    break;
                if( !FragGetNext(hFragT) )
                    break;
                hFragB = hFragT;
                hFragT = FragGetNext(hFragB);
            }

            if( SEQ_LEQ( seqT, seq ) )
            {
                // We go after this frag
                FragSetNext( hFrag, FragGetNext(hFragT) );
                FragSetNext( hFragT, hFrag );
            }
            else
            {
                // We go before hFragT and after hFragB, but we must
                // trim our data to hFragT's seq since if there is
                // an overlap, hFragT's data is older

                if( SEQ_GT( eseq, seqT ) )
                    *(UINT32 *)(pb+4) = seqT;   // eseq

                FragSetNext( hFrag, hFragT );

                if( !hFragB )
                    pt->hFrag = hFrag;
                else
                    FragSetNext( hFragB, hFrag );
            }
        }
        // We want this Frag
        return( 1 );
    }
    else
    {
        // This frag contains data we want. Note it may also contain
        // data duplicated in a held Frag. First, we'll trim it to
        // any held frag
        if( (hFragT = pt->hFrag) )
        {
            pbT    = FragGetBufParams( hFragT, 0, 0, 0 );
            seqT   = *(UINT32 *)pbT;

            if( SEQ_GT( eseq, seqT ) )
            {
                len -= ( eseq - seqT );
                eseq = seqT;
            }
        }

        for(;;)
        {
            //
            // Now process our verified data
            //

            // Trim off leading data if necessary
            if( SEQ_LT(seq, pt->rcv_nxt) )
            {
                off += (pt->rcv_nxt - seq);
                len -= (pt->rcv_nxt - seq);
                seq  = pt->rcv_nxt;

                // If we trimmed the eatseq, then the offset is really
                // one byte "back".
                if( eatflag && SEQ_GT(seq, eatseq) )
                    off--;
            }

            // Now ready to "receive"
            tcps.dwRcvPack++;
            tcps.dwRcvByte += len;
            pt->rcv_nxt += len;
            pt->t_flags |= TF_DELACK;

            // If this frag contains an eatseq, then adjust the length
            if( eatflag && SEQ_LEQ( seq, eatseq ) && SEQ_LEQ( eatseq, eseq ) )
                len--;

            // If any length left, copy the data to the SB
            if( len )
                SBWrite( pt->hSBRx, (INT32)len, pb+off, hFrag );
            else
                FragFree( hFrag );

            // We will notify the socket at the end. Now, we'll search the
            // frag list for data we can use - and always reset to the start
            // if we will holes.

assemblyLoop:
            // If no next frag to look at, break
            if( !hFragT )
                break;

            // If not yet ready for this frag, break
            if( SEQ_GT(seqT, pt->rcv_nxt) )
                break;

            // At this point, we KNOW we will consume the frag

            // Get data on this frag
            hFrag   = hFragT;
            pb      = pbT;
            seq     = seqT;
            eseq    = *(UINT32 *)(pb+4);
            off     = *(UINT32 *)(pb+8);
            eatflag = *(UINT32 *)(pb+12);
            eatseq  = *(UINT32 *)(pb+16);
            len     = eseq - seq;

            // Get initial data on next frag
            hFragT = pt->hFrag = FragGetNext( hFrag );
            FragSetNext( hFrag, 0 );
            if( hFragT )
            {
                pbT    = FragGetBufParams( hFrag, 0, 0, 0 );
                seqT   = *(UINT32 *)pbT;
            }

            // Its possible (if not the first time though the loop) that
            // this data is not needed
            if( SEQ_GEQ(pt->rcv_nxt, eseq) )
            {
                tcps.dwRcvDupPack++;
                tcps.dwRcvDupByte += (eseq - seq);
                // We don't want this Frag (and neither does anyone else)
                FragFree( hFrag );
                // We keep trying though...
                goto assemblyLoop;
            }

            // If we get this far, there's data to be appended.
            // We'll loop back to the top of the loop to handle it
        }

        // When we get here, its time to nofity Socket
        SockNotify( pt->hSock, SOCK_NOTIFY_RCVDATA );

        // We consumed the Frag that was passed-in
        return(1);
    }
}

//--------------------------------------------------------------------
// TcpEnterTimeWait()
//
// TCP Connection enters TimeWait state
//--------------------------------------------------------------------
static void TcpEnterTimeWait( TCPPROT *pt )
{
    pt->dwTicksRexmt   = 0;
    pt->dwTicksPersist = 0;
    pt->dwTicksKeep    = 0;
    pt->dwTicksWait2   = 2 * TCPTV_MSL;
    pt->t_state = TSTATE_TIMEWAIT;
    SBFlush( pt->hSBTx, 1 );
    SockNotify( pt->hSock, SOCK_NOTIFY_DISCONNECT );
}

//--------------------------------------------------------------------
// TcpInput()
//
// Rx TCP Packet
//--------------------------------------------------------------------
void TcpInput( HANDLE hPkt )
{
    TCPPROT    *pt;
    HANDLE     hFrag,hSock;
    uint       w,Offset,Valid,IPHdrLen,TCPLen;
    IPN        dwIPSrc,dwIPDst;
    UINT8      *pb,TcpFlags;
    IPHDR      *pIpHdr;
    TCPHDR     *pTcpHdr;
    int        OptLen;
    UINT32     ack,seq,tmpseq,eatseq,eatflag=0;
    UINT32     *pVal;
    INT32      len,win,todrop;
    int        AbortSpawnSocket = 0;    // Set to abort spawned socket
    int        CallOutput  = 0;         // Set to force call to TcpOutput
    int        FinAcked    = 0;         // Set if our FIN was ACK'd

    if( !(hFrag = PktGetFrag( hPkt )) )
    {
        DbgPrintf(DBG_ERROR,"TcpInput: No frag data");
        PktFree( hPkt );
        return;
    }

    // Get the size of the IP Header and pointer to our data
    w = PktGetFlags( hPkt );
    if( !(w & FLG_PKT_IP_VALID) || (w & FLG_PKT_LLC_VALID) )
    {
        DbgPrintf(DBG_ERROR,"TcpInput: Bad packet");
        PktFree( hPkt );
        return;
    }

    // Get the IP header len
    IPHdrLen = PktGetSizeNet( hPkt );

    // Get the buffer parameters
    pb = FragGetBufParams( hFrag, 0, &Valid, &Offset );

    // Assign an IP header pointer
    pIpHdr = (IPHDR *)(pb + Offset);

    // Assign a TCP header pointer
    pTcpHdr = (TCPHDR *)(pb + Offset + IPHdrLen);

    // Count the total number of packets in
    tcps.dwRcvTotal++;

    // Get the total length of the TCP message
    TCPLen = (uint)(HNC16( pIpHdr->TotalLen )) - IPHdrLen;

    // Check for packet too small
    if( TCPLen < TCPHDR_SIZE )
    {
        tcps.dwRcvShort++;
        PktFree( hPkt );
        return;
    }

    // Check for bad HdrLen
    w = (pTcpHdr->HdrLen >> 4) << 2;
    OptLen = (int)w - TCPHDR_SIZE;   // Set OptLen = TCP Option Length
    len = (INT32)(TCPLen - w);       // Set len = TCP Payload Length
    if( w < TCPHDR_SIZE || w > TCPLen )
    {
        tcps.dwRcvHdrSize++;
        PktFree( hPkt );
        return;
    }

    // We need some stuff for the pseudo header
    //
    // Get source and destination
    dwIPSrc = RdNet32(&pIpHdr->dwIPSrc);
    dwIPDst = RdNet32(&pIpHdr->dwIPDst);

    // Save TCP Flags
    TcpFlags = pTcpHdr->Flags;

    // Record the Transport Header Size
    PktSetSizeTP( hPkt, TCPLen );
    PktSetFlagsSet( hPkt, FLG_PKT_TP_VALID );

    // Init pseudo header for checksum
    tpseudo.dwIPSrc  = dwIPSrc;
    tpseudo.dwIPDst  = dwIPDst;
    tpseudo.Null     = 0;
    tpseudo.Protocol = 6;
    tpseudo.Length   = HNC16(TCPLen);

    // TCPLen is now the TCP header length
    TCPLen = w;

    // Verify checksum
    w = (uint)pTcpHdr->TCPChecksum;
    TcpChecksum( pTcpHdr );
    if( w != (uint)pTcpHdr->TCPChecksum )
    {
        tcps.dwRcvBadSum++;
        PktFree( hPkt );
        return;
    }

    // Get readable seq and ack values
    seq = RdNet32(&pTcpHdr->dwSeq);
    seq = HNC32(seq);
    ack = RdNet32(&pTcpHdr->dwAck);
    ack = HNC32(ack);

    // Convert 16 bit header values right in the header
    pTcpHdr->WindowSize = HNC16(pTcpHdr->WindowSize);
    pTcpHdr->UrgPtr = HNC16(pTcpHdr->UrgPtr);

    tmpseq = 0;                 // This may get reset in another loop
findpcb:
    //
    // If this is a new SYN request, then we'll need to spawn a
    // socket to accomodate it (assuming we're listening). Otherwise,
    // we must have an exact match for this connection.
    //
    if( (TcpFlags & (TCP_SYN|TCP_ACK)) == TCP_SYN )
    {
        // New Connection Attempt
        hSock = SockPcbResolve( SOCKPROT_TCP, dwIPDst, (uint)pTcpHdr->DstPort,
                         dwIPSrc, (uint)pTcpHdr->SrcPort, SOCK_RESOLVE_SPAWN );

        // There's a chance that our first ACK was lost, so the sender may
        // send another SYN. If this is the case, the SPAWN will fail, but
        // the standard resolve will succeed
        if( !hSock )
            goto normal_resolve;

        pt = (TCPPROT *)SockGetTP( hSock );
        if( !pt )
            goto dropwithresetfatal;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?