📄 tcpnetd.c
字号:
/* If the sending of selective acknowledgements is enabled, then before sending the ACK we are about to send, update our list of SACK blocks according to the sequence number rance of the message we are about to add to the holding queue, so that the ACK will include an up-to-date list of SACK blocks. */ if (svp->sv_flags2 & SV_OUT_SACKS_ENABLED) { tcp_add_out_sack_block(svp,seqno,length); } /* if */#endif /* TCP_SELACK_ENHANCEMENTS */ /* Send an immediate "duplicate" ACK here (cancelling the delayed ack that was scheduled earlier before we knew this was an out-of-order segment), to facilitate "fast retransmit" if the peer has that enabled. */ tcp_sndack(mp, svp); return (st)smhqin;} /* tcp_net_deliver *//************************************************************************* ** Function : ** ** Description : ** ** ** Parameters : None. ** ** Return : None. ** *************************************************************************//* Accept this packet (as if) from the network */pflocal st tcp_naccept (fast m * mp){ fast tcpsv_t * svp; fast TCPH_T * tcphp; u16 flags; if ((svp = mp->m_svp) == (tcpsv_t *)0) { debug0(tcp_debug, "tcp_naccept: no state vector\n"); return (st)mp->m_dispfn; } tcphp = (TCPH_T *)mp->m_cp; flags = NetToHost16(&tcphp[TCPH_FLAGS]); mp->m_hp = (char *)tcphp + tcphl(tcphp); smcritical(mp);/* NOTE: The processing of this packet is in a critical section from * this point on; this guarantees that the ordering of state * updates will be the same as that of receive queue insertion; */ /* The following assert seems is for the purpose of making sure that this segment contains the "next expected sequence number" within it. Supposedly we couldn't get here if it didn't. */ assert(MC32U(svp->sv_rnxt, >=, NetToHost32(&tcphp[TCPH_SEQNO])), "tcp_naccept: bad seqno\n"); /* Skip over any data at the beginning of the segment which we may have already "accepted" -- e.g., this could be retransmitted data which contains some data we already have. */ /* In the process, if this segment contains an urgent pointer, adjust it according to how much data we skip over. If we skip past the urgent pointer, turn off the urgent flag and zero the urgent pointer */ { int adjust_hp = ( MU32(svp->sv_rnxt) - NetToHost32(&tcphp[TCPH_SEQNO]) ); mp->m_hp += adjust_hp; if (URG_ON(flags)) { u16 urgoff = NetToHost16(&tcphp[TCPH_URGENT]); if (adjust_hp >= urgoff) { urgoff = 0; flags &= ~URG; HostToNet16(&tcphp[TCPH_FLAGS], flags); } else { urgoff -= adjust_hp; } HostToNet16(&tcphp[TCPH_URGENT], urgoff); } /* if urgent flag set */ } /* The following check is to make sure that the entire segment doesn't already contain data that we've already previously accepted, i.e. it could be a retransmitted segment and we've already seen the original segment */ if (mp->m_hp > mp->m_tp && (FIN_OFF(flags) || mp->m_hp - 1 != mp->m_tp)) { trace2(tcp_thq, "tcp_naccept: seq 0x%x oldie; rnxt 0x%x\n", NetToHost32(&tcphp[TCPH_SEQNO]), MU32(svp->sv_rnxt)); return (st)mp->m_dispfn; } /* Extract any out-of-band data from the segment before queuing the in-band data to the socket */ tcp_urgdata(mp); /* After any trimming we may have done above, does the segment still have any data to accept into the recieve buffer? */ if (tcp_dl(mp)) { /* Yes -- stick it where it counts */ assert(mp->m_dispfn == smdispose, "tcp_naccept: non-trivial dispfn\n"); if (mp->m_sop == (so_t *)0) { /* But we've lost the socket... */ debug0(tcp_debug && m_dsize(mp), "tcp_naccept: no socket for smrqin (lost real data)\n"); /* there's more to life than this */ return (st)tcp_nstate; } mp->m_dispfn = tcp_nstate; /* state update functions */ /* MBM note: tcp_nstate will look in the holding queue for previously-received out of order data that can now be acked due to the in-order data we just received and are about to put into the socket receive buffer */ /***** MBM note: the following lines were removed from here because it was seen that, if the receive queue is empty at this time, and between the time we set the F_SO_SHUTDOWN flag and invoke smrqin, the application task interrupts and does a "recv", the application will get returned an error (FNS_ESHUTDOWN from fns_recvfrom). It seems to me that the F_SO_SHUTDOWN flag shouldn't be set until the data from this segment is in the receive queue and the empty "EOF" message in the receive queue. So I am moving the following code into "tcp_finpkt" which puts the empty "EOF" message into the receive queue. */#if 0#ifndef WSI1_ONLY if (FIN_ON(NetToHost16(&tcphp[TCPH_FLAGS]))) { mp->m_sop->so_flags |= F_SO_RSHUTDOWN; }#endif /* WSI1_ONLY */#endif return (st)smrqin; } assert(m_dsize(mp) == 0, "tcp_naccept: non-0 m_dsize\n"); return (st)tcp_nstate; /* just update ACK's & such */} /* tcp_naccept *//************************************************************************* ** Function : ** ** Description : ** ** ** Parameters : None. ** ** Return : None. ** *************************************************************************//* Update socket state after 'tcp_naccept'. If this packet contains data or * a FIN bit, then call will be as a dispose function after 'smrqin' and * the 'm_dispfn' will have been set to smnil; otherwise it is called * directly by the state machine and the 'm_dispfn' will still be 'smdispose' * (this latter case occurs on ACKnowledgement-only packets). *//* THIS WHOLE FUNCTION RUNS IN CRITICAL SECTION DUE TO THE 'smcritical' * IN 'tcp_naccept' (above) */pflocal st tcp_nstate (fast m * mp){ fast tcpsv_t * svp; fast TCPH_T * tcphp; fast u16 flags; fast u32 seqno; fast u32 ackno; fast so_t * sop; int length; if (mp->m_err) { /* more here? --msd */ return (st)mp->m_dispfn; } trace0(tcp_trcv, "tcp_nstate: packet into receive queue\n"); if ((svp = mp->m_svp) == (tcpsv_t *)0) { debug0(tcp_debug, "tcp_nstate: no state vector\n"); return (st)mp->m_dispfn; } tcphp = (TCPH_T *)mp->m_cp; ackno = NetToHost32(&tcphp[TCPH_ACKNO]); seqno = NetToHost32(&tcphp[TCPH_SEQNO]); flags = NetToHost16(&tcphp[TCPH_FLAGS]); if (FIN_ON(flags)) /* generate EOF */ tcp_finpkt(mp, svp); length = tcp_dl(mp) + mp->m_oob; M32U(svp->sv_rnxt, =, seqno + length );#ifdef TCP_SELACK_ENHANCEMENTS /* If we are sending SACKS, adjust our SACK list according to the data just absorbed into the receive buffer */ if (svp->sv_flags2 & SV_OUT_SACKS_ENABLED) { tcp_adjust_out_sack_blocks_for_rnxt(svp); }#endif /* TCP_SELACK_ENHANCEMENTS */ if (URG_ON(flags)) { tcp_urgstate(mp); /* look for urgent information */ } switch (svp->sv_state) { case ESTAB: if ((svp->sv_flags & SV_RFINFLG) || FIN_ON(flags)) { /* FIN seen */ svp->sv_flags |= SV_RFINFLG; /* This must be the only place state is set * to CLOSE_WAIT */ set_state("tcp_nstate", svp, CLOSE_WAIT);#ifdef TCP_TRANSACTION_TCP /* If this is a transaction TCP connection and we are the passive side and have delivered data to the application and we are delaying our SYN-ACK to give the application time to form and send a response, don't do the "no_more_data_in" right now because that will generate an immediate ACK in lieu of the delayed one which has been scheduled */ if (!(TRANSACTION_DELAYING_SYNACK(svp))) {#endif /* TCP_TRANSACTION_TCP */ tcp_no_more_data_in(svp);#ifdef TCP_TRANSACTION_TCP }#endif /* TCP_TRANSACTION_TCP */ sop = sv_valid_sop(svp, sop); if (sop) {#ifdef TCP_KEEP_ALIVE if (so_keepalive(sop)) { /* don't need Keep-Alive anymore */ tcp_end_ka(svp); }#endif so_notify(sop, WSHUTDOWN_NOTIFY); } } break; case FIN1_WAIT: if (FIN_ON(flags)) { svp->sv_flags |= SV_RFINFLG; /* set FIN */ } if ((svp->sv_flags & SV_SFINFLG) && ACK_ON(flags) && UC32M(ackno, ==, svp->sv_snxt)) /* FIN ACKed */ if (FIN_ON(flags)) { /* 'tcp_stw' changes state to TIME_WAIT */ tcp_stw(svp, (u8)mp->m_ttl); break; /* switch */ } else set_state("tcp_nstate", svp, FIN2_WAIT); else if (FIN_ON(flags)) set_state("tcp_nstate", svp, CLOSING); break; case FIN2_WAIT: if (FIN_ON(flags)) { svp->sv_flags |= SV_RFINFLG;#ifdef KEEP_ON_CLOSE tcp_stw(svp, (u8)mp->m_ttl); /* 'tcp_stw' changes state to TIME_WAIT */#else tcp_stw(svp, (u8)0); /* 'tcp_stw' changes state to TIME_WAIT */#endif } break; } /* If no data was moved into the socket buffer from this packet, no reason to look at the holding queue */ if ( length == 0 || ((sop = sv_valid_sop(svp, sop)) == (so_t *)0) ) return (st)mp->m_dispfn; /* See if in light of the data we've just put into the receive queue, we can now process a message in the hold queue. After scanning the hold queue, if we did not find any new in-order data and the queue is non-empty (i.e., we still have out-of-order data), we should send an immediate ACK. */ { int still_have_out_of_order_data = false; int something_new_accepted; something_new_accepted = tcp_process_hold_queue(mp); still_have_out_of_order_data = (!(is_header(&(((m *) sop->so_hq.gq_q.q_next)->m_q)))); /* We have just processed an in-order segment. If it fills part of a gap left by some previously received out-of-order segments, and this segment didn't close the gap (i.e., we haven't received the segment immediately following the one we just processed), send an immediate ACK (canceling any delayed ack that may presently be scheduled) to facilitate the peer's fast retransmit/ fast recovery */ if ( still_have_out_of_order_data && !something_new_accepted ) { tcp_sndack(mp, svp); } /* if */ } /* We're completely finished with the incoming message */ return (st)mp->m_dispfn;}/***************************************************************************//* This function looks thru the hold queue for the state vector *//* associated with the passed-in message for a segment containing the *//* next-expected sequence number. If it finds one, it removes that message *//* from the hold queue and puts it on the work queue of the passed-in *//* message to be processed by "tcp_naccept". *//* The function returns a 1 if a contiguous message was found and enqued*//* for processing by "tcp_naccept". It returns a zero otherwise. *//* As a side effect, if any segments are found in the hold queue whose *//* entire sequence number range duplicates data that has already been *//* received, those segments are put on the work queue of the passed-in *//* message to be disposed of. *//* ASSUMPTIONS: *//* -- the message is bound to a vaild state vector *//* -- the state vector is bound to a valid socket *//* -- this function is invoked from within a critical section *//***************************************************************************/pflocal int tcp_process_hold_queue(m *mp){ tcpsv_t *svp = mp->m_svp; so_t *sop; m *nmp, *nnmp; u32 seqno; sop = sv_valid_sop(svp, sop); for (nmp = (m *)sop->so_hq.gq_q.q_next; !is_header(&nmp->m_q); nmp = nnmp) { /* Don't wan
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -