2 * Copyright (c) 2012-2017 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
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.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
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.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
29 #include <sys/param.h>
30 #include <sys/systm.h>
31 #include <sys/kernel.h>
33 #include <sys/mcache.h>
34 #include <sys/syslog.h>
35 #include <sys/socket.h>
36 #include <sys/socketvar.h>
37 #include <sys/protosw.h>
38 #include <sys/proc_internal.h>
40 #include <mach/boolean.h>
41 #include <kern/zalloc.h>
42 #include <kern/locks.h>
44 #include <netinet/mp_pcb.h>
45 #include <netinet/mptcp_var.h>
46 #include <netinet6/in6_pcb.h>
48 static lck_grp_t
*mp_lock_grp
;
49 static lck_attr_t
*mp_lock_attr
;
50 static lck_grp_attr_t
*mp_lock_grp_attr
;
51 decl_lck_mtx_data(static, mp_lock
); /* global MULTIPATH lock */
52 decl_lck_mtx_data(static, mp_timeout_lock
);
54 static TAILQ_HEAD(, mppcbinfo
) mppi_head
= TAILQ_HEAD_INITIALIZER(mppi_head
);
56 static boolean_t mp_timeout_run
; /* MP timer is scheduled to run */
57 static boolean_t mp_garbage_collecting
;
58 static boolean_t mp_ticking
;
59 static void mp_sched_timeout(void);
60 static void mp_timeout(void *);
63 mpp_lock_assert_held(struct mppcb
*mp
)
68 LCK_MTX_ASSERT(&mp
->mpp_lock
, LCK_MTX_ASSERT_OWNED
);
74 static int mp_initialized
= 0;
76 VERIFY(!mp_initialized
);
79 mp_lock_grp_attr
= lck_grp_attr_alloc_init();
80 mp_lock_grp
= lck_grp_alloc_init("multipath", mp_lock_grp_attr
);
81 mp_lock_attr
= lck_attr_alloc_init();
82 lck_mtx_init(&mp_lock
, mp_lock_grp
, mp_lock_attr
);
83 lck_mtx_init(&mp_timeout_lock
, mp_lock_grp
, mp_lock_attr
);
90 struct mppcbinfo
*mppi
;
96 * Update coarse-grained networking timestamp (in sec.); the idea
97 * is to piggy-back on the timeout callout to update the counter
98 * returnable via net_uptime().
102 lck_mtx_lock_spin(&mp_timeout_lock
);
103 gc
= mp_garbage_collecting
;
104 mp_garbage_collecting
= FALSE
;
110 lck_mtx_unlock(&mp_timeout_lock
);
112 lck_mtx_lock(&mp_lock
);
113 TAILQ_FOREACH(mppi
, &mppi_head
, mppi_entry
) {
114 if ((gc
&& mppi
->mppi_gc
!= NULL
) ||
115 (t
&& mppi
->mppi_timer
!= NULL
)) {
116 lck_mtx_lock(&mppi
->mppi_lock
);
117 if (gc
&& mppi
->mppi_gc
!= NULL
) {
118 gc_act
+= mppi
->mppi_gc(mppi
);
120 if (t
&& mppi
->mppi_timer
!= NULL
) {
121 t_act
+= mppi
->mppi_timer(mppi
);
123 lck_mtx_unlock(&mppi
->mppi_lock
);
126 lck_mtx_unlock(&mp_lock
);
128 lck_mtx_lock_spin(&mp_timeout_lock
);
131 /* lock was dropped above, so check first before overriding */
132 if (!mp_garbage_collecting
) {
133 mp_garbage_collecting
= (gc_act
!= 0);
136 mp_ticking
= (t_act
!= 0);
139 /* re-arm the timer if there's work to do */
140 mp_timeout_run
= FALSE
;
142 lck_mtx_unlock(&mp_timeout_lock
);
146 mp_sched_timeout(void)
148 LCK_MTX_ASSERT(&mp_timeout_lock
, LCK_MTX_ASSERT_OWNED
);
150 if (!mp_timeout_run
&& (mp_garbage_collecting
|| mp_ticking
)) {
151 lck_mtx_convert_spin(&mp_timeout_lock
);
152 mp_timeout_run
= TRUE
;
153 timeout(mp_timeout
, NULL
, hz
);
160 lck_mtx_lock_spin(&mp_timeout_lock
);
161 mp_garbage_collecting
= TRUE
;
163 lck_mtx_unlock(&mp_timeout_lock
);
167 mptcp_timer_sched(void)
169 lck_mtx_lock_spin(&mp_timeout_lock
);
172 lck_mtx_unlock(&mp_timeout_lock
);
176 mp_pcbinfo_attach(struct mppcbinfo
*mppi
)
178 struct mppcbinfo
*mppi0
;
180 lck_mtx_lock(&mp_lock
);
181 TAILQ_FOREACH(mppi0
, &mppi_head
, mppi_entry
) {
183 panic("%s: mppi %p already in the list\n",
188 TAILQ_INSERT_TAIL(&mppi_head
, mppi
, mppi_entry
);
189 lck_mtx_unlock(&mp_lock
);
193 mp_pcbinfo_detach(struct mppcbinfo
*mppi
)
195 struct mppcbinfo
*mppi0
;
198 lck_mtx_lock(&mp_lock
);
199 TAILQ_FOREACH(mppi0
, &mppi_head
, mppi_entry
) {
205 TAILQ_REMOVE(&mppi_head
, mppi0
, mppi_entry
);
209 lck_mtx_unlock(&mp_lock
);
215 mp_pcballoc(struct socket
*so
, struct mppcbinfo
*mppi
)
217 struct mppcb
*mpp
= NULL
;
220 VERIFY(mpsotomppcb(so
) == NULL
);
222 mpp
= zalloc(mppi
->mppi_zone
);
227 bzero(mpp
, mppi
->mppi_size
);
228 lck_mtx_init(&mpp
->mpp_lock
, mppi
->mppi_lock_grp
, mppi
->mppi_lock_attr
);
229 mpp
->mpp_pcbinfo
= mppi
;
230 mpp
->mpp_state
= MPPCB_STATE_INUSE
;
231 mpp
->mpp_socket
= so
;
234 error
= mptcp_session_create(mpp
);
236 lck_mtx_destroy(&mpp
->mpp_lock
, mppi
->mppi_lock_grp
);
237 zfree(mppi
->mppi_zone
, mpp
);
241 lck_mtx_lock(&mppi
->mppi_lock
);
242 mpp
->mpp_flags
|= MPP_ATTACHED
;
243 TAILQ_INSERT_TAIL(&mppi
->mppi_pcbs
, mpp
, mpp_entry
);
246 lck_mtx_unlock(&mppi
->mppi_lock
);
252 mp_pcbdetach(struct socket
*mp_so
)
254 struct mppcb
*mpp
= mpsotomppcb(mp_so
);
256 mpp
->mpp_state
= MPPCB_STATE_DEAD
;
262 mp_pcbdispose(struct mppcb
*mpp
)
264 struct mppcbinfo
*mppi
= mpp
->mpp_pcbinfo
;
266 VERIFY(mppi
!= NULL
);
268 LCK_MTX_ASSERT(&mppi
->mppi_lock
, LCK_MTX_ASSERT_OWNED
);
269 mpp_lock_assert_held(mpp
);
271 VERIFY(mpp
->mpp_state
== MPPCB_STATE_DEAD
);
272 VERIFY(mpp
->mpp_flags
& MPP_ATTACHED
);
274 mpp
->mpp_flags
&= ~MPP_ATTACHED
;
275 TAILQ_REMOVE(&mppi
->mppi_pcbs
, mpp
, mpp_entry
);
276 VERIFY(mppi
->mppi_count
!= 0);
279 if (mppi
->mppi_count
== 0) {
280 if (mptcp_cellicon_refcount
) {
281 os_log_error(mptcp_log_handle
, "%s: No more MPTCP-flows, but cell icon counter is %u\n",
282 __func__
, mptcp_cellicon_refcount
);
283 mptcp_clear_cellicon();
284 mptcp_cellicon_refcount
= 0;
288 VERIFY(mpp
->mpp_inside
== 0);
292 necp_mppcb_dispose(mpp
);
295 lck_mtx_destroy(&mpp
->mpp_lock
, mppi
->mppi_lock_grp
);
297 VERIFY(mpp
->mpp_socket
!= NULL
);
298 VERIFY(mpp
->mpp_socket
->so_usecount
== 0);
299 mpp
->mpp_socket
->so_pcb
= NULL
;
300 mpp
->mpp_socket
= NULL
;
302 zfree(mppi
->mppi_zone
, mpp
);
306 mp_getaddr_v4(struct socket
*mp_so
, struct sockaddr
**nam
, boolean_t peer
)
308 struct mptses
*mpte
= mpsotompte(mp_so
);
309 struct sockaddr_in
*sin
;
312 * Do the malloc first in case it blocks.
314 MALLOC(sin
, struct sockaddr_in
*, sizeof(*sin
), M_SONAME
, M_WAITOK
);
318 bzero(sin
, sizeof(*sin
));
319 sin
->sin_family
= AF_INET
;
320 sin
->sin_len
= sizeof(*sin
);
323 sin
->sin_port
= mpte
->__mpte_src_v4
.sin_port
;
324 sin
->sin_addr
= mpte
->__mpte_src_v4
.sin_addr
;
326 sin
->sin_port
= mpte
->__mpte_dst_v4
.sin_port
;
327 sin
->sin_addr
= mpte
->__mpte_dst_v4
.sin_addr
;
330 *nam
= (struct sockaddr
*)sin
;
335 mp_getaddr_v6(struct socket
*mp_so
, struct sockaddr
**nam
, boolean_t peer
)
337 struct mptses
*mpte
= mpsotompte(mp_so
);
338 struct in6_addr addr
;
342 port
= mpte
->__mpte_src_v6
.sin6_port
;
343 addr
= mpte
->__mpte_src_v6
.sin6_addr
;
345 port
= mpte
->__mpte_dst_v6
.sin6_port
;
346 addr
= mpte
->__mpte_dst_v6
.sin6_addr
;
349 *nam
= in6_sockaddr(port
, &addr
);
358 mp_getsockaddr(struct socket
*mp_so
, struct sockaddr
**nam
)
360 struct mptses
*mpte
= mpsotompte(mp_so
);
362 if (mpte
->mpte_src
.sa_family
== AF_INET
|| mpte
->mpte_src
.sa_family
== 0) {
363 return mp_getaddr_v4(mp_so
, nam
, false);
364 } else if (mpte
->mpte_src
.sa_family
== AF_INET6
) {
365 return mp_getaddr_v6(mp_so
, nam
, false);
372 mp_getpeeraddr(struct socket
*mp_so
, struct sockaddr
**nam
)
374 struct mptses
*mpte
= mpsotompte(mp_so
);
376 if (mpte
->mpte_src
.sa_family
== AF_INET
|| mpte
->mpte_src
.sa_family
== 0) {
377 return mp_getaddr_v4(mp_so
, nam
, true);
378 } else if (mpte
->mpte_src
.sa_family
== AF_INET6
) {
379 return mp_getaddr_v6(mp_so
, nam
, true);