tcp.c

来自「mcf5307实验源代码」· C语言 代码 · 共 1,562 行 · 第 1/5 页

C
1,562
字号
/*                                                                       */
/*      Send a tcp packet.                                               */
/*                                                                       */
/* CALLED BY                                                             */
/*      tcp_retransmit                                                   */
/*      netwrite                                                         */
/*                                                                       */
/* CALLS                                                                 */
/*                                                                       */
/*      intswap                                                          */
/*      longswap                                                         */
/*      ipcheck                                                          */
/*      tcpcheck                                                         */
/*      NET_Send                                                         */
/*                                                                       */
/* HISTORY                                                               */
/*                                                                       */
/* Maiqi Qian      12/11/96  Added assignment of retransmits value.      */
/*                                                                       */
/*************************************************************************/
int16 tcpsend(struct port *pport, struct pqueue HUGE *buf_ptr, uint16 dlen)
{
    TCPKT           *tcp_ptr;
    uint16          *temp_tcp;
    uint16          hlen;

    /* Check to see if there is an ACK timer event set.  If so clear  it out
       because the data packet that is about to be sent will include the ack. */
    if(pport->portFlags & ACK_TIMER_SET)
    {
        /*  Delete the ACK timeout timer.  */
        Stimerunset(CONCLASS, TCPACK, pport->pindex, (int32)1 );

        /* Clear the ACK timer flag in the port. */
        pport->portFlags &= (~ACK_TIMER_SET);
    }

    /* NFH - To take care of padding that is used for machines that
     * require word alignment, there is a padding field at the beginning
     * of the TCPKT.  This next code moves the pointer to the TCPPKT ahead
     * 2 bytes to make up for the padding.  */

    /* Get a pointer to the header information to be copied into the packet. */
    temp_tcp = (uint16 *) &pport->tcpout;
	temp_tcp++;

    /* Compute the length of the packet. */
    hlen = sizeof(DLAYER) + sizeof(IPLAYER) + sizeof(TCPLAYER) +
           buf_ptr->option_len;

    /* Move the header information into the packet. */
    memcpy ((void *)buf_ptr->packet, (const void *)temp_tcp, hlen);

    tcp_ptr = (TCPKT *)(buf_ptr->packet - 2);

    /* Compute and fill in the checksum. */
    tcp_ptr->t.check = tcpcheck((uint16 *)&pport->tcps,
                            (uint16 *) &tcp_ptr->t,
                            (uint16)(buf_ptr->data_len + buf_ptr->option_len +
                             sizeof(TCPLAYER)) );

    /* Initialize the number of times this packet has been retransmitted. */
    buf_ptr->retransmits = MAX_RETRANSMITS;

    /* Set a retransmit event for this packet. */
    Stimerset (CONCLASS, TCPRETRANS, pport->pindex, pport->rto,
               buf_ptr->seqnum);

    /* Increment the number of IP packets transmitted. */
    SNMP_ipOutRequests_Inc;

    /* Increment the number of TCP segments transmitted. */
    SNMP_tcpOutSegs_Inc;

    /* Send the packet. */
    NET_Send(buf_ptr, (int16)(dlen + sizeof(DLAYER) + sizeof(IPLAYER) +
             sizeof(TCPLAYER)), TCP_DATA_PKT);

    return(NU_SUCCESS);

}   /* end tcpsend() */

/*************************************************************************/
/*                                                                       */
/* FUNCTION                                                              */
/*                                                                       */
/*      ackcheck                                                         */
/*                                                                       */
/* DESCRIPTION                                                           */
/*                                                                       */
/*   Take an incoming packet and see if there is an ACK for the outgoing */
/*   side.  Use that ACK to dequeue outgoing data.                       */
/*                                                                       */
/* CALLED BY                                                             */
/*      tcpdo                                                            */
/*                                                                       */
/* CALLS                                                                 */
/*                                                                       */
/*      intswap                                                          */
/*      longswap                                                         */
/*      netputevent                                                      */
/*      Stimerunset                                                      */
/*      rmqueue                                                          */
/*      n_clicks                                                         */
/*                                                                       */
/* HISTORY                                                               */
/*                                                                       */
/*  NAME             DATE        REMARKS                                 */
/*                                                                       */
/*  G. Johnson      11/10/95     Added logic to deallocate all buffers   */
/*                               and clear all retransmit events if a    */
/*                               RST is received.                        */
/*                                                                       */
/*************************************************************************/
static int16 ackcheck(struct port *p, TCPKT *tcp_pkt)
{
    int32     ak;
    int32     rttl;
    sint      i;

    /*  We received a reset and the sequence number is within the current window
        then close the connection.  */
    if((tcp_pkt->t.flags & TRESET) &&
        (INT32_CMP(longswap(tcp_pkt->t.seq), p->in.nxt) >= 0)
        && (INT32_CMP(longswap(tcp_pkt->t.seq), (p->in.nxt+p->in.size)) <= 0))
    {

        /*  Indicate that we got a reset.  */
		NU_Tcp_Log_Error (TCP_RESET_HOST, TCP_RECOVERABLE,
						  __FILE__, __LINE__);

        /*  Indicate that the connection is closed.  */
        p->state = SCLOSED;

#if SNMP_INCLUDED
        if ((p->state == SCWAIT) || (p->state == SEST))
            SNMP_tcpEstabResets_Inc;

        SNMP_tcpConnTableUpdate(SNMP_DELETE, SEST, p->tcpout.i.ipsource,
                                p->in.port, p->tcpout.i.ipdest,
                                p->out.port);
#endif

        /* If there is an event set to transmit data then clear it. */
        if (p->xmitFlag == NU_SET)
        {
            Stimerunset (CONCLASS, CONTX, p->pindex, (int32)1);
            p->xmitFlag = NU_CLEAR;
        }

//		sprintf(buffer,"cleanup 1 :%u-%u",syntimes,++syntimes_add);
//		__TextOut(10,320,12,buffer);

		TCP_Cleanup(p);

		return (1);
    } /* end if */

    /*  If we did not get an ACK then return.  */
    if(!(tcp_pkt->t.flags & TACK))
        return(1);

    /*  Delete the timeout timer.  */
    Stimerunset(CONCLASS, TCPRETRANS, p->pindex, longswap(tcp_pkt->t.ack) );

    /*  Pick-up the other side's maximum transmission size and agree with
        him. */
    p->out.size = intswap(tcp_pkt->t.window);

    /* If the window size > 0 and the local host is currently probing the
       foreign host then restart the probing task. */
    if( (p->out.size > 0) && (p->probeFlag == NU_SET) )
    {
        /* Clear the window probe timer event. */
        Stimerunset(CONCLASS, WINPROBE, p->pindex, (int32)1);

        /* Clear the probe flag. */
        p->probeFlag = NU_CLEAR;

        /* Restart the probing task. */
#ifdef PLUS
        if (p->TXTask != NU_NULL)
            NU_Resume_Task(p->TXTask);
#else
        if (p->TXTask != -1)
            NU_Start(p->TXTask);
#endif

        /* Clear the the transmitting task pointer. */
        p->TXTask = NU_NULL;
    }

    /*  rmqueue any bytes which have been ACKed, update p->out.nxt to the
     *  new next seq number for outgoing.  Update send window.  */

    /*  Pick up the other side's ack number.  */
    ak = longswap(tcp_pkt->t.ack);

    /*  If ak is not increasing (above p->out.ack) then we should assume
     *  that it is a duplicate packet or one of those stupid keepalive
     *  packets that 4.2 sends out.  */

    if ((ak - (int32)p->out.ack) >= 0) {


        /*  Remove it from the window.  */
        rmqueue(&p->out, ak);

        p->out.ack = ak;

        /*  Check to see if this acked our most recent transmission.  If so,
            adjust the RTO value to reflect the newly measured RTT.  This
            formula reduces the RTO value so that it gradually approaches the
            most recent round trip measurement.  When a packet is retransmitted,
            this value is doubled (exponential backoff).  */
        rttl = n_clicks() - p->out.lasttime;

        /*  If there is not data in the output buffer, and the amount of
            time since the last transmission is less than the maximum
            retry timeout value and the current retry timeout value is
            greater than the minimum retry timeout value, then update
            the retry timeout value to reflect the amount of time that
            it took for the packet to be acknowledged.  */

        if (!p->out.contain && rttl < (long) (MAXRTO) && p->rto >= MINRTO)
        {
              /*  Convert the acknowledge time to an integer value.  */
              i = (int16) rttl;

              /*  Use a smoothing function to update the retry timeout
                  value.  */
              i=((p->rto - MINRTO) * 3 + i + 1) >> 2;

              /*  Update the timeout value.  */
              p->rto = (uint16) i+MINRTO;

        } /* end if - need to adjust the RTO.  */

        if (tasks_waiting_to_send > 0)
        {
#ifdef PLUS
            if (p->TXTask != NU_NULL)
            {
                /* One of the suspended tasks will be started, so decrement the
                   number of tasks waiting. */
                tasks_waiting_to_send--;

                NU_Resume_Task(p->TXTask);

                p->TXTask = NU_NULL;
            }

#else /* RTX */
            if (p->TXTask != -1)
            {
                /* One of the suspended tasks will be started, so decrement the
                   number of tasks waiting. */
                tasks_waiting_to_send--;

                NU_Resume_Task(p->TXTask);

                p->TXTask = -1;
            }
#endif /* PLUS */

        }

        /*  Indicate that the operation was successful.  */
        return(NU_SUCCESS);
    } /* end if */

    return(1);
}   /* end ackcheck() */

/*************************************************************************/
/*                                                                       */
/* FUNCTION                                                              */
/*                                                                       */
/*      estab1986                                                        */
/*                                                                       */
/* DESCRIPTION                                                           */
/*                                                                       */
/*   Take a packet which has arrived for an established connection and   */
/*   put it where it belongs.                                            */
/*                                                                       */
/* CALLED BY                                                             */
/*      tcpdo                                                            */
/*                                                                       */
/* CALLS                                                                 */
/*                                                                       */
/*      longswap                                                         */
/*      netputevent                                                      */
/*      checkfin                                                         */
/*      enqueue                                                          */
/*      dll_update_lists                                                 */
/*                                                                       */
/*************************************************************************/
static int16 estab1986(struct port *prt, TCPKT *pkt, uint16 tlen, uint16 hlen)
{
    uint16  dlen;
    uint32  sq,
            want;
    STATUS status;
      
    /*  Calculate the length of the data received.  */
    dlen = tlen - hlen;

    if(((MAXBUFFERS - Buffers_Used) <= 4) && (dlen >0))
    {
        /*  Before dropping this packet check the FIN bit to se

⌨️ 快捷键说明

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