/*
- * Copyright (c) 2012-2017 Apple Inc. All rights reserved.
+ * Copyright (c) 2012-2020 Apple Inc. All rights reserved.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_START@
*
#include <netinet/mptcp_seq.h>
#include <netinet/mptcp_timer.h>
#include <libkern/crypto/sha1.h>
-#if INET6
#include <netinet6/in6_pcb.h>
#include <netinet6/ip6protosw.h>
-#endif /* INET6 */
#include <dev/random/randomdev.h>
/*
static int mptcp_subflow_sosend(struct socket *, struct sockaddr *,
struct uio *, struct mbuf *, struct mbuf *, int);
static void mptcp_subflow_wupcall(struct socket *, void *, int);
-static void mptcp_subflow_eupcall1(struct socket *, void *, uint32_t);
+static void mptcp_subflow_eupcall1(struct socket *so, void *arg, long events);
static void mptcp_update_last_owner(struct socket *so, struct socket *mp_so);
static void mptcp_drop_tfo_data(struct mptses *, struct mptsub *);
MPTS_EVRET_DISCONNECT_FALLBACK = 4, /* abort all but preferred */
} ev_ret_t;
-static ev_ret_t mptcp_subflow_propagate_ev(struct mptses *, struct mptsub *, uint64_t *, uint64_t);
-static ev_ret_t mptcp_subflow_nosrcaddr_ev(struct mptses *, struct mptsub *, uint64_t *, uint64_t);
-static ev_ret_t mptcp_subflow_failover_ev(struct mptses *, struct mptsub *, uint64_t *, uint64_t);
-static ev_ret_t mptcp_subflow_ifdenied_ev(struct mptses *, struct mptsub *, uint64_t *, uint64_t);
-static ev_ret_t mptcp_subflow_connected_ev(struct mptses *, struct mptsub *, uint64_t *, uint64_t);
-static ev_ret_t mptcp_subflow_disconnected_ev(struct mptses *, struct mptsub *, uint64_t *, uint64_t);
-static ev_ret_t mptcp_subflow_mpstatus_ev(struct mptses *, struct mptsub *, uint64_t *, uint64_t);
-static ev_ret_t mptcp_subflow_mustrst_ev(struct mptses *, struct mptsub *, uint64_t *, uint64_t);
-static ev_ret_t mptcp_subflow_mpcantrcvmore_ev(struct mptses *, struct mptsub *, uint64_t *, uint64_t);
-static ev_ret_t mptcp_subflow_mpsuberror_ev(struct mptses *, struct mptsub *, uint64_t *, uint64_t);
-static ev_ret_t mptcp_subflow_adaptive_rtimo_ev(struct mptses *, struct mptsub *, uint64_t *, uint64_t);
-static ev_ret_t mptcp_subflow_adaptive_wtimo_ev(struct mptses *, struct mptsub *, uint64_t *, uint64_t);
+static ev_ret_t mptcp_subflow_propagate_ev(struct mptses *, struct mptsub *, long *, long);
+static ev_ret_t mptcp_subflow_nosrcaddr_ev(struct mptses *, struct mptsub *, long *, long);
+static ev_ret_t mptcp_subflow_failover_ev(struct mptses *, struct mptsub *, long *, long);
+static ev_ret_t mptcp_subflow_ifdenied_ev(struct mptses *, struct mptsub *, long *, long);
+static ev_ret_t mptcp_subflow_connected_ev(struct mptses *, struct mptsub *, long *, long);
+static ev_ret_t mptcp_subflow_disconnected_ev(struct mptses *, struct mptsub *, long *, long);
+static ev_ret_t mptcp_subflow_mpstatus_ev(struct mptses *, struct mptsub *, long *, long);
+static ev_ret_t mptcp_subflow_mustrst_ev(struct mptses *, struct mptsub *, long *, long);
+static ev_ret_t mptcp_subflow_mpcantrcvmore_ev(struct mptses *, struct mptsub *, long *, long);
+static ev_ret_t mptcp_subflow_mpsuberror_ev(struct mptses *, struct mptsub *, long *, long);
+static ev_ret_t mptcp_subflow_adaptive_rtimo_ev(struct mptses *, struct mptsub *, long *, long);
+static ev_ret_t mptcp_subflow_adaptive_wtimo_ev(struct mptses *, struct mptsub *, long *, long);
static void mptcp_do_sha1(mptcp_key_t *, char *);
static void mptcp_init_local_parms(struct mptses *);
-static unsigned int mptsub_zone_size; /* size of mptsub */
-static struct zone *mptsub_zone; /* zone for mptsub */
-
-static unsigned int mptopt_zone_size; /* size of mptopt */
-static struct zone *mptopt_zone; /* zone for mptopt */
-
-static unsigned int mpt_subauth_entry_size; /* size of subf auth entry */
-static struct zone *mpt_subauth_zone; /* zone of subf auth entry */
+static ZONE_DECLARE(mptsub_zone, "mptsub", sizeof(struct mptsub), ZC_ZFREE_CLEARMEM);
+static ZONE_DECLARE(mptopt_zone, "mptopt", sizeof(struct mptopt), ZC_ZFREE_CLEARMEM);
+static ZONE_DECLARE(mpt_subauth_zone, "mptauth",
+ sizeof(struct mptcp_subf_auth_entry), ZC_NONE);
struct mppcbinfo mtcbinfo;
static struct protosw mptcp_subflow_protosw;
static struct pr_usrreqs mptcp_subflow_usrreqs;
-#if INET6
static struct ip6protosw mptcp_subflow_protosw6;
static struct pr_usrreqs mptcp_subflow_usrreqs6;
-#endif /* INET6 */
static uint8_t mptcp_create_subflows_scheduled;
typedef struct mptcp_subflow_event_entry {
- uint64_t sofilt_hint_mask;
- ev_ret_t (*sofilt_hint_ev_hdlr)(
+ long sofilt_hint_mask;
+ ev_ret_t (*sofilt_hint_ev_hdlr)(
struct mptses *mpte,
struct mptsub *mpts,
- uint64_t *p_mpsofilt_hint,
- uint64_t event);
+ long *p_mpsofilt_hint,
+ long event);
} mptsub_ev_entry_t;
/* Using Symptoms Advisory to detect poor WiFi or poor Cell */
#pragma unused(dp)
static int mptcp_initialized = 0;
struct protosw *prp;
-#if INET6
struct ip6protosw *prp6;
-#endif /* INET6 */
VERIFY((pp->pr_flags & (PR_INITIALIZED | PR_ATTACHED)) == PR_ATTACHED);
mptcp_subflow_protosw.pr_filter_head.tqh_last =
(struct socket_filter **)(uintptr_t)0xdeadbeefdeadbeef;
-#if INET6
prp6 = (struct ip6protosw *)pffindproto_locked(PF_INET6,
IPPROTO_TCP, SOCK_STREAM);
VERIFY(prp6 != NULL);
(struct socket_filter *)(uintptr_t)0xdeadbeefdeadbeef;
mptcp_subflow_protosw6.pr_filter_head.tqh_last =
(struct socket_filter **)(uintptr_t)0xdeadbeefdeadbeef;
-#endif /* INET6 */
bzero(&mtcbinfo, sizeof(mtcbinfo));
TAILQ_INIT(&mtcbinfo.mppi_pcbs);
mtcbinfo.mppi_size = sizeof(struct mpp_mtp);
- if ((mtcbinfo.mppi_zone = zinit(mtcbinfo.mppi_size,
- 1024 * mtcbinfo.mppi_size, 8192, "mptcb")) == NULL) {
- panic("%s: unable to allocate MPTCP PCB zone\n", __func__);
- /* NOTREACHED */
- }
- zone_change(mtcbinfo.mppi_zone, Z_CALLERACCT, FALSE);
- zone_change(mtcbinfo.mppi_zone, Z_EXPAND, TRUE);
+ mtcbinfo.mppi_zone = zone_create("mptc", mtcbinfo.mppi_size,
+ ZC_NONE);
mtcbinfo.mppi_lock_grp_attr = lck_grp_attr_alloc_init();
mtcbinfo.mppi_lock_grp = lck_grp_alloc_init("mppcb",
/* attach to MP domain for garbage collection to take place */
mp_pcbinfo_attach(&mtcbinfo);
- mptsub_zone_size = sizeof(struct mptsub);
- if ((mptsub_zone = zinit(mptsub_zone_size, 1024 * mptsub_zone_size,
- 8192, "mptsub")) == NULL) {
- panic("%s: unable to allocate MPTCP subflow zone\n", __func__);
- /* NOTREACHED */
- }
- zone_change(mptsub_zone, Z_CALLERACCT, FALSE);
- zone_change(mptsub_zone, Z_EXPAND, TRUE);
-
- mptopt_zone_size = sizeof(struct mptopt);
- if ((mptopt_zone = zinit(mptopt_zone_size, 128 * mptopt_zone_size,
- 1024, "mptopt")) == NULL) {
- panic("%s: unable to allocate MPTCP option zone\n", __func__);
- /* NOTREACHED */
- }
- zone_change(mptopt_zone, Z_CALLERACCT, FALSE);
- zone_change(mptopt_zone, Z_EXPAND, TRUE);
-
- mpt_subauth_entry_size = sizeof(struct mptcp_subf_auth_entry);
- if ((mpt_subauth_zone = zinit(mpt_subauth_entry_size,
- 1024 * mpt_subauth_entry_size, 8192, "mptauth")) == NULL) {
- panic("%s: unable to allocate MPTCP address auth zone \n",
- __func__);
- /* NOTREACHED */
- }
- zone_change(mpt_subauth_zone, Z_CALLERACCT, FALSE);
- zone_change(mpt_subauth_zone, Z_EXPAND, TRUE);
-
mptcp_log_handle = os_log_create("com.apple.xnu.net.mptcp", "mptcp");
}
int
-mptcpstats_get_index_by_ifindex(struct mptcp_itf_stats *stats, int ifindex, boolean_t create)
+mptcpstats_get_index_by_ifindex(struct mptcp_itf_stats *stats, u_short ifindex, boolean_t create)
{
int i, index = -1;
mpte->mpte_itfinfo = &mpte->_mpte_itfinfo[0];
mpte->mpte_itfinfo_size = MPTE_ITFINFO_SIZE;
- if (mptcp_alternate_port) {
- mpte->mpte_alternate_port = htons(mptcp_alternate_port);
+ if (mptcp_alternate_port > 0 && mptcp_alternate_port < UINT16_MAX) {
+ mpte->mpte_alternate_port = htons((uint16_t)mptcp_alternate_port);
}
mpte->mpte_last_cellicon_set = tcp_now;
0x00, 0x00, 0x00, 0x00},
};
const char *ptrv4 = (const char *)addrv4;
- char buf[MAX_IPv6_STR_LEN];
char *ptr = (char *)addr;
if (IN_ZERONET(ntohl(addrv4->s_addr)) || // 0.0.0.0/8 Source hosts on local network
panic("NAT64-prefix len is wrong: %u\n", len);
}
- os_log_info(mptcp_log_handle, "%s: nat64prefix-len %u synthesized %s\n",
- __func__, len,
- inet_ntop(AF_INET6, (void *)addr, buf, sizeof(buf)));
-
return 0;
}
return false;
}
+/*
+ * In Handover mode, only create cell subflow if
+ * - Symptoms marked WiFi as weak:
+ * Here, if we are sending data, then we can check the RTO-state. That is a
+ * stronger signal of WiFi quality than the Symptoms indicator.
+ * If however we are not sending any data, the only thing we can do is guess
+ * and thus bring up Cell.
+ *
+ * - Symptoms marked WiFi as unknown:
+ * In this state we don't know what the situation is and thus remain
+ * conservative, only bringing up cell if there are retransmissions going on.
+ */
+static boolean_t
+mptcp_handover_use_cellular(struct mptses *mpte, struct tcpcb *tp)
+{
+ int unusable_state = mptcp_is_wifi_unusable_for_session(mpte);
+
+ if (unusable_state == 0) {
+ /* WiFi is good - don't use cell */
+ return false;
+ }
+
+ if (unusable_state == -1) {
+ /*
+ * We are in unknown state, only use Cell if we have confirmed
+ * that WiFi is bad.
+ */
+ if (mptetoso(mpte)->so_snd.sb_cc != 0 && tp->t_rxtshift >= mptcp_fail_thresh * 2) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ if (unusable_state == 1) {
+ /*
+ * WiFi is confirmed to be bad from Symptoms-Framework.
+ * If we are sending data, check the RTOs.
+ * Otherwise, be pessimistic and use Cell.
+ */
+ if (mptetoso(mpte)->so_snd.sb_cc != 0) {
+ if (tp->t_rxtshift >= mptcp_fail_thresh * 2) {
+ return true;
+ } else {
+ return false;
+ }
+ } else {
+ return true;
+ }
+ }
+
+ return false;
+}
+
void
mptcp_check_subflows_and_add(struct mptses *mpte)
{
need_to_ask_symptoms = TRUE;
}
- /*
- * In Handover mode, only create cell subflow if
- * 1. Wi-Fi Assist is active
- * 2. Symptoms marked WiFi as weak
- * 3. We are experiencing RTOs or we are not sending data.
- *
- * This covers the scenario, where:
- * 1. We send and get retransmission timeouts (thus,
- * we confirmed that WiFi is indeed bad).
- * 2. We are not sending and the server tries to send.
- * Establshing a cell-subflow gives the server a
- * chance to send us some data over cell if WiFi
- * is dead. We establish the subflow with the
- * backup-bit set, so the server is not allowed to
- * send on this subflow as long as WiFi is providing
- * good performance.
- */
- if (mpte->mpte_svctype == MPTCP_SVCTYPE_HANDOVER &&
- !IFNET_IS_CELLULAR(subifp) &&
- !mptcp_subflow_disconnecting(mpts) &&
- (mptcp_is_wifi_unusable_for_session(mpte) == 0 ||
- (tp->t_rxtshift < mptcp_fail_thresh * 2 && mptetoso(mpte)->so_snd.sb_cc))) {
- os_log_debug(mptcp_log_handle,
- "%s - %lx: handover, wifi state %d rxt %u first-party %u sb_cc %u ifindex %u this %u rtt %u rttvar %u rto %u\n",
+ if (mpte->mpte_svctype == MPTCP_SVCTYPE_HANDOVER) {
+ os_log(mptcp_log_handle,
+ "%s - %lx: handover: cell %u wifi-state %d flags %#x rxt %u first-party %u sb_cc %u ifindex %u this %u rtt %u rttvar %u rto %u\n",
__func__, (unsigned long)VM_KERNEL_ADDRPERM(mpte),
+ IFNET_IS_CELLULAR(subifp),
mptcp_is_wifi_unusable_for_session(mpte),
+ mpts->mpts_flags,
tp->t_rxtshift,
!!(mpte->mpte_flags & MPTE_FIRSTPARTY),
mptetoso(mpte)->so_snd.sb_cc,
tp->t_srtt >> TCP_RTT_SHIFT,
tp->t_rttvar >> TCP_RTTVAR_SHIFT,
tp->t_rxtcur);
- found = TRUE;
- /* We found a proper subflow on WiFi - no need for cell */
- want_cellular = FALSE;
- break;
+ if (!IFNET_IS_CELLULAR(subifp) &&
+ !mptcp_subflow_disconnecting(mpts) &&
+ (mpts->mpts_flags & MPTSF_CONNECTED) &&
+ !mptcp_handover_use_cellular(mpte, tp)) {
+ found = TRUE;
+
+ /* We found a proper subflow on WiFi - no need for cell */
+ want_cellular = FALSE;
+ break;
+ }
} else if (mpte->mpte_svctype == MPTCP_SVCTYPE_TARGET_BASED) {
uint64_t time_now = mach_continuous_time();
want_cellular = FALSE;
break;
}
- } else {
- os_log_debug(mptcp_log_handle,
- "%s - %lx: svc %u cell %u flags %#x unusable %d rtx %u first %u sbcc %u rtt %u rttvar %u rto %u\n",
- __func__, (unsigned long)VM_KERNEL_ADDRPERM(mpte),
- mpte->mpte_svctype, IFNET_IS_CELLULAR(subifp), mpts->mpts_flags,
- mptcp_is_wifi_unusable_for_session(mpte), tp->t_rxtshift,
- !!(mpte->mpte_flags & MPTE_FIRSTPARTY), mptetoso(mpte)->so_snd.sb_cc,
- tp->t_srtt >> TCP_RTT_SHIFT,
- tp->t_rttvar >> TCP_RTTVAR_SHIFT,
- tp->t_rxtcur);
}
if (subifp->if_index == ifindex &&
nat64prefixes[j].prefix_len,
&((struct sockaddr_in *)(void *)dst)->sin_addr);
if (error != 0) {
- os_log_info(mptcp_log_handle, "%s - %lx: cannot synthesize this addr\n",
+ os_log_error(mptcp_log_handle, "%s - %lx: cannot synthesize this addr\n",
__func__, (unsigned long)VM_KERNEL_ADDRPERM(mpte));
continue;
}
os_log_debug(mptcp_log_handle, "%s - %lx: rxt %u sb_cc %u unusable %d\n",
__func__, (unsigned long)VM_KERNEL_ADDRPERM(mpte), tp->t_rxtshift, mptetoso(mpte)->so_snd.sb_cc, wifi_unusable);
- /* Is this subflow in good condition? */
- if (tp->t_rxtshift == 0 && mptetoso(mpte)->so_snd.sb_cc) {
- found_working_subflow = true;
- }
-
- /* Or WiFi is fine */
- if (!wifi_unusable) {
+ if (!mptcp_handover_use_cellular(mpte, tp)) {
found_working_subflow = true;
+ break;
}
}
* Allocate an MPTCP socket option structure.
*/
struct mptopt *
-mptcp_sopt_alloc(int how)
+mptcp_sopt_alloc(zalloc_flags_t how)
{
- struct mptopt *mpo;
-
- mpo = (how == M_WAITOK) ? zalloc(mptopt_zone) :
- zalloc_noblock(mptopt_zone);
- if (mpo != NULL) {
- bzero(mpo, mptopt_zone_size);
- }
-
- return mpo;
+ return zalloc_flags(mptopt_zone, how | Z_ZERO);
}
/*
static struct mptsub *
mptcp_subflow_alloc(void)
{
- struct mptsub *mpts = zalloc(mptsub_zone);
-
- if (mpts == NULL) {
- return NULL;
- }
-
- bzero(mpts, mptsub_zone_size);
- return mpts;
+ return zalloc_flags(mptsub_zone, Z_WAITOK | Z_ZERO);
}
/*
os_log_error(mptcp_log_handle, "%s - %lx: Couldn't find proc for pid %u\n",
__func__, (unsigned long)VM_KERNEL_ADDRPERM(mpte), mp_so->last_pid);
+ mptcp_subflow_free(mpts);
return ESRCH;
}
case PF_INET:
(*so)->so_proto = &mptcp_subflow_protosw;
break;
-#if INET6
case PF_INET6:
(*so)->so_proto = (struct protosw *)&mptcp_subflow_protosw6;
break;
-#endif /* INET6 */
default:
VERIFY(0);
/* NOTREACHED */
dport = ntohs(SIN6(dst)->sin6_port);
}
- os_log_info(mptcp_log_handle,
+ os_log(mptcp_log_handle,
"%s - %lx: ifindex %u dst %s:%d pended %u\n", __func__, (unsigned long)VM_KERNEL_ADDRPERM(mpte),
mpts->mpts_ifscope, dbuf, dport, !!(mpts->mpts_flags & MPTSF_CONNECT_PENDING));
}
m->m_pkthdr.mp_dsn += off;
m->m_pkthdr.mp_rseq += off;
- m->m_pkthdr.mp_rlen = m->m_pkthdr.len;
+
+ VERIFY(m_pktlen(m) < UINT16_MAX);
+ m->m_pkthdr.mp_rlen = (uint16_t)m_pktlen(m);
} else {
if (!(mpts->mpts_flags & MPTSF_FULLY_ESTABLISHED)) {
/* data arrived without an DSS option mapping */
m->m_pkthdr.pkt_flags |= PKTF_MPTCP;
m->m_pkthdr.mp_dsn = dsn + off;
m->m_pkthdr.mp_rseq = rseq + off;
- m->m_pkthdr.mp_rlen = m->m_pkthdr.len;
+
+ VERIFY(m_pktlen(m) < UINT16_MAX);
+ m->m_pkthdr.mp_rlen = (uint16_t)m_pktlen(m);
}
}
OSIncrementAtomicLong(&p->p_stats->p_ru.ru_msgsnd);
- error = sosendcheck(so, NULL, top->m_pkthdr.len, 0, 1, 0, &sblocked, NULL);
+ error = sosendcheck(so, NULL, top->m_pkthdr.len, 0, 1, 0, &sblocked);
if (error) {
goto out;
}
struct tcpcb *tp;
uint64_t mpt_dsn = 0, off = 0;
int sb_cc = 0, error = 0, wakeup = 0;
- uint32_t dss_csum;
+ uint16_t dss_csum;
uint16_t tot_sent = 0;
boolean_t reinjected = FALSE;
head = tail = NULL;
while (tot_sent < sb_cc) {
- ssize_t mlen;
+ int32_t mlen;
mlen = mpt_mbuf->m_len;
mlen -= off;
- mlen = min(mlen, sb_cc - tot_sent);
+ mlen = MIN(mlen, sb_cc - tot_sent);
if (mlen < 0) {
os_log_error(mptcp_log_handle, "%s - %lx: mlen %d mp_rlen %u off %u sb_cc %u tot_sent %u\n",
- __func__, (unsigned long)VM_KERNEL_ADDRPERM(mpte), (int)mlen, mpt_mbuf->m_pkthdr.mp_rlen,
+ __func__, (unsigned long)VM_KERNEL_ADDRPERM(mpte), mlen, mpt_mbuf->m_pkthdr.mp_rlen,
(uint32_t)off, sb_cc, tot_sent);
goto out;
}
struct mbuf *tmp = n->m_nextpkt;
mptcplog((LOG_DEBUG, "%s m is covering that guy dsn %u len %u dsn %u len %u\n",
- __func__, m->m_pkthdr.mp_dsn, m->m_pkthdr.mp_rlen,
- n->m_pkthdr.mp_dsn, n->m_pkthdr.mp_rlen),
+ __func__, (uint32_t)m->m_pkthdr.mp_dsn, m->m_pkthdr.mp_rlen,
+ (uint32_t)n->m_pkthdr.mp_dsn, n->m_pkthdr.mp_rlen),
MPTCP_SOCKET_DBG, MPTCP_LOGLVL_VERBOSE);
m->m_nextpkt = NULL;
/* m is already fully covered by the previous mbuf in the queue */
if (prev->m_pkthdr.mp_dsn + prev->m_pkthdr.mp_rlen >= m->m_pkthdr.mp_dsn + m->m_pkthdr.len) {
mptcplog((LOG_DEBUG, "%s prev covers us from %u with len %u\n",
- __func__, prev->m_pkthdr.mp_dsn, prev->m_pkthdr.mp_rlen),
+ __func__, (uint32_t)prev->m_pkthdr.mp_dsn, prev->m_pkthdr.mp_rlen),
MPTCP_SOCKET_DBG, MPTCP_LOGLVL_VERBOSE);
goto dont_queue;
}
* Subflow socket control event upcall.
*/
static void
-mptcp_subflow_eupcall1(struct socket *so, void *arg, uint32_t events)
+mptcp_subflow_eupcall1(struct socket *so, void *arg, long events)
{
#pragma unused(so)
struct mptsub *mpts = arg;
*/
static ev_ret_t
mptcp_subflow_events(struct mptses *mpte, struct mptsub *mpts,
- uint64_t *p_mpsofilt_hint)
+ long *p_mpsofilt_hint)
{
ev_ret_t ret = MPTS_EVRET_OK;
int i, mpsub_ev_entry_count = sizeof(mpsub_ev_entry_tbl) /
DTRACE_MPTCP3(subflow__events, struct mptses *, mpte,
struct mptsub *, mpts, uint32_t, mpts->mpts_evctl);
- mptcplog((LOG_DEBUG, "%s cid %d events=%b\n", __func__,
- mpts->mpts_connid, mpts->mpts_evctl, SO_FILT_HINT_BITS),
- MPTCP_EVENTS_DBG, MPTCP_LOGLVL_VERBOSE);
-
/*
* Process all the socket filter hints and reset the hint
* once it is handled
}
}
- /*
- * We should be getting only events specified via sock_catchevents(),
- * so loudly complain if we have any unprocessed one(s).
- */
- if (mpts->mpts_evctl || ret < MPTS_EVRET_OK) {
- mptcplog((LOG_WARNING, "%s%s: cid %d evret %d unhandled events=%b\n", __func__,
- (mpts->mpts_evctl && ret == MPTS_EVRET_OK) ? "MPTCP_ERROR " : "",
- mpts->mpts_connid,
- ret, mpts->mpts_evctl, SO_FILT_HINT_BITS),
- MPTCP_EVENTS_DBG, MPTCP_LOGLVL_LOG);
- } else {
- mptcplog((LOG_DEBUG, "%s: Done, events %b\n", __func__,
- mpts->mpts_evctl, SO_FILT_HINT_BITS),
- MPTCP_EVENTS_DBG, MPTCP_LOGLVL_VERBOSE);
- }
-
return ret;
}
static ev_ret_t
mptcp_subflow_propagate_ev(struct mptses *mpte, struct mptsub *mpts,
- uint64_t *p_mpsofilt_hint, uint64_t event)
+ long *p_mpsofilt_hint, long event)
{
struct socket *mp_so, *so;
struct mptcb *mp_tp;
mp_tp = mpte->mpte_mptcb;
so = mpts->mpts_socket;
- mptcplog((LOG_DEBUG, "%s: cid %d event %d\n", __func__,
- mpts->mpts_connid, event),
- MPTCP_EVENTS_DBG, MPTCP_LOGLVL_LOG);
-
/*
* We got an event for this subflow that might need to be propagated,
* based on the state of the MPTCP connection.
*/
static ev_ret_t
mptcp_subflow_nosrcaddr_ev(struct mptses *mpte, struct mptsub *mpts,
- uint64_t *p_mpsofilt_hint, uint64_t event)
+ long *p_mpsofilt_hint, long event)
{
#pragma unused(p_mpsofilt_hint, event)
struct socket *mp_so;
static ev_ret_t
mptcp_subflow_mpsuberror_ev(struct mptses *mpte, struct mptsub *mpts,
- uint64_t *p_mpsofilt_hint, uint64_t event)
+ long *p_mpsofilt_hint, long event)
{
#pragma unused(event, p_mpsofilt_hint)
struct socket *so, *mp_so;
*/
static ev_ret_t
mptcp_subflow_mpcantrcvmore_ev(struct mptses *mpte, struct mptsub *mpts,
- uint64_t *p_mpsofilt_hint, uint64_t event)
+ long *p_mpsofilt_hint, long event)
{
#pragma unused(event)
struct mptcb *mp_tp = mpte->mpte_mptcb;
*/
static ev_ret_t
mptcp_subflow_failover_ev(struct mptses *mpte, struct mptsub *mpts,
- uint64_t *p_mpsofilt_hint, uint64_t event)
+ long *p_mpsofilt_hint, long event)
{
#pragma unused(event, p_mpsofilt_hint)
struct mptsub *mpts_alt = NULL;
*/
static ev_ret_t
mptcp_subflow_ifdenied_ev(struct mptses *mpte, struct mptsub *mpts,
- uint64_t *p_mpsofilt_hint, uint64_t event)
+ long *p_mpsofilt_hint, long event)
{
mptcplog((LOG_DEBUG, "%s: cid %d\n", __func__,
mpts->mpts_connid), MPTCP_EVENTS_DBG, MPTCP_LOGLVL_LOG);
}
}
+static void
+mptcp_try_alternate_port(struct mptses *mpte, struct mptsub *mpts)
+{
+ struct inpcb *inp;
+
+ if (!mptcp_ok_to_create_subflows(mpte->mpte_mptcb)) {
+ return;
+ }
+
+ inp = sotoinpcb(mpts->mpts_socket);
+ if (inp == NULL) {
+ return;
+ }
+
+ /* Should we try the alternate port? */
+ if (mpte->mpte_alternate_port &&
+ inp->inp_fport != mpte->mpte_alternate_port) {
+ union sockaddr_in_4_6 dst;
+ struct sockaddr_in *dst_in = (struct sockaddr_in *)&dst;
+
+ memcpy(&dst, &mpts->mpts_dst, mpts->mpts_dst.sa_len);
+
+ dst_in->sin_port = mpte->mpte_alternate_port;
+
+ mptcp_subflow_add(mpte, NULL, (struct sockaddr *)&dst,
+ mpts->mpts_ifscope, NULL);
+ } else { /* Else, we tried all we could, mark this interface as non-MPTCP */
+ unsigned int i;
+
+ if (inp->inp_last_outifp == NULL) {
+ return;
+ }
+
+ for (i = 0; i < mpte->mpte_itfinfo_size; i++) {
+ struct mpt_itf_info *info = &mpte->mpte_itfinfo[i];
+
+ if (inp->inp_last_outifp->if_index == info->ifindex) {
+ info->no_mptcp_support = 1;
+ break;
+ }
+ }
+ }
+}
+
/*
* Handle SO_FILT_HINT_CONNECTED subflow socket event.
*/
static ev_ret_t
mptcp_subflow_connected_ev(struct mptses *mpte, struct mptsub *mpts,
- uint64_t *p_mpsofilt_hint, uint64_t event)
+ long *p_mpsofilt_hint, long event)
{
#pragma unused(event, p_mpsofilt_hint)
struct socket *mp_so, *so;
mptcp_check_subflows_and_remove(mpte);
} else {
- unsigned int i;
-
- /* Should we try the alternate port? */
- if (mpte->mpte_alternate_port &&
- inp->inp_fport != mpte->mpte_alternate_port) {
- union sockaddr_in_4_6 dst;
- struct sockaddr_in *dst_in = (struct sockaddr_in *)&dst;
-
- memcpy(&dst, &mpts->mpts_dst, mpts->mpts_dst.sa_len);
-
- dst_in->sin_port = mpte->mpte_alternate_port;
-
- mptcp_subflow_add(mpte, NULL, (struct sockaddr *)&dst,
- mpts->mpts_ifscope, NULL);
- } else { /* Else, we tried all we could, mark this interface as non-MPTCP */
- for (i = 0; i < mpte->mpte_itfinfo_size; i++) {
- struct mpt_itf_info *info = &mpte->mpte_itfinfo[i];
-
- if (inp->inp_last_outifp->if_index == info->ifindex) {
- info->no_mptcp_support = 1;
- break;
- }
- }
- }
+ mptcp_try_alternate_port(mpte, mpts);
tcpstat.tcps_join_fallback++;
if (IFNET_IS_CELLULAR(inp->inp_last_outifp)) {
*/
static ev_ret_t
mptcp_subflow_disconnected_ev(struct mptses *mpte, struct mptsub *mpts,
- uint64_t *p_mpsofilt_hint, uint64_t event)
+ long *p_mpsofilt_hint, long event)
{
#pragma unused(event, p_mpsofilt_hint)
struct socket *mp_so, *so;
__func__), MPTCP_EVENTS_DBG, MPTCP_LOGLVL_LOG);
}
mpts->mpts_flags &= ~MPTSF_MPCAP_CTRSET;
+ } else {
+ if (so->so_flags & SOF_MP_SEC_SUBFLOW &&
+ !(mpts->mpts_flags & MPTSF_CONNECTED)) {
+ mptcp_try_alternate_port(mpte, mpts);
+ }
}
if (mp_tp->mpt_state < MPTCPS_ESTABLISHED ||
*/
static ev_ret_t
mptcp_subflow_mpstatus_ev(struct mptses *mpte, struct mptsub *mpts,
- uint64_t *p_mpsofilt_hint, uint64_t event)
+ long *p_mpsofilt_hint, long event)
{
#pragma unused(event, p_mpsofilt_hint)
ev_ret_t ret = MPTS_EVRET_OK;
*/
static ev_ret_t
mptcp_subflow_mustrst_ev(struct mptses *mpte, struct mptsub *mpts,
- uint64_t *p_mpsofilt_hint, uint64_t event)
+ long *p_mpsofilt_hint, long event)
{
#pragma unused(event)
struct socket *mp_so, *so;
so = mpts->mpts_socket;
/* We got an invalid option or a fast close */
- struct tcptemp *t_template;
struct inpcb *inp = sotoinpcb(so);
struct tcpcb *tp = NULL;
tp->t_mpflags |= TMPF_RESET;
- t_template = tcp_maketemplate(tp);
- if (t_template) {
- struct tcp_respond_args tra;
+ if (tp->t_state != TCPS_CLOSED) {
+ struct tcptemp *t_template = tcp_maketemplate(tp);
- bzero(&tra, sizeof(tra));
- if (inp->inp_flags & INP_BOUND_IF) {
- tra.ifscope = inp->inp_boundifp->if_index;
- } else {
- tra.ifscope = IFSCOPE_NONE;
- }
- tra.awdl_unrestricted = 1;
+ if (t_template) {
+ struct tcp_respond_args tra;
- tcp_respond(tp, t_template->tt_ipgen,
- &t_template->tt_t, (struct mbuf *)NULL,
- tp->rcv_nxt, tp->snd_una, TH_RST, &tra);
- (void) m_free(dtom(t_template));
+ bzero(&tra, sizeof(tra));
+ if (inp->inp_flags & INP_BOUND_IF) {
+ tra.ifscope = inp->inp_boundifp->if_index;
+ } else {
+ tra.ifscope = IFSCOPE_NONE;
+ }
+ tra.awdl_unrestricted = 1;
+
+ tcp_respond(tp, t_template->tt_ipgen,
+ &t_template->tt_t, (struct mbuf *)NULL,
+ tp->rcv_nxt, tp->snd_una, TH_RST, &tra);
+ (void) m_free(dtom(t_template));
+ }
}
if (!(mp_tp->mpt_flags & MPTCPF_FALLBACK_TO_TCP) && is_fastclose) {
mptcp_subflow_abort(mpts, ECONNABORTED);
-
if (mp_tp->mpt_gc_ticks == MPT_GC_TICKS) {
mp_tp->mpt_gc_ticks = MPT_GC_TICKS_FAST;
}
static ev_ret_t
mptcp_subflow_adaptive_rtimo_ev(struct mptses *mpte, struct mptsub *mpts,
- uint64_t *p_mpsofilt_hint, uint64_t event)
+ long *p_mpsofilt_hint, long event)
{
#pragma unused(event)
bool found_active = false;
static ev_ret_t
mptcp_subflow_adaptive_wtimo_ev(struct mptses *mpte, struct mptsub *mpts,
- uint64_t *p_mpsofilt_hint, uint64_t event)
+ long *p_mpsofilt_hint, long event)
{
#pragma unused(event)
bool found_active = false;
* Drop a MPTCP connection, reporting the specified error.
*/
struct mptses *
-mptcp_drop(struct mptses *mpte, struct mptcb *mp_tp, int errno)
+mptcp_drop(struct mptses *mpte, struct mptcb *mp_tp, u_short errno)
{
struct socket *mp_so = mptetoso(mpte);
mptcp_subflow_workloop(struct mptses *mpte)
{
boolean_t connect_pending = FALSE, disconnect_fallback = FALSE;
- uint64_t mpsofilt_hint_mask = SO_FILT_HINT_LOCKED;
+ long mpsofilt_hint_mask = SO_FILT_HINT_LOCKED;
struct mptsub *mpts, *tmpts;
struct socket *mp_so;
mpts->mpts_flags |= MPTSF_MP_DEGRADED;
if (mpts->mpts_flags & (MPTSF_DISCONNECTING |
- MPTSF_DISCONNECTED | MPTSF_CONNECT_PENDING)) {
+ MPTSF_DISCONNECTED)) {
continue;
}
VERIFY(m->m_flags & M_PKTHDR);
m->m_pkthdr.pkt_flags |= (PKTF_MPTCP | PKTF_MPSO);
m->m_pkthdr.mp_dsn = mp_tp->mpt_sndmax;
- m->m_pkthdr.mp_rlen = m_pktlen(m);
+ VERIFY(m_pktlen(m) >= 0 && m_pktlen(m) < UINT16_MAX);
+ m->m_pkthdr.mp_rlen = (uint16_t)m_pktlen(m);
mp_tp->mpt_sndmax += m_pktlen(m);
m = m->m_next;
}
uint64_t data_ack;
uint64_t dsn;
+ VERIFY(len >= 0);
+
if (!m || len == 0) {
return;
}
* Support for MP_FAIL option
*/
int
-mptcp_get_map_for_dsn(struct socket *so, u_int64_t dsn_fail, u_int32_t *tcp_seq)
+mptcp_get_map_for_dsn(struct socket *so, uint64_t dsn_fail, uint32_t *tcp_seq)
{
struct mbuf *m = so->so_snd.sb_mb;
- u_int64_t dsn;
+ uint16_t datalen;
+ uint64_t dsn;
int off = 0;
- u_int32_t datalen;
if (m == NULL) {
return -1;
datalen = m->m_pkthdr.mp_rlen;
if (MPTCP_SEQ_LEQ(dsn, dsn_fail) &&
(MPTCP_SEQ_GEQ(dsn + datalen, dsn_fail))) {
- off = dsn_fail - dsn;
+ off = (int)(dsn_fail - dsn);
*tcp_seq = m->m_pkthdr.mp_rseq + off;
- mptcplog((LOG_DEBUG, "%s: %llu %llu \n", __func__, dsn,
- dsn_fail), MPTCP_SENDER_DBG, MPTCP_LOGLVL_LOG);
return 0;
}
tcp_getconninfo(so, &flow->flow_ci);
inp = sotoinpcb(so);
-#if INET6
if ((inp->inp_vflag & INP_IPV6) != 0) {
flow->flow_src.ss_family = AF_INET6;
flow->flow_dst.ss_family = AF_INET6;
SIN6(&flow->flow_dst)->sin6_port = inp->in6p_fport;
SIN6(&flow->flow_src)->sin6_addr = inp->in6p_laddr;
SIN6(&flow->flow_dst)->sin6_addr = inp->in6p_faddr;
- } else
-#endif
- if ((inp->inp_vflag & INP_IPV4) != 0) {
+ } else if ((inp->inp_vflag & INP_IPV4) != 0) {
flow->flow_src.ss_family = AF_INET;
flow->flow_dst.ss_family = AF_INET;
flow->flow_src.ss_len = sizeof(struct sockaddr_in);
((notsent - (mp_tp->mpt_sndnxt - mp_tp->mpt_snduna)) <=
mp_tp->mpt_notsent_lowat)) {
mptcplog((LOG_DEBUG, "MPTCP Sender: "
- "lowat %d notsent %d actual %d \n",
+ "lowat %d notsent %d actual %llu \n",
mp_tp->mpt_notsent_lowat, notsent,
notsent - (mp_tp->mpt_sndnxt - mp_tp->mpt_snduna)),
MPTCP_SENDER_DBG, MPTCP_LOGLVL_VERBOSE);
mptcp_is_wifi_unusable_for_session(struct mptses *mpte)
{
if (mpte->mpte_flags & MPTE_FIRSTPARTY) {
- if (mptcp_advisory.sa_wifi_status) {
+ if (mpte->mpte_svctype != MPTCP_SVCTYPE_HANDOVER &&
+ mptcp_advisory.sa_wifi_status) {
return symptoms_is_wifi_lossy() ? 1 : 0;
}
* Returns true if the icon has been flipped to WiFi.
*/
static boolean_t
-__mptcp_unset_cellicon(long val)
+__mptcp_unset_cellicon(uint32_t val)
{
- if (OSAddAtomic(-val, &mptcp_cellicon_refcount) != 1) {
+ VERIFY(val < INT32_MAX);
+ if (OSAddAtomic((int32_t)-val, &mptcp_cellicon_refcount) != 1) {
return false;
}