Changeset View
Changeset View
Standalone View
Standalone View
sys/netinet/tcp_input.c
Show First 20 Lines • Show All 1,491 Lines • ▼ Show 20 Lines | |||||
void | void | ||||
tcp_handle_wakeup(struct tcpcb *tp, struct socket *so) | tcp_handle_wakeup(struct tcpcb *tp, struct socket *so) | ||||
{ | { | ||||
/* | /* | ||||
* Since tp might be gone if the session entered | * Since tp might be gone if the session entered | ||||
* the TIME_WAIT state before coming here, we need | * the TIME_WAIT state before coming here, we need | ||||
* to check if the socket is still connected. | * to check if the socket is still connected. | ||||
*/ | */ | ||||
if ((so->so_state & SS_ISCONNECTED) == 0) | if (tp == NULL) { | ||||
log(2, "%s#%d: tp is NULL\n", __func__, __LINE__); | |||||
return; | return; | ||||
} | |||||
if (so == NULL) { | |||||
log(2, "%s#%d: so is NULL\n", __func__, __LINE__); | |||||
return; | |||||
} | |||||
if ((so->so_state & SS_ISCONNECTED) == 0) { | |||||
log(2, "%s#%d: socket no longer connected, so_rcv is %slocked. called from: %pS, set at %d\n", | |||||
__func__, __LINE__, (tp->t_flags & TF_WAKESOR)?"":"not ", | |||||
__builtin_return_address(0), tp->cl4_spare); | |||||
} | |||||
INP_LOCK_ASSERT(tp->t_inpcb); | INP_LOCK_ASSERT(tp->t_inpcb); | ||||
if (tp->t_flags & TF_WAKESOR) { | if (tp->t_flags & TF_WAKESOR) { | ||||
tp->t_flags &= ~TF_WAKESOR; | tp->t_flags &= ~TF_WAKESOR; | ||||
SOCKBUF_UNLOCK_ASSERT(&so->so_rcv); | tp->cl4_spare = 0; | ||||
sorwakeup(so); | SOCKBUF_LOCK_ASSERT(&so->so_rcv); | ||||
sorwakeup_locked(so); | |||||
} | } | ||||
if (tp->t_flags & TF_WAKESOW) { | |||||
tp->t_flags &= ~TF_WAKESOW; | |||||
SOCKBUF_UNLOCK_ASSERT(&so->so_snd); | |||||
sowwakeup(so); | |||||
} | } | ||||
} | |||||
void | void | ||||
tcp_do_segment(struct mbuf *m, struct tcphdr *th, struct socket *so, | tcp_do_segment(struct mbuf *m, struct tcphdr *th, struct socket *so, | ||||
struct tcpcb *tp, int drop_hdrlen, int tlen, uint8_t iptos) | struct tcpcb *tp, int drop_hdrlen, int tlen, uint8_t iptos) | ||||
{ | { | ||||
int thflags, acked, ourfinisacked, needoutput = 0, sack_changed; | int thflags, acked, ourfinisacked, needoutput = 0, sack_changed; | ||||
int rstreason, todrop, win, incforsyn = 0; | int rstreason, todrop, win, incforsyn = 0; | ||||
uint32_t tiwin; | uint32_t tiwin; | ||||
Show All 9 Lines | #ifdef TCPDEBUG | ||||
/* | /* | ||||
* The size of tcp_saveipgen must be the size of the max ip header, | * The size of tcp_saveipgen must be the size of the max ip header, | ||||
* now IPv6. | * now IPv6. | ||||
*/ | */ | ||||
u_char tcp_saveipgen[IP6_HDR_LEN]; | u_char tcp_saveipgen[IP6_HDR_LEN]; | ||||
struct tcphdr tcp_savetcp; | struct tcphdr tcp_savetcp; | ||||
short ostate = 0; | short ostate = 0; | ||||
#endif | #endif | ||||
if ((tp != NULL) && (tp->t_flags & TF_WAKESOR)) { | |||||
log(2, "%s: WAKESOR left over from last invocation: %d\n", __func__, tp->cl4_spare); | |||||
tcp_handle_wakeup(tp, so); | |||||
} | |||||
thflags = th->th_flags; | thflags = th->th_flags; | ||||
inc = &tp->t_inpcb->inp_inc; | inc = &tp->t_inpcb->inp_inc; | ||||
tp->sackhint.last_sack_ack = 0; | tp->sackhint.last_sack_ack = 0; | ||||
sack_changed = 0; | sack_changed = 0; | ||||
nsegs = max(1, m->m_pkthdr.lro_nsegs); | nsegs = max(1, m->m_pkthdr.lro_nsegs); | ||||
NET_EPOCH_ASSERT(); | NET_EPOCH_ASSERT(); | ||||
INP_WLOCK_ASSERT(tp->t_inpcb); | INP_WLOCK_ASSERT(tp->t_inpcb); | ||||
▲ Show 20 Lines • Show All 334 Lines • ▼ Show 20 Lines | #ifdef TCPDEBUG | ||||
&tcp_savetcp, 0); | &tcp_savetcp, 0); | ||||
#endif | #endif | ||||
TCP_PROBE3(debug__input, tp, th, m); | TCP_PROBE3(debug__input, tp, th, m); | ||||
if (tp->snd_una == tp->snd_max) | if (tp->snd_una == tp->snd_max) | ||||
tcp_timer_activate(tp, TT_REXMT, 0); | tcp_timer_activate(tp, TT_REXMT, 0); | ||||
else if (!tcp_timer_active(tp, TT_PERSIST)) | else if (!tcp_timer_active(tp, TT_PERSIST)) | ||||
tcp_timer_activate(tp, TT_REXMT, | tcp_timer_activate(tp, TT_REXMT, | ||||
tp->t_rxtcur); | tp->t_rxtcur); | ||||
tp->t_flags |= TF_WAKESOW; | sowwakeup(so); | ||||
rscheff: This causes a doule-lock of so_snd later in the processing. Need to protect it by checking the… | |||||
if (sbavail(&so->so_snd)) | if (sbavail(&so->so_snd)) | ||||
(void) tp->t_fb->tfb_tcp_output(tp); | (void) tp->t_fb->tfb_tcp_output(tp); | ||||
goto check_delack; | goto check_delack; | ||||
} | } | ||||
} else if (th->th_ack == tp->snd_una && | } else if (th->th_ack == tp->snd_una && | ||||
tlen <= sbspace(&so->so_rcv)) { | tlen <= sbspace(&so->so_rcv)) { | ||||
int newsize = 0; /* automatic sockbuf scaling */ | int newsize = 0; /* automatic sockbuf scaling */ | ||||
▲ Show 20 Lines • Show All 48 Lines • ▼ Show 20 Lines | #endif | ||||
*/ | */ | ||||
if (newsize) | if (newsize) | ||||
if (!sbreserve_locked(&so->so_rcv, | if (!sbreserve_locked(&so->so_rcv, | ||||
newsize, so, NULL)) | newsize, so, NULL)) | ||||
so->so_rcv.sb_flags &= ~SB_AUTOSIZE; | so->so_rcv.sb_flags &= ~SB_AUTOSIZE; | ||||
m_adj(m, drop_hdrlen); /* delayed header drop */ | m_adj(m, drop_hdrlen); /* delayed header drop */ | ||||
sbappendstream_locked(&so->so_rcv, m, 0); | sbappendstream_locked(&so->so_rcv, m, 0); | ||||
} | } | ||||
SOCKBUF_UNLOCK(&so->so_rcv); | /* NB: sorwakeup_locked() does an implicit unlock. */ | ||||
tp->t_flags |= TF_WAKESOR; | sorwakeup_locked(so); | ||||
if (DELAY_ACK(tp, tlen)) { | if (DELAY_ACK(tp, tlen)) { | ||||
tp->t_flags |= TF_DELACK; | tp->t_flags |= TF_DELACK; | ||||
} else { | } else { | ||||
tp->t_flags |= TF_ACKNOW; | tp->t_flags |= TF_ACKNOW; | ||||
tp->t_fb->tfb_tcp_output(tp); | tp->t_fb->tfb_tcp_output(tp); | ||||
} | } | ||||
goto check_delack; | goto check_delack; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 521 Lines • ▼ Show 20 Lines | case TCPS_SYN_RECEIVED: | ||||
* simultaneous SYN, which is handled later. | * simultaneous SYN, which is handled later. | ||||
*/ | */ | ||||
if (SEQ_GT(th->th_ack, tp->snd_una) && !(tp->t_flags & TF_NEEDSYN)) | if (SEQ_GT(th->th_ack, tp->snd_una) && !(tp->t_flags & TF_NEEDSYN)) | ||||
incforsyn = 1; | incforsyn = 1; | ||||
/* | /* | ||||
* If segment contains data or ACK, will call tcp_reass() | * If segment contains data or ACK, will call tcp_reass() | ||||
* later; if not, do so now to pass queued data to user. | * later; if not, do so now to pass queued data to user. | ||||
*/ | */ | ||||
if (tlen == 0 && (thflags & TH_FIN) == 0) | if (tlen == 0 && (thflags & TH_FIN) == 0) { | ||||
(void) tcp_reass(tp, (struct tcphdr *)0, NULL, 0, | (void) tcp_reass(tp, (struct tcphdr *)0, NULL, 0, | ||||
(struct mbuf *)0); | (struct mbuf *)0); | ||||
tcp_handle_wakeup(tp, so); | |||||
} | |||||
tp->snd_wl1 = th->th_seq - 1; | tp->snd_wl1 = th->th_seq - 1; | ||||
/* FALLTHROUGH */ | /* FALLTHROUGH */ | ||||
/* | /* | ||||
* In ESTABLISHED state: drop duplicate ACKs; ACK out of range | * In ESTABLISHED state: drop duplicate ACKs; ACK out of range | ||||
* ACKs. If the ack is in the range | * ACKs. If the ack is in the range | ||||
* tp->snd_una < th->th_ack <= tp->snd_max | * tp->snd_una < th->th_ack <= tp->snd_max | ||||
* then advance tp->snd_una to th->th_ack and drop | * then advance tp->snd_una to th->th_ack and drop | ||||
▲ Show 20 Lines • Show All 115 Lines • ▼ Show 20 Lines | if (SEQ_LEQ(th->th_ack, tp->snd_una)) { | ||||
if (awnd < tp->snd_ssthresh) { | if (awnd < tp->snd_ssthresh) { | ||||
tp->snd_cwnd += maxseg; | tp->snd_cwnd += maxseg; | ||||
if (tp->snd_cwnd > tp->snd_ssthresh) | if (tp->snd_cwnd > tp->snd_ssthresh) | ||||
tp->snd_cwnd = tp->snd_ssthresh; | tp->snd_cwnd = tp->snd_ssthresh; | ||||
} | } | ||||
} else | } else | ||||
tp->snd_cwnd += maxseg; | tp->snd_cwnd += maxseg; | ||||
(void) tp->t_fb->tfb_tcp_output(tp); | (void) tp->t_fb->tfb_tcp_output(tp); | ||||
Not Done Inline Actionsperhaps getting rid of these could reduce diff? otis: perhaps getting rid of these could reduce diff? | |||||
goto drop; | goto drop; | ||||
} else if (tp->t_dupacks == tcprexmtthresh || | } else if (tp->t_dupacks == tcprexmtthresh || | ||||
(tp->t_flags & TF_SACK_PERMIT && | (tp->t_flags & TF_SACK_PERMIT && | ||||
V_tcp_do_newsack && | V_tcp_do_newsack && | ||||
tp->sackhint.sacked_bytes > | tp->sackhint.sacked_bytes > | ||||
(tcprexmtthresh - 1) * maxseg)) { | (tcprexmtthresh - 1) * maxseg)) { | ||||
enter_recovery: | enter_recovery: | ||||
/* | /* | ||||
▲ Show 20 Lines • Show All 285 Lines • ▼ Show 20 Lines | if (acked == 0) | ||||
goto step6; | goto step6; | ||||
/* | /* | ||||
* Let the congestion control algorithm update congestion | * Let the congestion control algorithm update congestion | ||||
* control related information. This typically means increasing | * control related information. This typically means increasing | ||||
* the congestion window. | * the congestion window. | ||||
*/ | */ | ||||
cc_ack_received(tp, th, nsegs, CC_ACK); | cc_ack_received(tp, th, nsegs, CC_ACK); | ||||
SOCKBUF_LOCK(&so->so_snd); | SOCKBUF_LOCK(&so->so_snd); | ||||
if (acked > sbavail(&so->so_snd)) { | if (acked > sbavail(&so->so_snd)) { | ||||
if (tp->snd_wnd >= sbavail(&so->so_snd)) | if (tp->snd_wnd >= sbavail(&so->so_snd)) | ||||
tp->snd_wnd -= sbavail(&so->so_snd); | tp->snd_wnd -= sbavail(&so->so_snd); | ||||
else | else | ||||
tp->snd_wnd = 0; | tp->snd_wnd = 0; | ||||
mfree = sbcut_locked(&so->so_snd, | mfree = sbcut_locked(&so->so_snd, | ||||
(int)sbavail(&so->so_snd)); | (int)sbavail(&so->so_snd)); | ||||
ourfinisacked = 1; | ourfinisacked = 1; | ||||
} else { | } else { | ||||
mfree = sbcut_locked(&so->so_snd, acked); | mfree = sbcut_locked(&so->so_snd, acked); | ||||
if (tp->snd_wnd >= (uint32_t) acked) | if (tp->snd_wnd >= (uint32_t) acked) | ||||
tp->snd_wnd -= acked; | tp->snd_wnd -= acked; | ||||
else | else | ||||
tp->snd_wnd = 0; | tp->snd_wnd = 0; | ||||
ourfinisacked = 0; | ourfinisacked = 0; | ||||
} | } | ||||
SOCKBUF_UNLOCK(&so->so_snd); | /* NB: sowwakeup_locked() does an implicit unlock. */ | ||||
tp->t_flags |= TF_WAKESOW; | sowwakeup_locked(so); | ||||
m_freem(mfree); | m_freem(mfree); | ||||
/* Detect una wraparound. */ | /* Detect una wraparound. */ | ||||
if (!IN_RECOVERY(tp->t_flags) && | if (!IN_RECOVERY(tp->t_flags) && | ||||
SEQ_GT(tp->snd_una, tp->snd_recover) && | SEQ_GT(tp->snd_una, tp->snd_recover) && | ||||
SEQ_LEQ(th->th_ack, tp->snd_recover)) | SEQ_LEQ(th->th_ack, tp->snd_recover)) | ||||
tp->snd_recover = th->th_ack - 1; | tp->snd_recover = th->th_ack - 1; | ||||
/* XXXLAS: Can this be moved up into cc_post_recovery? */ | /* XXXLAS: Can this be moved up into cc_post_recovery? */ | ||||
if (IN_RECOVERY(tp->t_flags) && | if (IN_RECOVERY(tp->t_flags) && | ||||
▲ Show 20 Lines • Show All 41 Lines • ▼ Show 20 Lines | process_ACK: | ||||
/* | /* | ||||
* In CLOSING STATE in addition to the processing for | * In CLOSING STATE in addition to the processing for | ||||
* the ESTABLISHED state if the ACK acknowledges our FIN | * the ESTABLISHED state if the ACK acknowledges our FIN | ||||
* then enter the TIME-WAIT state, otherwise ignore | * then enter the TIME-WAIT state, otherwise ignore | ||||
* the segment. | * the segment. | ||||
*/ | */ | ||||
case TCPS_CLOSING: | case TCPS_CLOSING: | ||||
if (ourfinisacked) { | if (ourfinisacked) { | ||||
if ((tp != NULL) && (tp->t_flags & TF_WAKESOR)) { | |||||
log(2, "%s#%d: WAKESOR left over from: %d\n", __func__,__LINE__, tp->cl4_spare); | |||||
tcp_handle_wakeup(tp, so); | |||||
} | |||||
tcp_twstart(tp); | tcp_twstart(tp); | ||||
m_freem(m); | m_freem(m); | ||||
return; | return; | ||||
} | } | ||||
break; | break; | ||||
/* | /* | ||||
* In LAST_ACK, we may still be waiting for data to drain | * In LAST_ACK, we may still be waiting for data to drain | ||||
▲ Show 20 Lines • Show All 147 Lines • ▼ Show 20 Lines | if (th->th_seq == tp->rcv_nxt && | ||||
thflags = th->th_flags & TH_FIN; | thflags = th->th_flags & TH_FIN; | ||||
TCPSTAT_INC(tcps_rcvpack); | TCPSTAT_INC(tcps_rcvpack); | ||||
TCPSTAT_ADD(tcps_rcvbyte, tlen); | TCPSTAT_ADD(tcps_rcvbyte, tlen); | ||||
SOCKBUF_LOCK(&so->so_rcv); | SOCKBUF_LOCK(&so->so_rcv); | ||||
if (so->so_rcv.sb_state & SBS_CANTRCVMORE) | if (so->so_rcv.sb_state & SBS_CANTRCVMORE) | ||||
m_freem(m); | m_freem(m); | ||||
else | else | ||||
sbappendstream_locked(&so->so_rcv, m, 0); | sbappendstream_locked(&so->so_rcv, m, 0); | ||||
SOCKBUF_UNLOCK(&so->so_rcv); | |||||
tp->t_flags |= TF_WAKESOR; | tp->t_flags |= TF_WAKESOR; | ||||
tp->cl4_spare = 1; | |||||
} else { | } else { | ||||
/* | /* | ||||
* XXX: Due to the header drop above "th" is | * XXX: Due to the header drop above "th" is | ||||
* theoretically invalid by now. Fortunately | * theoretically invalid by now. Fortunately | ||||
* m_adj() doesn't actually frees any mbufs | * m_adj() doesn't actually frees any mbufs | ||||
* when trimming from the head. | * when trimming from the head. | ||||
*/ | */ | ||||
tcp_seq temp = save_start; | tcp_seq temp = save_start; | ||||
Show All 28 Lines | if ((tp->t_flags & TF_SACK_PERMIT) && | ||||
/* Update of sackblks. */ | /* Update of sackblks. */ | ||||
tcp_update_dsack_list(tp, save_start, | tcp_update_dsack_list(tp, save_start, | ||||
save_start + save_tlen); | save_start + save_tlen); | ||||
} else if (tlen > 0) { | } else if (tlen > 0) { | ||||
tcp_update_dsack_list(tp, save_start, | tcp_update_dsack_list(tp, save_start, | ||||
save_start + tlen); | save_start + tlen); | ||||
} | } | ||||
} | } | ||||
tcp_handle_wakeup(tp, so); | |||||
#if 0 | #if 0 | ||||
/* | /* | ||||
* Note the amount of data that peer has sent into | * Note the amount of data that peer has sent into | ||||
* our window, in order to estimate the sender's | * our window, in order to estimate the sender's | ||||
* buffer size. | * buffer size. | ||||
* XXX: Unused. | * XXX: Unused. | ||||
*/ | */ | ||||
if (SEQ_GT(tp->rcv_adv, tp->rcv_nxt)) | if (SEQ_GT(tp->rcv_adv, tp->rcv_nxt)) | ||||
len = so->so_rcv.sb_hiwat - (tp->rcv_adv - tp->rcv_nxt); | len = so->so_rcv.sb_hiwat - (tp->rcv_adv - tp->rcv_nxt); | ||||
else | else | ||||
len = so->so_rcv.sb_hiwat; | len = so->so_rcv.sb_hiwat; | ||||
#endif | #endif | ||||
} else { | } else { | ||||
m_freem(m); | m_freem(m); | ||||
thflags &= ~TH_FIN; | thflags &= ~TH_FIN; | ||||
} | } | ||||
/* | /* | ||||
* If FIN is received ACK the FIN and let the user know | * If FIN is received ACK the FIN and let the user know | ||||
* that the connection is closing. | * that the connection is closing. | ||||
*/ | */ | ||||
if (thflags & TH_FIN) { | if (thflags & TH_FIN) { | ||||
if (TCPS_HAVERCVDFIN(tp->t_state) == 0) { | if (TCPS_HAVERCVDFIN(tp->t_state) == 0) { | ||||
socantrcvmore(so); | if (tp->t_flags & TF_WAKESOR) { | ||||
/* The socket upcall is handled by socantrcvmore. */ | /* The socket upcall is handled by socantrcvmore. */ | ||||
tp->t_flags &= ~TF_WAKESOR; | tp->t_flags &= ~TF_WAKESOR; | ||||
tp->cl4_spare = 0; | |||||
socantrcvmore_locked(so); | |||||
} else | |||||
socantrcvmore(so); | |||||
/* | /* | ||||
* If connection is half-synchronized | * If connection is half-synchronized | ||||
* (ie NEEDSYN flag on) then delay ACK, | * (ie NEEDSYN flag on) then delay ACK, | ||||
* so it may be piggybacked when SYN is sent. | * so it may be piggybacked when SYN is sent. | ||||
* Otherwise, since we received a FIN then no | * Otherwise, since we received a FIN then no | ||||
* more input can be expected, send ACK now. | * more input can be expected, send ACK now. | ||||
*/ | */ | ||||
if (tp->t_flags & TF_NEEDSYN) | if (tp->t_flags & TF_NEEDSYN) | ||||
Show All 23 Lines | case TCPS_FIN_WAIT_1: | ||||
break; | break; | ||||
/* | /* | ||||
* In FIN_WAIT_2 state enter the TIME_WAIT state, | * In FIN_WAIT_2 state enter the TIME_WAIT state, | ||||
* starting the time-wait timer, turning off the other | * starting the time-wait timer, turning off the other | ||||
* standard timers. | * standard timers. | ||||
*/ | */ | ||||
case TCPS_FIN_WAIT_2: | case TCPS_FIN_WAIT_2: | ||||
if ((tp != NULL) && (tp->t_flags & TF_WAKESOR)) { | |||||
log(2, "%s#%d: WAKESOR left over from: %d\n", __func__,__LINE__, tp->cl4_spare); | |||||
tcp_handle_wakeup(tp, so); | |||||
} | |||||
tcp_twstart(tp); | tcp_twstart(tp); | ||||
return; | return; | ||||
} | } | ||||
} | } | ||||
#ifdef TCPDEBUG | #ifdef TCPDEBUG | ||||
if (so->so_options & SO_DEBUG) | if (so->so_options & SO_DEBUG) | ||||
tcp_trace(TA_INPUT, ostate, tp, (void *)tcp_saveipgen, | tcp_trace(TA_INPUT, ostate, tp, (void *)tcp_saveipgen, | ||||
&tcp_savetcp, 0); | &tcp_savetcp, 0); | ||||
#endif | #endif | ||||
TCP_PROBE3(debug__input, tp, th, m); | TCP_PROBE3(debug__input, tp, th, m); | ||||
if ((tp != NULL) && (tp->t_flags & TF_WAKESOR)) { | |||||
log(2, "%s#%d: handling WAKESOR finally from %d\n", __func__,__LINE__, tp->cl4_spare); | |||||
tcp_handle_wakeup(tp, so); | |||||
} | |||||
/* | /* | ||||
* Return any desired output. | * Return any desired output. | ||||
*/ | */ | ||||
if (needoutput || (tp->t_flags & TF_ACKNOW)) | if (needoutput || (tp->t_flags & TF_ACKNOW)) | ||||
(void) tp->t_fb->tfb_tcp_output(tp); | (void) tp->t_fb->tfb_tcp_output(tp); | ||||
check_delack: | check_delack: | ||||
INP_WLOCK_ASSERT(tp->t_inpcb); | INP_WLOCK_ASSERT(tp->t_inpcb); | ||||
if (tp->t_flags & TF_DELACK) { | if (tp->t_flags & TF_DELACK) { | ||||
tp->t_flags &= ~TF_DELACK; | tp->t_flags &= ~TF_DELACK; | ||||
tcp_timer_activate(tp, TT_DELACK, tcp_delacktime); | tcp_timer_activate(tp, TT_DELACK, tcp_delacktime); | ||||
} | } | ||||
if ((tp != NULL) && (tp->t_flags & TF_WAKESOR)) { | |||||
log(2, "%s#%d: WAKESOR left over from: %d\n", __func__,__LINE__, tp->cl4_spare); | |||||
tcp_handle_wakeup(tp, so); | tcp_handle_wakeup(tp, so); | ||||
} | |||||
INP_WUNLOCK(tp->t_inpcb); | INP_WUNLOCK(tp->t_inpcb); | ||||
return; | return; | ||||
dropafterack: | dropafterack: | ||||
/* | /* | ||||
* Generate an ACK dropping incoming segment if it occupies | * Generate an ACK dropping incoming segment if it occupies | ||||
* sequence space, where the ACK reflects our state. | * sequence space, where the ACK reflects our state. | ||||
* | * | ||||
Show All 15 Lines | if (tp->t_state == TCPS_SYN_RECEIVED && (thflags & TH_ACK) && | ||||
goto dropwithreset; | goto dropwithreset; | ||||
} | } | ||||
#ifdef TCPDEBUG | #ifdef TCPDEBUG | ||||
if (so->so_options & SO_DEBUG) | if (so->so_options & SO_DEBUG) | ||||
tcp_trace(TA_DROP, ostate, tp, (void *)tcp_saveipgen, | tcp_trace(TA_DROP, ostate, tp, (void *)tcp_saveipgen, | ||||
&tcp_savetcp, 0); | &tcp_savetcp, 0); | ||||
#endif | #endif | ||||
TCP_PROBE3(debug__input, tp, th, m); | TCP_PROBE3(debug__input, tp, th, m); | ||||
if ((tp != NULL) && (tp->t_flags & TF_WAKESOR)) { | |||||
log(2, "%s#%d: WAKESOR left over from: %d\n", __func__,__LINE__, tp->cl4_spare); | |||||
tcp_handle_wakeup(tp, so); | |||||
} | |||||
tp->t_flags |= TF_ACKNOW; | tp->t_flags |= TF_ACKNOW; | ||||
(void) tp->t_fb->tfb_tcp_output(tp); | (void) tp->t_fb->tfb_tcp_output(tp); | ||||
tcp_handle_wakeup(tp, so); | |||||
INP_WUNLOCK(tp->t_inpcb); | INP_WUNLOCK(tp->t_inpcb); | ||||
m_freem(m); | m_freem(m); | ||||
return; | return; | ||||
dropwithreset: | dropwithreset: | ||||
if (tp != NULL) { | if (tp != NULL) { | ||||
tcp_dropwithreset(m, th, tp, tlen, rstreason); | if ((tp != NULL) && (tp->t_flags & TF_WAKESOR)) { | ||||
log(2, "%s#%d: WAKESOR left over from: %d\n", __func__,__LINE__, tp->cl4_spare); | |||||
tcp_handle_wakeup(tp, so); | tcp_handle_wakeup(tp, so); | ||||
} | |||||
tcp_dropwithreset(m, th, tp, tlen, rstreason); | |||||
INP_WUNLOCK(tp->t_inpcb); | INP_WUNLOCK(tp->t_inpcb); | ||||
} else | } else | ||||
tcp_dropwithreset(m, th, NULL, tlen, rstreason); | tcp_dropwithreset(m, th, NULL, tlen, rstreason); | ||||
return; | return; | ||||
drop: | drop: | ||||
/* | /* | ||||
* Drop space held by incoming segment and return. | * Drop space held by incoming segment and return. | ||||
*/ | */ | ||||
#ifdef TCPDEBUG | #ifdef TCPDEBUG | ||||
if (tp == NULL || (tp->t_inpcb->inp_socket->so_options & SO_DEBUG)) | if (tp == NULL || (tp->t_inpcb->inp_socket->so_options & SO_DEBUG)) | ||||
tcp_trace(TA_DROP, ostate, tp, (void *)tcp_saveipgen, | tcp_trace(TA_DROP, ostate, tp, (void *)tcp_saveipgen, | ||||
&tcp_savetcp, 0); | &tcp_savetcp, 0); | ||||
#endif | #endif | ||||
TCP_PROBE3(debug__input, tp, th, m); | TCP_PROBE3(debug__input, tp, th, m); | ||||
if (tp != NULL) { | if (tp != NULL) { | ||||
if ((tp != NULL ) && (tp->t_flags & TF_WAKESOR)) { | |||||
log(2, "%s#%d: WAKESOR left over from: %d\n", __func__,__LINE__, tp->cl4_spare); | |||||
tcp_handle_wakeup(tp, so); | tcp_handle_wakeup(tp, so); | ||||
} | |||||
INP_WUNLOCK(tp->t_inpcb); | INP_WUNLOCK(tp->t_inpcb); | ||||
} | } | ||||
m_freem(m); | m_freem(m); | ||||
} | } | ||||
/* | /* | ||||
* Issue RST and make ACK acceptable to originator of segment. | * Issue RST and make ACK acceptable to originator of segment. | ||||
* The mbuf must still include the original packet header. | * The mbuf must still include the original packet header. | ||||
▲ Show 20 Lines • Show All 51 Lines • ▼ Show 20 Lines | #endif | ||||
} else { | } else { | ||||
if (th->th_flags & TH_SYN) | if (th->th_flags & TH_SYN) | ||||
tlen++; | tlen++; | ||||
if (th->th_flags & TH_FIN) | if (th->th_flags & TH_FIN) | ||||
tlen++; | tlen++; | ||||
tcp_respond(tp, mtod(m, void *), th, m, th->th_seq+tlen, | tcp_respond(tp, mtod(m, void *), th, m, th->th_seq+tlen, | ||||
(tcp_seq)0, TH_RST|TH_ACK); | (tcp_seq)0, TH_RST|TH_ACK); | ||||
} | } | ||||
if ((tp != NULL) && (tp->t_flags & TF_WAKESOR)) | |||||
log(2, "%s#%d: WAKESOR left over from: %d\n", __func__,__LINE__, tp->cl4_spare); | |||||
return; | return; | ||||
drop: | drop: | ||||
m_freem(m); | m_freem(m); | ||||
if ((tp != NULL) && (tp->t_flags & TF_WAKESOR)) | |||||
log(2, "%s#%d: WAKESOR left over from: %d\n", __func__,__LINE__, tp->cl4_spare); | |||||
} | } | ||||
/* | /* | ||||
* Parse TCP options and place in tcpopt. | * Parse TCP options and place in tcpopt. | ||||
*/ | */ | ||||
void | void | ||||
tcp_dooptions(struct tcpopt *to, u_char *cp, int cnt, int flags) | tcp_dooptions(struct tcpopt *to, u_char *cp, int cnt, int flags) | ||||
{ | { | ||||
▲ Show 20 Lines • Show All 631 Lines • Show Last 20 Lines |
This causes a doule-lock of so_snd later in the processing. Need to protect it by checking the flag first. (381)