/*
- * Copyright (c) 2012-2014 Apple Inc. All rights reserved.
+ * Copyright (c) 2012-2017 Apple Inc. All rights reserved.
*
* @APPLE_OSREFERENCE_LICENSE_HEADER_START@
*
#include <netinet/ip_var.h>
#include <netinet/in_var.h>
#include <netinet/tcp.h>
-#include <netinet/tcp_var.h>
+#include <netinet/tcp_cache.h>
#include <netinet/tcp_seq.h>
#include <netinet/tcpip.h>
#include <netinet/tcp_fsm.h>
#include <mach/sdt.h>
-/*
- * SYSCTL for enforcing 64 bit dsn
- */
-int32_t force_64bit_dsn = 0;
-SYSCTL_INT(_net_inet_mptcp, OID_AUTO, force_64bit_dsn,
- CTLFLAG_RW|CTLFLAG_LOCKED, &force_64bit_dsn, 0,
- "Force MPTCP 64bit dsn");
-
-
static int mptcp_validate_join_hmac(struct tcpcb *, u_char*, int);
static int mptcp_snd_mpprio(struct tcpcb *tp, u_char *cp, int optlen);
+static void mptcp_send_remaddr_opt(struct tcpcb *, struct mptcp_remaddr_opt *);
/*
* MPTCP Options Output Processing
*/
static unsigned
-mptcp_setup_first_subflow_syn_opts(struct socket *so, int flags, u_char *opt,
- unsigned optlen)
+mptcp_setup_first_subflow_syn_opts(struct socket *so, u_char *opt, unsigned optlen)
{
+ struct mptcp_mpcapable_opt_common mptcp_opt;
struct tcpcb *tp = sototcpcb(so);
- struct mptcb *mp_tp = NULL;
- mp_tp = tptomptp(tp);
+ struct mptcb *mp_tp = tptomptp(tp);
- if (!(so->so_flags & SOF_MP_SUBFLOW))
- return (optlen);
+ mpte_lock_assert_held(mp_tp->mpt_mpte);
/*
* Avoid retransmitting the MP_CAPABLE option.
*/
- if (tp->t_rxtshift > mptcp_mpcap_retries)
+ if (tp->t_rxtshift > mptcp_mpcap_retries) {
+ if (!(mp_tp->mpt_flags & (MPTCPF_FALLBACK_HEURISTIC | MPTCPF_HEURISTIC_TRAC))) {
+ mp_tp->mpt_flags |= MPTCPF_HEURISTIC_TRAC;
+ tcp_heuristic_mptcp_loss(tp);
+ }
return (optlen);
+ }
- if ((flags & (TH_SYN | TH_ACK)) == (TH_SYN | TH_ACK)) {
- struct mptcp_mpcapable_opt_rsp mptcp_opt;
- mptcp_key_t mp_localkey = 0;
-
- mp_localkey = mptcp_get_localkey(mp_tp);
- if (mp_localkey == 0) {
- /* an embryonic connection was closed from above */
- return (optlen);
- }
- bzero(&mptcp_opt,
- sizeof (struct mptcp_mpcapable_opt_rsp));
- mptcp_opt.mmc_common.mmco_kind = TCPOPT_MULTIPATH;
- mptcp_opt.mmc_common.mmco_len =
- sizeof (struct mptcp_mpcapable_opt_rsp);
- mptcp_opt.mmc_common.mmco_subtype = MPO_CAPABLE;
- MPT_LOCK_SPIN(mp_tp);
- mptcp_opt.mmc_common.mmco_version = mp_tp->mpt_version;
- mptcp_opt.mmc_common.mmco_flags |= MPCAP_PROPOSAL_SBIT;
- if (mp_tp->mpt_flags & MPTCPF_CHECKSUM)
- mptcp_opt.mmc_common.mmco_flags |=
- MPCAP_CHECKSUM_CBIT;
- MPT_UNLOCK(mp_tp);
- mptcp_opt.mmc_localkey = mp_localkey;
- memcpy(opt + optlen, &mptcp_opt,
- mptcp_opt.mmc_common.mmco_len);
- optlen += mptcp_opt.mmc_common.mmco_len;
- } else {
- /* Only the SYN flag is set */
- struct mptcp_mpcapable_opt_common mptcp_opt;
- mptcp_key_t mp_localkey = 0;
- mp_localkey = mptcp_get_localkey(mp_tp);
- so->so_flags |= SOF_MPTCP_CLIENT;
- if (mp_localkey == 0) {
- /* an embryonic connection was closed */
- return (optlen);
- }
- bzero(&mptcp_opt,
- sizeof (struct mptcp_mpcapable_opt_common));
- mptcp_opt.mmco_kind = TCPOPT_MULTIPATH;
- mptcp_opt.mmco_len =
- sizeof (struct mptcp_mpcapable_opt_common) +
- sizeof (mptcp_key_t);
- mptcp_opt.mmco_subtype = MPO_CAPABLE;
- MPT_LOCK_SPIN(mp_tp);
- mptcp_opt.mmco_version = mp_tp->mpt_version;
- mptcp_opt.mmco_flags |= MPCAP_PROPOSAL_SBIT;
- if (mp_tp->mpt_flags & MPTCPF_CHECKSUM)
- mptcp_opt.mmco_flags |= MPCAP_CHECKSUM_CBIT;
- MPT_UNLOCK(mp_tp);
- (void) memcpy(opt + optlen, &mptcp_opt,
- sizeof (struct mptcp_mpcapable_opt_common));
- optlen += sizeof (struct mptcp_mpcapable_opt_common);
- (void) memcpy(opt + optlen, &mp_localkey,
- sizeof (mptcp_key_t));
- optlen += sizeof (mptcp_key_t);
+ if (!tcp_heuristic_do_mptcp(tp)) {
+ mp_tp->mpt_flags |= MPTCPF_FALLBACK_HEURISTIC;
+ return (optlen);
}
+ bzero(&mptcp_opt, sizeof (struct mptcp_mpcapable_opt_common));
+
+ mptcp_opt.mmco_kind = TCPOPT_MULTIPATH;
+ mptcp_opt.mmco_len =
+ sizeof (struct mptcp_mpcapable_opt_common) +
+ sizeof (mptcp_key_t);
+ mptcp_opt.mmco_subtype = MPO_CAPABLE;
+ mptcp_opt.mmco_version = mp_tp->mpt_version;
+ mptcp_opt.mmco_flags |= MPCAP_PROPOSAL_SBIT;
+ if (mp_tp->mpt_flags & MPTCPF_CHECKSUM)
+ mptcp_opt.mmco_flags |= MPCAP_CHECKSUM_CBIT;
+ memcpy(opt + optlen, &mptcp_opt, sizeof (struct mptcp_mpcapable_opt_common));
+ optlen += sizeof (struct mptcp_mpcapable_opt_common);
+ memcpy(opt + optlen, &mp_tp->mpt_localkey, sizeof (mptcp_key_t));
+ optlen += sizeof (mptcp_key_t);
+
return (optlen);
}
static unsigned
-mptcp_setup_join_subflow_syn_opts(struct socket *so, int flags, u_char *opt,
- unsigned optlen)
+mptcp_setup_join_subflow_syn_opts(struct socket *so, u_char *opt, unsigned optlen)
{
+ struct mptcp_mpjoin_opt_req mpjoin_req;
struct inpcb *inp = sotoinpcb(so);
struct tcpcb *tp = NULL;
+ struct mptsub *mpts;
if (!inp)
return (optlen);
if (!tp)
return (optlen);
- if (!tp->t_mptcb)
- return (optlen);
+ mpts = tp->t_mpsub;
- if ((flags & (TH_SYN | TH_ACK)) == (TH_SYN | TH_ACK)) {
- struct mptcp_mpjoin_opt_rsp mpjoin_rsp;
- struct mptcb *mp_tp = tptomptp(tp);
+ VERIFY(tptomptp(tp));
+ mpte_lock_assert_held(tptomptp(tp)->mpt_mpte);
- if (mp_tp == NULL)
- return (optlen);
+ bzero(&mpjoin_req, sizeof (mpjoin_req));
+ mpjoin_req.mmjo_kind = TCPOPT_MULTIPATH;
+ mpjoin_req.mmjo_len = sizeof (mpjoin_req);
+ mpjoin_req.mmjo_subtype_bkp = MPO_JOIN << 4;
- MPT_LOCK(mp_tp);
- if (mptcp_get_localkey(mp_tp) == 0) {
- MPT_UNLOCK(mp_tp);
- return (optlen);
- }
- MPT_UNLOCK(mp_tp);
- bzero(&mpjoin_rsp, sizeof (mpjoin_rsp));
- mpjoin_rsp.mmjo_kind = TCPOPT_MULTIPATH;
- mpjoin_rsp.mmjo_len = sizeof (mpjoin_rsp);
- mpjoin_rsp.mmjo_subtype_bkp = MPO_JOIN << 4;
- if (tp->t_mpflags & TMPF_BACKUP_PATH)
- mpjoin_rsp.mmjo_subtype_bkp |= MPTCP_BACKUP;
- mpjoin_rsp.mmjo_addr_id = tp->t_local_aid;
- mptcp_get_rands(tp->t_local_aid, tptomptp(tp),
- &mpjoin_rsp.mmjo_rand, NULL);
- mpjoin_rsp.mmjo_mac = mptcp_get_trunced_hmac(tp->t_local_aid,
- mp_tp);
- memcpy(opt + optlen, &mpjoin_rsp, mpjoin_rsp.mmjo_len);
- optlen += mpjoin_rsp.mmjo_len;
- } else {
- struct mptcp_mpjoin_opt_req mpjoin_req;
- bzero(&mpjoin_req, sizeof (mpjoin_req));
- mpjoin_req.mmjo_kind = TCPOPT_MULTIPATH;
- mpjoin_req.mmjo_len = sizeof (mpjoin_req);
- mpjoin_req.mmjo_subtype_bkp = MPO_JOIN << 4;
- /* A secondary subflow is started off as backup */
+ if (tp->t_mpflags & TMPF_BACKUP_PATH) {
+ mpjoin_req.mmjo_subtype_bkp |= MPTCP_BACKUP;
+ } else if (inp->inp_boundifp && IFNET_IS_CELLULAR(inp->inp_boundifp) &&
+ mpts->mpts_mpte->mpte_svctype != MPTCP_SVCTYPE_AGGREGATE) {
mpjoin_req.mmjo_subtype_bkp |= MPTCP_BACKUP;
tp->t_mpflags |= TMPF_BACKUP_PATH;
- mpjoin_req.mmjo_addr_id = tp->t_local_aid;
- mpjoin_req.mmjo_peer_token = mptcp_get_remotetoken(tp->t_mptcb);
- if (mpjoin_req.mmjo_peer_token == 0) {
- mptcplog((LOG_DEBUG, "MPTCP Socket: %s: peer token 0",
- __func__),
- MPTCP_SOCKET_DBG, MPTCP_LOGLVL_ERR);
- }
- mptcp_get_rands(tp->t_local_aid, tptomptp(tp),
- &mpjoin_req.mmjo_rand, NULL);
- memcpy(opt + optlen, &mpjoin_req, mpjoin_req.mmjo_len);
- optlen += mpjoin_req.mmjo_len;
- /* send an event up, if Fast Join is requested */
- if (mptcp_zerortt_fastjoin &&
- (so->so_flags & SOF_MPTCP_FASTJOIN)) {
- soevent(so,
- (SO_FILT_HINT_LOCKED | SO_FILT_HINT_MPFASTJ));
- }
+ } else {
+ mpts->mpts_flags |= MPTSF_PREFERRED;
}
+
+ mpjoin_req.mmjo_addr_id = tp->t_local_aid;
+ mpjoin_req.mmjo_peer_token = tptomptp(tp)->mpt_remotetoken;
+ if (mpjoin_req.mmjo_peer_token == 0) {
+ mptcplog((LOG_DEBUG, "%s: peer token 0", __func__),
+ MPTCP_SOCKET_DBG, MPTCP_LOGLVL_ERR);
+ }
+ mptcp_get_rands(tp->t_local_aid, tptomptp(tp),
+ &mpjoin_req.mmjo_rand, NULL);
+ memcpy(opt + optlen, &mpjoin_req, mpjoin_req.mmjo_len);
+ optlen += mpjoin_req.mmjo_len;
+
return (optlen);
}
join_rsp2.mmjo_len = sizeof (struct mptcp_mpjoin_opt_rsp2);
join_rsp2.mmjo_subtype = MPO_JOIN;
mptcp_get_hmac(tp->t_local_aid, tptomptp(tp),
- (u_char*)&join_rsp2.mmjo_mac,
- sizeof (join_rsp2.mmjo_mac));
+ (u_char*)&join_rsp2.mmjo_mac);
memcpy(opt + optlen, &join_rsp2, join_rsp2.mmjo_len);
new_optlen = optlen + join_rsp2.mmjo_len;
- tp->t_mpflags |= TMPF_FASTJOINBY2_SEND;
return (new_optlen);
}
unsigned
-mptcp_setup_syn_opts(struct socket *so, int flags, u_char *opt, unsigned optlen)
+mptcp_setup_syn_opts(struct socket *so, u_char *opt, unsigned optlen)
{
unsigned new_optlen;
- if (mptcp_enable == 0) {
- /* do nothing */
- return (optlen);
- }
+ if (!(so->so_flags & SOF_MP_SEC_SUBFLOW))
+ new_optlen = mptcp_setup_first_subflow_syn_opts(so, opt, optlen);
+ else
+ new_optlen = mptcp_setup_join_subflow_syn_opts(so, opt, optlen);
- if (!(so->so_flags & SOF_MP_SEC_SUBFLOW)) {
- new_optlen = mptcp_setup_first_subflow_syn_opts(so, flags, opt,
- optlen);
- } else {
- /*
- * To simulate SYN_ACK with no join opt, comment this line on
- * OS X server side. This serves as a testing hook.
- */
- new_optlen = mptcp_setup_join_subflow_syn_opts(so, flags, opt,
- optlen);
- }
return (new_optlen);
}
return (optlen);
}
+ mpte_lock_assert_held(mp_tp->mpt_mpte);
+
/* if option space low give up */
if ((MAX_TCPOPTLEN - optlen) < sizeof (struct mptcp_mpfail_opt)) {
tp->t_mpflags &= ~TMPF_SND_MPFAIL;
return (optlen);
- }
+ }
- MPT_LOCK(mp_tp);
dsn = mp_tp->mpt_rcvnxt;
- MPT_UNLOCK(mp_tp);
bzero(&fail_opt, sizeof (fail_opt));
fail_opt.mfail_kind = TCPOPT_MULTIPATH;
memcpy(opt + optlen, &fail_opt, len);
optlen += len;
tp->t_mpflags &= ~TMPF_SND_MPFAIL;
- mptcplog((LOG_DEBUG, "MPTCP Socket: %s: %d \n", __func__,
- tp->t_local_aid), (MPTCP_SOCKET_DBG | MPTCP_SENDER_DBG),
+ mptcplog((LOG_DEBUG, "%s: %d \n", __func__,
+ tp->t_local_aid), (MPTCP_SOCKET_DBG | MPTCP_SENDER_DBG),
MPTCP_LOGLVL_LOG);
return (optlen);
}
struct mptcb *mp_tp = NULL;
size_t len = sizeof (struct mptcp_dsn_opt);
struct socket *so = tp->t_inpcb->inp_socket;
- int error = 0;
int csum_len = 0;
if (!so)
if (mp_tp == NULL)
return (optlen);
- MPT_LOCK(mp_tp);
+ mpte_lock_assert_held(mp_tp->mpt_mpte);
+
if (mp_tp->mpt_flags & MPTCPF_CHECKSUM)
csum_len = 2;
/* try later */
- if ((MAX_TCPOPTLEN - optlen) < (len + csum_len)) {
- MPT_UNLOCK(mp_tp);
+ if ((MAX_TCPOPTLEN - optlen) < (len + csum_len))
return (optlen);
- }
+
bzero(&infin_opt, sizeof (infin_opt));
infin_opt.mdss_copt.mdss_kind = TCPOPT_MULTIPATH;
infin_opt.mdss_copt.mdss_len = len + csum_len;
((mp_tp->mpt_local_idsn + 1) == mp_tp->mpt_snduna)) {
infin_opt.mdss_subflow_seqn = 1;
- mptcplog((LOG_DEBUG, "MPTCP Socket: %s: idsn %llu"
- "snduna %llu \n", __func__, mp_tp->mpt_local_idsn,
+ mptcplog((LOG_DEBUG, "%s: idsn %llu snduna %llu \n",
+ __func__, mp_tp->mpt_local_idsn,
mp_tp->mpt_snduna),
(MPTCP_SOCKET_DBG | MPTCP_SENDER_DBG),
MPTCP_LOGLVL_LOG);
} else {
- infin_opt.mdss_subflow_seqn = tp->snd_una - tp->iss;
+ infin_opt.mdss_subflow_seqn = tp->snd_una - tp->t_mpsub->mpts_iss;
}
infin_opt.mdss_dsn = (u_int32_t)
MPTCP_DATASEQ_LOW32(mp_tp->mpt_snduna);
}
- MPT_UNLOCK(mp_tp);
- if (error != 0)
- return (optlen);
+
if ((infin_opt.mdss_dsn == 0) || (infin_opt.mdss_subflow_seqn == 0)) {
return (optlen);
}
optlen += csum_len;
}
- mptcplog((LOG_DEBUG, "MPTCP Socket: %s: dsn = %x, seq = %x len = %x\n",
- __func__,
+ mptcplog((LOG_DEBUG, "%s: dsn = %x, seq = %x len = %x\n", __func__,
ntohl(infin_opt.mdss_dsn),
ntohl(infin_opt.mdss_subflow_seqn),
ntohs(infin_opt.mdss_data_len)),
(MPTCP_SOCKET_DBG | MPTCP_SENDER_DBG),
MPTCP_LOGLVL_LOG);
- /* so->so_flags &= ~SOF_MPTCP_CLIENT; */
tp->t_mpflags |= TMPF_INFIN_SENT;
tcpstat.tcps_estab_fallback++;
return (optlen);
static int
mptcp_ok_to_fin(struct tcpcb *tp, u_int64_t dsn, u_int32_t datalen)
{
- struct mptcb *mp_tp = NULL;
- mp_tp = tptomptp(tp);
-
- MPT_LOCK(mp_tp);
- dsn = (mp_tp->mpt_sndmax & MPTCP_DATASEQ_LOW32_MASK) | dsn;
- if ((dsn + datalen) == mp_tp->mpt_sndmax) {
- MPT_UNLOCK(mp_tp);
- return (1);
- }
- MPT_UNLOCK(mp_tp);
- return (0);
-}
-
-
-/* Must be called from tcp_output to fill in the fast close option */
-static int
-mptcp_send_fastclose(struct tcpcb *tp, u_char *opt, unsigned int optlen,
- int flags)
-{
- struct mptcp_fastclose_opt fastclose_opt;
struct mptcb *mp_tp = tptomptp(tp);
- /* Only ACK flag should be set */
- if (flags != TH_ACK)
- return (optlen);
+ mpte_lock_assert_held(mp_tp->mpt_mpte);
- if ((MAX_TCPOPTLEN - optlen) <
- sizeof (struct mptcp_fastclose_opt)) {
- return (optlen);
- }
-
- bzero(&fastclose_opt, sizeof (struct mptcp_fastclose_opt));
- fastclose_opt.mfast_kind = TCPOPT_MULTIPATH;
- fastclose_opt.mfast_len = sizeof (struct mptcp_fastclose_opt);
- fastclose_opt.mfast_subtype = MPO_FASTCLOSE;
- MPT_LOCK_SPIN(mp_tp);
- fastclose_opt.mfast_key = mptcp_get_remotekey(mp_tp);
- MPT_UNLOCK(mp_tp);
- memcpy(opt + optlen, &fastclose_opt, fastclose_opt.mfast_len);
- optlen += fastclose_opt.mfast_len;
+ dsn = (mp_tp->mpt_sndmax & MPTCP_DATASEQ_LOW32_MASK) | dsn;
+ if ((dsn + datalen) == mp_tp->mpt_sndmax)
+ return (1);
- return (optlen);
+ return (0);
}
unsigned int
mptcp_setup_opts(struct tcpcb *tp, int32_t off, u_char *opt,
- unsigned int optlen, int flags, int datalen,
- unsigned int **dss_lenp, u_int8_t **finp, u_int64_t *dss_valp,
- u_int32_t **sseqp, boolean_t *p_mptcp_acknow)
+ unsigned int optlen, int flags, int len,
+ boolean_t *p_mptcp_acknow)
{
struct inpcb *inp = (struct inpcb *)tp->t_inpcb;
struct socket *so = inp->inp_socket;
boolean_t do_csum = FALSE;
boolean_t send_64bit_dsn = FALSE;
boolean_t send_64bit_ack = FALSE;
- u_int32_t old_mpt_flags = tp->t_mpflags &
- (TMPF_SND_MPPRIO | TMPF_SND_REM_ADDR | TMPF_SND_MPFAIL |
- TMPF_MPCAP_RETRANSMIT);
-
- if ((mptcp_enable == 0) ||
- (mp_tp == NULL) ||
- (mp_tp->mpt_flags & MPTCPF_PEEL_OFF) ||
- (tp->t_state == TCPS_CLOSED)) {
+ u_int32_t old_mpt_flags = tp->t_mpflags & TMPF_MPTCP_SIGNALS;
+
+ if (mptcp_enable == 0 || mp_tp == NULL || tp->t_state == TCPS_CLOSED) {
/* do nothing */
goto ret_optlen;
}
+ mpte_lock_assert_held(mp_tp->mpt_mpte);
+
if (mp_tp->mpt_flags & MPTCPF_CHECKSUM) {
do_csum = TRUE;
}
if ((MAX_TCPOPTLEN - optlen) <
sizeof (struct mptcp_mpcapable_opt_common)) {
- mptcplog((LOG_ERR, "MPTCP Socket: "
- "%s: no space left %d flags %x "
- "tp->t_mpflags %x "
- "len %d\n", __func__, optlen, flags, tp->t_mpflags,
- datalen), MPTCP_SOCKET_DBG, MPTCP_LOGLVL_ERR);
- goto ret_optlen;
- }
-
- if (tp->t_mpflags & TMPF_FASTCLOSE) {
- optlen = mptcp_send_fastclose(tp, opt, optlen, flags);
- VERIFY(datalen == 0);
+ mptcplog((LOG_ERR, "%s: no space left %d flags %x tp->t_mpflags %x len %d\n",
+ __func__, optlen, flags, tp->t_mpflags, len),
+ MPTCP_SOCKET_DBG, MPTCP_LOGLVL_ERR);
goto ret_optlen;
}
goto ret_optlen;
}
- if (tp->t_mpflags & TMPF_SND_MPPRIO) {
- optlen = mptcp_snd_mpprio(tp, opt, optlen);
- goto ret_optlen;
- }
-
- if (((tp->t_mpflags & TMPF_FASTJOINBY2_SEND) ||
- (tp->t_mpflags & TMPF_FASTJOIN_SEND )) &&
- (datalen > 0)) {
- tp->t_mpflags &= ~TMPF_FASTJOINBY2_SEND;
- tp->t_mpflags &= ~TMPF_FASTJOIN_SEND;
- goto fastjoin_send;
- }
-
- if (((tp->t_mpflags & TMPF_PREESTABLISHED) &&
- (!(tp->t_mpflags & TMPF_SENT_KEYS)) &&
- (!(tp->t_mpflags & TMPF_JOINED_FLOW))) ||
- (tp->t_mpflags & TMPF_MPCAP_RETRANSMIT)) {
+ if (tp->t_mpflags & TMPF_SND_KEYS) {
struct mptcp_mpcapable_opt_rsp1 mptcp_opt;
if ((MAX_TCPOPTLEN - optlen) <
sizeof (struct mptcp_mpcapable_opt_rsp1))
mptcp_opt.mmc_common.mmco_version = mp_tp->mpt_version;
/* HMAC-SHA1 is the proposal */
mptcp_opt.mmc_common.mmco_flags |= MPCAP_PROPOSAL_SBIT;
- MPT_LOCK(mp_tp);
if (mp_tp->mpt_flags & MPTCPF_CHECKSUM)
mptcp_opt.mmc_common.mmco_flags |= MPCAP_CHECKSUM_CBIT;
- mptcp_opt.mmc_localkey = mptcp_get_localkey(mp_tp);
- mptcp_opt.mmc_remotekey = mptcp_get_remotekey(mp_tp);
- MPT_UNLOCK(mp_tp);
+ mptcp_opt.mmc_localkey = mp_tp->mpt_localkey;
+ mptcp_opt.mmc_remotekey = mp_tp->mpt_remotekey;
memcpy(opt + optlen, &mptcp_opt, mptcp_opt.mmc_common.mmco_len);
optlen += mptcp_opt.mmc_common.mmco_len;
- tp->t_mpflags |= TMPF_SENT_KEYS | TMPF_MPTCP_TRUE;
- so->so_flags |= SOF_MPTCP_TRUE;
- tp->t_mpflags &= ~TMPF_PREESTABLISHED;
- tp->t_mpflags &= ~TMPF_MPCAP_RETRANSMIT;
+ tp->t_mpflags &= ~TMPF_SND_KEYS;
if (!tp->t_mpuna) {
tp->t_mpuna = tp->snd_una;
/* its a retransmission of the MP_CAPABLE ACK */
}
goto ret_optlen;
- } else if (tp->t_mpflags & TMPF_MPTCP_TRUE) {
- if (tp->t_mpflags & TMPF_SND_REM_ADDR) {
- int rem_opt_len = sizeof (struct mptcp_remaddr_opt);
- if ((optlen + rem_opt_len) <= MAX_TCPOPTLEN) {
- mptcp_send_remaddr_opt(tp,
- (struct mptcp_remaddr_opt *)(opt + optlen));
- optlen += rem_opt_len;
- goto ret_optlen;
- } else {
- tp->t_mpflags &= ~TMPF_SND_REM_ADDR;
- }
- }
}
- if ((tp->t_mpflags & TMPF_JOINED_FLOW) &&
- (tp->t_mpflags & TMPF_PREESTABLISHED) &&
- (!(tp->t_mpflags & TMPF_RECVD_JOIN)) &&
- (tp->t_mpflags & TMPF_SENT_JOIN) &&
- (!(tp->t_mpflags & TMPF_MPTCP_TRUE))) {
- MPT_LOCK(mp_tp);
- if (mptcp_get_localkey(mp_tp) == 0) {
- MPT_UNLOCK(mp_tp);
- goto ret_optlen;
- }
- MPT_UNLOCK(mp_tp);
+ if (tp->t_mpflags & TMPF_SND_JACK) {
/* Do the ACK part */
optlen = mptcp_setup_join_ack_opts(tp, opt, optlen);
if (!tp->t_mpuna) {
/* Start a timer to retransmit the ACK */
tp->t_timer[TCPT_JACK_RXMT] =
OFFSET_FROM_START(tp, tcp_jack_rxmt);
+
+ tp->t_mpflags &= ~TMPF_SND_JACK;
goto ret_optlen;
}
if (!(tp->t_mpflags & TMPF_MPTCP_TRUE))
goto ret_optlen;
-fastjoin_send:
- /*
- * From here on, all options are sent only if MPTCP_TRUE
+ /*
+ * From here on, all options are sent only if MPTCP_TRUE
* or when data is sent early on as in Fast Join
*/
- MPT_LOCK(mp_tp);
- if ((mp_tp->mpt_flags & MPTCPF_SND_64BITDSN) || force_64bit_dsn) {
+ if ((tp->t_mpflags & TMPF_MPTCP_TRUE) &&
+ (tp->t_mpflags & TMPF_SND_REM_ADDR)) {
+ int rem_opt_len = sizeof (struct mptcp_remaddr_opt);
+ if ((optlen + rem_opt_len) <= MAX_TCPOPTLEN) {
+ mptcp_send_remaddr_opt(tp,
+ (struct mptcp_remaddr_opt *)(opt + optlen));
+ optlen += rem_opt_len;
+ } else {
+ tp->t_mpflags &= ~TMPF_SND_REM_ADDR;
+ }
+ }
+
+ if (tp->t_mpflags & TMPF_SND_MPPRIO) {
+ optlen = mptcp_snd_mpprio(tp, opt, optlen);
+ }
+
+ if (mp_tp->mpt_flags & MPTCPF_SND_64BITDSN) {
send_64bit_dsn = TRUE;
}
- if (mp_tp->mpt_flags & MPTCPF_SND_64BITACK) {
+ if (mp_tp->mpt_flags & MPTCPF_SND_64BITACK)
send_64bit_ack = TRUE;
- }
- MPT_UNLOCK(mp_tp);
-#define CHECK_OPTLEN { \
- if ((MAX_TCPOPTLEN - optlen) < len) { \
- mptcplog((LOG_ERR, "MPTCP Socket: " \
- "%s: len %d optlen %d \n", __func__, len, optlen), \
- MPTCP_SOCKET_DBG, MPTCP_LOGLVL_ERR); \
- goto ret_optlen; \
- } \
+#define CHECK_OPTLEN { \
+ if ((MAX_TCPOPTLEN - optlen) < dssoptlen) { \
+ mptcplog((LOG_ERR, "%s: dssoptlen %d optlen %d \n", __func__, \
+ dssoptlen, optlen), \
+ MPTCP_SOCKET_DBG, MPTCP_LOGLVL_ERR); \
+ goto ret_optlen; \
+ } \
}
#define DO_FIN(dsn_opt) { \
int sndfin = 0; \
- sndfin = mptcp_ok_to_fin(tp, dsn_opt.mdss_dsn, datalen); \
+ sndfin = mptcp_ok_to_fin(tp, dsn_opt.mdss_dsn, len); \
if (sndfin) { \
dsn_opt.mdss_copt.mdss_flags |= MDSS_F; \
- *finp = opt + optlen + offsetof(struct mptcp_dss_copt, \
- mdss_flags); \
- dsn_opt.mdss_data_len += 1; \
+ dsn_opt.mdss_data_len += 1; \
+ if (do_csum) \
+ dss_csum = in_addword(dss_csum, 1); \
} \
}
#define CHECK_DATALEN { \
/* MPTCP socket does not support IP options */ \
- if ((datalen + optlen + len) > tp->t_maxopd) { \
- mptcplog((LOG_ERR, "MPTCP Socket: " \
- "%s: nosp %d len %d opt %d %d %d\n", \
- __func__, datalen, len, optlen, \
+ if ((len + optlen + dssoptlen) > tp->t_maxopd) { \
+ mptcplog((LOG_ERR, "%s: nosp %d len %d opt %d %d %d\n", \
+ __func__, len, dssoptlen, optlen, \
tp->t_maxseg, tp->t_maxopd), \
MPTCP_SOCKET_DBG, MPTCP_LOGLVL_ERR); \
/* remove option length from payload len */ \
- datalen = tp->t_maxopd - optlen - len; \
+ len = tp->t_maxopd - optlen - dssoptlen; \
} \
}
* XXX If this delay causes issue, remove the 2-byte padding.
*/
struct mptcp_dss64_ack32_opt dsn_ack_opt;
- unsigned int len = sizeof (dsn_ack_opt);
+ unsigned int dssoptlen = sizeof (dsn_ack_opt);
+ uint16_t dss_csum;
if (do_csum) {
- len += 2;
+ dssoptlen += 2;
}
CHECK_OPTLEN;
bzero(&dsn_ack_opt, sizeof (dsn_ack_opt));
dsn_ack_opt.mdss_copt.mdss_kind = TCPOPT_MULTIPATH;
dsn_ack_opt.mdss_copt.mdss_subtype = MPO_DSS;
- dsn_ack_opt.mdss_copt.mdss_len = len;
+ dsn_ack_opt.mdss_copt.mdss_len = dssoptlen;
dsn_ack_opt.mdss_copt.mdss_flags |=
MDSS_M | MDSS_m | MDSS_A;
CHECK_DATALEN;
- mptcp_output_getm_dsnmap64(so, off, (u_int32_t)datalen,
- &dsn_ack_opt.mdss_dsn,
- &dsn_ack_opt.mdss_subflow_seqn,
- &dsn_ack_opt.mdss_data_len);
-
- *dss_valp = dsn_ack_opt.mdss_dsn;
+ mptcp_output_getm_dsnmap64(so, off,
+ &dsn_ack_opt.mdss_dsn,
+ &dsn_ack_opt.mdss_subflow_seqn,
+ &dsn_ack_opt.mdss_data_len,
+ &dss_csum);
if ((dsn_ack_opt.mdss_data_len == 0) ||
(dsn_ack_opt.mdss_dsn == 0)) {
DO_FIN(dsn_ack_opt);
}
- MPT_LOCK(mp_tp);
dsn_ack_opt.mdss_ack =
htonl(MPTCP_DATAACK_LOW32(mp_tp->mpt_rcvnxt));
- MPT_UNLOCK(mp_tp);
dsn_ack_opt.mdss_dsn = mptcp_hton64(dsn_ack_opt.mdss_dsn);
dsn_ack_opt.mdss_subflow_seqn = htonl(
dsn_ack_opt.mdss_subflow_seqn);
dsn_ack_opt.mdss_data_len = htons(
dsn_ack_opt.mdss_data_len);
- *dss_lenp = (unsigned int *)(void *)(opt + optlen +
- offsetof(struct mptcp_dss64_ack32_opt, mdss_data_len));
memcpy(opt + optlen, &dsn_ack_opt, sizeof (dsn_ack_opt));
+ if (do_csum)
+ *((uint16_t *)(void *)(opt + optlen + sizeof (dsn_ack_opt))) = dss_csum;
- if (do_csum) {
- *sseqp = (u_int32_t *)(void *)(opt + optlen +
- offsetof(struct mptcp_dss64_ack32_opt,
- mdss_subflow_seqn));
- }
- optlen += len;
- mptcplog((LOG_DEBUG,"MPTCP Socket: "
- "%s: long DSS = %llx ACK = %llx \n",
- __func__,
+ optlen += dssoptlen;
+ mptcplog((LOG_DEBUG,"%s: long DSS = %llx ACK = %llx \n", __func__,
mptcp_ntoh64(dsn_ack_opt.mdss_dsn),
mptcp_ntoh64(dsn_ack_opt.mdss_ack)),
MPTCP_SOCKET_DBG, MPTCP_LOGLVL_LOG);
-
+
tp->t_mpflags &= ~TMPF_MPTCP_ACKNOW;
goto ret_optlen;
}
(!send_64bit_dsn) &&
!(tp->t_mpflags & TMPF_MPTCP_ACKNOW)) {
struct mptcp_dsn_opt dsn_opt;
- unsigned int len = sizeof (struct mptcp_dsn_opt);
+ unsigned int dssoptlen = sizeof (struct mptcp_dsn_opt);
+ uint16_t dss_csum;
if (do_csum) {
- len += 2;
+ dssoptlen += 2;
}
CHECK_OPTLEN;
bzero(&dsn_opt, sizeof (dsn_opt));
dsn_opt.mdss_copt.mdss_kind = TCPOPT_MULTIPATH;
dsn_opt.mdss_copt.mdss_subtype = MPO_DSS;
- dsn_opt.mdss_copt.mdss_len = len;
+ dsn_opt.mdss_copt.mdss_len = dssoptlen;
dsn_opt.mdss_copt.mdss_flags |= MDSS_M;
CHECK_DATALEN;
- mptcp_output_getm_dsnmap32(so, off, (u_int32_t)datalen,
- &dsn_opt.mdss_dsn,
- &dsn_opt.mdss_subflow_seqn, &dsn_opt.mdss_data_len,
- dss_valp);
+ mptcp_output_getm_dsnmap32(so, off, &dsn_opt.mdss_dsn,
+ &dsn_opt.mdss_subflow_seqn,
+ &dsn_opt.mdss_data_len,
+ &dss_csum);
if ((dsn_opt.mdss_data_len == 0) ||
(dsn_opt.mdss_dsn == 0)) {
dsn_opt.mdss_dsn = htonl(dsn_opt.mdss_dsn);
dsn_opt.mdss_subflow_seqn = htonl(dsn_opt.mdss_subflow_seqn);
dsn_opt.mdss_data_len = htons(dsn_opt.mdss_data_len);
- *dss_lenp = (unsigned int *)(void *)(opt + optlen +
- offsetof(struct mptcp_dsn_opt, mdss_data_len));
memcpy(opt + optlen, &dsn_opt, sizeof (dsn_opt));
- if (do_csum) {
- *sseqp = (u_int32_t *)(void *)(opt + optlen +
- offsetof(struct mptcp_dsn_opt, mdss_subflow_seqn));
- }
- optlen += len;
+ if (do_csum)
+ *((uint16_t *)(void *)(opt + optlen + sizeof (dsn_opt))) = dss_csum;
+
+ optlen += dssoptlen;
tp->t_mpflags &= ~TMPF_MPTCP_ACKNOW;
goto ret_optlen;
}
!(tp->t_mpflags & TMPF_SEND_DFIN)) {
struct mptcp_data_ack_opt dack_opt;
- unsigned int len = 0;
+ unsigned int dssoptlen = 0;
do_ack32_only:
- len = sizeof (dack_opt);
+ dssoptlen = sizeof (dack_opt);
CHECK_OPTLEN;
- bzero(&dack_opt, len);
+ bzero(&dack_opt, dssoptlen);
dack_opt.mdss_copt.mdss_kind = TCPOPT_MULTIPATH;
- dack_opt.mdss_copt.mdss_len = len;
+ dack_opt.mdss_copt.mdss_len = dssoptlen;
dack_opt.mdss_copt.mdss_subtype = MPO_DSS;
dack_opt.mdss_copt.mdss_flags |= MDSS_A;
- MPT_LOCK_SPIN(mp_tp);
dack_opt.mdss_ack =
htonl(MPTCP_DATAACK_LOW32(mp_tp->mpt_rcvnxt));
- MPT_UNLOCK(mp_tp);
- memcpy(opt + optlen, &dack_opt, len);
- optlen += len;
+ memcpy(opt + optlen, &dack_opt, dssoptlen);
+ optlen += dssoptlen;
VERIFY(optlen <= MAX_TCPOPTLEN);
tp->t_mpflags &= ~TMPF_MPTCP_ACKNOW;
goto ret_optlen;
!(tp->t_mpflags & TMPF_SEND_DSN) &&
!(tp->t_mpflags & TMPF_SEND_DFIN)) {
struct mptcp_data_ack64_opt dack_opt;
- unsigned int len = 0;
+ unsigned int dssoptlen = 0;
do_ack64_only:
- len = sizeof (dack_opt);
+ dssoptlen = sizeof (dack_opt);
CHECK_OPTLEN;
- bzero(&dack_opt, len);
+ bzero(&dack_opt, dssoptlen);
dack_opt.mdss_copt.mdss_kind = TCPOPT_MULTIPATH;
- dack_opt.mdss_copt.mdss_len = len;
+ dack_opt.mdss_copt.mdss_len = dssoptlen;
dack_opt.mdss_copt.mdss_subtype = MPO_DSS;
dack_opt.mdss_copt.mdss_flags |= (MDSS_A | MDSS_a);
- MPT_LOCK_SPIN(mp_tp);
dack_opt.mdss_ack = mptcp_hton64(mp_tp->mpt_rcvnxt);
/*
* The other end should retransmit 64-bit DSN until it
* receives a 64-bit ACK.
*/
mp_tp->mpt_flags &= ~MPTCPF_SND_64BITACK;
- MPT_UNLOCK(mp_tp);
- memcpy(opt + optlen, &dack_opt, len);
- optlen += len;
+ memcpy(opt + optlen, &dack_opt, dssoptlen);
+ optlen += dssoptlen;
VERIFY(optlen <= MAX_TCPOPTLEN);
tp->t_mpflags &= ~TMPF_MPTCP_ACKNOW;
goto ret_optlen;
(!send_64bit_ack) &&
(tp->t_mpflags & TMPF_MPTCP_ACKNOW)) {
struct mptcp_dss_ack_opt dss_ack_opt;
- unsigned int len = sizeof (dss_ack_opt);
+ unsigned int dssoptlen = sizeof (dss_ack_opt);
+ uint16_t dss_csum;
if (do_csum)
- len += 2;
+ dssoptlen += 2;
CHECK_OPTLEN;
bzero(&dss_ack_opt, sizeof (dss_ack_opt));
dss_ack_opt.mdss_copt.mdss_kind = TCPOPT_MULTIPATH;
- dss_ack_opt.mdss_copt.mdss_len = len;
+ dss_ack_opt.mdss_copt.mdss_len = dssoptlen;
dss_ack_opt.mdss_copt.mdss_subtype = MPO_DSS;
dss_ack_opt.mdss_copt.mdss_flags |= MDSS_A | MDSS_M;
- MPT_LOCK_SPIN(mp_tp);
dss_ack_opt.mdss_ack =
htonl(MPTCP_DATAACK_LOW32(mp_tp->mpt_rcvnxt));
- MPT_UNLOCK(mp_tp);
CHECK_DATALEN;
- mptcp_output_getm_dsnmap32(so, off, (u_int32_t)datalen,
- &dss_ack_opt.mdss_dsn,
- &dss_ack_opt.mdss_subflow_seqn,
- &dss_ack_opt.mdss_data_len,
- dss_valp);
+ mptcp_output_getm_dsnmap32(so, off, &dss_ack_opt.mdss_dsn,
+ &dss_ack_opt.mdss_subflow_seqn,
+ &dss_ack_opt.mdss_data_len,
+ &dss_csum);
if ((dss_ack_opt.mdss_data_len == 0) ||
(dss_ack_opt.mdss_dsn == 0)) {
dss_ack_opt.mdss_subflow_seqn =
htonl(dss_ack_opt.mdss_subflow_seqn);
dss_ack_opt.mdss_data_len = htons(dss_ack_opt.mdss_data_len);
- *dss_lenp = (unsigned int *)(void *)(opt + optlen +
- offsetof(struct mptcp_dss_ack_opt, mdss_data_len));
memcpy(opt + optlen, &dss_ack_opt, sizeof (dss_ack_opt));
- if (do_csum) {
- *sseqp = (u_int32_t *)(void *)(opt + optlen +
- offsetof(struct mptcp_dss_ack_opt,
- mdss_subflow_seqn));
- }
+ if (do_csum)
+ *((uint16_t *)(void *)(opt + optlen + sizeof (dss_ack_opt))) = dss_csum;
- optlen += len;
+ optlen += dssoptlen;
if (optlen > MAX_TCPOPTLEN)
panic("optlen too large");
(send_64bit_ack) &&
(tp->t_mpflags & TMPF_MPTCP_ACKNOW)) {
struct mptcp_dss32_ack64_opt dss_ack_opt;
- unsigned int len = sizeof (dss_ack_opt);
+ unsigned int dssoptlen = sizeof (dss_ack_opt);
+ uint16_t dss_csum;
if (do_csum)
- len += 2;
+ dssoptlen += 2;
CHECK_OPTLEN;
bzero(&dss_ack_opt, sizeof (dss_ack_opt));
dss_ack_opt.mdss_copt.mdss_kind = TCPOPT_MULTIPATH;
- dss_ack_opt.mdss_copt.mdss_len = len;
+ dss_ack_opt.mdss_copt.mdss_len = dssoptlen;
dss_ack_opt.mdss_copt.mdss_subtype = MPO_DSS;
dss_ack_opt.mdss_copt.mdss_flags |= MDSS_M | MDSS_A | MDSS_a;
- MPT_LOCK_SPIN(mp_tp);
dss_ack_opt.mdss_ack =
mptcp_hton64(mp_tp->mpt_rcvnxt);
- MPT_UNLOCK(mp_tp);
CHECK_DATALEN;
- mptcp_output_getm_dsnmap32(so, off, (u_int32_t)datalen,
- &dss_ack_opt.mdss_dsn, &dss_ack_opt.mdss_subflow_seqn,
- &dss_ack_opt.mdss_data_len, dss_valp);
+ mptcp_output_getm_dsnmap32(so, off, &dss_ack_opt.mdss_dsn,
+ &dss_ack_opt.mdss_subflow_seqn,
+ &dss_ack_opt.mdss_data_len,
+ &dss_csum);
if ((dss_ack_opt.mdss_data_len == 0) ||
(dss_ack_opt.mdss_dsn == 0)) {
dss_ack_opt.mdss_subflow_seqn =
htonl(dss_ack_opt.mdss_subflow_seqn);
dss_ack_opt.mdss_data_len = htons(dss_ack_opt.mdss_data_len);
- *dss_lenp = (unsigned int *)(void *)(opt + optlen +
- offsetof(struct mptcp_dss32_ack64_opt, mdss_data_len));
memcpy(opt + optlen, &dss_ack_opt, sizeof (dss_ack_opt));
- if (do_csum) {
- *sseqp = (u_int32_t *)(void *)(opt + optlen +
- offsetof(struct mptcp_dss32_ack64_opt,
- mdss_subflow_seqn));
- }
+ if (do_csum)
+ *((uint16_t *)(void *)(opt + optlen + sizeof (dss_ack_opt))) = dss_csum;
- optlen += len;
+ optlen += dssoptlen;
if (optlen > MAX_TCPOPTLEN)
panic("optlen too large");
}
if (tp->t_mpflags & TMPF_SEND_DFIN) {
+ unsigned int dssoptlen = sizeof(struct mptcp_dss_ack_opt);
struct mptcp_dss_ack_opt dss_ack_opt;
- unsigned int len = sizeof (struct mptcp_dss_ack_opt);
+ uint16_t dss_csum;
- if (do_csum)
- len += 2;
+ if (do_csum) {
+ uint64_t dss_val = mptcp_hton64(mp_tp->mpt_sndmax - 1);
+ uint16_t dlen = htons(1);
+ uint32_t sseq = 0;
+ uint32_t sum;
+
+
+ dssoptlen += 2;
+
+ sum = in_pseudo64(dss_val, sseq, dlen);
+ ADDCARRY(sum);
+ dss_csum = ~sum & 0xffff;
+ }
CHECK_OPTLEN;
bzero(&dss_ack_opt, sizeof (dss_ack_opt));
- MPT_LOCK(mp_tp);
/*
* Data FIN occupies one sequence space.
* Don't send it if it has been Acked.
*/
- if (((mp_tp->mpt_sndnxt + 1) != mp_tp->mpt_sndmax) ||
- (mp_tp->mpt_snduna == mp_tp->mpt_sndmax)) {
- MPT_UNLOCK(mp_tp);
+ if ((mp_tp->mpt_sndnxt + 1 != mp_tp->mpt_sndmax) ||
+ (mp_tp->mpt_snduna == mp_tp->mpt_sndmax))
goto ret_optlen;
- }
dss_ack_opt.mdss_copt.mdss_kind = TCPOPT_MULTIPATH;
- dss_ack_opt.mdss_copt.mdss_len = len;
+ dss_ack_opt.mdss_copt.mdss_len = dssoptlen;
dss_ack_opt.mdss_copt.mdss_subtype = MPO_DSS;
dss_ack_opt.mdss_copt.mdss_flags |= MDSS_A | MDSS_M | MDSS_F;
dss_ack_opt.mdss_ack =
htonl(MPTCP_DATAACK_LOW32(mp_tp->mpt_rcvnxt));
dss_ack_opt.mdss_dsn =
- htonl(MPTCP_DATASEQ_LOW32(mp_tp->mpt_sndnxt));
- MPT_UNLOCK(mp_tp);
+ htonl(MPTCP_DATASEQ_LOW32(mp_tp->mpt_sndmax - 1));
dss_ack_opt.mdss_subflow_seqn = 0;
dss_ack_opt.mdss_data_len = 1;
dss_ack_opt.mdss_data_len = htons(dss_ack_opt.mdss_data_len);
memcpy(opt + optlen, &dss_ack_opt, sizeof (dss_ack_opt));
- if (do_csum) {
- *dss_valp = mp_tp->mpt_sndnxt;
- *sseqp = (u_int32_t *)(void *)(opt + optlen +
- offsetof(struct mptcp_dss_ack_opt,
- mdss_subflow_seqn));
- }
- optlen += len;
+ if (do_csum)
+ *((uint16_t *)(void *)(opt + optlen + sizeof (dss_ack_opt))) = dss_csum;
+
+ optlen += dssoptlen;
}
ret_optlen:
if (TRUE == *p_mptcp_acknow ) {
VERIFY(old_mpt_flags != 0);
- u_int32_t new_mpt_flags = tp->t_mpflags &
- (TMPF_SND_MPPRIO | TMPF_SND_REM_ADDR | TMPF_SND_MPFAIL |
- TMPF_MPCAP_RETRANSMIT);
+ u_int32_t new_mpt_flags = tp->t_mpflags & TMPF_MPTCP_SIGNALS;
/*
* If none of the above mpflags were acted on by
* this routine, reset these flags and set p_mptcp_acknow
* to false.
- * XXX The reset value of p_mptcp_acknow can be used
+ *
+ * XXX The reset value of p_mptcp_acknow can be used
* to communicate tcp_output to NOT send a pure ack without any
* MPTCP options as it will be treated as a dup ack.
* Since the instances of mptcp_setup_opts not acting on
* we haven't modified the logic in tcp_output to avoid
* that.
*/
- if ((old_mpt_flags == new_mpt_flags) || (new_mpt_flags == 0)) {
- tp->t_mpflags &= ~(TMPF_SND_MPPRIO
- | TMPF_SND_REM_ADDR | TMPF_SND_MPFAIL |
- TMPF_MPCAP_RETRANSMIT);
+ if (old_mpt_flags == new_mpt_flags) {
+ tp->t_mpflags &= ~TMPF_MPTCP_SIGNALS;
*p_mptcp_acknow = FALSE;
- mptcplog((LOG_DEBUG, "MPTCP Sender: %s: no action \n",
- __func__), MPTCP_SENDER_DBG, MPTCP_LOGLVL_LOG);
+ mptcplog((LOG_DEBUG, "%s: no action \n", __func__),
+ MPTCP_SENDER_DBG, MPTCP_LOGLVL_LOG);
} else {
- mptcplog((LOG_DEBUG, "MPTCP Sender: acknow set, "
- "old flags %x new flags %x \n",
- old_mpt_flags, new_mpt_flags),
+ mptcplog((LOG_DEBUG, "%s: acknow set, old flags %x new flags %x \n",
+ __func__, old_mpt_flags, new_mpt_flags),
MPTCP_SENDER_DBG, MPTCP_LOGLVL_LOG);
}
}
int ret = 1;
if (mp_tp == NULL) {
- mptcplog((LOG_ERR, "MPTCP Socket: %s: NULL mpsocket \n",
- __func__), MPTCP_SOCKET_DBG, MPTCP_LOGLVL_ERR);
+ mptcplog((LOG_ERR, "%s: NULL mpsocket \n", __func__),
+ MPTCP_SOCKET_DBG, MPTCP_LOGLVL_ERR);
return (0);
}
break;
default:
ret = 0;
- mptcplog((LOG_ERR, "MPTCP Socket: "
- "%s: type = %d \n", __func__,
+ mptcplog((LOG_ERR, "%s: type = %d \n", __func__,
mptcp_subtype),
MPTCP_SOCKET_DBG, MPTCP_LOGLVL_ERR);
break;
mptcp_do_mpcapable_opt(struct tcpcb *tp, u_char *cp, struct tcphdr *th,
int optlen)
{
- struct mptcp_mpcapable_opt_rsp1 *rsp1 = NULL;
struct mptcp_mpcapable_opt_rsp *rsp = NULL;
struct mptcb *mp_tp = tptomptp(tp);
-#define MPTCP_OPT_ERROR_PATH(tp) { \
- tp->t_mpflags |= TMPF_RESET; \
- tcpstat.tcps_invalid_mpcap++; \
- if (tp->t_inpcb->inp_socket != NULL) { \
- soevent(tp->t_inpcb->inp_socket, \
- SO_FILT_HINT_LOCKED | SO_FILT_HINT_MUSTRST); \
- } \
-}
+ mpte_lock_assert_held(mp_tp->mpt_mpte);
+
+ /* Only valid on SYN/ACK */
+ if ((th->th_flags & (TH_SYN | TH_ACK)) != (TH_SYN | TH_ACK))
+ return;
/* Validate the kind, len, flags */
if (mptcp_valid_mpcapable_common_opt(cp) != 1) {
return;
}
- /* A SYN contains only the MP_CAPABLE option */
- if ((th->th_flags & (TH_SYN | TH_ACK)) == TH_SYN) {
- /* XXX passive side not supported yet */
+ /* handle SYN/ACK retransmission by acknowledging with ACK */
+ if (mp_tp->mpt_state >= MPTCPS_ESTABLISHED)
return;
- } else if ((th->th_flags & (TH_SYN | TH_ACK)) == (TH_SYN | TH_ACK)) {
-
- /* Handle old duplicate SYN/ACK retransmission */
- if (SEQ_GT(tp->rcv_nxt, (tp->irs + 1)))
- return;
-
- /* handle SYN/ACK retransmission by acknowledging with ACK */
- if (mp_tp->mpt_state >= MPTCPS_ESTABLISHED) {
- tp->t_mpflags |= TMPF_MPCAP_RETRANSMIT;
- return;
- }
-
- /* A SYN/ACK contains peer's key and flags */
- if (optlen != sizeof (struct mptcp_mpcapable_opt_rsp)) {
- /* complain */
- mptcplog((LOG_ERR, "MPTCP Socket: "
- "%s: SYN_ACK optlen = %d, sizeof mp opt = %lu \n",
- __func__, optlen,
- sizeof (struct mptcp_mpcapable_opt_rsp)),
- MPTCP_SOCKET_DBG, MPTCP_LOGLVL_ERR);
- tcpstat.tcps_invalid_mpcap++;
- return;
- }
-
- /*
- * If checksum flag is set, enable MPTCP checksum, even if
- * it was not negotiated on the first SYN.
- */
- if (((struct mptcp_mpcapable_opt_common *)cp)->mmco_flags &
- MPCAP_CHECKSUM_CBIT)
- mp_tp->mpt_flags |= MPTCPF_CHECKSUM;
-
- rsp = (struct mptcp_mpcapable_opt_rsp *)cp;
- MPT_LOCK(mp_tp);
- mp_tp->mpt_remotekey = rsp->mmc_localkey;
- /* For now just downgrade to the peer's version */
- mp_tp->mpt_peer_version = rsp->mmc_common.mmco_version;
- if (rsp->mmc_common.mmco_version < mp_tp->mpt_version) {
- mp_tp->mpt_version = rsp->mmc_common.mmco_version;
- tcpstat.tcps_mp_verdowngrade++;
- }
- if (mptcp_init_remote_parms(mp_tp) != 0) {
- tcpstat.tcps_invalid_mpcap++;
- MPT_UNLOCK(mp_tp);
- return;
- }
- MPT_UNLOCK(mp_tp);
- tp->t_mpflags |= TMPF_PREESTABLISHED;
-
- } else if ((th->th_flags & TH_ACK) &&
- (tp->t_mpflags & TMPF_PREESTABLISHED)) {
- /*
- * Verify checksum flag is set, if we initially negotiated
- * checksum.
- */
- if ((mp_tp->mpt_flags & MPTCPF_CHECKSUM) &&
- !(((struct mptcp_mpcapable_opt_common *)cp)->mmco_flags &
- MPCAP_CHECKSUM_CBIT)) {
- mptcplog((LOG_ERR, "MPTCP Socket: "
- "%s: checksum negotiation failure \n", __func__),
- MPTCP_SOCKET_DBG, MPTCP_LOGLVL_ERR);
- MPTCP_OPT_ERROR_PATH(tp);
- return;
- }
-
- if (!(mp_tp->mpt_flags & MPTCPF_CHECKSUM) &&
- (((struct mptcp_mpcapable_opt_common *)cp)->mmco_flags &
- MPCAP_CHECKSUM_CBIT)) {
- mptcplog((LOG_ERR, "MPTCP Socket: "
- "%s: checksum negotiation failure 2.\n", __func__),
- MPTCP_SOCKET_DBG, MPTCP_LOGLVL_ERR);
- MPTCP_OPT_ERROR_PATH(tp);
- return;
- }
-
- /*
- * The ACK of a three way handshake contains peer's key and
- * flags.
- */
- if (optlen != sizeof (struct mptcp_mpcapable_opt_rsp1)) {
- /* complain */
- mptcplog((LOG_ERR, "MPTCP Socket: "
- "%s: ACK optlen = %d , sizeof mp option = %lu, "
- " state = %d \n", __func__, optlen,
- sizeof (struct mptcp_mpcapable_opt_rsp1),
- tp->t_state), MPTCP_SOCKET_DBG, MPTCP_LOGLVL_ERR);
- MPTCP_OPT_ERROR_PATH(tp);
- return;
- }
-
- rsp1 = (struct mptcp_mpcapable_opt_rsp1 *)cp;
+ /* A SYN/ACK contains peer's key and flags */
+ if (optlen != sizeof (struct mptcp_mpcapable_opt_rsp)) {
+ /* complain */
+ mptcplog((LOG_ERR, "%s: SYN_ACK optlen = %d, sizeof mp opt = %lu \n",
+ __func__, optlen,
+ sizeof (struct mptcp_mpcapable_opt_rsp)),
+ MPTCP_SOCKET_DBG, MPTCP_LOGLVL_ERR);
+ tcpstat.tcps_invalid_mpcap++;
+ return;
+ }
- /* Skipping MPT_LOCK for invariant key */
- if (rsp1->mmc_remotekey != *mp_tp->mpt_localkey) {
- mptcplog((LOG_ERR, "MPTCP Socket: "
- "%s: key mismatch locally stored key. "
- "rsp = %llx local = %llx \n", __func__,
- rsp1->mmc_remotekey, *mp_tp->mpt_localkey),
- MPTCP_SOCKET_DBG, MPTCP_LOGLVL_ERR);
- MPTCP_OPT_ERROR_PATH(tp);
- return;
- } else {
- /* We received both keys. Almost an MPTCP connection */
- /* Skipping MPT_LOCK for invariant key */
- if (mp_tp->mpt_remotekey != rsp1->mmc_localkey) {
- mptcplog((LOG_ERR, "MPTCP Socket: "
- "%s: keys don't match\n", __func__),
- MPTCP_SOCKET_DBG, MPTCP_LOGLVL_ERR);
- tp->t_mpflags &= ~TMPF_PREESTABLISHED;
- MPTCP_OPT_ERROR_PATH(tp);
- return;
- }
- tp->t_mpflags &= ~TMPF_PREESTABLISHED;
- tp->t_mpflags |= TMPF_MPTCP_RCVD_KEY;
- tp->t_mpflags |= TMPF_MPTCP_TRUE;
- tp->t_inpcb->inp_socket->so_flags |= SOF_MPTCP_TRUE;
- MPT_LOCK(mp_tp);
- DTRACE_MPTCP2(state__change, struct mptcb *, mp_tp,
- uint32_t, 0 /* event */);
- mptcplog((LOG_DEBUG, "MPTCP State: "
- "MPTCPS_ESTABLISHED \n"),
- MPTCP_STATE_DBG, MPTCP_LOGLVL_LOG);
-
- mp_tp->mpt_state = MPTCPS_ESTABLISHED;
- MPT_UNLOCK(mp_tp);
- }
- if (tp->t_mpuna) {
- tp->t_mpuna = 0;
- }
+ /*
+ * If checksum flag is set, enable MPTCP checksum, even if
+ * it was not negotiated on the first SYN.
+ */
+ if (((struct mptcp_mpcapable_opt_common *)cp)->mmco_flags &
+ MPCAP_CHECKSUM_CBIT)
+ mp_tp->mpt_flags |= MPTCPF_CHECKSUM;
+
+ rsp = (struct mptcp_mpcapable_opt_rsp *)cp;
+ mp_tp->mpt_remotekey = rsp->mmc_localkey;
+ /* For now just downgrade to the peer's version */
+ mp_tp->mpt_peer_version = rsp->mmc_common.mmco_version;
+ if (rsp->mmc_common.mmco_version < mp_tp->mpt_version) {
+ mp_tp->mpt_version = rsp->mmc_common.mmco_version;
+ tcpstat.tcps_mp_verdowngrade++;
+ }
+ if (mptcp_init_remote_parms(mp_tp) != 0) {
+ tcpstat.tcps_invalid_mpcap++;
+ return;
}
+ tcp_heuristic_mptcp_success(tp);
+ tp->t_mpflags |= (TMPF_SND_KEYS | TMPF_MPTCP_TRUE);
}
} \
}
int error = 0;
+ struct mptcp_mpjoin_opt_rsp *join_rsp =
+ (struct mptcp_mpjoin_opt_rsp *)cp;
- if ((th->th_flags & (TH_SYN | TH_ACK)) == TH_SYN) {
- /* We won't accept join requests as an active opener */
- if (tp->t_inpcb->inp_socket->so_flags & SOF_MPTCP_CLIENT) {
- MPTCP_JOPT_ERROR_PATH(tp);
- return;
- }
-
- if (optlen != sizeof (struct mptcp_mpjoin_opt_req)) {
- mptcplog((LOG_ERR, "MPTCP Socket: "
- "%s: SYN: unexpected optlen = %d, mp option"
- "= %lu\n", __func__, optlen,
- sizeof (struct mptcp_mpjoin_opt_req)),
- MPTCP_SOCKET_DBG, MPTCP_LOGLVL_ERR);
- /* send RST and close */
- MPTCP_JOPT_ERROR_PATH(tp);
- return;
- }
- /* not supported yet */
+ /* Only valid on SYN/ACK */
+ if ((th->th_flags & (TH_SYN | TH_ACK)) != (TH_SYN | TH_ACK))
return;
-#ifdef MPTCP_NOTYET
- struct mptcp_mpjoin_opt_req *join_req =
- (struct mptcp_mpjoin_opt_req *)cp;
- mp_so = mptcp_find_mpso(join_req->mmjo_peer_token);
- if (!mp_so) {
- mptcplog((LOG_ERR, "MPTCP Socket: "
- "%s: cannot find mp_so token = %x\n",
- __func__, join_req->mmjo_peer_token),
- MPTCP_SOCKET_DBG, MPTCP_LOGLVL_ERR);
- /* send RST */
- MPTCP_JOPT_ERROR_PATH(tp);
- return;
- }
- if (tp->t_mpflags & TMPF_PREESTABLISHED) {
- return;
- }
- mp_so->ms_remote_addr_id = join_req->mmjo_addr_id;
- mp_so->ms_remote_rand = join_req->mmjo_rand;
- tp->t_mpflags |= TMPF_PREESTABLISHED | TMPF_JOINED_FLOW;
- tp->t_mpflags |= TMPF_RECVD_JOIN;
- tp->t_inpcb->inp_socket->so_flags |= SOF_MP_SEC_SUBFLOW;
- if (join_req->mmjo_subtype & MPTCP_BACKUP) {
- tp->t_mpflags |= TMPF_BACKUP_PATH;
- }
-#endif
- } else if ((th->th_flags & (TH_SYN | TH_ACK)) == (TH_SYN | TH_ACK)) {
- struct mptcp_mpjoin_opt_rsp *join_rsp =
- (struct mptcp_mpjoin_opt_rsp *)cp;
-
- if (optlen != sizeof (struct mptcp_mpjoin_opt_rsp)) {
- mptcplog((LOG_ERR, "MPTCP Socket: "
- "SYN_ACK: unexpected optlen = %d mp "
- "option = %lu\n", optlen,
- sizeof (struct mptcp_mpjoin_opt_rsp)),
- MPTCP_SOCKET_DBG, MPTCP_LOGLVL_ERR);
- tp->t_mpflags &= ~TMPF_PREESTABLISHED;
- /* send RST and close */
- MPTCP_JOPT_ERROR_PATH(tp);
- return;
- }
-
- mptcp_set_raddr_rand(tp->t_local_aid,
- tptomptp(tp),
- join_rsp->mmjo_addr_id, join_rsp->mmjo_rand);
- error = mptcp_validate_join_hmac(tp,
- (u_char*)&join_rsp->mmjo_mac, SHA1_TRUNCATED);
- if (error) {
- mptcplog((LOG_ERR, "MPTCP Socket: %s: "
- "SYN_ACK error = %d \n", __func__, error),
- MPTCP_SOCKET_DBG, MPTCP_LOGLVL_ERR);
- tp->t_mpflags &= ~TMPF_PREESTABLISHED;
- /* send RST and close */
- MPTCP_JOPT_ERROR_PATH(tp);
- return;
- }
- tp->t_mpflags |= TMPF_SENT_JOIN;
- } else if ((th->th_flags & TH_ACK) &&
- (tp->t_mpflags & TMPF_PREESTABLISHED)) {
- struct mptcp_mpjoin_opt_rsp2 *join_rsp2 =
- (struct mptcp_mpjoin_opt_rsp2 *)cp;
-
- if (optlen != sizeof (struct mptcp_mpjoin_opt_rsp2)) {
- mptcplog((LOG_ERR, "MPTCP Socket: "
- "ACK: unexpected optlen = %d mp option "
- "= %lu \n", optlen,
- sizeof (struct mptcp_mpjoin_opt_rsp2)),
- MPTCP_SOCKET_DBG, MPTCP_LOGLVL_ERR);
- tp->t_mpflags &= ~TMPF_PREESTABLISHED;
- /* send RST and close */
- MPTCP_JOPT_ERROR_PATH(tp);
- return;
- }
+ if (optlen != sizeof (struct mptcp_mpjoin_opt_rsp)) {
+ mptcplog((LOG_ERR, "%s: SYN_ACK: unexpected optlen = %d mp "
+ "option = %lu\n", __func__, optlen,
+ sizeof (struct mptcp_mpjoin_opt_rsp)),
+ MPTCP_SOCKET_DBG, MPTCP_LOGLVL_ERR);
+ tp->t_mpflags &= ~TMPF_PREESTABLISHED;
+ /* send RST and close */
+ MPTCP_JOPT_ERROR_PATH(tp);
+ return;
+ }
- error = mptcp_validate_join_hmac(tp, join_rsp2->mmjo_mac,
- SHA1_RESULTLEN);
- if (error) {
- mptcplog((LOG_ERR, "MPTCP Socket: "
- "%s: ACK error = %d\n", __func__, error),
- MPTCP_SOCKET_DBG, MPTCP_LOGLVL_ERR);
- tp->t_mpflags &= ~TMPF_PREESTABLISHED;
- MPTCP_JOPT_ERROR_PATH(tp);
- return;
- }
- tp->t_mpflags |= TMPF_MPTCP_TRUE;
+ mptcp_set_raddr_rand(tp->t_local_aid, tptomptp(tp),
+ join_rsp->mmjo_addr_id, join_rsp->mmjo_rand);
+ error = mptcp_validate_join_hmac(tp,
+ (u_char*)&join_rsp->mmjo_mac, SHA1_TRUNCATED);
+ if (error) {
+ mptcplog((LOG_ERR, "%s: SYN_ACK error = %d \n", __func__, error),
+ MPTCP_SOCKET_DBG, MPTCP_LOGLVL_ERR);
tp->t_mpflags &= ~TMPF_PREESTABLISHED;
- tp->t_flags |= TF_ACKNOW;
- tp->t_mpflags |= TMPF_MPTCP_ACKNOW;
- tp->t_inpcb->inp_socket->so_flags |= SOF_MPTCP_TRUE;
+ /* send RST and close */
+ MPTCP_JOPT_ERROR_PATH(tp);
+ return;
}
+ tp->t_mpflags |= (TMPF_SENT_JOIN | TMPF_SND_JACK);
}
static int
mptcp_validate_join_hmac(struct tcpcb *tp, u_char* hmac, int mac_len)
{
u_char digest[SHA1_RESULTLEN] = {0};
- struct mptcb *mp_tp = NULL;
- mptcp_key_t rem_key, loc_key;
+ struct mptcb *mp_tp = tptomptp(tp);
u_int32_t rem_rand, loc_rand;
- mp_tp = tp->t_mptcb;
+ mpte_lock_assert_held(mp_tp->mpt_mpte);
rem_rand = loc_rand = 0;
- MPT_LOCK(mp_tp);
- rem_key = mp_tp->mpt_remotekey;
- loc_key = *mp_tp->mpt_localkey;
- MPT_UNLOCK(mp_tp);
-
mptcp_get_rands(tp->t_local_aid, mp_tp, &loc_rand, &rem_rand);
if ((rem_rand == 0) || (loc_rand == 0))
return (-1);
- mptcp_hmac_sha1(rem_key, loc_key, rem_rand, loc_rand,
- digest, sizeof (digest));
+ mptcp_hmac_sha1(mp_tp->mpt_remotekey, mp_tp->mpt_localkey, rem_rand, loc_rand,
+ digest);
if (bcmp(digest, hmac, mac_len) == 0)
return (0); /* matches */
else {
printf("%s: remote key %llx local key %llx remote rand %x "
- "local rand %x \n", __func__, rem_key, loc_key,
+ "local rand %x \n", __func__, mp_tp->mpt_remotekey, mp_tp->mpt_localkey,
rem_rand, loc_rand);
return (-1);
}
}
+/*
+ * Update the mptcb send state variables, but the actual sbdrop occurs
+ * in MPTCP layer
+ */
+void
+mptcp_data_ack_rcvd(struct mptcb *mp_tp, struct tcpcb *tp, u_int64_t full_dack)
+{
+ u_int64_t acked = full_dack - mp_tp->mpt_snduna;
+
+ if (acked) {
+ struct socket *mp_so = mptetoso(mp_tp->mpt_mpte);
+
+ if (acked > mp_so->so_snd.sb_cc) {
+ if (acked > mp_so->so_snd.sb_cc + 1 ||
+ mp_tp->mpt_state < MPTCPS_FIN_WAIT_1)
+ mptcplog((LOG_ERR, "%s: acked %u, sb_cc %u full %u suna %u state %u\n",
+ __func__, (uint32_t)acked, mp_so->so_snd.sb_cc,
+ (uint32_t)full_dack, (uint32_t)mp_tp->mpt_snduna,
+ mp_tp->mpt_state),
+ MPTCP_RECEIVER_DBG, MPTCP_LOGLVL_ERR);
+
+ sbdrop(&mp_so->so_snd, (int)mp_so->so_snd.sb_cc);
+ } else {
+ sbdrop(&mp_so->so_snd, acked);
+ }
+
+ mp_tp->mpt_snduna += acked;
+ /* In degraded mode, we may get some Data ACKs */
+ if ((tp->t_mpflags & TMPF_TCP_FALLBACK) &&
+ !(mp_tp->mpt_flags & MPTCPF_POST_FALLBACK_SYNC) &&
+ MPTCP_SEQ_GT(mp_tp->mpt_sndnxt, mp_tp->mpt_snduna)) {
+ /* bring back sndnxt to retransmit MPTCP data */
+ mp_tp->mpt_sndnxt = mp_tp->mpt_dsn_at_csum_fail;
+ mp_tp->mpt_flags |= MPTCPF_POST_FALLBACK_SYNC;
+ tp->t_inpcb->inp_socket->so_flags1 |=
+ SOF1_POST_FALLBACK_SYNC;
+ }
+
+ mptcp_clean_reinjectq(mp_tp->mpt_mpte);
+
+ sowwakeup(mp_so);
+ }
+ if (full_dack == mp_tp->mpt_sndmax &&
+ mp_tp->mpt_state >= MPTCPS_FIN_WAIT_1) {
+ mptcp_close_fsm(mp_tp, MPCE_RECV_DATA_ACK);
+ tp->t_mpflags &= ~TMPF_SEND_DFIN;
+ }
+}
+
+void
+mptcp_update_window_wakeup(struct tcpcb *tp)
+{
+ struct mptcb *mp_tp = tptomptp(tp);
+
+ mpte_lock_assert_held(mp_tp->mpt_mpte);
+
+ if (mp_tp->mpt_flags & MPTCPF_FALLBACK_TO_TCP) {
+ mp_tp->mpt_sndwnd = tp->snd_wnd;
+ mp_tp->mpt_sndwl1 = mp_tp->mpt_rcvnxt;
+ mp_tp->mpt_sndwl2 = mp_tp->mpt_snduna;
+ }
+
+ sowwakeup(tp->t_inpcb->inp_socket);
+}
+
+static void
+mptcp_update_window(struct mptcb *mp_tp, u_int64_t ack, u_int64_t seq, u_int32_t tiwin)
+{
+ if (SEQ_LT(mp_tp->mpt_sndwl1, seq) ||
+ (mp_tp->mpt_sndwl1 == seq &&
+ (SEQ_LT(mp_tp->mpt_sndwl2, ack) ||
+ (mp_tp->mpt_sndwl2 == ack && tiwin > mp_tp->mpt_sndwnd)))) {
+ mp_tp->mpt_sndwnd = tiwin;
+ mp_tp->mpt_sndwl1 = seq;
+ mp_tp->mpt_sndwl2 = ack;
+ }
+}
+
static void
-mptcp_do_dss_opt_ack_meat(u_int64_t full_dack, struct tcpcb *tp)
+mptcp_do_dss_opt_ack_meat(u_int64_t full_dack, u_int64_t full_dsn,
+ struct tcpcb *tp, u_int32_t tiwin)
{
struct mptcb *mp_tp = tptomptp(tp);
int close_notify = 0;
- MPT_LOCK(mp_tp);
+ tp->t_mpflags |= TMPF_RCVD_DACK;
+
if (MPTCP_SEQ_LEQ(full_dack, mp_tp->mpt_sndmax) &&
MPTCP_SEQ_GEQ(full_dack, mp_tp->mpt_snduna)) {
mptcp_data_ack_rcvd(mp_tp, tp, full_dack);
if (mp_tp->mpt_state > MPTCPS_FIN_WAIT_2)
close_notify = 1;
- MPT_UNLOCK(mp_tp);
if (mp_tp->mpt_flags & MPTCPF_RCVD_64BITACK) {
mp_tp->mpt_flags &= ~MPTCPF_RCVD_64BITACK;
mp_tp->mpt_flags &= ~MPTCPF_SND_64BITDSN;
if (close_notify)
mptcp_notify_close(tp->t_inpcb->inp_socket);
} else {
- MPT_UNLOCK(mp_tp);
- mptcplog((LOG_ERR,"MPTCP Socket: "
- "%s: unexpected dack %llx snduna %llx "
- "sndmax %llx\n", __func__, full_dack,
- mp_tp->mpt_snduna, mp_tp->mpt_sndmax),
- (MPTCP_SOCKET_DBG|MPTCP_RECEIVER_DBG),
- MPTCP_LOGLVL_LOG);
+ os_log_error(mptcp_log_handle,
+ "%s: unexpected dack %u snduna %u sndmax %u\n",
+ __func__, (u_int32_t)full_dack,
+ (u_int32_t)mp_tp->mpt_snduna,
+ (u_int32_t)mp_tp->mpt_sndmax);
}
+
+ mptcp_update_window(mp_tp, full_dack, full_dsn, tiwin);
}
static void
-mptcp_do_dss_opt_meat(u_char *cp, struct tcpcb *tp)
+mptcp_do_dss_opt_meat(u_char *cp, struct tcpcb *tp, struct tcphdr *th)
{
struct mptcp_dss_copt *dss_rsp = (struct mptcp_dss_copt *)cp;
u_int64_t full_dack = 0;
+ u_int32_t tiwin = th->th_win << tp->snd_scale;
struct mptcb *mp_tp = tptomptp(tp);
int csum_len = 0;
-#define MPTCP_DSS_OPT_SZ_CHK(len, expected_len) { \
- if (len != expected_len) { \
- mptcplog((LOG_ERR, "MPTCP Socket: " \
- "%s: bad len = %d dss: %x \n", __func__, \
- len, dss_rsp->mdss_flags), \
- (MPTCP_SOCKET_DBG|MPTCP_RECEIVER_DBG), \
- MPTCP_LOGLVL_LOG); \
- return; \
- } \
+#define MPTCP_DSS_OPT_SZ_CHK(len, expected_len) { \
+ if (len != expected_len) { \
+ mptcplog((LOG_ERR, "%s: bad len = %d dss: %x \n", __func__, \
+ len, dss_rsp->mdss_flags), \
+ (MPTCP_SOCKET_DBG|MPTCP_RECEIVER_DBG), \
+ MPTCP_LOGLVL_LOG); \
+ return; \
+ } \
}
- /*
- * mp_tp might become NULL after the call to mptcp_do_fin_opt().
- * Review after rdar://problem/24083886
- */
- if (!mp_tp)
- return;
-
if (mp_tp->mpt_flags & MPTCPF_CHECKSUM)
csum_len = 2;
u_int32_t dack = dack_opt->mdss_ack;
NTOHL(dack);
- MPT_LOCK_SPIN(mp_tp);
MPTCP_EXTEND_DSN(mp_tp->mpt_snduna, dack, full_dack);
- MPT_UNLOCK(mp_tp);
- mptcp_do_dss_opt_ack_meat(full_dack, tp);
+ mptcp_do_dss_opt_ack_meat(full_dack, mp_tp->mpt_sndwl1, tp, tiwin);
break;
}
case (MDSS_M | MDSS_A):
/* 32-bit Data ACK + 32-bit DSS */
struct mptcp_dss_ack_opt *dss_ack_rsp;
dss_ack_rsp = (struct mptcp_dss_ack_opt *)cp;
+ u_int64_t full_dsn;
+ uint16_t csum = 0;
MPTCP_DSS_OPT_SZ_CHK(dss_ack_rsp->mdss_copt.mdss_len,
sizeof (struct mptcp_dss_ack_opt) + csum_len);
u_int32_t dack = dss_ack_rsp->mdss_ack;
NTOHL(dack);
- MPT_LOCK_SPIN(mp_tp);
MPTCP_EXTEND_DSN(mp_tp->mpt_snduna, dack, full_dack);
- MPT_UNLOCK(mp_tp);
- mptcp_do_dss_opt_ack_meat(full_dack, tp);
- if (csum_len == 0)
- mptcp_update_rcv_state_f(dss_ack_rsp, tp, 0);
- else
- mptcp_update_rcv_state_f(dss_ack_rsp, tp,
- *(uint16_t *)(void *)(cp +
- (dss_ack_rsp->mdss_copt.mdss_len -
- csum_len)));
+
+ NTOHL(dss_ack_rsp->mdss_dsn);
+ NTOHL(dss_ack_rsp->mdss_subflow_seqn);
+ NTOHS(dss_ack_rsp->mdss_data_len);
+ MPTCP_EXTEND_DSN(mp_tp->mpt_rcvnxt, dss_ack_rsp->mdss_dsn, full_dsn);
+
+ mptcp_do_dss_opt_ack_meat(full_dack, full_dsn, tp, tiwin);
+
+ if (csum_len != 0)
+ csum = *(uint16_t *)(void *)(cp + (dss_ack_rsp->mdss_copt.mdss_len - csum_len));
+
+ mptcp_update_rcv_state_meat(mp_tp, tp,
+ full_dsn,
+ dss_ack_rsp->mdss_subflow_seqn,
+ dss_ack_rsp->mdss_data_len,
+ csum);
break;
}
case (MDSS_M | MDSS_m):
struct mptcp_dsn64_opt *dsn64;
dsn64 = (struct mptcp_dsn64_opt *)cp;
u_int64_t full_dsn;
+ uint16_t csum = 0;
MPTCP_DSS_OPT_SZ_CHK(dsn64->mdss_copt.mdss_len,
sizeof (struct mptcp_dsn64_opt) + csum_len);
- mptcplog((LOG_DEBUG,"MPTCP Socket: "
- "%s: 64-bit M present.\n", __func__),
- (MPTCP_SOCKET_DBG|MPTCP_RECEIVER_DBG),
- MPTCP_LOGLVL_LOG);
-
- MPT_LOCK_SPIN(mp_tp);
mp_tp->mpt_flags |= MPTCPF_SND_64BITACK;
- MPT_UNLOCK(mp_tp);
full_dsn = mptcp_ntoh64(dsn64->mdss_dsn);
NTOHL(dsn64->mdss_subflow_seqn);
NTOHS(dsn64->mdss_data_len);
- if (csum_len == 0)
- mptcp_update_rcv_state_meat(mp_tp, tp, full_dsn,
- dsn64->mdss_subflow_seqn,
- dsn64->mdss_data_len,
- 0);
- else
- mptcp_update_rcv_state_meat(mp_tp, tp, full_dsn,
- dsn64->mdss_subflow_seqn,
- dsn64->mdss_data_len,
- *(uint16_t *)(void *)(cp +
- dsn64->mdss_copt.mdss_len - csum_len));
+
+ if (csum_len != 0)
+ csum = *(uint16_t *)(void *)(cp + dsn64->mdss_copt.mdss_len - csum_len);
+
+ mptcp_update_rcv_state_meat(mp_tp, tp, full_dsn,
+ dsn64->mdss_subflow_seqn,
+ dsn64->mdss_data_len,
+ csum);
break;
}
case (MDSS_A | MDSS_a):
MPTCP_DSS_OPT_SZ_CHK(dack64->mdss_copt.mdss_len,
sizeof (struct mptcp_data_ack64_opt));
- mptcplog((LOG_DEBUG,"MPTCP Socket: "
- "%s: 64-bit A present. \n", __func__),
- (MPTCP_SOCKET_DBG|MPTCP_RECEIVER_DBG),
- MPTCP_LOGLVL_LOG);
-
- MPT_LOCK_SPIN(mp_tp);
mp_tp->mpt_flags |= MPTCPF_RCVD_64BITACK;
- MPT_UNLOCK(mp_tp);
full_dack = mptcp_ntoh64(dack64->mdss_ack);
- mptcp_do_dss_opt_ack_meat(full_dack, tp);
+ mptcp_do_dss_opt_ack_meat(full_dack, mp_tp->mpt_sndwl1, tp, tiwin);
break;
}
case (MDSS_M | MDSS_m | MDSS_A):
/* 64-bit DSS + 32-bit Data ACK */
struct mptcp_dss64_ack32_opt *dss_ack_rsp;
dss_ack_rsp = (struct mptcp_dss64_ack32_opt *)cp;
+ u_int64_t full_dsn;
+ uint16_t csum = 0;
MPTCP_DSS_OPT_SZ_CHK(dss_ack_rsp->mdss_copt.mdss_len,
sizeof (struct mptcp_dss64_ack32_opt) + csum_len);
- mptcplog((LOG_DEBUG,"MPTCP Socket: "
- "%s: 64-bit M and 32-bit A present.\n", __func__),
- (MPTCP_SOCKET_DBG|MPTCP_RECEIVER_DBG),
- MPTCP_LOGLVL_LOG);
-
u_int32_t dack = dss_ack_rsp->mdss_ack;
NTOHL(dack);
- MPT_LOCK_SPIN(mp_tp);
mp_tp->mpt_flags |= MPTCPF_SND_64BITACK;
MPTCP_EXTEND_DSN(mp_tp->mpt_snduna, dack, full_dack);
- MPT_UNLOCK(mp_tp);
- mptcp_do_dss_opt_ack_meat(full_dack, tp);
- if (csum_len == 0)
- mptcp_update_rcv_state_g(dss_ack_rsp, tp, 0);
- else
- mptcp_update_rcv_state_g(dss_ack_rsp, tp,
- *(uint16_t *)(void *)(cp +
- dss_ack_rsp->mdss_copt.mdss_len -
- csum_len));
+
+ full_dsn = mptcp_ntoh64(dss_ack_rsp->mdss_dsn);
+ NTOHL(dss_ack_rsp->mdss_subflow_seqn);
+ NTOHS(dss_ack_rsp->mdss_data_len);
+
+ mptcp_do_dss_opt_ack_meat(full_dack, full_dsn, tp, tiwin);
+
+ if (csum_len != 0)
+ csum = *(uint16_t *)(void *)(cp + dss_ack_rsp->mdss_copt.mdss_len - csum_len);
+
+ mptcp_update_rcv_state_meat(mp_tp, tp, full_dsn,
+ dss_ack_rsp->mdss_subflow_seqn,
+ dss_ack_rsp->mdss_data_len,
+ csum);
+
break;
}
case (MDSS_M | MDSS_A | MDSS_a):
dss32_ack64_opt->mdss_copt.mdss_len,
sizeof (struct mptcp_dss32_ack64_opt) + csum_len);
- mptcplog((LOG_DEBUG,"MPTCP Socket: "
- "%s: 32-bit M and 64-bit A present.\n", __func__),
- (MPTCP_SOCKET_DBG|MPTCP_RECEIVER_DBG),
- MPTCP_LOGLVL_LOG);
-
full_dack = mptcp_ntoh64(dss32_ack64_opt->mdss_ack);
- mptcp_do_dss_opt_ack_meat(full_dack, tp);
NTOHL(dss32_ack64_opt->mdss_dsn);
- MPT_LOCK_SPIN(mp_tp);
mp_tp->mpt_flags |= MPTCPF_RCVD_64BITACK;
MPTCP_EXTEND_DSN(mp_tp->mpt_rcvnxt,
dss32_ack64_opt->mdss_dsn, full_dsn);
- MPT_UNLOCK(mp_tp);
NTOHL(dss32_ack64_opt->mdss_subflow_seqn);
NTOHS(dss32_ack64_opt->mdss_data_len);
+
+ mptcp_do_dss_opt_ack_meat(full_dack, full_dsn, tp, tiwin);
if (csum_len == 0)
mptcp_update_rcv_state_meat(mp_tp, tp, full_dsn,
dss32_ack64_opt->mdss_subflow_seqn,
MPTCP_DSS_OPT_SZ_CHK(dss64_ack64->mdss_copt.mdss_len,
sizeof (struct mptcp_dss64_ack64_opt) + csum_len);
- mptcplog((LOG_DEBUG,"MPTCP Socket: "
- "%s: 64-bit M and 64-bit A present.\n", __func__),
- (MPTCP_SOCKET_DBG|MPTCP_RECEIVER_DBG),
- MPTCP_LOGLVL_LOG);
-
- MPT_LOCK_SPIN(mp_tp);
mp_tp->mpt_flags |= MPTCPF_RCVD_64BITACK;
mp_tp->mpt_flags |= MPTCPF_SND_64BITACK;
- MPT_UNLOCK(mp_tp);
full_dsn = mptcp_ntoh64(dss64_ack64->mdss_dsn);
full_dack = mptcp_ntoh64(dss64_ack64->mdss_dsn);
- mptcp_do_dss_opt_ack_meat(full_dack, tp);
+ mptcp_do_dss_opt_ack_meat(full_dack, full_dsn, tp, tiwin);
NTOHL(dss64_ack64->mdss_subflow_seqn);
NTOHS(dss64_ack64->mdss_data_len);
if (csum_len == 0)
break;
}
default:
- mptcplog((LOG_DEBUG,"MPTCP Socket: "
- "%s: File bug, DSS flags = %x\n", __func__,
- dss_rsp->mdss_flags),
+ mptcplog((LOG_DEBUG,"%s: File bug, DSS flags = %x\n",
+ __func__, dss_rsp->mdss_flags),
(MPTCP_SOCKET_DBG|MPTCP_RECEIVER_DBG),
MPTCP_LOGLVL_LOG);
break;
}
}
-
-static void
-mptcp_do_fin_opt(struct tcpcb *tp)
-{
- struct mptcb *mp_tp = (struct mptcb *)tp->t_mptcb;
-
- mptcplog((LOG_DEBUG,"MPTCP Socket: %s \n", __func__),
- (MPTCP_SOCKET_DBG|MPTCP_RECEIVER_DBG),
- MPTCP_LOGLVL_LOG);
-
- if (!(tp->t_mpflags & TMPF_RECV_DFIN)) {
- if (mp_tp != NULL) {
- MPT_LOCK(mp_tp);
- mptcp_close_fsm(mp_tp, MPCE_RECV_DATA_FIN);
- MPT_UNLOCK(mp_tp);
-
- if (tp->t_inpcb->inp_socket != NULL) {
- soevent(tp->t_inpcb->inp_socket,
- SO_FILT_HINT_LOCKED |
- SO_FILT_HINT_MPCANTRCVMORE);
- }
-
- }
- tp->t_mpflags |= TMPF_RECV_DFIN;
- }
-
- tp->t_mpflags |= TMPF_MPTCP_ACKNOW;
- /*
- * Since this is a data level FIN, TCP needs to be explicitly told
- * to send back an ACK on which the Data ACK is piggybacked.
- */
- tp->t_flags |= TF_ACKNOW;
-}
-
static void
mptcp_do_dss_opt(struct tcpcb *tp, u_char *cp, struct tcphdr *th, int optlen)
{
-#pragma unused(th, optlen)
- struct mptcb *mp_tp = (struct mptcb *)tp->t_mptcb;
+#pragma unused(optlen)
+ struct mptcb *mp_tp = tptomptp(tp);
if (!mp_tp)
return;
struct mptcp_dss_copt *dss_rsp = (struct mptcp_dss_copt *)cp;
if (dss_rsp->mdss_subtype == MPO_DSS) {
- if (dss_rsp->mdss_flags & MDSS_F) {
- mptcp_do_fin_opt(tp);
- }
+ if (dss_rsp->mdss_flags & MDSS_F)
+ tp->t_rcv_map.mpt_dfin = 1;
- mptcp_do_dss_opt_meat(cp, tp);
+ mptcp_do_dss_opt_meat(cp, tp, th);
}
}
}
if (th->th_flags != TH_ACK)
return;
- mptcplog((LOG_DEBUG,"MPTCP Socket: %s: \n", __func__),
- (MPTCP_SOCKET_DBG|MPTCP_RECEIVER_DBG),
- MPTCP_LOGLVL_LOG);
-
if (fc_opt->mfast_len != sizeof (struct mptcp_fastclose_opt)) {
tcpstat.tcps_invalid_opt++;
return;
}
- mp_tp = (struct mptcb *)tp->t_mptcb;
+ mp_tp = tptomptp(tp);
if (!mp_tp)
return;
- if (fc_opt->mfast_key != mptcp_get_localkey(mp_tp)) {
+ if (fc_opt->mfast_key != mp_tp->mpt_localkey) {
tcpstat.tcps_invalid_opt++;
return;
}
}
/* Reset this flow */
- tp->t_mpflags |= TMPF_RESET;
+ tp->t_mpflags |= (TMPF_RESET | TMPF_FASTCLOSERCV);
if (tp->t_inpcb->inp_socket != NULL) {
soevent(tp->t_inpcb->inp_socket,
if ((th->th_flags != TH_ACK) && (th->th_flags != TH_RST))
return;
- mptcplog((LOG_DEBUG, "MPTCP Socket: %s: \n", __func__),
- (MPTCP_SOCKET_DBG|MPTCP_RECEIVER_DBG), MPTCP_LOGLVL_LOG);
-
if (fail_opt->mfail_len != sizeof (struct mptcp_mpfail_opt))
return;
- mp_tp = (struct mptcb *)tp->t_mptcb;
- MPT_LOCK(mp_tp);
+ mp_tp = tptomptp(tp);
+
mp_tp->mpt_flags |= MPTCPF_RECVD_MPFAIL;
mp_tp->mpt_dsn_at_csum_fail = mptcp_hton64(fail_opt->mfail_dsn);
- MPT_UNLOCK(mp_tp);
- error = mptcp_get_map_for_dsn(tp->t_inpcb->inp_socket,
+ error = mptcp_get_map_for_dsn(tp->t_inpcb->inp_socket,
mp_tp->mpt_dsn_at_csum_fail, &mdss_subflow_seqn);
if (error == 0) {
mp_tp->mpt_ssn_at_csum_fail = mdss_subflow_seqn;
struct tcpopt *to, int optlen)
{
int mptcp_subtype;
+ struct mptcb *mp_tp = tptomptp(tp);
+
+ if (mp_tp == NULL)
+ return;
+
+ mpte_lock_assert_held(mp_tp->mpt_mpte);
/* All MPTCP options have atleast 4 bytes */
if (optlen < 4)
return;
}
-/*
- * MPTCP ADD_ADDR and REMOVE_ADDR options
- */
-
-/*
- * ADD_ADDR is only placeholder code - not sent on wire
- * The ADD_ADDR option is not sent on wire because of security issues
- * around connection hijacking.
- */
-void
-mptcp_send_addaddr_opt(struct tcpcb *tp, struct mptcp_addaddr_opt *opt)
-{
-
- opt->ma_kind = TCPOPT_MULTIPATH;
- opt->ma_len = sizeof (struct mptcp_addaddr_opt);
- opt->ma_subtype = MPO_ADD_ADDR;
- opt->ma_addr_id = tp->t_local_aid;
-#ifdef MPTCP_NOTYET
- struct inpcb *inp = tp->t_inpcb;
- if (inp->inp_vflag == AF_INET) {
- opt->ma_ipver = MA_IPVer_V4;
- bcopy((char *)&sin->sin_addr.s_addr, (char *)opt + opt->ma_len,
- sizeof (in_addr_t));
- opt->ma_len += sizeof (in_addr_t);
- } else if (inp->inp_vflag == AF_INET6) {
- opt->ma_ipver = MA_IPVer_V6;
- bcopy((char *)&sin6->sin6_addr, (char *)opt + opt->ma_len,
- sizeof (struct in6_addr));
- opt->ma_len += sizeof (struct in6_addr);
- }
-#if 0
- if (tp->t_mp_port) {
- /* add ports XXX */
- }
-#endif
-#endif
-}
-
/* REMOVE_ADDR option is sent when a source address goes away */
-void
+static void
mptcp_send_remaddr_opt(struct tcpcb *tp, struct mptcp_remaddr_opt *opt)
{
- mptcplog((LOG_DEBUG,"MPTCP Socket: %s: local id %d remove id %d \n",
+ mptcplog((LOG_DEBUG,"%s: local id %d remove id %d \n",
__func__, tp->t_local_aid, tp->t_rem_aid),
(MPTCP_SOCKET_DBG|MPTCP_SENDER_DBG), MPTCP_LOGLVL_LOG);
tp->t_mpflags &= ~TMPF_SND_REM_ADDR;
}
-/*
- * MPTCP MP_PRIO option
- */
-
-#if 0
-/*
- * Current implementation drops incoming MP_PRIO option and this code is
- * just a placeholder. The option is dropped because only the mobile client can
- * decide which of the subflows is preferred (usually wifi is preferred
- * over Cellular).
- */
-void
-mptcp_do_mpprio_opt(struct tcpcb *tp, u_char *cp, struct tcphdr *th,
- int optlen)
-{
- int bkp = 0;
- struct mptcp_mpprio_opt *mpprio = (struct mptcp_mpprio_opt *)cp;
-
- if ((tp == NULL) || !(tp->t_mpflags & TMPF_MPTCP_TRUE))
- return;
-
- if ((mpprio->mpprio_len != sizeof (struct mptcp_mpprio_addr_opt)) &&
- (mpprio->mpprio_len != sizeof (struct mptcp_mpprio_opt)))
- return;
-}
-#endif
-
/* We send MP_PRIO option based on the values set by the SIOCSCONNORDER ioctl */
static int
mptcp_snd_mpprio(struct tcpcb *tp, u_char *cp, int optlen)
return (optlen);
}
- if (mptcp_mpprio_enable != 1) {
- tp->t_mpflags &= ~TMPF_SND_MPPRIO;
- return (optlen);
- }
-
if ((MAX_TCPOPTLEN - optlen) <
(int)sizeof (mpprio))
return (optlen);
memcpy(cp + optlen, &mpprio, sizeof (mpprio));
optlen += sizeof (mpprio);
tp->t_mpflags &= ~TMPF_SND_MPPRIO;
- mptcplog((LOG_DEBUG, "MPTCP Socket: %s: aid = %d \n", __func__,
+ mptcplog((LOG_DEBUG, "%s: aid = %d \n", __func__,
tp->t_local_aid),
(MPTCP_SOCKET_DBG|MPTCP_SENDER_DBG), MPTCP_LOGLVL_LOG);
return (optlen);
}
+