tcpin.c

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

C
1,084
字号
        // Set the new socket state to LISTEN
        pt->t_state = TSTATE_LISTEN;

        AbortSpawnSocket = 1;
    }
    else
    {
normal_resolve:
        // Send to existing socket
        hSock = SockPcbResolve( SOCKPROT_TCP, dwIPDst, (uint)pTcpHdr->DstPort,
                        dwIPSrc, (uint)pTcpHdr->SrcPort, SOCK_RESOLVE_EXACT );
        if( !hSock )
            goto dropwithreset;
        pt = (TCPPROT *)SockGetTP( hSock );
        if( !pt )
            goto dropwithresetfatal;
    }

    //
    // We now have a valid TCPROT* in pt, and a valid SOCK in hSock.
    //

    // If the state is closed, perform silent drop
    if( pt->t_state == TSTATE_CLOSED )
        goto drop;

    // Since segment received, reset IDLE and KEEPALIVE
    pt->t_tidle     = 0;
    pt->dwTicksKeep = TCPTV_KEEP_IDLE;

    // Process Options
    if( OptLen > 0 )
    {
        int    i = 0;
        INT8   opt,olen;
        uint   mss;

        for( ; i < OptLen; i+=olen )
        {
            opt = pTcpHdr->Options[i];
            if( opt == TCPOPT_EOL )
                break;
            if( opt == TCPOPT_NOP )
                olen = 1;
            else
            {
                olen = (INT8) pTcpHdr->Options[i+1];
                if( opt == TCPOPT_MAXSEG )
                {
                    if( olen == TCPOLEN_MAXSEG && (TcpFlags & TCP_SYN) )
                    {
                        // Get the MSS and notify our metrics routine
                        mss = pTcpHdr->Options[i+3]+pTcpHdr->Options[i+2]*256;
                        TcpValidateMetrics( pt, mss );
                    }
                }
            }
        }
    }

    // Calc our receive window
    win = SBGetSpace( pt->hSBRx );
    if( win < 0 )
        win = 0;
    if( win < (INT32)(pt->rcv_adv - pt->rcv_nxt) )
        win = (INT32)(pt->rcv_adv - pt->rcv_nxt);

    //
    //  Handle LISTEN and SYNSENT special
    //
    if( pt->t_state == TSTATE_LISTEN )
    {
        //
        // Socket is listening for a new connection
        //
        if( TcpFlags & TCP_RST )
            goto drop;
        if( TcpFlags & TCP_ACK )
            goto dropwithreset;
        if( !(TcpFlags & TCP_SYN) )
            goto drop;
        // RFC1122 - Discard SYN pkts sent via BCAST
        if( PktGetFlags( hPkt ) & (FLG_PKT_MACBCAST | FLG_PKT_MACMCAST) )
            goto drop;

        // Initialize ISS
        if( tmpseq )
            pt->iss = tmpseq;
        else
            pt->iss = tcp_iss;
        tcp_iss += TCP_ISSINCR / 2;
        pt->snd_una = pt->snd_nxt = pt->snd_max = pt->snd_up = pt->iss;

        // Initialize IRS
        pt->irs = seq;
        pt->rcv_adv = pt->rcv_nxt = pt->irs+1;

        // Initialize the send window
        pt->snd_wnd = (INT32)pTcpHdr->WindowSize;

        // Set the new state
        pt->t_flags |= TF_ACKNOW;
        pt->t_state = TSTATE_SYNRCVD;
        pt->dwTicksKeep = TCPTV_KEEP_INIT;

        // Bump Stats
        tcps.dwAccepts++;

        // Try and get a route for this socket
        TcpValidateMetrics( pt, 0 );

        // Don't drop the (possibly) newly spawned socket
        AbortSpawnSocket = 0;

        goto continueSYN;
    }
    else if( pt->t_state == TSTATE_SYNSENT )
    {
        //
        // Socket is connecting
        //

        // Check for an illegal ACK
        if( (TcpFlags & TCP_ACK) &&
                 (SEQ_LEQ(ack, pt->iss) || SEQ_GT(ack, pt->snd_max)) )
            goto dropwithreset;

        // Check for refused connection
        if( TcpFlags & TCP_RST )
        {
            // If ACK set (we know its OK at this point), send
            // Connection Refused. Else we just drop the segment
            if( TcpFlags & TCP_ACK )
                TcpDrop( pt, ECONNREFUSED );
            goto drop;
        }

        // Check for no SYN
        if( !(TcpFlags & TCP_SYN) )
            goto drop;

        // Initialize IRS
        pt->irs = seq;
        pt->rcv_adv = pt->rcv_nxt = pt->irs+1;

        // We ack the SYN no matter what...
        pt->t_flags |= TF_ACKNOW;

        // See if sender is ACK'ing. If not, enter the SYNRCVD state
        if( !(TcpFlags & TCP_ACK) )
            pt->t_state = TSTATE_SYNRCVD;
        else
        {
            // We're connected
            tcps.dwConnects++;

            // Update ACK'd data
            pt->snd_una = ack;

            // Turn off retransmit timer
            pt->dwTicksRexmt = 0;

            // Set state
            pt->t_state = TSTATE_ESTAB;

            // Notify Socket
            SockNotify( pt->hSock, SOCK_NOTIFY_CONNECT );
        }

continueSYN:
        // Force a window update (snd_wl1 will be < seq)
        pt->snd_wl1 = seq;

        // Advance Seq to account for the SYN
        seq++;

        // Trim data for fit our window
        if( len > win )
        {
            len = win;
            // If we trim, we can't have a FIN (we trimmed it!)
            TcpFlags &= ~TCP_FIN;
        }

        // Init urgent data sequence number
        pt->rcv_up  = seq;

        goto continueALL;
    }

    //
    //  The state is other than LISTEN or SYNSENT
    //

    //
    // Drop duplicate data
    //
    todrop = pt->rcv_nxt - seq;
    if( todrop > 0 )
    {
        // If there's a SYN, its one less byte to drop
        if( TcpFlags & TCP_SYN )
        {
            // Skip SYN (we've already seen it)
            TcpFlags &= ~TCP_SYN;

            // Adjust seq to reflect elimination of SYN
            seq++;

            // Also adjust URG
            if( TcpFlags & TCP_URG )
            {
                if( pTcpHdr->UrgPtr > 1 )
                    pTcpHdr->UrgPtr--;
                else
                    TcpFlags &= ~TCP_URG;
            }

            // Now we don't drop as much
            todrop--;
        }

        // See if entire packet is redundant
        if( todrop > len ||
            (todrop == len && !(TcpFlags & TCP_FIN)) )
        {
            //
            // Duplicate packet
            //
            tcps.dwRcvDupPack++;
            tcps.dwRcvDupByte += (UINT32)len;

            // Set todrop to entire packet
            todrop = len;

            // Drop any DUP FIN
            TcpFlags &= ~TCP_FIN;

            // ACK now to resynch
            pt->t_flags |= TF_ACKNOW;
        }
        else
        {
            // Partial dup packet
            tcps.dwRcvPartDupPack++;
            tcps.dwRcvPartDupByte += (UINT32)todrop;
        }

        // Now adjust the packet
        seq += todrop;
        len -= todrop;
        Offset += (uint)todrop;

        // Also adjust URG
        if( TcpFlags & TCP_URG )
        {
            if( pTcpHdr->UrgPtr > (UINT16)todrop )
                pTcpHdr->UrgPtr -= (UINT16)todrop;
            else
                TcpFlags &= ~TCP_URG;
        }
    }

    //
    // Can't receive data on a closed segment
    //
    if( pt->t_state > TSTATE_ESTAB && len &&
             pt->t_state != TSTATE_FINWAIT1 && pt->t_state != TSTATE_FINWAIT2 )
    {
        TcpClose( pt );
        tcps.dwRcvAfterClose++;
        goto dropwithreset;
    }

    //
    // Trim data to our window size
    //
    todrop = (seq + (UINT32)len) - (pt->rcv_nxt + win);
    if( todrop > 0 )
    {
        tcps.dwRcvAfterWinPack++;

        if( todrop < len )
            tcps.dwRcvAfterWinByte += (UINT32)todrop;
        else
        {
            // If this is a SYN request and we are in TIMEWAIT,
            // we can close now and restart
            if( (TcpFlags & TCP_SYN) &&
                pt->t_state == TSTATE_TIMEWAIT &&
                SEQ_GT( seq, pt->rcv_nxt ) )
            {
                tmpseq = pt->rcv_nxt + TCP_ISSINCR;
                TcpClose( pt );
                goto findpcb;
            }

            // If our window is closed and this is a single
            // byte, then it is a probe. ACK it now.
            if( !win && seq == pt->rcv_nxt )
            {
                pt->t_flags |= TF_ACKNOW;
                tcps.dwRcvWinProbe++;
            }
            else
            {
                // This is simply bad data we send a RST
                // unless the RST flag is set in this segment
                goto dropafterack;
            }
        }

        // Drop data past window
        len -= todrop;

        // Ignore PSH, and we must have trimmed off any FIN
        TcpFlags &= ~(TCP_PSH|TCP_FIN);
    }

    //
    // Process a RST
    //
    if( TcpFlags & TCP_RST )
    {
        // What we do is state dependent
        // 1. Set error as required
        // 2. Bump the Drops stat as needed
        // 3. Proceed directly to CLOSED without passing GO
        // 4. Drop the packet
        switch( pt->t_state )
        {
        case TSTATE_SYNRCVD:
        case TSTATE_ESTAB:
        case TSTATE_FINWAIT1:
        case TSTATE_FINWAIT2:
        case TSTATE_CLOSEWAIT:
            if( pt->t_state == TSTATE_SYNRCVD )
                SockSetError( pt->hSock, ECONNREFUSED );
            else
                SockSetError( pt->hSock, ECONNRESET );
            tcps.dwDrops++;

        case TSTATE_CLOSING:
        case TSTATE_LASTACK:
        case TSTATE_TIMEWAIT:
            TcpClose( pt );
            goto drop;
        }
    }

    //
    // If we still have a SYN (i.e.: wasn't removed as a dup),
    // then we've got problems
    //
    if( TcpFlags & TCP_SYN )
    {
        TcpDrop( pt, ECONNRESET );
        goto dropwithreset;
    }

    //
    // If the ACK bit isn't set at this point, then its an illegal packet

⌨️ 快捷键说明

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