📄 tcpmisc.c
字号:
{ if ((svp->sv_state == ESTAB) || (svp->sv_state == CLOSE_WAIT)) count++; } normal; return count; /* 's ok */}#endif /* SNMP */#ifdef SV_SKEPTIC/* called by h_nwfree() *//* quickly scan the state vectors for any reference to the item being freed. */export boolean sv_check (fast u32 * ref){ fast tcpsv_t * svp; use_critical; if (tcp_prp == (pr_t *)0) return true; /* allow time to initialize */ critical; for (svp = (tcpsv_t *)tcp_q.q_next; svp != (tcpsv_t *)&tcp_q; svp = (tcpsv_t *)svp->sv_q.q_next) { fast int i; for (i = 0; i < MAXREF; i++) if (svp->sv_ref[i] == ref) { normal; return false; /* there is a reference! */ } } normal; return true; /* it's ok */}#endif/* msd: There are several notions that are wrong with this attach/detach * code. First, the idea that TCP needs a private shared resource mechanism * with such control is ludicrous; this mechanism should be generalized and * this code omitted. Second, the assumption is made here that the argument * bound to the 'ref' parameter is always a data space pointer (such as is * used with 'os_sleep'); however, this assumption is routinely violated by * TCP by its passing function pointers as 'ref', thus providing ambiguity * on machines where code and data pointers are not mutually exclusive. *//* detach a state vector in tcp_q, returning the next state vector in the queue. */export tcpsv_t *#ifdef SV_SKEPTIC_sv_detach (fast tcpsv_t * svp, fast u32 * ref, fast boolean m_ok)#else_sv_detach (fast tcpsv_t * svp)#endif{#ifdef SV_SKEPTIC fast int i, cnt;#endif tcpsv_t * nsvp; use_critical; critical; assert(svp->sv_refcnt != 0, "sv_detach: incorrect refcnt!\n");#ifdef SV_SKEPTIC for (i = 0, cnt = 0; i < MAXREF; i++) { if (svp->sv_ref[i] == ref) { cnt++; if (cnt == 1) svp->sv_ref[i] = (u32 *)0; } } if (cnt == 0 && svp->sv_overflow > 0) { /* might have been one that overflowed... */ svp->sv_overflow--; cnt = 1; /* pretend that we found it */ } debug2(!m_ok && cnt > 1, "sv_detach: multiple references (%d) @ 0x%x\n", cnt, ref); assert(cnt > 0, "sv_detach: not referenced\n"); assert(m_ok || (cnt == 1), "sv_detach: multiple references\n");#endif /*SV_SKEPTIC*/ nsvp = (tcpsv_t *)svp->sv_q.q_next; /* pointer to the next state vector */ if (--svp->sv_refcnt == 0) { if (svp->sv_q.q_flags & F_Q_ZAPPED) { /* zombie */ q_out(&svp->sv_q); h_free((i32 *)svp); } } normal; return nsvp;} /* _sv_detach *//* bind a state vector so it won't go away on us */export void#ifdef SV_SKEPTIC_sv_bind (fast tcpsv_t * svp, fast u32 * ref, fast boolean m_ok)#else_sv_bind (fast tcpsv_t * svp)#endif{#ifdef SV_SKEPTIC fast int i; boolean stored; use_critical; critical; if (!m_ok) { /* some types of references can be multiple (like routines) */ /* check for multiple reference */ for (i = 0; i < MAXREF; i++) if (svp->sv_ref[i] == ref) { OS_PANIC0("sv_bind: already referenced\n"); } } /* store the reference in an available slot (if any) */ for (i = 0, stored = false; i < MAXREF; i++) if (svp->sv_ref[i] == (u32 *)0) { svp->sv_ref[i] = ref; stored = true; break; /* for */ } if (!stored) svp->sv_overflow++; svp->sv_refcnt++; normal;#else svp->sv_refcnt++;#endif} /* _sv_bind */ /*******************************************************************/static void tcp_free_saved_messages(tcpsv_t *svp){ int iter; m *dmp; /* Free any saved MSS-sized messages that have been saved for reuse */ for (iter = 0; iter < svp->sv_num_mss_sized_msgs; iter++) { dmp = svp->sv_tcp_mss_sized_msgs[iter]; if (dmp == (m *) 0 ) { continue; } svp->sv_tcp_mss_sized_msgs[iter] = (m *) 0; dmp->m_dispfn = smnil; dmp->m_owners = 1; /* hack to make sure m_free frees this message even if its gone thru m_free before and not gotten freed due to m_termfn, but the owners field would have been decremented then */ sv_m_detach(dmp); smkill(dmp); } /* for */ svp->sv_num_mss_sized_msgs = 0; /* Free any saved ACK-sized messages that have been saved for reuse */ for (iter = 0; iter < svp->sv_num_ack_sized_msgs; iter++) { dmp = svp->sv_tcp_ack_sized_msgs[iter]; if (dmp == (m *) 0 ) { continue; } svp->sv_tcp_ack_sized_msgs[iter] = (m *) 0; dmp->m_dispfn = smnil; dmp->m_owners = 1; /* hack to make sure m_free frees this message even if its gone thru m_free before and not gotten freed due to m_termfn, but the owners field would have been decremented then */ sv_m_detach(dmp); smkill(dmp); } /* for */ svp->sv_num_ack_sized_msgs = 0; } /* tcp_free_saved_messages *//*******************************************************************//* Retransmission Timeout Event */export int tcp_rextimer (void * uarg){#define lsvp ((tcpsv_t *)uarg) so_t * sop; use_critical; trace0(tcp_trxmit, "tcp_rextimer\n"); assert((lsvp->sv_q.q_flags & F_Q_ZAPPED) == 0, "tcp_rextimer: called with zapped sv\n"); critical; (void) t_stop(lsvp->sv_rextcb); /* stop further timer events on this sv */ if (lsvp->sv_flags & SV_EOF) tcp_finpkt((m *)0, lsvp); /* generate an EOF packet */ if (lsvp->sv_abort && --lsvp->sv_abort == 0) { /* check for abortion */ trace0(tcp_trxmit,"ABORT ABORT ABORT \n"); /* abort a state vector, according to state */ switch (lsvp->sv_state) { case CLOSED: /* MUST be the only place the sv is ZAPPED */ /* mark it for death, (zombie) */ lsvp->sv_q.q_flags |= F_Q_ZAPPED; /* delete the acknowledgement and performance timers */#ifdef TCP_KEEP_ALIVE tcp_end_ka(lsvp); /* no more Keep-alives */#endif tcp_no_more_data_in(lsvp); /* now delete this (the retransmission) timer; * note that the state vector evaporates during * the 'sv_detach' call, since this is the last * reference */ t_delete(lsvp->sv_rextcb); /* Before "evaporating" the state vector, free any mss-sized messages and any ack-sized messages that may still be hanging on to this svp */ tcp_free_saved_messages(lsvp); sv_detach(lsvp, lsvp->sv_rextcb, false); break; case TIME_WAIT: tcp_rslf(lsvp, AB_UC); /* normal close */ /* Reset self changes state to CLOSED. */ break; default: /* reset(current) */ sop = sv_valid_sop(lsvp, sop); if (sop != (so_t *)0) so_notify(sop, TIMEOUT_NOTIFY); tcpabort(lsvp, FNS_ETIMEDOUT); debug0(tcp_debug, "tcp_rextimer: connection timed out\n"); } normal; return 0; }#if 0 else os_printf("\n(%d) tcp_rextimer: retransmit timeout, period=%d\n", t_time,t_period(lsvp->sv_rextcb));#endif#ifdef TCP_SS_CA_FRETR_FREC /* When slow-start/congestion avoidance is enabled, a retransmission timeout causes us to reduce the congestion window to the "slow start" value (one segment), and to set the "slow start threshold" to 1/2 the current operational send window (but not less than two segments). */ if (lsvp->sv_flags2 & SV_SLOW_START_CA) { lsvp->sv_ssthresh = ((TCP_OPERATIONAL_SEND_WINDOW(lsvp)) >> 1); if (lsvp->sv_ssthresh < ( ((u32) lsvp->sv_mssd) << 1) ) { lsvp->sv_ssthresh = (lsvp->sv_mssd << 1); } lsvp->sv_cwnd = lsvp->sv_mssd; /* puts us into slow-start */ } /* if */#endif /* Retransmission timer backoff -- double the retrnasmission timer until we get a good rtt measurment again -- but keep it bounded by the configured limits */ {u32 delay = (lsvp->sv_retrtim <<= 1); if (delay > lsvp->sv_maxretrim) { delay = lsvp->sv_maxretrim;} else if (delay < lsvp->sv_minretrim) { delay = lsvp->sv_minretrim;} lsvp->sv_retrtim = delay; }# /* bug fix do not include re-transmission in RTT computation */ lsvp->sv_flags &= ~(SV_NOPROBE|SV_XTIME); /* can probe again now */ /* Retransmission */ trace2(tcp_trxmit, "<RETRANSMIT: RTT %d S %d> " /*msddebug*/ ,(int)(lsvp->sv_retrtim) /*msddebug*/ ,(u16)(MU32(lsvp->sv_suna) % 10000L)); /*msddebug*/ tcp_retransmit_fsm(lsvp, TCP_RETR_TIMEOUT); /* will always return true in this circumstance so no need to check return value, just call sqxmit */ normal; tcp_sqxmit(lsvp); /* retransmit */ return 0;#undef lsvp}#ifdef TCP_WND_SCALE/************************************************************************//* Set the receive scale factor for a connection according to the size *//* of the socket receive buffer. This value will be advertised in the *//* Window Scale option of a SYN we send out. It will be stored in the *//* state vector if windowscaling is negotiated by the exchanged of SYNs *//* This function assumes that the size of the receive buffer for this *//* connection is already finalized. */export u16 tcp_rcv_wscale_value(fast tcpsv_t *svp){ so_t *sop; int rqmax; u16 wscale; sop = sv_valid_sop(svp,sop); assert(sop != (so_t *) 0, "tcp_rcv_wscale_set: NULL socket pointer"); wscale = 0; rqmax = svp->sv_rq_max; while (rqmax >= 65536) { wscale++; rqmax >>= 1; } /* while */ return(wscale);} /* tcp_rcv_wscale_value */#endif/************************************************************************//* set a potentially new send MSS *//* MUST be called in critical section *//* This routine is called from tcp_rsyn on receipt of a SYN packet with the * remote side's MSS option, and from tcp_dink when sending a SYN. It just * sets the MSS in the state vector to the smaller of it's present value * (if any) and the new value. *//* MBM -- added "source" parameter to indicate whether this value comes from a received SYN or not. If the SV_USE_PEER_MSS_OPTION flag is set (meaning the corresponding socket option was set), then an mss coming from a received SYN overrides any other value *//* MBM -- its getting more complicated all the time. For transaction TCP, we cache the MSS from the previous (if any) transaction with the other host. And we use that initally for this transaction. */export void tcp_set_send_mss (fast tcpsv_t *svp, fast u16 mss, int source){ so_t *sop; int its_been_decided = 0; use_critical; sop = sv_valid_sop(svp,sop); assert(sop != (so_t *) 0, "tcp_set_send_mss: NULL socket pointer");#ifdef IP_RFC_1191 /* some pre-processing based on the source of this MSS value */ if (source == TCP_MSS_SOURCE_PEER) { /* remember the peer-sent MSS for later use */ svp->sv_peer_mss = mss; } else if (source == TCP_MSS_SOURCE_PATH_MTU) { /* Don't allow an MSS coming from path-mtu-discovery cause us to set our send MSS larger than that which came from the peer */ if ( (svp->sv_peer_mss != 0) && (mss > svp->sv_peer_mss) ) { mss = svp->sv_peer_mss; } }#endif /* IP_RFC_1191 */ /* never allow an MSS to be set beyond the absolute configured maximum */ if ((u16)tcp_max_mss && mss > (u16)tcp_max_mss) mss = (u16)tcp_max_mss; /* If this socket is configured to let the peer's MSS option override any other considerations, take care of that */ if (svp->sv_flags2 & SV_USE_PEER_MSS_OPTION) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -