]> git.saurik.com Git - apple/xnu.git/blob - bsd/netinet/tcp_timer.c
706ec823c640ea62fde4e844439b3bd3f499c6fd
[apple/xnu.git] / bsd / netinet / tcp_timer.c
1 /*
2 * Copyright (c) 2000-2011 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28 /*
29 * Copyright (c) 1982, 1986, 1988, 1990, 1993, 1995
30 * The Regents of the University of California. All rights reserved.
31 *
32 * Redistribution and use in source and binary forms, with or without
33 * modification, are permitted provided that the following conditions
34 * are met:
35 * 1. Redistributions of source code must retain the above copyright
36 * notice, this list of conditions and the following disclaimer.
37 * 2. Redistributions in binary form must reproduce the above copyright
38 * notice, this list of conditions and the following disclaimer in the
39 * documentation and/or other materials provided with the distribution.
40 * 3. All advertising materials mentioning features or use of this software
41 * must display the following acknowledgement:
42 * This product includes software developed by the University of
43 * California, Berkeley and its contributors.
44 * 4. Neither the name of the University nor the names of its contributors
45 * may be used to endorse or promote products derived from this software
46 * without specific prior written permission.
47 *
48 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
49 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
50 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
51 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
52 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
53 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
54 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
55 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
56 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
57 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
58 * SUCH DAMAGE.
59 *
60 * @(#)tcp_timer.c 8.2 (Berkeley) 5/24/95
61 * $FreeBSD: src/sys/netinet/tcp_timer.c,v 1.34.2.11 2001/08/22 00:59:12 silby Exp $
62 */
63
64
65 #include <sys/param.h>
66 #include <sys/systm.h>
67 #include <sys/kernel.h>
68 #include <sys/mbuf.h>
69 #include <sys/sysctl.h>
70 #include <sys/socket.h>
71 #include <sys/socketvar.h>
72 #include <sys/protosw.h>
73 #include <sys/domain.h>
74 #include <sys/mcache.h>
75 #include <sys/queue.h>
76 #include <kern/locks.h>
77
78 #include <kern/cpu_number.h> /* before tcp_seq.h, for tcp_random18() */
79
80 #include <net/route.h>
81
82 #include <netinet/in.h>
83 #include <netinet/in_systm.h>
84 #include <netinet/in_pcb.h>
85 #if INET6
86 #include <netinet6/in6_pcb.h>
87 #endif
88 #include <netinet/ip_var.h>
89 #include <netinet/tcp.h>
90 #include <netinet/tcp_fsm.h>
91 #include <netinet/tcp_seq.h>
92 #include <netinet/tcp_timer.h>
93 #include <netinet/tcp_var.h>
94 #include <netinet/tcp_cc.h>
95 #if INET6
96 #include <netinet6/tcp6_var.h>
97 #endif
98 #include <netinet/tcpip.h>
99 #if TCPDEBUG
100 #include <netinet/tcp_debug.h>
101 #endif
102 #include <sys/kdebug.h>
103 #include <mach/sdt.h>
104
105 extern void postevent(struct socket *, struct sockbuf *,
106 int);
107 #define DBG_FNC_TCP_FAST NETDBG_CODE(DBG_NETTCP, (5 << 8))
108 #define DBG_FNC_TCP_SLOW NETDBG_CODE(DBG_NETTCP, (5 << 8) | 1)
109
110 #define TIMERENTRY_TO_TP(te) ((struct tcpcb *)((uintptr_t)te - offsetof(struct tcpcb, tentry.le.le_next)))
111
112 #define VERIFY_NEXT_LINK(elm,field) do { \
113 if (LIST_NEXT((elm),field) != NULL && \
114 LIST_NEXT((elm),field)->field.le_prev != \
115 &((elm)->field.le_next)) \
116 panic("Bad link elm %p next->prev != elm", (elm)); \
117 } while(0)
118
119 #define VERIFY_PREV_LINK(elm,field) do { \
120 if (*(elm)->field.le_prev != (elm)) \
121 panic("Bad link elm %p prev->next != elm", (elm)); \
122 } while(0)
123
124 static int background_io_trigger = 5;
125 SYSCTL_INT(_net_inet_tcp, OID_AUTO, background_io_trigger, CTLFLAG_RW | CTLFLAG_LOCKED,
126 &background_io_trigger, 0, "Background IO Trigger Setting");
127
128 static int
129 sysctl_msec_to_ticks SYSCTL_HANDLER_ARGS
130 {
131 #pragma unused(arg1, arg2)
132 int error, s, tt;
133
134 tt = *(int *)oidp->oid_arg1;
135 s = tt * 1000 / TCP_RETRANSHZ;;
136
137 error = sysctl_handle_int(oidp, &s, 0, req);
138 if (error || !req->newptr)
139 return (error);
140
141 tt = s * TCP_RETRANSHZ / 1000;
142 if (tt < 1)
143 return (EINVAL);
144
145 *(int *)oidp->oid_arg1 = tt;
146 return (0);
147 }
148
149 int tcp_keepinit;
150 SYSCTL_PROC(_net_inet_tcp, TCPCTL_KEEPINIT, keepinit, CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED,
151 &tcp_keepinit, 0, sysctl_msec_to_ticks, "I", "");
152
153 int tcp_keepidle;
154 SYSCTL_PROC(_net_inet_tcp, TCPCTL_KEEPIDLE, keepidle, CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED,
155 &tcp_keepidle, 0, sysctl_msec_to_ticks, "I", "");
156
157 int tcp_keepintvl;
158 SYSCTL_PROC(_net_inet_tcp, TCPCTL_KEEPINTVL, keepintvl, CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED,
159 &tcp_keepintvl, 0, sysctl_msec_to_ticks, "I", "");
160
161 int tcp_msl;
162 SYSCTL_PROC(_net_inet_tcp, OID_AUTO, msl, CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED,
163 &tcp_msl, 0, sysctl_msec_to_ticks, "I", "Maximum segment lifetime");
164
165 /*
166 * Avoid DoS via TCP Robustness in Persist Condition (see http://www.ietf.org/id/draft-ananth-tcpm-persist-02.txt)
167 * by allowing a system wide maximum persistence timeout value when in Zero Window Probe mode.
168 * Expressed in milliseconds to be consistent without timeout related values, the TCP socket option is in seconds.
169 */
170 u_int32_t tcp_max_persist_timeout = 0;
171 SYSCTL_PROC(_net_inet_tcp, OID_AUTO, max_persist_timeout, CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED,
172 &tcp_max_persist_timeout, 0, sysctl_msec_to_ticks, "I", "Maximum persistence timout for ZWP");
173
174 static int always_keepalive = 0;
175 SYSCTL_INT(_net_inet_tcp, OID_AUTO, always_keepalive, CTLFLAG_RW | CTLFLAG_LOCKED,
176 &always_keepalive , 0, "Assume SO_KEEPALIVE on all TCP connections");
177
178 /* This parameter determines how long the timer list will stay in fast mode even
179 * though all connections are idle. In fast mode, the timer will fire more frequently
180 * anticipating new data.
181 */
182 int timer_fastmode_idlemax = TCP_FASTMODE_IDLEGEN_MAX;
183 SYSCTL_INT(_net_inet_tcp, OID_AUTO, timer_fastmode_idlemax, CTLFLAG_RW | CTLFLAG_LOCKED,
184 &timer_fastmode_idlemax, 0, "Maximum idle generations in fast mode");
185
186 /*
187 * See tcp_syn_backoff[] for interval values between SYN retransmits;
188 * the value set below defines the number of retransmits, before we
189 * disable the timestamp and window scaling options during subsequent
190 * SYN retransmits. Setting it to 0 disables the dropping off of those
191 * two options.
192 */
193 static int tcp_broken_peer_syn_rxmit_thres = 7;
194 SYSCTL_INT(_net_inet_tcp, OID_AUTO, broken_peer_syn_rxmit_thres, CTLFLAG_RW | CTLFLAG_LOCKED,
195 &tcp_broken_peer_syn_rxmit_thres, 0, "Number of retransmitted SYNs before "
196 "TCP disables rfc1323 and rfc1644 during the rest of attempts");
197
198 static int tcp_timer_advanced = 0;
199 SYSCTL_INT(_net_inet_tcp, OID_AUTO, tcp_timer_advanced, CTLFLAG_RD | CTLFLAG_LOCKED,
200 &tcp_timer_advanced, 0, "Number of times one of the timers was advanced");
201
202 static int tcp_resched_timerlist = 0;
203 SYSCTL_INT(_net_inet_tcp, OID_AUTO, tcp_resched_timerlist, CTLFLAG_RD | CTLFLAG_LOCKED,
204 &tcp_resched_timerlist, 0,
205 "Number of times timer list was rescheduled as part of processing a packet");
206
207 int tcp_pmtud_black_hole_detect = 1 ;
208 SYSCTL_INT(_net_inet_tcp, OID_AUTO, pmtud_blackhole_detection, CTLFLAG_RW | CTLFLAG_LOCKED,
209 &tcp_pmtud_black_hole_detect, 0, "Path MTU Discovery Black Hole Detection");
210
211 int tcp_pmtud_black_hole_mss = 1200 ;
212 SYSCTL_INT(_net_inet_tcp, OID_AUTO, pmtud_blackhole_mss, CTLFLAG_RW | CTLFLAG_LOCKED,
213 &tcp_pmtud_black_hole_mss, 0, "Path MTU Discovery Black Hole Detection lowered MSS");
214
215 static int tcp_keepcnt = TCPTV_KEEPCNT;
216 static int tcp_gc_done = FALSE; /* perfromed garbage collection of "used" sockets */
217 /* max idle probes */
218 int tcp_maxpersistidle;
219 /* max idle time in persist */
220 int tcp_maxidle;
221
222 /* TCP delack timer is set to 100 ms. Since the processing of timer list in fast
223 * mode will happen no faster than 100 ms, the delayed ack timer will fire some where
224 * between 100 and 200 ms.
225 */
226 int tcp_delack = TCP_RETRANSHZ / 10;
227
228 struct inpcbhead time_wait_slots[N_TIME_WAIT_SLOTS];
229 int cur_tw_slot = 0;
230
231 /* tcp timer list */
232 struct tcptimerlist tcp_timer_list;
233
234 /* The frequency of running through the TCP timer list in
235 * fast and slow mode can be configured.
236 */
237 SYSCTL_UINT(_net_inet_tcp, OID_AUTO, timer_fastquantum, CTLFLAG_RW | CTLFLAG_LOCKED,
238 &tcp_timer_list.fast_quantum, TCP_FASTTIMER_QUANTUM,
239 "Frequency of running timer list in fast mode");
240
241 SYSCTL_UINT(_net_inet_tcp, OID_AUTO, timer_slowquantum, CTLFLAG_RW | CTLFLAG_LOCKED,
242 &tcp_timer_list.slow_quantum, TCP_SLOWTIMER_QUANTUM,
243 "Frequency of running timer list in slow mode");
244
245 static void tcp_remove_timer(struct tcpcb *tp);
246 static void tcp_sched_timerlist(uint32_t offset);
247 static uint32_t tcp_run_conn_timer(struct tcpcb *tp, uint16_t *next_index);
248 static void tcp_sched_timers(struct tcpcb *tp);
249 static inline void tcp_set_lotimer_index(struct tcpcb *);
250
251 /* Macro to compare two timers. If there is a reset of the sign bit, it is
252 * safe to assume that the timer has wrapped around. By doing signed comparision,
253 * we take care of wrap around such that the value with the sign bit reset is
254 * actually ahead of the other.
255 */
256
257 static inline int32_t
258 timer_diff(uint32_t t1, uint32_t toff1, uint32_t t2, uint32_t toff2) {
259 return (int32_t)((t1 + toff1) - (t2 + toff2));
260 };
261
262 /* Returns true if the timer is on the timer list */
263 #define TIMER_IS_ON_LIST(tp) ((tp)->t_flags & TF_TIMER_ONLIST)
264
265
266 void add_to_time_wait_locked(struct tcpcb *tp, uint32_t delay);
267 void add_to_time_wait(struct tcpcb *tp, uint32_t delay) ;
268
269 static void tcp_garbage_collect(struct inpcb *, int);
270
271 void add_to_time_wait_locked(struct tcpcb *tp, uint32_t delay)
272 {
273 int tw_slot;
274 struct inpcbinfo *pcbinfo = &tcbinfo;
275 uint32_t timer;
276
277 /* pcb list should be locked when we get here */
278 lck_rw_assert(pcbinfo->mtx, LCK_RW_ASSERT_EXCLUSIVE);
279
280 LIST_REMOVE(tp->t_inpcb, inp_list);
281
282 /* if (tp->t_timer[TCPT_2MSL] <= 0)
283 tp->t_timer[TCPT_2MSL] = 1; */
284
285 /*
286 * Because we're pulling this pcb out of the main TCP pcb list,
287 * we need to recalculate the TCPT_2MSL timer value for tcp_slowtimo
288 * higher timer granularity.
289 */
290
291 timer = (delay / TCP_RETRANSHZ) * PR_SLOWHZ;
292 tp->t_rcvtime = (tp->t_rcvtime / TCP_RETRANSHZ) * PR_SLOWHZ;
293
294 tp->t_rcvtime += timer & (N_TIME_WAIT_SLOTS - 1);
295
296 tw_slot = (timer & (N_TIME_WAIT_SLOTS - 1)) + cur_tw_slot;
297 if (tw_slot >= N_TIME_WAIT_SLOTS)
298 tw_slot -= N_TIME_WAIT_SLOTS;
299
300 LIST_INSERT_HEAD(&time_wait_slots[tw_slot], tp->t_inpcb, inp_list);
301 }
302
303 void add_to_time_wait(struct tcpcb *tp, uint32_t delay)
304 {
305 struct inpcbinfo *pcbinfo = &tcbinfo;
306
307 if (!lck_rw_try_lock_exclusive(pcbinfo->mtx)) {
308 tcp_unlock(tp->t_inpcb->inp_socket, 0, 0);
309 lck_rw_lock_exclusive(pcbinfo->mtx);
310 tcp_lock(tp->t_inpcb->inp_socket, 0, 0);
311 }
312 add_to_time_wait_locked(tp, delay);
313 lck_rw_done(pcbinfo->mtx);
314 }
315
316 static void
317 tcp_garbage_collect(struct inpcb *inp, int istimewait)
318 {
319 struct socket *so;
320 struct tcpcb *tp;
321
322 so = inp->inp_socket;
323 tp = intotcpcb(inp);
324
325 /*
326 * Skip if still in use or busy; it would have been more efficient
327 * if we were to test so_usecount against 0, but this isn't possible
328 * due to the current implementation of tcp_dropdropablreq() where
329 * overflow sockets that are eligible for garbage collection have
330 * their usecounts set to 1.
331 */
332 if (so->so_usecount > 1 || !lck_mtx_try_lock_spin(&inp->inpcb_mtx))
333 return;
334
335 /* Check again under the lock */
336 if (so->so_usecount > 1) {
337 lck_mtx_unlock(&inp->inpcb_mtx);
338 return;
339 }
340
341 /*
342 * Overflowed socket dropped from the listening queue? Do this
343 * only if we are called to clean up the time wait slots, since
344 * tcp_dropdropablreq() considers a socket to have been fully
345 * dropped after add_to_time_wait() is finished.
346 * Also handle the case of connections getting closed by the peer while in the queue as
347 * seen with rdar://6422317
348 *
349 */
350 if (so->so_usecount == 1 &&
351 ((istimewait && (so->so_flags & SOF_OVERFLOW)) ||
352 ((tp != NULL) && (tp->t_state == TCPS_CLOSED) && (so->so_head != NULL)
353 && ((so->so_state & (SS_INCOMP|SS_CANTSENDMORE|SS_CANTRCVMORE)) ==
354 (SS_INCOMP|SS_CANTSENDMORE|SS_CANTRCVMORE))))) {
355
356 if (inp->inp_state != INPCB_STATE_DEAD) {
357 /* Become a regular mutex */
358 lck_mtx_convert_spin(&inp->inpcb_mtx);
359 #if INET6
360 if (INP_CHECK_SOCKAF(so, AF_INET6))
361 in6_pcbdetach(inp);
362 else
363 #endif /* INET6 */
364 in_pcbdetach(inp);
365 }
366 so->so_usecount--;
367 lck_mtx_unlock(&inp->inpcb_mtx);
368 return;
369 } else if (inp->inp_wantcnt != WNT_STOPUSING) {
370 lck_mtx_unlock(&inp->inpcb_mtx);
371 return;
372 }
373
374 /*
375 * We get here because the PCB is no longer searchable (WNT_STOPUSING);
376 * detach (if needed) and dispose if it is dead (usecount is 0). This
377 * covers all cases, including overflow sockets and those that are
378 * considered as "embryonic", i.e. created by sonewconn() in TCP input
379 * path, and have not yet been committed. For the former, we reduce
380 * the usecount to 0 as done by the code above. For the latter, the
381 * usecount would have reduced to 0 as part calling soabort() when the
382 * socket is dropped at the end of tcp_input().
383 */
384 if (so->so_usecount == 0) {
385 DTRACE_TCP4(state__change, void, NULL, struct inpcb *, inp,
386 struct tcpcb *, tp, int32_t, TCPS_CLOSED);
387 /* Become a regular mutex */
388 lck_mtx_convert_spin(&inp->inpcb_mtx);
389 if (inp->inp_state != INPCB_STATE_DEAD) {
390 #if INET6
391 if (INP_CHECK_SOCKAF(so, AF_INET6))
392 in6_pcbdetach(inp);
393 else
394 #endif /* INET6 */
395 in_pcbdetach(inp);
396 }
397 in_pcbdispose(inp);
398 } else {
399 lck_mtx_unlock(&inp->inpcb_mtx);
400 }
401 }
402
403 void
404 tcp_slowtimo(void)
405 {
406 struct inpcb *inp, *nxt;
407 struct tcpcb *tp;
408 #if TCPDEBUG
409 int ostate;
410 #endif
411
412 #if KDEBUG
413 static int tws_checked = 0;
414 #endif
415
416 struct inpcbinfo *pcbinfo = &tcbinfo;
417
418 KERNEL_DEBUG(DBG_FNC_TCP_SLOW | DBG_FUNC_START, 0,0,0,0,0);
419
420 tcp_maxidle = tcp_keepcnt * tcp_keepintvl;
421
422 /* Update tcp_now here as it may get used while processing the slow timer */
423 calculate_tcp_clock();
424
425 /* Garbage collect socket/tcpcb: We need to acquire the list lock
426 * exclusively to do this
427 */
428
429 if (lck_rw_try_lock_exclusive(pcbinfo->mtx) == FALSE) {
430 if (tcp_gc_done == TRUE) { /* don't sweat it this time. cleanup was done last time */
431 tcp_gc_done = FALSE;
432 KERNEL_DEBUG(DBG_FNC_TCP_SLOW | DBG_FUNC_END, tws_checked, cur_tw_slot,0,0,0);
433 return; /* Upgrade failed and lost lock - give up this time. */
434 }
435 lck_rw_lock_exclusive(pcbinfo->mtx); /* Upgrade failed, lost lock now take it again exclusive */
436 }
437 tcp_gc_done = TRUE;
438
439 /*
440 * Process the items in the current time-wait slot
441 */
442 #if KDEBUG
443 tws_checked = 0;
444 #endif
445 KERNEL_DEBUG(DBG_FNC_TCP_SLOW | DBG_FUNC_NONE, tws_checked,0,0,0,0);
446
447 LIST_FOREACH(inp, &time_wait_slots[cur_tw_slot], inp_list) {
448 #if KDEBUG
449 tws_checked++;
450 #endif
451
452 if (in_pcb_checkstate(inp, WNT_ACQUIRE, 0) == WNT_STOPUSING)
453 continue;
454
455 tcp_lock(inp->inp_socket, 1, 0);
456
457 if (in_pcb_checkstate(inp, WNT_RELEASE, 1) == WNT_STOPUSING)
458 goto twunlock;
459
460 tp = intotcpcb(inp);
461 if (tp == NULL) /* tp already closed, remove from list */
462 goto twunlock;
463
464 if (tp->t_timer[TCPT_2MSL] >= N_TIME_WAIT_SLOTS) {
465 tp->t_timer[TCPT_2MSL] -= N_TIME_WAIT_SLOTS;
466 tp->t_rcvtime += N_TIME_WAIT_SLOTS;
467 }
468 else
469 tp->t_timer[TCPT_2MSL] = 0;
470
471 if (tp->t_timer[TCPT_2MSL] == 0) {
472
473 /* That pcb is ready for a close */
474 tcp_free_sackholes(tp);
475 tp = tcp_close(tp);
476 }
477 twunlock:
478 tcp_unlock(inp->inp_socket, 1, 0);
479 }
480
481
482 LIST_FOREACH_SAFE(inp, &tcb, inp_list, nxt) {
483 tcp_garbage_collect(inp, 0);
484 }
485
486 /* Now cleanup the time wait ones */
487 LIST_FOREACH_SAFE(inp, &time_wait_slots[cur_tw_slot], inp_list, nxt) {
488 tcp_garbage_collect(inp, 1);
489 }
490
491 if (++cur_tw_slot >= N_TIME_WAIT_SLOTS)
492 cur_tw_slot = 0;
493
494 lck_rw_done(pcbinfo->mtx);
495 KERNEL_DEBUG(DBG_FNC_TCP_SLOW | DBG_FUNC_END, tws_checked, cur_tw_slot,0,0,0);
496 }
497
498 /*
499 * Cancel all timers for TCP tp.
500 */
501 void
502 tcp_canceltimers(tp)
503 struct tcpcb *tp;
504 {
505 register int i;
506
507 tcp_remove_timer(tp);
508 for (i = 0; i < TCPT_NTIMERS; i++)
509 tp->t_timer[i] = 0;
510 tp->tentry.timer_start = tcp_now;
511 tp->tentry.index = TCPT_NONE;
512 }
513
514 int tcp_syn_backoff[TCP_MAXRXTSHIFT + 1] =
515 { 1, 1, 1, 1, 1, 2, 4, 8, 16, 32, 64, 64, 64 };
516
517 int tcp_backoff[TCP_MAXRXTSHIFT + 1] =
518 { 1, 2, 4, 8, 16, 32, 64, 64, 64, 64, 64, 64, 64 };
519
520 static int tcp_totbackoff = 511; /* sum of tcp_backoff[] */
521
522 /*
523 * TCP timer processing.
524 */
525 struct tcpcb *
526 tcp_timers(tp, timer)
527 register struct tcpcb *tp;
528 int timer;
529 {
530 register int rexmt;
531 struct socket *so_tmp;
532 struct tcptemp *t_template;
533 int optlen = 0;
534 int idle_time = 0;
535
536 #if TCPDEBUG
537 int ostate;
538 #endif
539
540 #if INET6
541 int isipv6 = (tp->t_inpcb->inp_vflag & INP_IPV4) == 0;
542 #endif /* INET6 */
543
544 so_tmp = tp->t_inpcb->inp_socket;
545 idle_time = tcp_now - tp->t_rcvtime;
546
547 switch (timer) {
548
549 /*
550 * 2 MSL timeout in shutdown went off. If we're closed but
551 * still waiting for peer to close and connection has been idle
552 * too long, or if 2MSL time is up from TIME_WAIT or FIN_WAIT_2,
553 * delete connection control block.
554 * Otherwise, (this case shouldn't happen) check again in a bit
555 * we keep the socket in the main list in that case.
556 */
557 case TCPT_2MSL:
558 tcp_free_sackholes(tp);
559 if (tp->t_state != TCPS_TIME_WAIT &&
560 tp->t_state != TCPS_FIN_WAIT_2 &&
561 ((idle_time > 0) && (idle_time < tcp_maxidle))) {
562 tp->t_timer[TCPT_2MSL] = OFFSET_FROM_START(tp, (u_int32_t)tcp_keepintvl);
563 }
564 else {
565 tp = tcp_close(tp);
566 return(tp);
567 }
568 break;
569
570 /*
571 * Retransmission timer went off. Message has not
572 * been acked within retransmit interval. Back off
573 * to a longer retransmit interval and retransmit one segment.
574 */
575 case TCPT_REXMT:
576 tcp_free_sackholes(tp);
577 /* Drop a connection in the retransmit timer
578 * 1. If we have retransmitted more than TCP_MAXRXTSHIFT times
579 * 2. If the time spent in this retransmission episode is more than
580 * the time limit set with TCP_RXT_CONNDROPTIME socket option
581 * 3. If TCP_RXT_FINDROP socket option was set and we have already
582 * retransmitted the FIN 3 times without receiving an ack
583 */
584 if (++tp->t_rxtshift > TCP_MAXRXTSHIFT ||
585 (tp->rxt_conndroptime > 0 && tp->rxt_start > 0 &&
586 (tcp_now - tp->rxt_start) >= tp->rxt_conndroptime) ||
587 ((tp->t_flagsext & TF_RXTFINDROP) != 0 &&
588 (tp->t_flags & TF_SENTFIN) != 0 &&
589 tp->t_rxtshift >= 4)) {
590
591 if ((tp->t_flagsext & TF_RXTFINDROP) != 0) {
592 tcpstat.tcps_rxtfindrop++;
593 } else {
594 tcpstat.tcps_timeoutdrop++;
595 }
596 tp->t_rxtshift = TCP_MAXRXTSHIFT;
597 tp = tcp_drop(tp, tp->t_softerror ?
598 tp->t_softerror : ETIMEDOUT);
599 postevent(so_tmp, 0, EV_TIMEOUT);
600 break;
601 }
602
603 if (tp->t_rxtshift == 1) {
604 /*
605 * first retransmit; record ssthresh and cwnd so they can
606 * be recovered if this turns out to be a "bad" retransmit.
607 * A retransmit is considered "bad" if an ACK for this
608 * segment is received within RTT/2 interval; the assumption
609 * here is that the ACK was already in flight. See
610 * "On Estimating End-to-End Network Path Properties" by
611 * Allman and Paxson for more details.
612 */
613 tp->snd_cwnd_prev = tp->snd_cwnd;
614 tp->snd_ssthresh_prev = tp->snd_ssthresh;
615 tp->snd_recover_prev = tp->snd_recover;
616 if (IN_FASTRECOVERY(tp))
617 tp->t_flags |= TF_WASFRECOVERY;
618 else
619 tp->t_flags &= ~TF_WASFRECOVERY;
620 tp->t_badrxtwin = tcp_now + (tp->t_srtt >> (TCP_RTT_SHIFT));
621
622 /* Set the time at which retransmission on this
623 * connection started
624 */
625 tp->rxt_start = tcp_now;
626 }
627 tcpstat.tcps_rexmttimeo++;
628 if (tp->t_state == TCPS_SYN_SENT)
629 rexmt = TCP_REXMTVAL(tp) * tcp_syn_backoff[tp->t_rxtshift];
630 else
631 rexmt = TCP_REXMTVAL(tp) * tcp_backoff[tp->t_rxtshift];
632 TCPT_RANGESET(tp->t_rxtcur, rexmt,
633 tp->t_rttmin, TCPTV_REXMTMAX,
634 TCP_ADD_REXMTSLOP(tp));
635 tp->t_timer[TCPT_REXMT] = OFFSET_FROM_START(tp, tp->t_rxtcur);
636
637 /*
638 * Check for potential Path MTU Discovery Black Hole
639 */
640
641 if (tcp_pmtud_black_hole_detect && (tp->t_state == TCPS_ESTABLISHED)) {
642 if (((tp->t_flags & (TF_PMTUD|TF_MAXSEGSNT)) == (TF_PMTUD|TF_MAXSEGSNT)) && (tp->t_rxtshift == 2)) {
643 /*
644 * Enter Path MTU Black-hole Detection mechanism:
645 * - Disable Path MTU Discovery (IP "DF" bit).
646 * - Reduce MTU to lower value than what we negociated with peer.
647 */
648
649 tp->t_flags &= ~TF_PMTUD; /* Disable Path MTU Discovery for now */
650 tp->t_flags |= TF_BLACKHOLE; /* Record that we may have found a black hole */
651 optlen = tp->t_maxopd - tp->t_maxseg;
652 tp->t_pmtud_saved_maxopd = tp->t_maxopd; /* Keep track of previous MSS */
653 if (tp->t_maxopd > tcp_pmtud_black_hole_mss)
654 tp->t_maxopd = tcp_pmtud_black_hole_mss; /* Reduce the MSS to intermediary value */
655 else {
656 tp->t_maxopd = /* use the default MSS */
657 #if INET6
658 isipv6 ? tcp_v6mssdflt :
659 #endif /* INET6 */
660 tcp_mssdflt;
661 }
662 tp->t_maxseg = tp->t_maxopd - optlen;
663
664 /*
665 * Reset the slow-start flight size as it may depends on the new MSS
666 */
667 if (CC_ALGO(tp)->cwnd_init != NULL)
668 CC_ALGO(tp)->cwnd_init(tp);
669 }
670 /*
671 * If further retransmissions are still unsuccessful with a lowered MTU,
672 * maybe this isn't a Black Hole and we restore the previous MSS and
673 * blackhole detection flags.
674 */
675 else {
676
677 if ((tp->t_flags & TF_BLACKHOLE) && (tp->t_rxtshift > 4)) {
678 tp->t_flags |= TF_PMTUD;
679 tp->t_flags &= ~TF_BLACKHOLE;
680 optlen = tp->t_maxopd - tp->t_maxseg;
681 tp->t_maxopd = tp->t_pmtud_saved_maxopd;
682 tp->t_maxseg = tp->t_maxopd - optlen;
683 /*
684 * Reset the slow-start flight size as it may depends on the new MSS
685 */
686 if (CC_ALGO(tp)->cwnd_init != NULL)
687 CC_ALGO(tp)->cwnd_init(tp);
688 }
689 }
690 }
691
692
693 /*
694 * Disable rfc1323 and rfc1644 if we haven't got any response to
695 * our SYN (after we reach the threshold) to work-around some
696 * broken terminal servers (most of which have hopefully been
697 * retired) that have bad VJ header compression code which
698 * trashes TCP segments containing unknown-to-them TCP options.
699 */
700 if ((tp->t_state == TCPS_SYN_SENT) &&
701 (tp->t_rxtshift == tcp_broken_peer_syn_rxmit_thres))
702 tp->t_flags &= ~(TF_REQ_SCALE|TF_REQ_TSTMP|TF_REQ_CC);
703 /*
704 * If losing, let the lower level know and try for
705 * a better route. Also, if we backed off this far,
706 * our srtt estimate is probably bogus. Clobber it
707 * so we'll take the next rtt measurement as our srtt;
708 * move the current srtt into rttvar to keep the current
709 * retransmit times until then.
710 */
711 if (tp->t_rxtshift > TCP_MAXRXTSHIFT / 4) {
712 #if INET6
713 if (isipv6)
714 in6_losing(tp->t_inpcb);
715 else
716 #endif /* INET6 */
717 in_losing(tp->t_inpcb);
718 tp->t_rttvar += (tp->t_srtt >> TCP_RTT_SHIFT);
719 tp->t_srtt = 0;
720 }
721 tp->snd_nxt = tp->snd_una;
722 /*
723 * Note: We overload snd_recover to function also as the
724 * snd_last variable described in RFC 2582
725 */
726 tp->snd_recover = tp->snd_max;
727 /*
728 * Force a segment to be sent.
729 */
730 tp->t_flags |= TF_ACKNOW;
731 /*
732 * If timing a segment in this window, stop the timer.
733 */
734 tp->t_rtttime = 0;
735
736 if (CC_ALGO(tp)->after_timeout != NULL)
737 CC_ALGO(tp)->after_timeout(tp);
738
739 tp->t_dupacks = 0;
740 EXIT_FASTRECOVERY(tp);
741
742 DTRACE_TCP5(cc, void, NULL, struct inpcb *, tp->t_inpcb,
743 struct tcpcb *, tp, struct tcphdr *, NULL,
744 int32_t, TCP_CC_REXMT_TIMEOUT);
745
746 (void) tcp_output(tp);
747 break;
748
749 /*
750 * Persistance timer into zero window.
751 * Force a byte to be output, if possible.
752 */
753 case TCPT_PERSIST:
754 tcpstat.tcps_persisttimeo++;
755 /*
756 * Hack: if the peer is dead/unreachable, we do not
757 * time out if the window is closed. After a full
758 * backoff, drop the connection if the idle time
759 * (no responses to probes) reaches the maximum
760 * backoff that we would use if retransmitting.
761 *
762 * Drop the connection if we reached the maximum allowed time for
763 * Zero Window Probes without a non-zero update from the peer.
764 * See rdar://5805356
765 */
766 if ((tp->t_rxtshift == TCP_MAXRXTSHIFT &&
767 (idle_time >= tcp_maxpersistidle ||
768 idle_time >= TCP_REXMTVAL(tp) * tcp_totbackoff)) ||
769 ((tp->t_persist_stop != 0) && (tp->t_persist_stop <= tcp_now))) {
770 tcpstat.tcps_persistdrop++;
771 so_tmp = tp->t_inpcb->inp_socket;
772 tp = tcp_drop(tp, ETIMEDOUT);
773 postevent(so_tmp, 0, EV_TIMEOUT);
774 break;
775 }
776 tcp_setpersist(tp);
777 tp->t_force = 1;
778 (void) tcp_output(tp);
779 tp->t_force = 0;
780 break;
781
782 /*
783 * Keep-alive timer went off; send something
784 * or drop connection if idle for too long.
785 */
786 case TCPT_KEEP:
787 tcpstat.tcps_keeptimeo++;
788 if (tp->t_state < TCPS_ESTABLISHED)
789 goto dropit;
790 if ((always_keepalive ||
791 tp->t_inpcb->inp_socket->so_options & SO_KEEPALIVE) &&
792 (tp->t_state <= TCPS_CLOSING || tp->t_state == TCPS_FIN_WAIT_2)) {
793 if (idle_time >= TCP_KEEPIDLE(tp) + (u_int32_t)tcp_maxidle)
794 goto dropit;
795 /*
796 * Send a packet designed to force a response
797 * if the peer is up and reachable:
798 * either an ACK if the connection is still alive,
799 * or an RST if the peer has closed the connection
800 * due to timeout or reboot.
801 * Using sequence number tp->snd_una-1
802 * causes the transmitted zero-length segment
803 * to lie outside the receive window;
804 * by the protocol spec, this requires the
805 * correspondent TCP to respond.
806 */
807 tcpstat.tcps_keepprobe++;
808 t_template = tcp_maketemplate(tp);
809 if (t_template) {
810 unsigned int ifscope, nocell = 0;
811
812 if (tp->t_inpcb->inp_flags & INP_BOUND_IF)
813 ifscope = tp->t_inpcb->inp_boundif;
814 else
815 ifscope = IFSCOPE_NONE;
816
817 /*
818 * If the socket isn't allowed to use the
819 * cellular interface, indicate it as such.
820 */
821 if (tp->t_inpcb->inp_flags & INP_NO_IFT_CELLULAR)
822 nocell = 1;
823
824 tcp_respond(tp, t_template->tt_ipgen,
825 &t_template->tt_t, (struct mbuf *)NULL,
826 tp->rcv_nxt, tp->snd_una - 1, 0, ifscope,
827 nocell);
828 (void) m_free(dtom(t_template));
829 }
830 tp->t_timer[TCPT_KEEP] = OFFSET_FROM_START(tp, tcp_keepintvl);
831 } else
832 tp->t_timer[TCPT_KEEP] = OFFSET_FROM_START(tp, TCP_KEEPIDLE(tp));
833 break;
834 case TCPT_DELACK:
835 if (tcp_delack_enabled && (tp->t_flags & TF_DELACK)) {
836 tp->t_flags &= ~TF_DELACK;
837 tp->t_timer[TCPT_DELACK] = 0;
838 tp->t_flags |= TF_ACKNOW;
839
840 /* If delayed ack timer fired while we are stretching acks,
841 * go back to acking every other packet
842 */
843 if ((tp->t_flags & TF_STRETCHACK) != 0)
844 tcp_reset_stretch_ack(tp);
845
846 tcpstat.tcps_delack++;
847 (void) tcp_output(tp);
848 }
849 break;
850
851 #if TCPDEBUG
852 if (tp->t_inpcb->inp_socket->so_options & SO_DEBUG)
853 tcp_trace(TA_USER, ostate, tp, (void *)0, (struct tcphdr *)0,
854 PRU_SLOWTIMO);
855 #endif
856 dropit:
857 tcpstat.tcps_keepdrops++;
858 tp = tcp_drop(tp, ETIMEDOUT);
859 postevent(so_tmp, 0, EV_TIMEOUT);
860 break;
861 }
862 return (tp);
863 }
864
865 /* Remove a timer entry from timer list */
866 void
867 tcp_remove_timer(struct tcpcb *tp)
868 {
869 struct tcptimerlist *listp = &tcp_timer_list;
870
871 lck_mtx_assert(&tp->t_inpcb->inpcb_mtx, LCK_MTX_ASSERT_OWNED);
872 if (!(TIMER_IS_ON_LIST(tp))) {
873 return;
874 }
875 lck_mtx_lock(listp->mtx);
876
877 /* Check if pcb is on timer list again after acquiring the lock */
878 if (!(TIMER_IS_ON_LIST(tp))) {
879 lck_mtx_unlock(listp->mtx);
880 return;
881 }
882
883 if (listp->next_te != NULL && listp->next_te == &tp->tentry)
884 listp->next_te = LIST_NEXT(&tp->tentry, le);
885
886 LIST_REMOVE(&tp->tentry, le);
887 tp->t_flags &= ~(TF_TIMER_ONLIST);
888
889 listp->entries--;
890 lck_mtx_unlock(listp->mtx);
891
892 tp->tentry.le.le_next = NULL;
893 tp->tentry.le.le_prev = NULL;
894 }
895
896 /* Function to check if the timerlist needs to be rescheduled to run
897 * the timer entry correctly. Basically, this is to check if we can avoid
898 * taking the list lock.
899 */
900
901 static boolean_t
902 need_to_resched_timerlist(uint32_t runtime, uint16_t index) {
903 struct tcptimerlist *listp = &tcp_timer_list;
904 int32_t diff;
905 boolean_t is_fast;
906
907 if (runtime == 0 || index == TCPT_NONE)
908 return FALSE;
909 is_fast = !(IS_TIMER_SLOW(index));
910
911 /* If the list is being processed then the state of the list is in flux.
912 * In this case always acquire the lock and set the state correctly.
913 */
914 if (listp->running) {
915 return TRUE;
916 }
917
918 diff = timer_diff(listp->runtime, 0, runtime, 0);
919 if (diff <= 0) {
920 /* The list is going to run before this timer */
921 return FALSE;
922 } else {
923 if (is_fast) {
924 if (diff <= listp->fast_quantum)
925 return FALSE;
926 } else {
927 if (diff <= listp->slow_quantum)
928 return FALSE;
929 }
930 }
931 return TRUE;
932 }
933
934 void
935 tcp_sched_timerlist(uint32_t offset)
936 {
937
938 uint64_t deadline = 0;
939 struct tcptimerlist *listp = &tcp_timer_list;
940
941 lck_mtx_assert(listp->mtx, LCK_MTX_ASSERT_OWNED);
942
943 listp->runtime = tcp_now + offset;
944
945 clock_interval_to_deadline(offset, NSEC_PER_SEC / TCP_RETRANSHZ,
946 &deadline);
947
948 thread_call_enter_delayed(listp->call, deadline);
949 }
950
951 /* Function to run the timers for a connection.
952 *
953 * Returns the offset of next timer to be run for this connection which
954 * can be used to reschedule the timerlist.
955 */
956 uint32_t
957 tcp_run_conn_timer(struct tcpcb *tp, uint16_t *next_index) {
958
959 struct socket *so;
960 uint16_t i = 0, index = TCPT_NONE, lo_index = TCPT_NONE;
961 uint32_t timer_val, offset = 0, lo_timer = 0;
962 int32_t diff;
963 boolean_t needtorun[TCPT_NTIMERS];
964 int count = 0;
965
966 VERIFY(tp != NULL);
967 bzero(needtorun, sizeof(needtorun));
968
969 tcp_lock(tp->t_inpcb->inp_socket, 1, 0);
970
971 so = tp->t_inpcb->inp_socket;
972 /* Release the want count on inp */
973 if (in_pcb_checkstate(tp->t_inpcb, WNT_RELEASE, 1) == WNT_STOPUSING) {
974 if (TIMER_IS_ON_LIST(tp)) {
975 tcp_remove_timer(tp);
976 }
977
978 /* Looks like the TCP connection got closed while we
979 * were waiting for the lock.. Done
980 */
981 goto done;
982 }
983
984 /* Since the timer thread needs to wait for tcp lock, it may race
985 * with another thread that can cancel or reschedule the timer that is
986 * about to run. Check if we need to run anything.
987 */
988 index = tp->tentry.index;
989 timer_val = tp->t_timer[index];
990
991 if (index == TCPT_NONE || tp->tentry.runtime == 0)
992 goto done;
993
994 diff = timer_diff(tp->tentry.runtime, 0, tcp_now, 0);
995 if (diff > 0) {
996 if (tp->tentry.index != TCPT_NONE) {
997 offset = diff;
998 *(next_index) = tp->tentry.index;
999 }
1000 goto done;
1001 }
1002
1003 tp->t_timer[index] = 0;
1004 if (timer_val > 0) {
1005 tp = tcp_timers(tp, index);
1006 if (tp == NULL)
1007 goto done;
1008 }
1009
1010 /* Check if there are any other timers that need to be run. While doing it,
1011 * adjust the timer values wrt tcp_now.
1012 */
1013 for (i = 0; i < TCPT_NTIMERS; ++i) {
1014 if (tp->t_timer[i] != 0) {
1015 diff = timer_diff(tp->tentry.timer_start, tp->t_timer[i], tcp_now, 0);
1016 if (diff <= 0) {
1017 tp->t_timer[i] = 0;
1018 needtorun[i] = TRUE;
1019 count++;
1020 } else {
1021 tp->t_timer[i] = diff;
1022 needtorun[i] = FALSE;
1023 if (lo_timer == 0 || diff < lo_timer) {
1024 lo_timer = diff;
1025 lo_index = i;
1026 }
1027 }
1028 }
1029 }
1030
1031 tp->tentry.timer_start = tcp_now;
1032 tp->tentry.index = lo_index;
1033 if (lo_index != TCPT_NONE) {
1034 tp->tentry.runtime = tp->tentry.timer_start + tp->t_timer[lo_index];
1035 } else {
1036 tp->tentry.runtime = 0;
1037 }
1038
1039 if (count > 0) {
1040 /* run any other timers that are also outstanding at this time. */
1041 for (i = 0; i < TCPT_NTIMERS; ++i) {
1042 if (needtorun[i]) {
1043 tp->t_timer[i] = 0;
1044 tp = tcp_timers(tp, i);
1045 if (tp == NULL)
1046 goto done;
1047 }
1048 }
1049 tcp_set_lotimer_index(tp);
1050 }
1051
1052 if (tp->tentry.index < TCPT_NONE) {
1053 offset = tp->t_timer[tp->tentry.index];
1054 *(next_index) = tp->tentry.index;
1055 }
1056
1057 done:
1058 if (tp != NULL && tp->tentry.index == TCPT_NONE) {
1059 tcp_remove_timer(tp);
1060 }
1061 tcp_unlock(so, 1, 0);
1062 return offset;
1063 }
1064
1065 void
1066 tcp_run_timerlist(void * arg1, void * arg2) {
1067
1068 #pragma unused(arg1, arg2)
1069
1070 struct tcptimerentry *te, *next_te;
1071 struct tcptimerlist *listp = &tcp_timer_list;
1072 struct tcpcb *tp;
1073 uint32_t next_timer = 0;
1074 uint16_t index = TCPT_NONE;
1075 boolean_t need_fast = FALSE;
1076 uint32_t active_count = 0;
1077 uint32_t mode = TCP_TIMERLIST_FASTMODE;
1078
1079 calculate_tcp_clock();
1080
1081 lck_mtx_lock(listp->mtx);
1082
1083 listp->running = TRUE;
1084
1085 LIST_FOREACH_SAFE(te, &listp->lhead, le, next_te) {
1086 uint32_t offset = 0;
1087 uint32_t runtime = te->runtime;
1088 if (TSTMP_GT(runtime, tcp_now)) {
1089 offset = timer_diff(runtime, 0, tcp_now, 0);
1090 if (next_timer == 0 || offset < next_timer) {
1091 next_timer = offset;
1092 }
1093 continue;
1094 }
1095 active_count++;
1096
1097 tp = TIMERENTRY_TO_TP(te);
1098
1099 /* Acquire an inp wantcnt on the inpcb so that the socket won't get
1100 * detached even if tcp_close is called
1101 */
1102 if (in_pcb_checkstate(tp->t_inpcb, WNT_ACQUIRE, 0) == WNT_STOPUSING) {
1103 /* Some how this pcb went into dead state while on the timer list,
1104 * just take it off the list. Since the timer list entry pointers
1105 * are protected by the timer list lock, we can do it here
1106 */
1107 if (TIMER_IS_ON_LIST(tp)) {
1108 tp->t_flags &= ~(TF_TIMER_ONLIST);
1109 LIST_REMOVE(&tp->tentry, le);
1110 listp->entries--;
1111
1112 tp->tentry.le.le_next = NULL;
1113 tp->tentry.le.le_prev = NULL;
1114 }
1115 continue;
1116 }
1117
1118 /* Store the next timerentry pointer before releasing the list lock.
1119 * If that entry has to be removed when we release the lock, this
1120 * pointer will be updated to the element after that.
1121 */
1122 listp->next_te = next_te;
1123
1124 VERIFY_NEXT_LINK(&tp->tentry, le);
1125 VERIFY_PREV_LINK(&tp->tentry, le);
1126
1127 lck_mtx_unlock(listp->mtx);
1128
1129 index = TCPT_NONE;
1130 offset = tcp_run_conn_timer(tp, &index);
1131
1132 lck_mtx_lock(listp->mtx);
1133
1134 next_te = listp->next_te;
1135 listp->next_te = NULL;
1136
1137 if (offset > 0) {
1138 if (index < TCPT_NONE) {
1139 /* Check if this is a fast_timer. */
1140 if (!need_fast && !(IS_TIMER_SLOW(index))) {
1141 need_fast = TRUE;
1142 }
1143
1144 if (next_timer == 0 || offset < next_timer) {
1145 next_timer = offset;
1146 }
1147 }
1148 }
1149 }
1150
1151 if (!LIST_EMPTY(&listp->lhead)) {
1152 if (listp->mode == TCP_TIMERLIST_FASTMODE) {
1153 if (need_fast || active_count > 0 ||
1154 listp->pref_mode == TCP_TIMERLIST_FASTMODE) {
1155 listp->idlegen = 0;
1156 } else {
1157 listp->idlegen++;
1158 if (listp->idlegen > timer_fastmode_idlemax) {
1159 mode = TCP_TIMERLIST_SLOWMODE;
1160 listp->idlegen = 0;
1161 }
1162 }
1163 } else {
1164 if (!need_fast) {
1165 mode = TCP_TIMERLIST_SLOWMODE;
1166 }
1167 }
1168
1169 if (mode == TCP_TIMERLIST_FASTMODE ||
1170 listp->pref_mode == TCP_TIMERLIST_FASTMODE) {
1171 next_timer = listp->fast_quantum;
1172 } else {
1173 if (listp->pref_offset != 0 &&
1174 listp->pref_offset < next_timer)
1175 next_timer = listp->pref_offset;
1176 if (next_timer < listp->slow_quantum)
1177 next_timer = listp->slow_quantum;
1178 }
1179
1180 listp->mode = mode;
1181
1182 tcp_sched_timerlist(next_timer);
1183 } else {
1184 /* No need to reschedule this timer */
1185 listp->runtime = 0;
1186 }
1187
1188 listp->running = FALSE;
1189 listp->pref_mode = 0;
1190 listp->pref_offset = 0;
1191
1192 lck_mtx_unlock(listp->mtx);
1193 }
1194
1195 /* Function to verify if a change in timer state is required for a connection */
1196 void
1197 tcp_sched_timers(struct tcpcb *tp)
1198 {
1199 struct tcptimerentry *te = &tp->tentry;
1200 uint16_t index = te->index;
1201 struct tcptimerlist *listp = &tcp_timer_list;
1202 uint32_t offset = 0;
1203 boolean_t is_fast;
1204 int list_locked = 0;
1205
1206 if (tp->t_inpcb->inp_state == INPCB_STATE_DEAD) {
1207 /* Just return without adding the dead pcb to the list */
1208 if (TIMER_IS_ON_LIST(tp)) {
1209 tcp_remove_timer(tp);
1210 }
1211 return;
1212 }
1213
1214 if (index == TCPT_NONE) {
1215 tcp_remove_timer(tp);
1216 return;
1217 }
1218
1219 is_fast = !(IS_TIMER_SLOW(index));
1220 offset = te->runtime - tcp_now;
1221 if (offset == 0) {
1222 offset = 1;
1223 tcp_timer_advanced++;
1224 }
1225 if (is_fast)
1226 offset = listp->fast_quantum;
1227
1228 if (!TIMER_IS_ON_LIST(tp)) {
1229 if (!list_locked) {
1230 lck_mtx_lock(listp->mtx);
1231 list_locked = 1;
1232 }
1233
1234 LIST_INSERT_HEAD(&listp->lhead, te, le);
1235 tp->t_flags |= TF_TIMER_ONLIST;
1236
1237 listp->entries++;
1238 if (listp->entries > listp->maxentries)
1239 listp->maxentries = listp->entries;
1240
1241 /* if the list is not scheduled, just schedule it */
1242 if (listp->runtime == 0)
1243 goto schedule;
1244
1245 }
1246
1247
1248 /* timer entry is currently on the list */
1249 if (need_to_resched_timerlist(te->runtime, index)) {
1250 tcp_resched_timerlist++;
1251
1252 if (!list_locked) {
1253 lck_mtx_lock(listp->mtx);
1254 list_locked = 1;
1255 }
1256
1257 VERIFY_NEXT_LINK(te, le);
1258 VERIFY_PREV_LINK(te, le);
1259
1260 if (listp->running) {
1261 if (is_fast) {
1262 listp->pref_mode = TCP_TIMERLIST_FASTMODE;
1263 } else if (listp->pref_offset == 0 ||
1264 ((int)offset) < listp->pref_offset) {
1265 listp->pref_offset = offset;
1266 }
1267 } else {
1268 int32_t diff;
1269 diff = timer_diff(listp->runtime, 0, tcp_now, offset);
1270 if (diff <= 0) {
1271 /* The list is going to run before this timer */
1272 goto done;
1273 } else {
1274 goto schedule;
1275 }
1276 }
1277 }
1278 goto done;
1279
1280 schedule:
1281 if (is_fast) {
1282 listp->mode = TCP_TIMERLIST_FASTMODE;
1283 listp->idlegen = 0;
1284 }
1285 tcp_sched_timerlist(offset);
1286
1287 done:
1288 if (list_locked)
1289 lck_mtx_unlock(listp->mtx);
1290
1291 return;
1292 }
1293
1294 void
1295 tcp_set_lotimer_index(struct tcpcb *tp) {
1296 uint16_t i, lo_index = TCPT_NONE;
1297 uint32_t lo_timer = 0;
1298 for (i = 0; i < TCPT_NTIMERS; ++i) {
1299 if (tp->t_timer[i] != 0 &&
1300 (lo_timer == 0 || tp->t_timer[i] < lo_timer)) {
1301 lo_timer = tp->t_timer[i];
1302 lo_index = i;
1303 }
1304 }
1305 tp->tentry.index = lo_index;
1306 if (lo_index != TCPT_NONE) {
1307 tp->tentry.runtime = tp->tentry.timer_start + tp->t_timer[lo_index];
1308 } else {
1309 tp->tentry.runtime = 0;
1310 }
1311 }
1312
1313 void
1314 tcp_check_timer_state(struct tcpcb *tp) {
1315
1316 lck_mtx_assert(&tp->t_inpcb->inpcb_mtx, LCK_MTX_ASSERT_OWNED);
1317
1318 tcp_set_lotimer_index(tp);
1319
1320 tcp_sched_timers(tp);
1321 return;
1322 }