📄 tcp_subr.c
字号:
* discard internet protocol block * wake up any sleepers */struct tcpcb *tcp_close(tp) register struct tcpcb *tp;{ register struct tcpiphdr *t; struct inpcb *inp = tp->t_inpcb; struct socket *so = inp->inp_socket; register struct mbuf *m; register struct rtentry *rt;#ifdef WV_INSTRUMENTATION#ifdef INCLUDE_WVNET /* WV_NET_INFO event */ WV_NET_MARKER_1 (NET_AUX_EVENT, WV_NET_INFO, 39, 4, WV_NETEVENT_TCPCLOSE_START, so->so_fd)#endif /* INCLUDE_WVNET */#endif /* * If we sent enough data to get some meaningful characteristics, * save them in the routing entry. 'Enough' is arbitrarily * defined as the sendpipesize (default 4K) * 16. This would * give us 16 rtt samples assuming we only get one sample per * window (the usual case on a long haul net). 16 samples is * enough for the srtt filter to converge to within 5% of the correct * value; fewer samples and we could save a very bogus rtt. * * Don't update the default route's characteristics and don't * update anything that the user "locked". */ if (SEQ_LT(tp->iss + so->so_snd.sb_hiwat * 16, tp->snd_max) && (rt = inp->inp_route.ro_rt) && ((struct sockaddr_in *)rt_key(rt))->sin_addr.s_addr != INADDR_ANY) { register u_long i = 0; if ((rt->rt_rmx.rmx_locks & RTV_RTT) == 0) { i = tp->t_srtt * (RTM_RTTUNIT / (PR_SLOWHZ * TCP_RTT_SCALE)); if (rt->rt_rmx.rmx_rtt && i) /* * filter this update to half the old & half * the new values, converting scale. * See route.h and tcp_var.h for a * description of the scaling constants. */ rt->rt_rmx.rmx_rtt = (rt->rt_rmx.rmx_rtt + i) / 2; else rt->rt_rmx.rmx_rtt = i; } if ((rt->rt_rmx.rmx_locks & RTV_RTTVAR) == 0) { i = tp->t_rttvar * (RTM_RTTUNIT / (PR_SLOWHZ * TCP_RTTVAR_SCALE)); if (rt->rt_rmx.rmx_rttvar && i) rt->rt_rmx.rmx_rttvar = (rt->rt_rmx.rmx_rttvar + i) / 2; else rt->rt_rmx.rmx_rttvar = i; } /* * update the pipelimit (ssthresh) if it has been updated * already or if a pipesize was specified & the threshhold * got below half the pipesize. I.e., wait for bad news * before we start updating, then update on both good * and bad news. * * Update the slow start threshold when all of the * following conditions apply: * 1) The value is not locked (via a routing socket). * 2) Some packet loss occurred during the connection * (snd_ssthresh is not zero) * 3) Packet loss also occurred during an earlier * connection (rmx_ssthresh is not zero). This * condition also applies if a user set a value * in advance via a routing socket. * * If none of the above conditions apply, the system * still updates the slow start threshold if the * value for this connection's packet loss is less * than half the rmx_sendpipe value set via a routing * socket. If that pipe size is available, the update * occurs even if no packet loss happened. */ if (((rt->rt_rmx.rmx_locks & RTV_SSTHRESH) == 0 && (i = tp->snd_ssthresh) && rt->rt_rmx.rmx_ssthresh) || i < (rt->rt_rmx.rmx_sendpipe / 2)) { /* * convert the limit from user data bytes to * packets then to packet data bytes. */ i = (i + tp->t_maxseg / 2) / tp->t_maxseg; if (i < 2) i = 2; i *= (u_long)(tp->t_maxseg + sizeof (struct tcpiphdr)); if (rt->rt_rmx.rmx_ssthresh) rt->rt_rmx.rmx_ssthresh = (rt->rt_rmx.rmx_ssthresh + i) / 2; else rt->rt_rmx.rmx_ssthresh = i; } } /* free the reassembly queue, if any */ t = tp->seg_next; while (t != (struct tcpiphdr *)tp) { t = (struct tcpiphdr *)t->ti_next; m = REASS_MBUF((struct tcpiphdr *)t->ti_prev); remque(t->ti_prev); m_freem(m); } if (tp->t_template) (void) m_free(tp->t_template); FREE(tp, MT_PCB); inp->inp_ppcb = 0; soisdisconnected(so); /* clobber input pcb cache if we're closing the cached connection */ if (inp == tcp_last_inpcb) tcp_last_inpcb = NULL; in_pcbdetach(inp); tcpstat.tcps_closed++; return ((struct tcpcb *)0);}voidtcp_drain(){}/* * Notify a tcp user of an asynchronous error; * store error as soft error, but wake up user * (for now, won't do anything until can select for soft error). */void tcp_notify ( struct inpcb *inp, int error ) { register struct tcpcb *tp = (struct tcpcb *)inp->inp_ppcb; register struct socket *so = inp->inp_socket; /* * Ignore some errors if we are hooked up. * If connection hasn't completed, has retransmitted several times, * and receives a second error, give up now. This is better * than waiting a long time to establish a connection that * can never complete. */ if (tp->t_state == TCPS_ESTABLISHED && (error == EHOSTUNREACH || error == ENETUNREACH || error == EHOSTDOWN)) {#ifdef WV_INSTRUMENTATION#ifdef INCLUDE_WVNET /* WV_NET_INFO event */ WV_NET_MARKER_2 (NET_AUX_EVENT, WV_NET_INFO, 40, 5, WV_NETEVENT_TCPNOTIFY_IGNORE, so->so_fd, error)#endif /* INCLUDE_WVNET */#endif return; } else if (tp->t_state < TCPS_ESTABLISHED && tp->t_rxtshift > 3 && tp->t_softerror) {#ifdef WV_INSTRUMENTATION#ifdef INCLUDE_WVNET /* WV_NET_INFO event */ WV_NET_MARKER_2 (NET_AUX_EVENT, WV_NET_INFO, 41, 6, WV_NETEVENT_TCPNOTIFY_KILL, so->so_fd, error)#endif /* INCLUDE_WVNET */#endif so->so_error = error; } else {#ifdef WV_INSTRUMENTATION#ifdef INCLUDE_WVNET /* WV_NET_INFO event */ WV_NET_MARKER_2 (NET_AUX_EVENT, WV_NET_INFO, 42, 7, WV_NETEVENT_TCPNOTIFY_ERROR, so->so_fd, error)#endif /* INCLUDE_WVNET */#endif tp->t_softerror = error; } if (so->so_timeoSem) wakeup(so->so_timeoSem); sorwakeup(so); sowwakeup(so); }voidtcp_ctlinput(cmd, sa, ip) int cmd; struct sockaddr *sa; register struct ip *ip;{ register struct tcphdr *th; extern struct in_addr zeroin_addr; extern u_char inetctlerrmap[]; void (*notify) (struct inpcb *, int) = tcp_notify;#ifdef WV_INSTRUMENTATION#ifdef INCLUDE_WVNET /* WV_NET_INFO event */ WV_NET_MARKER_1 (NET_AUX_EVENT, WV_NET_INFO, 43, 8, WV_NETEVENT_TCPCTLIN_START, cmd)#endif /* INCLUDE_WVNET */#endif if (cmd == PRC_QUENCH) notify = tcp_quench; else if (cmd == PRC_MSGSIZE) notify = tcp_updatemtu; else if (!PRC_IS_REDIRECT(cmd) && ((unsigned)cmd > PRC_NCMDS || inetctlerrmap[cmd] == 0)) return; if (ip) { th = (struct tcphdr *)((caddr_t)ip + (ip->ip_hl << 2)); in_pcbnotify(&tcb, sa, th->th_dport, ip->ip_src, th->th_sport, cmd, notify); } else in_pcbnotify(&tcb, sa, 0, zeroin_addr, 0, cmd, notify);}/* * When a source quench is received, close congestion window * to one segment. We will gradually open it again as we proceed. */voidtcp_quench(inp, error) struct inpcb *inp; int error;{ struct tcpcb *tp = intotcpcb(inp); if (tp) tp->snd_cwnd = tp->t_maxseg;}/* * Look-up the routing entry to the peer of this inpcb. If no route * is found and it cannot be allocated the return NULL. This routine * is called by TCP routines that access the rmx structure. */struct rtentry *tcp_rtlookup(inp) struct inpcb *inp;{ struct route *ro; struct rtentry *rt; ro = &inp->inp_route; rt = ro->ro_rt; if (rt == NULL || !(rt->rt_flags & RTF_UP)) { /* No route yet, so try to acquire one */ if (inp->inp_faddr.s_addr != INADDR_ANY) { ro->ro_dst.sa_family = AF_INET; ro->ro_dst.sa_len = sizeof(ro->ro_dst); ((struct sockaddr_in *) &ro->ro_dst)->sin_addr = inp->inp_faddr; TOS_SET (&ro->ro_dst, inp->inp_ip.ip_tos); rtalloc(ro); rt = ro->ro_rt; } } return rt;}/* * When an ICMP error "need fragmentation" message causes the stack to * update the MSS based on the (already updated) path MTU estimate and * signal TCP to send data so that the dropped packet is detected. This * routine duplicates some code from the tcp_mss() routine in tcp_input.c */void tcp_updatemtu ( struct inpcb * inp, int error ) { struct tcpcb *tp = intotcpcb(inp); struct rtentry *rt; struct socket *so = inp->inp_socket; int mss; int maxseg; int cwnd = 0; if (tp) { rt = tcp_rtlookup (inp); if ( (rt == NULL) || (rt->rt_rmx.rmx_locks & RTV_MTU)) { /* * New path MTU estimate unavailable or discovery process * ended - set segment size to default value if less than * current estimate. */ tp->t_maxsize = min (tp->t_maxsize, tcp_mssdflt); tp->t_maxseg = min (so->so_snd.sb_hiwat, tp->t_maxsize); return; } maxseg = rt->rt_rmx.rmx_mtu - sizeof(struct tcpiphdr); mss = rt->rt_rmx.rmx_mss; /* * The following comparison violates the TCP specification by * permitting IP datagrams larger than the mandatory default * if the peer has not sent the initial SYN (which assigns the * MSS value). Although TCP is forbidden to exceed the default * unless explicitly allowed by the MSS option from a peer, that * behavior would probably prevent path MTU discovery from occurring * since the default is already less than many typical MTU sizes. * * Avoiding the conservative default might not have a significant * impact. Any unexpectedly large segments will only occur when * sending an initial SYN which includes options and/or data to a * host which has never been connected. Once the remote peer sends * a return SYN (during the connection handshake), the system will * record a MSS value and reduce the maximum segment size if * necessary. If that remote peer ignores the generally recommended * "liberal acceptance" policy and discards the segment which its * network layer successfully received, the failed connection attempts * will reveal the problem. */ if (mss) { /* * If necessary, reduce the path MTU estimate according to the * known segment size which the peer is required to accept. */ maxseg = min (maxseg, mss); } /* * Do not allow ICMP error messages to increase the maximum * segment size above the initial value determined in the * tcp_mss() routine. */ if (tp->t_maxsize <= maxseg) return; tp->t_maxsize = maxseg; /* Update the mss to ignore newly received options? */ if ((tp->t_flags & (TF_REQ_TSTMP|TF_NOOPT)) == TF_REQ_TSTMP && (tp->t_flags & TF_RCVD_TSTMP) == TF_RCVD_TSTMP) maxseg -= TCPOLEN_TSTAMP_APPA;#if (MCLBYTES & (MCLBYTES - 1)) == 0 if (maxseg > MCLBYTES) maxseg &= ~(MCLBYTES-1);#else if (maxseg > MCLBYTES) maxseg = maxseg / MCLBYTES * MCLBYTES;#endif if (so->so_snd.sb_hiwat < maxseg) maxseg = so->so_snd.sb_hiwat; tp->t_maxseg = maxseg; tp->t_rtt = 0; tp->snd_nxt = tp->snd_una; /* * If tcp_updatemtu was called in response to an ICMP fragmentation- * needed message (error = EMSGSIZE), trigger slow-start without * changing the congestion window. Temporarily set cwnd to 1 segment * and then restore it to original value after tcp_output. tcp_updatemtu * is also called from tcp_output but in that case error is 0. We do * not want to trigger slow-start for that scenario. */ if (error == EMSGSIZE) { cwnd = tp->snd_cwnd; tp->snd_cwnd = maxseg; } tcp_output(tp); if (error == EMSGSIZE) tp->snd_cwnd = cwnd; } }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -