📄 tcpin.c
字号:
GOTO_DROP;
}
} else
tp->t_dupacks = 0;
break;
}
tp->t_dupacks = 0;
if (SEQ_GT(ptcp->th_ack, tp->snd_max))
{
TCP_STAT_INC(tcps_rcvacktoomuch);
goto dropafterack;
}
acked = (int)(ptcp->th_ack - tp->snd_una);
TCP_STAT_INC(tcps_rcvackpack);
TCP_STAT_ADD(tcps_rcvackbyte, acked);
/*
* If transmit timer is running and timed sequence
* number was acked, update smoothed round trip time.
* Since we now have an rtt measurement, cancel the
* timer backoff (cf., Phil Karn's retransmit alg.).
* Recompute the initial retransmit timer.
*/
if (tp->t_rtt && SEQ_GT(ptcp->th_ack, tp->t_rtseq))
tcp_xmit_timer(tp);
/*
* If all outstanding data is acked, stop retransmit
* timer and remember to restart (more output or persist).
* If there is more data to be acked, restart retransmit
* timer, using current (possibly backed-off) value.
*/
if (ptcp->th_ack == tp->snd_max)
{
tp->t_timer[TCPT_REXMT] = 0;
needoutput = 1;
} else if (tp->t_timer[TCPT_PERSIST] == 0)
tp->t_timer[TCPT_REXMT] = tp->t_rxtcur;
/*
* When new data is acked, open the congestion window.
* If the window gives us less than ssthresh packets
* in flight, open exponentially (maxseg per packet).
* Otherwise open linearly (maxseg per window,
* or maxseg^2 / cwnd per packet).
*/
{
u_short cw = tp->snd_cwnd;
u_short incr = tp->t_maxseg;
if (cw > tp->snd_ssthresh)
incr = MAX( (incr * incr / cw), (ALIGN_TYPE << 2) );
tp->snd_cwnd = MIN(cw + (u_short)incr, (IP_MAXPACKET));
}
/* If he acked more than we have sent assume he's acking a FIN.
* Note that we can also get into this when receiving ack of syn/ack
* packet, but that should be harmless.
*/
if (acked > (int)so->sendq.sb_cc)
{
tp->snd_wnd -= (u_short)so->sendq.sb_cc;
m_sbdrop(&so->sendq, so->sendq.sb_cc); /* drop everything */
ourfinisacked = 1; /* set local flag */
}
else /* acked some data */
{
m_sbdrop(&so->sendq, acked); /* drop amount he acked */
tp->snd_wnd -= (u_short)acked;
ourfinisacked = 0;
/* callback app in case it's sleeping on send */
//Printu("call tcp tx back proc\r\n");
if(so->callback)
so->callback(M_TXDATA, so, NULL);
}
/* wake up anybody sleeping on a send */
if((tp->t_state == TCPS_ESTABLISHED) &&
(acked > 0))
{
//Printu("tcp wakeup\r\n");
tcp_wakeup(&so->sendq);
}
/* update variable for our next seq number from rcvd ack */
tp->snd_una = ptcp->th_ack;
if (SEQ_LT(tp->snd_nxt, tp->snd_una))
tp->snd_nxt = tp->snd_una;
switch (tp->t_state)
{
/*
* In FIN_WAIT_1 STATE in addition to the processing
* for the ESTABLISHED state if our FIN is now acknowledged
* then enter FIN_WAIT_2.
*/
case TCPS_FIN_WAIT_1:
if (ourfinisacked)
{
/*
* If we can't receive any more
* data, then closing user can proceed.
* Starting the timer is contrary to the
* specification, but if we don't get a FIN
* we'll hang forever.
*/
if (so->state & SS_CANTRCVMORE)
{
m_disconnected(so);
tp->t_timer[TCPT_2MSL] = tcp_maxidle;
}
tp->t_state = TCPS_FIN_WAIT_2;
}
break;
/*
* In CLOSING STATE in addition to the processing for
* the ESTABLISHED state if the ACK acknowledges our FIN
* then enter the TIME-WAIT state, otherwise ignore
* the segment.
*/
case TCPS_CLOSING:
if (ourfinisacked)
{
tp->t_state = TCPS_TIME_WAIT;
tcp_canceltimers(tp);
tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL;
m_disconnected(so);
}
break;
/*
* In LAST_ACK, we may still be waiting for data to drain
* and/or to be acked, as well as for the ack of our FIN.
* If our FIN is now acknowledged, delete the TCB,
* enter the closed state and return.
*/
case TCPS_LAST_ACK:
if (ourfinisacked)
{
m_tcpclose(tp);
GOTO_DROP;
}
break;
/*
* In TIME_WAIT state the only thing that should arrive
* is a retransmission of the remote FIN. Acknowledge
* it and restart the finack timer.
*/
case TCPS_TIME_WAIT:
tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL;
goto dropafterack;
}
}
step6:
/*
* Update window information.
* Don't look at window if no ACK: TAC's send garbage on first SYN.
*/
#if DebugTcpin <= 0x03
Printu("step6\r\n");
#endif
if ((tiflags & TH_ACK) &&
(SEQ_LT(tp->snd_wl1, ptcp->th_seq) || tp->snd_wl1 == ptcp->th_seq &&
(SEQ_LT(tp->snd_wl2, ptcp->th_ack) ||
tp->snd_wl2 == ptcp->th_ack && ptcp->th_win > tp->snd_wnd)))
{
/* keep track of pure window updates */
if (pip->ip_len == 0 &&
tp->snd_wl2 == ptcp->th_ack && ptcp->th_win > tp->snd_wnd)
{
TCP_STAT_INC(tcps_rcvwinupd);
}
tp->snd_wnd = ptcp->th_win;
tp->snd_wl1 = ptcp->th_seq;
tp->snd_wl2 = ptcp->th_ack;
if (tp->snd_wnd > tp->max_sndwnd)
tp->max_sndwnd = tp->snd_wnd;
needoutput = 1;
}
/*
* pull receive urgent pointer along
* with the receive window.
*/
if (SEQ_GT(tp->rcv_nxt, tp->rcv_up))
tp->rcv_up = tp->rcv_nxt;
/*
* Process the segment text, merging it into the TCP sequencing queue,
* and arranging for acknowledgment of receipt if necessary. If a FIN
* has already been received on this connection then we just ignore
* the data.
*
* NOTE: this step also involes moving the received packet to a socket
* queue or back intto the free queue, so the pkt should not be
* referenced after this.
*/
if ((pkt->m_len || (tiflags & TH_FIN)) &&
(TCPS_HAVERCVDFIN(tp->t_state) == 0))
{
/* put data packets in the received pkt que */
#if DebugTcpin <= 0x03
Printu("tcp5 \t");
#endif
if(pkt->m_len){
#if DebugTcpin <= 0x03
Printu("11\r\n");
#endif
m_tcpreass(tp, ptcp, pkt);
}else{
#if DebugTcpin <= 0x03
Printu("12\r\n");
#endif
tcp_pktfree(pkt);
}
#if DebugTcpin <= 0x03
Printu("tcp9999\r\n");
#endif
/*
* Note the amount of data that peer has sent into
* our window, in order to estimate the sender's
* buffer size.
*/
len = (int)(mt_defrxwin - (tp->rcv_adv - tp->rcv_nxt));
if (len > (int)tp->max_rcvd)
tp->max_rcvd = (u_short)len;
if (so->callback)
{
#if DebugTcpin <= 0x03
Printu("ready to call\r\n");
#endif
m_data_upcall(so);
/* if we have FIN and app has all data, do shutdown */
if ((tiflags & TH_FIN) &&
(so->sendq.sb_cc == 0))
{
so->error = ESHUTDOWN;
/* if sock has callback, do close notify */
if(so->callback)
so->callback(M_CLOSED, so, NULL);
so->state |= SS_UPCFIN; /* flag that upcall was FINed */
}
}
}
else
{
#if DebugTcpin <= 0x03
Printu("tcp52\r\n");
#endif
tcp_pktfree(pkt);
tiflags &= ~TH_FIN;
}
/*
* If FIN is received ACK the FIN and let the user know
* that the connection is closing.
*/
if (tiflags & TH_FIN)
{
#if DebugTcpin <= 0x03
Printu("tcp fin\r\n");
#endif
if (TCPS_HAVERCVDFIN(tp->t_state) == 0)
{
so->state |= SS_CANTRCVMORE;
tp->t_flags |= TF_ACKNOW;
tp->rcv_nxt++;
}
switch (tp->t_state)
{
/*
* In SYN_RECEIVED and ESTABLISHED STATES
* enter the CLOSE_WAIT state.
*/
case TCPS_SYN_RECEIVED:
case TCPS_ESTABLISHED:
tp->t_state = TCPS_CLOSE_WAIT;
break;
/*
* If still in FIN_WAIT_1 STATE FIN has not been acked so
* enter the CLOSING state.
*/
case TCPS_FIN_WAIT_1:
tp->t_state = TCPS_CLOSING;
break;
/*
* In FIN_WAIT_2 state enter the TIME_WAIT state,
* starting the time-wait timer, turning off the other
* standard timers.
*/
case TCPS_FIN_WAIT_2:
tp->t_state = TCPS_TIME_WAIT;
tcp_canceltimers(tp);
tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL;
so->state &= ~(SS_ISCONNECTING|SS_ISCONNECTED|SS_ISDISCONNECTING);
so->state |= (SS_CANTRCVMORE|SS_CANTSENDMORE);
tcp_wakeup ((char *)so);
break;
/*
* In TIME_WAIT state restart the 2 MSL time_wait timer.
*/
case TCPS_TIME_WAIT:
tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL;
break;
}
}
#ifdef DO_TCPTRACE
if (so->so_options & SO_DEBUG)
tcp_trace("TCP_IN: state: %d, tcpcb: %x saveti: %x",
ostate, tp, &tcp_saveti);
#endif
/* see if we need to do a connect upcall */
if((tp->t_flags & TF_OPENUP) && /* flag is set */
(so->callback != NULL)) /* callback exists */
{
tp->t_flags &= ~TF_OPENUP; /* clear flag */
#if DebugTcpin <= 0x03
PrintFromUART(DebugTcpin,"TF_OPENUP!\n");
#endif
so->callback(M_OPENOK, so, NULL); /* notify application */
/* wake any task which is blocked on connect */
tcp_wakeup(so);
}
#if DebugTcpin <= 0x03
Printu("tcp4\t");
#endif
/* Return any desired output. */
if (needoutput || (tp->t_flags & TF_ACKNOW))
(void) tcp_output(tp);
return SUCCESS;
dropafterack:
/*
* Generate an ACK dropping incoming segment if it occupies
* sequence space, where the ACK reflects our state.
*/
#if DebugTcpin <= 0x03
Printu("tcp dropafterack\r\n");
#endif
if (tiflags & TH_RST)
GOTO_DROP;
tcp_pktfree(pkt);
tp->t_flags |= TF_ACKNOW;
(void) tcp_output (tp);
return SUCCESS;
dropwithreset:
#if DebugTcpin <= 0x03
Printu("tcp dropwithreset\r\n");
#endif
TCP_MIB_INC(tcpInErrs); /* keep MIB stats */
/*
* Generate a RST, dropping incoming segment.
* Make ACK acceptable to originator of segment.
* Don't bother to respond if destination was broadcast.
*/
if (tiflags & TH_RST)
GOTO_DROP;
mask = ~pkt->net->snmask; /* set mask for broadcast detection */
if((pip->ip_dest & mask) == mask) /* don't reset broadcasts */
GOTO_DROP;
if(tp == NULL || so == NULL)
{
/* dtrap("tcpin 4\n");*/ /* (yaxon del) */
GOTO_DROP;
}
/* If socket is in LISTEN state template is not set */
if(tp->t_template == NULL)
GOTO_DROP;
if (tiflags & TH_SYN)
tp->snd_nxt++;
tp->t_flags |= TF_SENDRST; /* force a reset */
tcp_output(tp);
TCP_MIB_INC(tcpOutRsts);
drop:
#if DebugTcpin <= 0x03
Printu("tcp drop\r\n");
#endif
tcp_pktfree(pkt);
/* destroy temporarily created socket */
if (dropsocket)
m_delsocket(so);
return SUCCESS;
}
/* FUNCTION: tcp_xmit_timer()
*
* PARAM1: struct tcpcb * tp
*
* RETURNS:
*/
void
tcp_xmit_timer(struct tcpcb * tp)
{
short delta;
TCP_STAT_INC(tcps_rttupdated);
if (tp->t_srtt != 0)
{
/*
* srtt is stored as fixed point with 3 bits
* after the binary point (i.e., scaled by 8).
* The following magic is equivalent
* to the smoothing algorithm in rfc793
* with an alpha of .875
* (srtt = rtt/8 + srtt*7/8 in fixed point).
* Adjust t_rtt to origin 0.
*/
delta = (short)(tp->t_rtt - 1 - (tp->t_srtt >> 3));
if ((tp->t_srtt += delta) <= 0)
tp->t_srtt = 1;
/*
* We accumulate a smoothed rtt variance
* (actually, a smoothed mean difference),
* then set the retransmit timer to smoothed
* rtt + 2 times the smoothed variance.
* rttvar is stored as fixed point
* with 2 bits after the binary point
* (scaled by 4). The following is equivalent
* to rfc793 smoothing with an alpha of .75
* (rttvar = rttvar*3/4 + |delta| / 4).
* This replaces rfc793's wired-in beta.
*/
if (delta < 0)
delta = -delta;
delta -= (short)(tp->t_rttvar >> 2);
if ((tp->t_rttvar += delta) <= 0)
tp->t_rttvar = 1;
}
else
{
/*
* No rtt measurement yet - use the
* unsmoothed rtt. Set the variance
* to half the rtt (so our first
* retransmit happens at 2*rtt)
*/
tp->t_srtt = tp->t_rtt << 3;
tp->t_rttvar = tp->t_rtt << 1;
}
tp->t_rtt = 0;
tp->t_rxtshift = 0;
TCPT_RANGESET(tp->t_rxtcur,
(short)(((tp->t_srtt >> 2) + tp->t_rttvar) >> 1),
TCPTV_MIN, TCPTV_REXMTMAX);
}
/* end of file tcp_in.c */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -