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 + -
显示快捷键?