]> git.saurik.com Git - apple/xnu.git/blob - bsd/netinet/mptcp_timer.c
xnu-3248.40.184.tar.gz
[apple/xnu.git] / bsd / netinet / mptcp_timer.c
1 /*
2 * Copyright (c) 2012-2013 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 #include <sys/param.h>
30 #include <sys/systm.h>
31 #include <sys/kernel.h>
32 #include <sys/mcache.h>
33 #include <sys/socket.h>
34 #include <sys/socketvar.h>
35 #include <sys/syslog.h>
36 #include <sys/protosw.h>
37 #include <sys/sysctl.h>
38
39 #include <mach/sdt.h>
40
41 #include <netinet/mp_pcb.h>
42 #include <netinet/mptcp_var.h>
43 #include <netinet/mptcp_timer.h>
44 #include <netinet/mptcp_seq.h>
45
46 #include <kern/locks.h>
47
48 /*
49 * MPTCP Retransmission Timer comes into play only when subflow level
50 * data is acked, but Data ACK is not received. Time is in seconds.
51 */
52 static u_int32_t mptcp_rto = 3;
53 SYSCTL_INT(_net_inet_mptcp, OID_AUTO, rto, CTLFLAG_RW | CTLFLAG_LOCKED,
54 &mptcp_rto, 0, "MPTCP Retransmission Timeout");
55
56 static int mptcp_nrtos = 3;
57 SYSCTL_INT(_net_inet_mptcp, OID_AUTO, nrto, CTLFLAG_RW | CTLFLAG_LOCKED,
58 &mptcp_rto, 0, "MPTCP Retransmissions");
59
60 /*
61 * MPTCP connections timewait interval in seconds.
62 */
63 static u_int32_t mptcp_tw = 60;
64 SYSCTL_INT(_net_inet_mptcp, OID_AUTO, tw, CTLFLAG_RW | CTLFLAG_LOCKED,
65 &mptcp_tw, 0, "MPTCP Timewait Period");
66
67 #define TIMEVAL_TO_HZ(_tv_) ((_tv_).tv_sec * hz + (_tv_).tv_usec / hz)
68
69 static int
70 mptcp_timer_demux(struct mptses *mpte, uint32_t now_msecs)
71 {
72 struct mptcb *mp_tp = NULL;
73 mp_tp = mpte->mpte_mptcb;
74 int resched_timer = 0;
75
76 DTRACE_MPTCP2(timer, struct mptses *, mpte, struct mptcb *, mp_tp);
77
78 MPTE_LOCK_ASSERT_HELD(mpte);
79 MPT_LOCK(mp_tp);
80 switch (mp_tp->mpt_timer_vals) {
81 case MPTT_REXMT:
82 if (mp_tp->mpt_rxtstart == 0)
83 break;
84 if ((now_msecs - mp_tp->mpt_rxtstart) >
85 (mptcp_rto*hz)) {
86 if (MPTCP_SEQ_GT(mp_tp->mpt_snduna,
87 mp_tp->mpt_rtseq)) {
88 mp_tp->mpt_timer_vals = 0;
89 mp_tp->mpt_rtseq = 0;
90 break;
91 }
92 mp_tp->mpt_rxtshift++;
93 if (mp_tp->mpt_rxtshift > mptcp_nrtos) {
94 mp_tp->mpt_softerror = ETIMEDOUT;
95 DTRACE_MPTCP1(error, struct mptcb *, mp_tp);
96 } else {
97 mp_tp->mpt_sndnxt = mp_tp->mpt_rtseq;
98 MPT_UNLOCK(mp_tp);
99 mptcplog((LOG_DEBUG, "MPTCP Socket: "
100 "%s: REXMT %d times.\n",
101 __func__, mp_tp->mpt_rxtshift),
102 MPTCP_SOCKET_DBG, MPTCP_LOGLVL_LOG);
103 mptcp_output(mpte);
104 MPT_LOCK(mp_tp);
105 }
106 } else {
107 resched_timer = 1;
108 }
109 break;
110 case MPTT_TW:
111 /* Allows for break before make XXX */
112 if (mp_tp->mpt_timewait == 0)
113 VERIFY(0);
114 if ((now_msecs - mp_tp->mpt_timewait) >
115 (mptcp_tw * hz)) {
116 mp_tp->mpt_softerror = ETIMEDOUT;
117 DTRACE_MPTCP1(error, struct mptcb *, mp_tp);
118 } else {
119 resched_timer = 1;
120 }
121 break;
122 case MPTT_FASTCLOSE:
123 /* TODO XXX */
124 break;
125 default:
126 break;
127 }
128 MPT_UNLOCK(mp_tp);
129
130 return (resched_timer);
131 }
132
133 uint32_t
134 mptcp_timer(struct mppcbinfo *mppi)
135 {
136 struct mppcb *mpp, *tmpp;
137 struct timeval now;
138 u_int32_t now_msecs;
139 uint32_t resched_timer = 0;
140
141 lck_mtx_assert(&mppi->mppi_lock, LCK_MTX_ASSERT_OWNED);
142
143 microuptime(&now);
144 now_msecs = TIMEVAL_TO_HZ(now);
145 TAILQ_FOREACH_SAFE(mpp, &mppi->mppi_pcbs, mpp_entry, tmpp) {
146 struct socket *mp_so;
147 struct mptses *mpte;
148
149 mp_so = mpp->mpp_socket;
150 VERIFY(mp_so != NULL);
151 mpte = mptompte(mpp);
152 VERIFY(mpte != NULL);
153 MPTE_LOCK(mpte);
154 VERIFY(mpp->mpp_flags & MPP_ATTACHED);
155
156 if (mpp->mpp_flags & MPP_DEFUNCT) {
157 MPTE_UNLOCK(mpte);
158 continue;
159 }
160
161 if (mptcp_timer_demux(mpte, now_msecs))
162 resched_timer = 1;
163 MPTE_UNLOCK(mpte);
164 }
165
166 return (resched_timer);
167 }
168
169 void
170 mptcp_start_timer(struct mptses *mpte, int timer_type)
171 {
172 struct timeval now;
173 struct mptcb *mp_tp = mpte->mpte_mptcb;
174
175 microuptime(&now);
176
177 DTRACE_MPTCP2(start__timer, struct mptcb *, mp_tp, int, timer_type);
178 mptcplog((LOG_DEBUG, "MPTCP Socket: %s: %d\n", __func__, timer_type),
179 MPTCP_SOCKET_DBG, MPTCP_LOGLVL_VERBOSE);
180
181 switch (timer_type) {
182 case MPTT_REXMT:
183 MPT_LOCK(mp_tp);
184 mp_tp->mpt_timer_vals |= MPTT_REXMT;
185 mp_tp->mpt_rxtstart = TIMEVAL_TO_HZ(now);
186 mp_tp->mpt_rxtshift = 0;
187 mp_tp->mpt_rtseq = mp_tp->mpt_sndnxt;
188 MPT_UNLOCK(mp_tp);
189 break;
190 case MPTT_TW:
191 /* XXX: Not implemented yet */
192 MPT_LOCK(mp_tp);
193 mp_tp->mpt_timer_vals |= MPTT_TW;
194 mp_tp->mpt_timewait = TIMEVAL_TO_HZ(now);
195 MPT_UNLOCK(mp_tp);
196 break;
197 case MPTT_FASTCLOSE:
198 /* NO-OP */
199 break;
200 default:
201 VERIFY(0);
202 /* NOTREACHED */
203 }
204 mptcp_timer_sched();
205 }
206
207 void
208 mptcp_cancel_timer(struct mptcb *mp_tp, int timer_type)
209 {
210 MPT_LOCK_ASSERT_HELD(mp_tp);
211 DTRACE_MPTCP2(cancel__timer, struct mptcb *, mp_tp, int, timer_type);
212
213 switch (timer_type) {
214 case MPTT_REXMT:
215 mp_tp->mpt_rxtstart = 0;
216 mp_tp->mpt_rxtshift = 0;
217 mp_tp->mpt_timer_vals = 0;
218 break;
219 case MPTT_TW:
220 /* NO-OP */
221 break;
222 case MPTT_FASTCLOSE:
223 /* NO-OP */
224 break;
225 default:
226 break;
227 }
228 }
229
230 void
231 mptcp_cancel_all_timers(struct mptcb *mp_tp)
232 {
233 mptcp_cancel_timer(mp_tp, MPTT_REXMT);
234 mptcp_cancel_timer(mp_tp, MPTT_TW);
235 mptcp_cancel_timer(mp_tp, MPTT_FASTCLOSE);
236 }