tcp.c

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

C
1,562
字号
/*************************************************************************/
/*                                                                       */
/* FUNCTION                                                              */
/*                                                                       */
/*      tcpresetfin                                                      */
/*                                                                       */
/* DESCRIPTION                                                           */
/*                                                                       */
/*  Send a reset packet back to sender                                   */
/*  Use the packet which just came in as a template to return to         */
/*  sender.  Fill in all of the fields necessary and dlayersend it back. */
/*                                                                       */
/* CALLED BY                                                             */
/*      TCP_Interpret                                                    */
/*                                                                       */
/* CALLS                                                                 */
/*                                                                       */
/*      intswap                                                          */
/*      longswap                                                         */
/*      ipcheck                                                          */
/*      tcpcheck                                                         */
/*      NET_Send                                                         */
/*                                                                       */
/*************************************************************************/
static int16 tcpresetfin(TCPKT *t, uint16 dlen)
{
    uint16              tport;
    struct pseudotcp    xxx;
    struct pqueue HUGE  *buf_ptr;
    TCPKT               *out_tcp;
      
    if(t->t.flags&TRESET)     /* don't reset a reset */
        return(1);

    /* We need to build a new packet to transmit this reset back to the
       sender.  Therefore, we must get the packet itself and we must acquire
       a header packet for the transmit operation (see below).  */

    /* Allocate a buffer to place the arp packet in. */
    buf_ptr = (struct pqueue HUGE *)dll_dequeue((tqe_t *)&buffer_freelist);

    if(buf_ptr == NU_NULL)
    {
        return (NU_NULL);
    }

    /* Initialize each field in the allocated buffer. */
    buf_ptr->data_len = 0;
    buf_ptr->next = (struct pqueue *)NU_NULL;
    buf_ptr->previous = (struct pqueue *)NU_NULL;
    buf_ptr->seqnum = 0;

    /* Set up a pointer to the packet. */
    out_tcp = (TCPKT *)(buf_ptr->packet - 2);

    /*  Now we start building the packet itself.  We move the data from
        the TCP packet that we received into our newly allocated packet.  */

    /*  Swap TCP layer portions for sending back. */
    if(t->t.flags&TACK)
    {
        out_tcp->t.seq=t->t.ack;        /* ack becomes next seq # */
        out_tcp->t.ack=0L;              /* ack # is 0 */
        out_tcp->t.flags=TRESET|TFIN;
    } /* end if */
    else
    {
        out_tcp->t.seq=0L;
        if(t->t.flags&TSYN)
            out_tcp->t.ack=longswap(longswap(t->t.seq)+ dlen + 1);
        else
            out_tcp->t.ack=longswap(longswap(t->t.seq)+ dlen);
        out_tcp->t.flags=TRESET|TACK|TFIN;
    } /* end else */

    tport=t->t.source;              /* swap port #'s */
    out_tcp->t.source=t->t.dest;
    out_tcp->t.dest=tport;
    out_tcp->t.hlen=20<<2;                /* header len */
    out_tcp->t.window=0;
    out_tcp->t.urgent = t->t.urgent;

    /*  Create pseudo header for checksum.  */
    xxx.z=0;
    xxx.proto=t->i.protocol;
    xxx.tcplen=intswap(20);
    memcpy ((void *)xxx.source, (const void *)t->i.ipsource, 4);
    memcpy ((void *)xxx.dest, (const void *)t->i.ipdest, 4);
    out_tcp->t.check=0;
    out_tcp->t.check=tcpcheck( (uint16 *) &xxx, (uint16 *) &out_tcp->t,
                           (uint16)sizeof(struct tcph));

    /*  IP and data link layers. */

    /* machine it came from */
    memcpy ((void *)out_tcp->i.ipdest, (const void *)t->i.ipsource, 4);
    memcpy ((void *)out_tcp->i.ipsource, (const void *)nnipnum, 4);
    out_tcp->i.versionandhdrlen = t->i.versionandhdrlen;
    out_tcp->i.service = t->i.service;
    out_tcp->i.protocol = t->i.protocol;
    out_tcp->i.frags = t->i.frags;
    out_tcp->i.tlen=intswap(sizeof(IPLAYER)+sizeof(TCPLAYER));
    out_tcp->i.ident = (uint16)nnipident++;
    out_tcp->i.ttl=30;
    out_tcp->i.check=0;
    out_tcp->i.check=ipcheck((uint16 *)&out_tcp->i,10);
    out_tcp->d.type = t->d.type;

    /* data link address */
    memcpy ((void *)out_tcp->d.dest, (const void *)t->d.me, DADDLEN);

    /* my address */
    memcpy ((void *)out_tcp->d.me, (const void *)blankd.me, DADDLEN);
      
    /* Increment the number of IP packets transmitted. */
    SNMP_ipOutRequests_Inc;

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

    /* Increment the number of TCP resets sent. */
    SNMP_tcpOutRsts_Inc;

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

    return (0);
}   /* end tcpresetfin() */

/*************************************************************************/
/*                                                                       */
/* FUNCTION                                                              */
/*                                                                       */
/*      tcp_update_headers                                               */
/*                                                                       */
/* DESCRIPTION                                                           */
/*                                                                       */
/*      Update the fields in the IP  and TCP headers that change from    */
/*      packet to packet.  Depending on the type parameter, call         */
/*      either tcpsend or tcp_sendack.                                   */
/*                                                                       */
/* CALLED BY                                                             */
/*      transq                                                           */
/*      netread                                                          */
/*      netest                                                           */
/*      doconnect                                                        */
/*      netopen                                                          */
/*      netclose                                                         */
/*      tcpdo                                                            */
/*                                                                       */
/* CALLS                                                                 */
/*                                                                       */
/*      intswap                                                          */
/*      longswap                                                         */
/*      ipcheck                                                          */
/*      tcpcheck                                                         */
/*                                                                       */
/*************************************************************************/
int16 tcp_update_headers (struct port *pport, uint16 dlen, uint32 seq_num,
                          int16 tcp_hlen)
{
    struct port          *prt;

    prt = pport;

    if (prt == NU_NULL)
	{
		NU_Tcp_Log_Error (TCP_INV_PORT, TCP_RECOVERABLE,
						  __FILE__, __LINE__);
		return (-1);
	} /* end if */

	/* do IP header first */
    prt->tcpout.i.ident = intswap ((uint16)nnipident++);
    prt->tcpout.i.tlen = intswap ( (uint16)(sizeof(struct iph) +
               sizeof(struct tcph) + dlen));
    prt->tcpout.i.check = 0;
    prt->tcpout.i.check = ipcheck ((uint16 *)&prt->tcpout.i, 10);

	/* do TCP header */
    prt->tcpout.t.seq = seq_num;         /* byte swapped */

    /* Update the ack value that will be sent. */
    prt->tcpout.t.ack = longswap (pport->in.nxt);

    /* Update the tcp header len */
    prt->tcpout.t.hlen = (tcp_hlen << 4);

   /*
	*  if the port has some credit limit, use it instead of large
	*  window buffer.  Generally demanded by hardware limitations.
	*/
    if ((uint)(prt->credit) < (prt->in.size))
	{
        prt->tcpout.t.window = intswap (prt->credit);
	}
	else
	{
        prt->tcpout.t.window = intswap (prt->in.size);  /* window size */
	}

	/* prepare pseudo-header for checksum */
    prt->tcps.tcplen = intswap ((uint16)(dlen + sizeof(TCPLAYER)));

    /* get the checksum */
    prt->tcpout.t.check = 0;

    return NU_SUCCESS;

} /* end tcp_update_headers.  */

/*************************************************************************/
/*                                                                       */
/* FUNCTION                                                              */
/*                                                                       */
/*      tcp_sendack                                                      */
/*                                                                       */
/* DESCRIPTION                                                           */
/*                                                                       */
/*      Transmit an ack packet or a packet that contains options.        */
/*      Acks work this way so that we don't have to allocate a buffer    */
/*      for a packet that will contain no data.                          */
/*                                                                       */
/* CALLED BY                                                             */
/*      transq                                                           */
/*      netread                                                          */
/*      netest                                                           */
/*      doconnect                                                        */
/*      netopen                                                          */
/*      netclose                                                         */
/*      tcpdo                                                            */
/*                                                                       */
/* CALLS                                                                 */
/*                                                                       */
/*      intswap                                                          */
/*      longswap                                                         */
/*      ipcheck                                                          */
/*      tcpcheck                                                         */
/*      NET_Send                                                         */
/*                                                                       */
/*************************************************************************/
int16 tcp_sendack(struct port *pport, uint16 dlen)
{
    TCPKT           *tcp_ptr;
    struct pqueue HUGE *buf_ptr;
    uint16         *temp_tcp;
    uint16         hlen;

    /*  Clear the PUSH flag if no data to be sent. */
    if (!pport->out.contain)
        pport->tcpout.t.flags &= ~TPUSH;

    /* Update the IP and TCP headers with the latest info.  The TCP header is
       always 5 words in size for an ACK packet. */
    tcp_update_headers(pport, dlen, longswap(pport->out.nxt), 5);

    /* Allocate a buffer to place the ack packet in. */
    buf_ptr = (struct pqueue HUGE *)dll_dequeue((tqe_t *)&buffer_freelist);

    if(buf_ptr == NU_NULL)
    {
        return (NU_NULL);
    }

    /* Initialize each field in the allocated buffer. */
    buf_ptr->data_len = dlen;
    buf_ptr->next = (struct pqueue *)NU_NULL;
    buf_ptr->previous = (struct pqueue *)NU_NULL;
    buf_ptr->seqnum = 0;

    /* 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.  */

    temp_tcp = (uint16 *) &pport->tcpout;
	temp_tcp++;

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

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

    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) (dlen + sizeof(TCPLAYER)) );


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

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

    NET_Send(buf_ptr, (int16)(dlen + sizeof(DLAYER) + sizeof(IPLAYER) +
             sizeof(TCPLAYER)), OTHER_PKT);

    return(NU_SUCCESS);
}   /* end tcp_sendack */

/*************************************************************************/
/*                                                                       */
/* FUNCTION                                                              */
/*                                                                       */
/*      tcpsend                                                          */
/*                                                                       */
/* DESCRIPTION                                                           */

⌨️ 快捷键说明

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