X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/39236c6e673c41db228275375ab7fdb0f837b292..c3c9b80d004dbbfdf763edeb97968c6997e3b45b:/bsd/netinet/mp_pcb.c diff --git a/bsd/netinet/mp_pcb.c b/bsd/netinet/mp_pcb.c index 9dfc68ed3..581be9c54 100644 --- a/bsd/netinet/mp_pcb.c +++ b/bsd/netinet/mp_pcb.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2013 Apple Inc. All rights reserved. + * Copyright (c) 2012-2017 Apple Inc. All rights reserved. * * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * @@ -43,21 +43,31 @@ #include #include +#include -static lck_grp_t *mp_lock_grp; -static lck_attr_t *mp_lock_attr; -static lck_grp_attr_t *mp_lock_grp_attr; -decl_lck_mtx_data(static, mp_lock); /* global MULTIPATH lock */ +static lck_grp_t *mp_lock_grp; +static lck_attr_t *mp_lock_attr; +static lck_grp_attr_t *mp_lock_grp_attr; +decl_lck_mtx_data(static, mp_lock); /* global MULTIPATH lock */ decl_lck_mtx_data(static, mp_timeout_lock); static TAILQ_HEAD(, mppcbinfo) mppi_head = TAILQ_HEAD_INITIALIZER(mppi_head); -static boolean_t mp_timeout_run; /* MP timer is scheduled to run */ +static boolean_t mp_timeout_run; /* MP timer is scheduled to run */ static boolean_t mp_garbage_collecting; static boolean_t mp_ticking; static void mp_sched_timeout(void); static void mp_timeout(void *); +static void +mpp_lock_assert_held(struct mppcb *mp) +{ +#if !MACH_ASSERT +#pragma unused(mp) +#endif + LCK_MTX_ASSERT(&mp->mpp_lock, LCK_MTX_ASSERT_OWNED); +} + void mp_pcbinit(void) { @@ -104,10 +114,12 @@ mp_timeout(void *arg) if ((gc && mppi->mppi_gc != NULL) || (t && mppi->mppi_timer != NULL)) { lck_mtx_lock(&mppi->mppi_lock); - if (gc && mppi->mppi_gc != NULL) + if (gc && mppi->mppi_gc != NULL) { gc_act += mppi->mppi_gc(mppi); - if (t && mppi->mppi_timer != NULL) + } + if (t && mppi->mppi_timer != NULL) { t_act += mppi->mppi_timer(mppi); + } lck_mtx_unlock(&mppi->mppi_lock); } } @@ -117,10 +129,12 @@ mp_timeout(void *arg) } /* lock was dropped above, so check first before overriding */ - if (!mp_garbage_collecting) + if (!mp_garbage_collecting) { mp_garbage_collecting = (gc_act != 0); - if (!mp_ticking) + } + if (!mp_ticking) { mp_ticking = (t_act != 0); + } /* re-arm the timer if there's work to do */ mp_timeout_run = FALSE; @@ -131,7 +145,7 @@ mp_timeout(void *arg) static void mp_sched_timeout(void) { - lck_mtx_assert(&mp_timeout_lock, LCK_MTX_ASSERT_OWNED); + LCK_MTX_ASSERT(&mp_timeout_lock, LCK_MTX_ASSERT_OWNED); if (!mp_timeout_run && (mp_garbage_collecting || mp_ticking)) { lck_mtx_convert_spin(&mp_timeout_lock); @@ -183,36 +197,32 @@ mp_pcbinfo_detach(struct mppcbinfo *mppi) lck_mtx_lock(&mp_lock); TAILQ_FOREACH(mppi0, &mppi_head, mppi_entry) { - if (mppi0 == mppi) + if (mppi0 == mppi) { break; + } } - if (mppi0 != NULL) + if (mppi0 != NULL) { TAILQ_REMOVE(&mppi_head, mppi0, mppi_entry); - else + } else { error = ENXIO; + } lck_mtx_unlock(&mp_lock); - return (error); + return error; } int mp_pcballoc(struct socket *so, struct mppcbinfo *mppi) { - struct mppcb *mpp; + struct mppcb *mpp = NULL; + int error; - VERIFY(sotomppcb(so) == NULL); - - lck_mtx_lock(&mppi->mppi_lock); - if (mppi->mppi_count >= mptcp_socket_limit) { - lck_mtx_unlock(&mppi->mppi_lock); - mptcplog((LOG_ERR, "Reached MPTCP socket limit.")); - return (ENOBUFS); - } - lck_mtx_unlock(&mppi->mppi_lock); + VERIFY(mpsotomppcb(so) == NULL); mpp = zalloc(mppi->mppi_zone); - if (mpp == NULL) - return (ENOBUFS); + if (mpp == NULL) { + return ENOBUFS; + } bzero(mpp, mppi->mppi_size); lck_mtx_init(&mpp->mpp_lock, mppi->mppi_lock_grp, mppi->mppi_lock_attr); @@ -221,25 +231,29 @@ mp_pcballoc(struct socket *so, struct mppcbinfo *mppi) mpp->mpp_socket = so; so->so_pcb = mpp; + error = mptcp_session_create(mpp); + if (error) { + lck_mtx_destroy(&mpp->mpp_lock, mppi->mppi_lock_grp); + zfree(mppi->mppi_zone, mpp); + return error; + } + lck_mtx_lock(&mppi->mppi_lock); mpp->mpp_flags |= MPP_ATTACHED; TAILQ_INSERT_TAIL(&mppi->mppi_pcbs, mpp, mpp_entry); mppi->mppi_count++; + lck_mtx_unlock(&mppi->mppi_lock); - return (0); + return 0; } void -mp_pcbdetach(struct mppcb *mpp) +mp_pcbdetach(struct socket *mp_so) { - struct socket *so = mpp->mpp_socket; - - VERIFY(so->so_pcb == mpp); + struct mppcb *mpp = mpsotomppcb(mp_so); mpp->mpp_state = MPPCB_STATE_DEAD; - if (!(so->so_flags & SOF_PCBCLEARING)) - so->so_flags |= SOF_PCBCLEARING; mp_gc_sched(); } @@ -251,23 +265,119 @@ mp_pcbdispose(struct mppcb *mpp) VERIFY(mppi != NULL); - lck_mtx_assert(&mppi->mppi_lock, LCK_MTX_ASSERT_OWNED); - lck_mtx_assert(&mpp->mpp_lock, LCK_MTX_ASSERT_OWNED); + LCK_MTX_ASSERT(&mppi->mppi_lock, LCK_MTX_ASSERT_OWNED); + mpp_lock_assert_held(mpp); VERIFY(mpp->mpp_state == MPPCB_STATE_DEAD); - VERIFY(mpp->mpp_flags & MPP_ATTACHED); + mpp->mpp_flags &= ~MPP_ATTACHED; TAILQ_REMOVE(&mppi->mppi_pcbs, mpp, mpp_entry); VERIFY(mppi->mppi_count != 0); mppi->mppi_count--; + if (mppi->mppi_count == 0) { + if (mptcp_cellicon_refcount) { + os_log_error(mptcp_log_handle, "%s: No more MPTCP-flows, but cell icon counter is %u\n", + __func__, mptcp_cellicon_refcount); + mptcp_clear_cellicon(); + mptcp_cellicon_refcount = 0; + } + } + + VERIFY(mpp->mpp_inside == 0); + mpp_unlock(mpp); + +#if NECP + necp_mppcb_dispose(mpp); +#endif /* NECP */ + + lck_mtx_destroy(&mpp->mpp_lock, mppi->mppi_lock_grp); + VERIFY(mpp->mpp_socket != NULL); VERIFY(mpp->mpp_socket->so_usecount == 0); mpp->mpp_socket->so_pcb = NULL; mpp->mpp_socket = NULL; - lck_mtx_unlock(&mpp->mpp_lock); - lck_mtx_destroy(&mpp->mpp_lock, mppi->mppi_lock_grp); zfree(mppi->mppi_zone, mpp); } + +static int +mp_getaddr_v4(struct socket *mp_so, struct sockaddr **nam, boolean_t peer) +{ + struct mptses *mpte = mpsotompte(mp_so); + struct sockaddr_in *sin; + + /* + * Do the malloc first in case it blocks. + */ + MALLOC(sin, struct sockaddr_in *, sizeof(*sin), M_SONAME, M_WAITOK); + if (sin == NULL) { + return ENOBUFS; + } + bzero(sin, sizeof(*sin)); + sin->sin_family = AF_INET; + sin->sin_len = sizeof(*sin); + + if (!peer) { + sin->sin_port = mpte->__mpte_src_v4.sin_port; + sin->sin_addr = mpte->__mpte_src_v4.sin_addr; + } else { + sin->sin_port = mpte->__mpte_dst_v4.sin_port; + sin->sin_addr = mpte->__mpte_dst_v4.sin_addr; + } + + *nam = (struct sockaddr *)sin; + return 0; +} + +static int +mp_getaddr_v6(struct socket *mp_so, struct sockaddr **nam, boolean_t peer) +{ + struct mptses *mpte = mpsotompte(mp_so); + struct in6_addr addr; + in_port_t port; + + if (!peer) { + port = mpte->__mpte_src_v6.sin6_port; + addr = mpte->__mpte_src_v6.sin6_addr; + } else { + port = mpte->__mpte_dst_v6.sin6_port; + addr = mpte->__mpte_dst_v6.sin6_addr; + } + + *nam = in6_sockaddr(port, &addr); + if (*nam == NULL) { + return ENOBUFS; + } + + return 0; +} + +int +mp_getsockaddr(struct socket *mp_so, struct sockaddr **nam) +{ + struct mptses *mpte = mpsotompte(mp_so); + + if (mpte->mpte_src.sa_family == AF_INET || mpte->mpte_src.sa_family == 0) { + return mp_getaddr_v4(mp_so, nam, false); + } else if (mpte->mpte_src.sa_family == AF_INET6) { + return mp_getaddr_v6(mp_so, nam, false); + } else { + return EINVAL; + } +} + +int +mp_getpeeraddr(struct socket *mp_so, struct sockaddr **nam) +{ + struct mptses *mpte = mpsotompte(mp_so); + + if (mpte->mpte_src.sa_family == AF_INET || mpte->mpte_src.sa_family == 0) { + return mp_getaddr_v4(mp_so, nam, true); + } else if (mpte->mpte_src.sa_family == AF_INET6) { + return mp_getaddr_v6(mp_so, nam, true); + } else { + return EINVAL; + } +}