162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* Multipath TCP 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Copyright (c) 2017 - 2019, Intel Corporation. 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#define pr_fmt(fmt) "MPTCP: " fmt 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <linux/kernel.h> 1062306a36Sopenharmony_ci#include <crypto/sha2.h> 1162306a36Sopenharmony_ci#include <net/tcp.h> 1262306a36Sopenharmony_ci#include <net/mptcp.h> 1362306a36Sopenharmony_ci#include "protocol.h" 1462306a36Sopenharmony_ci#include "mib.h" 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci#include <trace/events/mptcp.h> 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_cistatic bool mptcp_cap_flag_sha256(u8 flags) 1962306a36Sopenharmony_ci{ 2062306a36Sopenharmony_ci return (flags & MPTCP_CAP_FLAG_MASK) == MPTCP_CAP_HMAC_SHA256; 2162306a36Sopenharmony_ci} 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_cistatic void mptcp_parse_option(const struct sk_buff *skb, 2462306a36Sopenharmony_ci const unsigned char *ptr, int opsize, 2562306a36Sopenharmony_ci struct mptcp_options_received *mp_opt) 2662306a36Sopenharmony_ci{ 2762306a36Sopenharmony_ci u8 subtype = *ptr >> 4; 2862306a36Sopenharmony_ci int expected_opsize; 2962306a36Sopenharmony_ci u16 subopt; 3062306a36Sopenharmony_ci u8 version; 3162306a36Sopenharmony_ci u8 flags; 3262306a36Sopenharmony_ci u8 i; 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci switch (subtype) { 3562306a36Sopenharmony_ci case MPTCPOPT_MP_CAPABLE: 3662306a36Sopenharmony_ci /* strict size checking */ 3762306a36Sopenharmony_ci if (!(TCP_SKB_CB(skb)->tcp_flags & TCPHDR_SYN)) { 3862306a36Sopenharmony_ci if (skb->len > tcp_hdr(skb)->doff << 2) 3962306a36Sopenharmony_ci expected_opsize = TCPOLEN_MPTCP_MPC_ACK_DATA; 4062306a36Sopenharmony_ci else 4162306a36Sopenharmony_ci expected_opsize = TCPOLEN_MPTCP_MPC_ACK; 4262306a36Sopenharmony_ci subopt = OPTION_MPTCP_MPC_ACK; 4362306a36Sopenharmony_ci } else { 4462306a36Sopenharmony_ci if (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_ACK) { 4562306a36Sopenharmony_ci expected_opsize = TCPOLEN_MPTCP_MPC_SYNACK; 4662306a36Sopenharmony_ci subopt = OPTION_MPTCP_MPC_SYNACK; 4762306a36Sopenharmony_ci } else { 4862306a36Sopenharmony_ci expected_opsize = TCPOLEN_MPTCP_MPC_SYN; 4962306a36Sopenharmony_ci subopt = OPTION_MPTCP_MPC_SYN; 5062306a36Sopenharmony_ci } 5162306a36Sopenharmony_ci } 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci /* Cfr RFC 8684 Section 3.3.0: 5462306a36Sopenharmony_ci * If a checksum is present but its use had 5562306a36Sopenharmony_ci * not been negotiated in the MP_CAPABLE handshake, the receiver MUST 5662306a36Sopenharmony_ci * close the subflow with a RST, as it is not behaving as negotiated. 5762306a36Sopenharmony_ci * If a checksum is not present when its use has been negotiated, the 5862306a36Sopenharmony_ci * receiver MUST close the subflow with a RST, as it is considered 5962306a36Sopenharmony_ci * broken 6062306a36Sopenharmony_ci * We parse even option with mismatching csum presence, so that 6162306a36Sopenharmony_ci * later in subflow_data_ready we can trigger the reset. 6262306a36Sopenharmony_ci */ 6362306a36Sopenharmony_ci if (opsize != expected_opsize && 6462306a36Sopenharmony_ci (expected_opsize != TCPOLEN_MPTCP_MPC_ACK_DATA || 6562306a36Sopenharmony_ci opsize != TCPOLEN_MPTCP_MPC_ACK_DATA_CSUM)) 6662306a36Sopenharmony_ci break; 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci /* try to be gentle vs future versions on the initial syn */ 6962306a36Sopenharmony_ci version = *ptr++ & MPTCP_VERSION_MASK; 7062306a36Sopenharmony_ci if (opsize != TCPOLEN_MPTCP_MPC_SYN) { 7162306a36Sopenharmony_ci if (version != MPTCP_SUPPORTED_VERSION) 7262306a36Sopenharmony_ci break; 7362306a36Sopenharmony_ci } else if (version < MPTCP_SUPPORTED_VERSION) { 7462306a36Sopenharmony_ci break; 7562306a36Sopenharmony_ci } 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci flags = *ptr++; 7862306a36Sopenharmony_ci if (!mptcp_cap_flag_sha256(flags) || 7962306a36Sopenharmony_ci (flags & MPTCP_CAP_EXTENSIBILITY)) 8062306a36Sopenharmony_ci break; 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci /* RFC 6824, Section 3.1: 8362306a36Sopenharmony_ci * "For the Checksum Required bit (labeled "A"), if either 8462306a36Sopenharmony_ci * host requires the use of checksums, checksums MUST be used. 8562306a36Sopenharmony_ci * In other words, the only way for checksums not to be used 8662306a36Sopenharmony_ci * is if both hosts in their SYNs set A=0." 8762306a36Sopenharmony_ci */ 8862306a36Sopenharmony_ci if (flags & MPTCP_CAP_CHECKSUM_REQD) 8962306a36Sopenharmony_ci mp_opt->suboptions |= OPTION_MPTCP_CSUMREQD; 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci mp_opt->deny_join_id0 = !!(flags & MPTCP_CAP_DENY_JOIN_ID0); 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci mp_opt->suboptions |= subopt; 9462306a36Sopenharmony_ci if (opsize >= TCPOLEN_MPTCP_MPC_SYNACK) { 9562306a36Sopenharmony_ci mp_opt->sndr_key = get_unaligned_be64(ptr); 9662306a36Sopenharmony_ci ptr += 8; 9762306a36Sopenharmony_ci } 9862306a36Sopenharmony_ci if (opsize >= TCPOLEN_MPTCP_MPC_ACK) { 9962306a36Sopenharmony_ci mp_opt->rcvr_key = get_unaligned_be64(ptr); 10062306a36Sopenharmony_ci ptr += 8; 10162306a36Sopenharmony_ci } 10262306a36Sopenharmony_ci if (opsize >= TCPOLEN_MPTCP_MPC_ACK_DATA) { 10362306a36Sopenharmony_ci /* Section 3.1.: 10462306a36Sopenharmony_ci * "the data parameters in a MP_CAPABLE are semantically 10562306a36Sopenharmony_ci * equivalent to those in a DSS option and can be used 10662306a36Sopenharmony_ci * interchangeably." 10762306a36Sopenharmony_ci */ 10862306a36Sopenharmony_ci mp_opt->suboptions |= OPTION_MPTCP_DSS; 10962306a36Sopenharmony_ci mp_opt->use_map = 1; 11062306a36Sopenharmony_ci mp_opt->mpc_map = 1; 11162306a36Sopenharmony_ci mp_opt->use_ack = 0; 11262306a36Sopenharmony_ci mp_opt->data_len = get_unaligned_be16(ptr); 11362306a36Sopenharmony_ci ptr += 2; 11462306a36Sopenharmony_ci } 11562306a36Sopenharmony_ci if (opsize == TCPOLEN_MPTCP_MPC_ACK_DATA_CSUM) { 11662306a36Sopenharmony_ci mp_opt->csum = get_unaligned((__force __sum16 *)ptr); 11762306a36Sopenharmony_ci mp_opt->suboptions |= OPTION_MPTCP_CSUMREQD; 11862306a36Sopenharmony_ci ptr += 2; 11962306a36Sopenharmony_ci } 12062306a36Sopenharmony_ci pr_debug("MP_CAPABLE version=%x, flags=%x, optlen=%d sndr=%llu, rcvr=%llu len=%d csum=%u", 12162306a36Sopenharmony_ci version, flags, opsize, mp_opt->sndr_key, 12262306a36Sopenharmony_ci mp_opt->rcvr_key, mp_opt->data_len, mp_opt->csum); 12362306a36Sopenharmony_ci break; 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci case MPTCPOPT_MP_JOIN: 12662306a36Sopenharmony_ci if (opsize == TCPOLEN_MPTCP_MPJ_SYN) { 12762306a36Sopenharmony_ci mp_opt->suboptions |= OPTION_MPTCP_MPJ_SYN; 12862306a36Sopenharmony_ci mp_opt->backup = *ptr++ & MPTCPOPT_BACKUP; 12962306a36Sopenharmony_ci mp_opt->join_id = *ptr++; 13062306a36Sopenharmony_ci mp_opt->token = get_unaligned_be32(ptr); 13162306a36Sopenharmony_ci ptr += 4; 13262306a36Sopenharmony_ci mp_opt->nonce = get_unaligned_be32(ptr); 13362306a36Sopenharmony_ci ptr += 4; 13462306a36Sopenharmony_ci pr_debug("MP_JOIN bkup=%u, id=%u, token=%u, nonce=%u", 13562306a36Sopenharmony_ci mp_opt->backup, mp_opt->join_id, 13662306a36Sopenharmony_ci mp_opt->token, mp_opt->nonce); 13762306a36Sopenharmony_ci } else if (opsize == TCPOLEN_MPTCP_MPJ_SYNACK) { 13862306a36Sopenharmony_ci mp_opt->suboptions |= OPTION_MPTCP_MPJ_SYNACK; 13962306a36Sopenharmony_ci mp_opt->backup = *ptr++ & MPTCPOPT_BACKUP; 14062306a36Sopenharmony_ci mp_opt->join_id = *ptr++; 14162306a36Sopenharmony_ci mp_opt->thmac = get_unaligned_be64(ptr); 14262306a36Sopenharmony_ci ptr += 8; 14362306a36Sopenharmony_ci mp_opt->nonce = get_unaligned_be32(ptr); 14462306a36Sopenharmony_ci ptr += 4; 14562306a36Sopenharmony_ci pr_debug("MP_JOIN bkup=%u, id=%u, thmac=%llu, nonce=%u", 14662306a36Sopenharmony_ci mp_opt->backup, mp_opt->join_id, 14762306a36Sopenharmony_ci mp_opt->thmac, mp_opt->nonce); 14862306a36Sopenharmony_ci } else if (opsize == TCPOLEN_MPTCP_MPJ_ACK) { 14962306a36Sopenharmony_ci mp_opt->suboptions |= OPTION_MPTCP_MPJ_ACK; 15062306a36Sopenharmony_ci ptr += 2; 15162306a36Sopenharmony_ci memcpy(mp_opt->hmac, ptr, MPTCPOPT_HMAC_LEN); 15262306a36Sopenharmony_ci pr_debug("MP_JOIN hmac"); 15362306a36Sopenharmony_ci } 15462306a36Sopenharmony_ci break; 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci case MPTCPOPT_DSS: 15762306a36Sopenharmony_ci pr_debug("DSS"); 15862306a36Sopenharmony_ci ptr++; 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci /* we must clear 'mpc_map' be able to detect MP_CAPABLE 16162306a36Sopenharmony_ci * map vs DSS map in mptcp_incoming_options(), and reconstruct 16262306a36Sopenharmony_ci * map info accordingly 16362306a36Sopenharmony_ci */ 16462306a36Sopenharmony_ci mp_opt->mpc_map = 0; 16562306a36Sopenharmony_ci flags = (*ptr++) & MPTCP_DSS_FLAG_MASK; 16662306a36Sopenharmony_ci mp_opt->data_fin = (flags & MPTCP_DSS_DATA_FIN) != 0; 16762306a36Sopenharmony_ci mp_opt->dsn64 = (flags & MPTCP_DSS_DSN64) != 0; 16862306a36Sopenharmony_ci mp_opt->use_map = (flags & MPTCP_DSS_HAS_MAP) != 0; 16962306a36Sopenharmony_ci mp_opt->ack64 = (flags & MPTCP_DSS_ACK64) != 0; 17062306a36Sopenharmony_ci mp_opt->use_ack = (flags & MPTCP_DSS_HAS_ACK); 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci pr_debug("data_fin=%d dsn64=%d use_map=%d ack64=%d use_ack=%d", 17362306a36Sopenharmony_ci mp_opt->data_fin, mp_opt->dsn64, 17462306a36Sopenharmony_ci mp_opt->use_map, mp_opt->ack64, 17562306a36Sopenharmony_ci mp_opt->use_ack); 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci expected_opsize = TCPOLEN_MPTCP_DSS_BASE; 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci if (mp_opt->use_ack) { 18062306a36Sopenharmony_ci if (mp_opt->ack64) 18162306a36Sopenharmony_ci expected_opsize += TCPOLEN_MPTCP_DSS_ACK64; 18262306a36Sopenharmony_ci else 18362306a36Sopenharmony_ci expected_opsize += TCPOLEN_MPTCP_DSS_ACK32; 18462306a36Sopenharmony_ci } 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci if (mp_opt->use_map) { 18762306a36Sopenharmony_ci if (mp_opt->dsn64) 18862306a36Sopenharmony_ci expected_opsize += TCPOLEN_MPTCP_DSS_MAP64; 18962306a36Sopenharmony_ci else 19062306a36Sopenharmony_ci expected_opsize += TCPOLEN_MPTCP_DSS_MAP32; 19162306a36Sopenharmony_ci } 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci /* Always parse any csum presence combination, we will enforce 19462306a36Sopenharmony_ci * RFC 8684 Section 3.3.0 checks later in subflow_data_ready 19562306a36Sopenharmony_ci */ 19662306a36Sopenharmony_ci if (opsize != expected_opsize && 19762306a36Sopenharmony_ci opsize != expected_opsize + TCPOLEN_MPTCP_DSS_CHECKSUM) 19862306a36Sopenharmony_ci break; 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci mp_opt->suboptions |= OPTION_MPTCP_DSS; 20162306a36Sopenharmony_ci if (mp_opt->use_ack) { 20262306a36Sopenharmony_ci if (mp_opt->ack64) { 20362306a36Sopenharmony_ci mp_opt->data_ack = get_unaligned_be64(ptr); 20462306a36Sopenharmony_ci ptr += 8; 20562306a36Sopenharmony_ci } else { 20662306a36Sopenharmony_ci mp_opt->data_ack = get_unaligned_be32(ptr); 20762306a36Sopenharmony_ci ptr += 4; 20862306a36Sopenharmony_ci } 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci pr_debug("data_ack=%llu", mp_opt->data_ack); 21162306a36Sopenharmony_ci } 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci if (mp_opt->use_map) { 21462306a36Sopenharmony_ci if (mp_opt->dsn64) { 21562306a36Sopenharmony_ci mp_opt->data_seq = get_unaligned_be64(ptr); 21662306a36Sopenharmony_ci ptr += 8; 21762306a36Sopenharmony_ci } else { 21862306a36Sopenharmony_ci mp_opt->data_seq = get_unaligned_be32(ptr); 21962306a36Sopenharmony_ci ptr += 4; 22062306a36Sopenharmony_ci } 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci mp_opt->subflow_seq = get_unaligned_be32(ptr); 22362306a36Sopenharmony_ci ptr += 4; 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci mp_opt->data_len = get_unaligned_be16(ptr); 22662306a36Sopenharmony_ci ptr += 2; 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci if (opsize == expected_opsize + TCPOLEN_MPTCP_DSS_CHECKSUM) { 22962306a36Sopenharmony_ci mp_opt->suboptions |= OPTION_MPTCP_CSUMREQD; 23062306a36Sopenharmony_ci mp_opt->csum = get_unaligned((__force __sum16 *)ptr); 23162306a36Sopenharmony_ci ptr += 2; 23262306a36Sopenharmony_ci } 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci pr_debug("data_seq=%llu subflow_seq=%u data_len=%u csum=%d:%u", 23562306a36Sopenharmony_ci mp_opt->data_seq, mp_opt->subflow_seq, 23662306a36Sopenharmony_ci mp_opt->data_len, !!(mp_opt->suboptions & OPTION_MPTCP_CSUMREQD), 23762306a36Sopenharmony_ci mp_opt->csum); 23862306a36Sopenharmony_ci } 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci break; 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci case MPTCPOPT_ADD_ADDR: 24362306a36Sopenharmony_ci mp_opt->echo = (*ptr++) & MPTCP_ADDR_ECHO; 24462306a36Sopenharmony_ci if (!mp_opt->echo) { 24562306a36Sopenharmony_ci if (opsize == TCPOLEN_MPTCP_ADD_ADDR || 24662306a36Sopenharmony_ci opsize == TCPOLEN_MPTCP_ADD_ADDR_PORT) 24762306a36Sopenharmony_ci mp_opt->addr.family = AF_INET; 24862306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_MPTCP_IPV6) 24962306a36Sopenharmony_ci else if (opsize == TCPOLEN_MPTCP_ADD_ADDR6 || 25062306a36Sopenharmony_ci opsize == TCPOLEN_MPTCP_ADD_ADDR6_PORT) 25162306a36Sopenharmony_ci mp_opt->addr.family = AF_INET6; 25262306a36Sopenharmony_ci#endif 25362306a36Sopenharmony_ci else 25462306a36Sopenharmony_ci break; 25562306a36Sopenharmony_ci } else { 25662306a36Sopenharmony_ci if (opsize == TCPOLEN_MPTCP_ADD_ADDR_BASE || 25762306a36Sopenharmony_ci opsize == TCPOLEN_MPTCP_ADD_ADDR_BASE_PORT) 25862306a36Sopenharmony_ci mp_opt->addr.family = AF_INET; 25962306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_MPTCP_IPV6) 26062306a36Sopenharmony_ci else if (opsize == TCPOLEN_MPTCP_ADD_ADDR6_BASE || 26162306a36Sopenharmony_ci opsize == TCPOLEN_MPTCP_ADD_ADDR6_BASE_PORT) 26262306a36Sopenharmony_ci mp_opt->addr.family = AF_INET6; 26362306a36Sopenharmony_ci#endif 26462306a36Sopenharmony_ci else 26562306a36Sopenharmony_ci break; 26662306a36Sopenharmony_ci } 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci mp_opt->suboptions |= OPTION_MPTCP_ADD_ADDR; 26962306a36Sopenharmony_ci mp_opt->addr.id = *ptr++; 27062306a36Sopenharmony_ci mp_opt->addr.port = 0; 27162306a36Sopenharmony_ci mp_opt->ahmac = 0; 27262306a36Sopenharmony_ci if (mp_opt->addr.family == AF_INET) { 27362306a36Sopenharmony_ci memcpy((u8 *)&mp_opt->addr.addr.s_addr, (u8 *)ptr, 4); 27462306a36Sopenharmony_ci ptr += 4; 27562306a36Sopenharmony_ci if (opsize == TCPOLEN_MPTCP_ADD_ADDR_PORT || 27662306a36Sopenharmony_ci opsize == TCPOLEN_MPTCP_ADD_ADDR_BASE_PORT) { 27762306a36Sopenharmony_ci mp_opt->addr.port = htons(get_unaligned_be16(ptr)); 27862306a36Sopenharmony_ci ptr += 2; 27962306a36Sopenharmony_ci } 28062306a36Sopenharmony_ci } 28162306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_MPTCP_IPV6) 28262306a36Sopenharmony_ci else { 28362306a36Sopenharmony_ci memcpy(mp_opt->addr.addr6.s6_addr, (u8 *)ptr, 16); 28462306a36Sopenharmony_ci ptr += 16; 28562306a36Sopenharmony_ci if (opsize == TCPOLEN_MPTCP_ADD_ADDR6_PORT || 28662306a36Sopenharmony_ci opsize == TCPOLEN_MPTCP_ADD_ADDR6_BASE_PORT) { 28762306a36Sopenharmony_ci mp_opt->addr.port = htons(get_unaligned_be16(ptr)); 28862306a36Sopenharmony_ci ptr += 2; 28962306a36Sopenharmony_ci } 29062306a36Sopenharmony_ci } 29162306a36Sopenharmony_ci#endif 29262306a36Sopenharmony_ci if (!mp_opt->echo) { 29362306a36Sopenharmony_ci mp_opt->ahmac = get_unaligned_be64(ptr); 29462306a36Sopenharmony_ci ptr += 8; 29562306a36Sopenharmony_ci } 29662306a36Sopenharmony_ci pr_debug("ADD_ADDR%s: id=%d, ahmac=%llu, echo=%d, port=%d", 29762306a36Sopenharmony_ci (mp_opt->addr.family == AF_INET6) ? "6" : "", 29862306a36Sopenharmony_ci mp_opt->addr.id, mp_opt->ahmac, mp_opt->echo, ntohs(mp_opt->addr.port)); 29962306a36Sopenharmony_ci break; 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci case MPTCPOPT_RM_ADDR: 30262306a36Sopenharmony_ci if (opsize < TCPOLEN_MPTCP_RM_ADDR_BASE + 1 || 30362306a36Sopenharmony_ci opsize > TCPOLEN_MPTCP_RM_ADDR_BASE + MPTCP_RM_IDS_MAX) 30462306a36Sopenharmony_ci break; 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci ptr++; 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci mp_opt->suboptions |= OPTION_MPTCP_RM_ADDR; 30962306a36Sopenharmony_ci mp_opt->rm_list.nr = opsize - TCPOLEN_MPTCP_RM_ADDR_BASE; 31062306a36Sopenharmony_ci for (i = 0; i < mp_opt->rm_list.nr; i++) 31162306a36Sopenharmony_ci mp_opt->rm_list.ids[i] = *ptr++; 31262306a36Sopenharmony_ci pr_debug("RM_ADDR: rm_list_nr=%d", mp_opt->rm_list.nr); 31362306a36Sopenharmony_ci break; 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci case MPTCPOPT_MP_PRIO: 31662306a36Sopenharmony_ci if (opsize != TCPOLEN_MPTCP_PRIO) 31762306a36Sopenharmony_ci break; 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci mp_opt->suboptions |= OPTION_MPTCP_PRIO; 32062306a36Sopenharmony_ci mp_opt->backup = *ptr++ & MPTCP_PRIO_BKUP; 32162306a36Sopenharmony_ci pr_debug("MP_PRIO: prio=%d", mp_opt->backup); 32262306a36Sopenharmony_ci break; 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci case MPTCPOPT_MP_FASTCLOSE: 32562306a36Sopenharmony_ci if (opsize != TCPOLEN_MPTCP_FASTCLOSE) 32662306a36Sopenharmony_ci break; 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci ptr += 2; 32962306a36Sopenharmony_ci mp_opt->rcvr_key = get_unaligned_be64(ptr); 33062306a36Sopenharmony_ci ptr += 8; 33162306a36Sopenharmony_ci mp_opt->suboptions |= OPTION_MPTCP_FASTCLOSE; 33262306a36Sopenharmony_ci pr_debug("MP_FASTCLOSE: recv_key=%llu", mp_opt->rcvr_key); 33362306a36Sopenharmony_ci break; 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci case MPTCPOPT_RST: 33662306a36Sopenharmony_ci if (opsize != TCPOLEN_MPTCP_RST) 33762306a36Sopenharmony_ci break; 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci if (!(TCP_SKB_CB(skb)->tcp_flags & TCPHDR_RST)) 34062306a36Sopenharmony_ci break; 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci mp_opt->suboptions |= OPTION_MPTCP_RST; 34362306a36Sopenharmony_ci flags = *ptr++; 34462306a36Sopenharmony_ci mp_opt->reset_transient = flags & MPTCP_RST_TRANSIENT; 34562306a36Sopenharmony_ci mp_opt->reset_reason = *ptr; 34662306a36Sopenharmony_ci pr_debug("MP_RST: transient=%u reason=%u", 34762306a36Sopenharmony_ci mp_opt->reset_transient, mp_opt->reset_reason); 34862306a36Sopenharmony_ci break; 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci case MPTCPOPT_MP_FAIL: 35162306a36Sopenharmony_ci if (opsize != TCPOLEN_MPTCP_FAIL) 35262306a36Sopenharmony_ci break; 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci ptr += 2; 35562306a36Sopenharmony_ci mp_opt->suboptions |= OPTION_MPTCP_FAIL; 35662306a36Sopenharmony_ci mp_opt->fail_seq = get_unaligned_be64(ptr); 35762306a36Sopenharmony_ci pr_debug("MP_FAIL: data_seq=%llu", mp_opt->fail_seq); 35862306a36Sopenharmony_ci break; 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci default: 36162306a36Sopenharmony_ci break; 36262306a36Sopenharmony_ci } 36362306a36Sopenharmony_ci} 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_civoid mptcp_get_options(const struct sk_buff *skb, 36662306a36Sopenharmony_ci struct mptcp_options_received *mp_opt) 36762306a36Sopenharmony_ci{ 36862306a36Sopenharmony_ci const struct tcphdr *th = tcp_hdr(skb); 36962306a36Sopenharmony_ci const unsigned char *ptr; 37062306a36Sopenharmony_ci int length; 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci /* initialize option status */ 37362306a36Sopenharmony_ci mp_opt->suboptions = 0; 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci length = (th->doff * 4) - sizeof(struct tcphdr); 37662306a36Sopenharmony_ci ptr = (const unsigned char *)(th + 1); 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci while (length > 0) { 37962306a36Sopenharmony_ci int opcode = *ptr++; 38062306a36Sopenharmony_ci int opsize; 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci switch (opcode) { 38362306a36Sopenharmony_ci case TCPOPT_EOL: 38462306a36Sopenharmony_ci return; 38562306a36Sopenharmony_ci case TCPOPT_NOP: /* Ref: RFC 793 section 3.1 */ 38662306a36Sopenharmony_ci length--; 38762306a36Sopenharmony_ci continue; 38862306a36Sopenharmony_ci default: 38962306a36Sopenharmony_ci if (length < 2) 39062306a36Sopenharmony_ci return; 39162306a36Sopenharmony_ci opsize = *ptr++; 39262306a36Sopenharmony_ci if (opsize < 2) /* "silly options" */ 39362306a36Sopenharmony_ci return; 39462306a36Sopenharmony_ci if (opsize > length) 39562306a36Sopenharmony_ci return; /* don't parse partial options */ 39662306a36Sopenharmony_ci if (opcode == TCPOPT_MPTCP) 39762306a36Sopenharmony_ci mptcp_parse_option(skb, ptr, opsize, mp_opt); 39862306a36Sopenharmony_ci ptr += opsize - 2; 39962306a36Sopenharmony_ci length -= opsize; 40062306a36Sopenharmony_ci } 40162306a36Sopenharmony_ci } 40262306a36Sopenharmony_ci} 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_cibool mptcp_syn_options(struct sock *sk, const struct sk_buff *skb, 40562306a36Sopenharmony_ci unsigned int *size, struct mptcp_out_options *opts) 40662306a36Sopenharmony_ci{ 40762306a36Sopenharmony_ci struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(sk); 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci /* we will use snd_isn to detect first pkt [re]transmission 41062306a36Sopenharmony_ci * in mptcp_established_options_mp() 41162306a36Sopenharmony_ci */ 41262306a36Sopenharmony_ci subflow->snd_isn = TCP_SKB_CB(skb)->end_seq; 41362306a36Sopenharmony_ci if (subflow->request_mptcp) { 41462306a36Sopenharmony_ci opts->suboptions = OPTION_MPTCP_MPC_SYN; 41562306a36Sopenharmony_ci opts->csum_reqd = mptcp_is_checksum_enabled(sock_net(sk)); 41662306a36Sopenharmony_ci opts->allow_join_id0 = mptcp_allow_join_id0(sock_net(sk)); 41762306a36Sopenharmony_ci *size = TCPOLEN_MPTCP_MPC_SYN; 41862306a36Sopenharmony_ci return true; 41962306a36Sopenharmony_ci } else if (subflow->request_join) { 42062306a36Sopenharmony_ci pr_debug("remote_token=%u, nonce=%u", subflow->remote_token, 42162306a36Sopenharmony_ci subflow->local_nonce); 42262306a36Sopenharmony_ci opts->suboptions = OPTION_MPTCP_MPJ_SYN; 42362306a36Sopenharmony_ci opts->join_id = subflow->local_id; 42462306a36Sopenharmony_ci opts->token = subflow->remote_token; 42562306a36Sopenharmony_ci opts->nonce = subflow->local_nonce; 42662306a36Sopenharmony_ci opts->backup = subflow->request_bkup; 42762306a36Sopenharmony_ci *size = TCPOLEN_MPTCP_MPJ_SYN; 42862306a36Sopenharmony_ci return true; 42962306a36Sopenharmony_ci } 43062306a36Sopenharmony_ci return false; 43162306a36Sopenharmony_ci} 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_cistatic void clear_3rdack_retransmission(struct sock *sk) 43462306a36Sopenharmony_ci{ 43562306a36Sopenharmony_ci struct inet_connection_sock *icsk = inet_csk(sk); 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci sk_stop_timer(sk, &icsk->icsk_delack_timer); 43862306a36Sopenharmony_ci icsk->icsk_ack.timeout = 0; 43962306a36Sopenharmony_ci icsk->icsk_ack.ato = 0; 44062306a36Sopenharmony_ci icsk->icsk_ack.pending &= ~(ICSK_ACK_SCHED | ICSK_ACK_TIMER); 44162306a36Sopenharmony_ci} 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_cistatic bool mptcp_established_options_mp(struct sock *sk, struct sk_buff *skb, 44462306a36Sopenharmony_ci bool snd_data_fin_enable, 44562306a36Sopenharmony_ci unsigned int *size, 44662306a36Sopenharmony_ci struct mptcp_out_options *opts) 44762306a36Sopenharmony_ci{ 44862306a36Sopenharmony_ci struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(sk); 44962306a36Sopenharmony_ci struct mptcp_sock *msk = mptcp_sk(subflow->conn); 45062306a36Sopenharmony_ci struct mptcp_ext *mpext; 45162306a36Sopenharmony_ci unsigned int data_len; 45262306a36Sopenharmony_ci u8 len; 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci /* When skb is not available, we better over-estimate the emitted 45562306a36Sopenharmony_ci * options len. A full DSS option (28 bytes) is longer than 45662306a36Sopenharmony_ci * TCPOLEN_MPTCP_MPC_ACK_DATA(22) or TCPOLEN_MPTCP_MPJ_ACK(24), so 45762306a36Sopenharmony_ci * tell the caller to defer the estimate to 45862306a36Sopenharmony_ci * mptcp_established_options_dss(), which will reserve enough space. 45962306a36Sopenharmony_ci */ 46062306a36Sopenharmony_ci if (!skb) 46162306a36Sopenharmony_ci return false; 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci /* MPC/MPJ needed only on 3rd ack packet, DATA_FIN and TCP shutdown take precedence */ 46462306a36Sopenharmony_ci if (subflow->fully_established || snd_data_fin_enable || 46562306a36Sopenharmony_ci subflow->snd_isn != TCP_SKB_CB(skb)->seq || 46662306a36Sopenharmony_ci sk->sk_state != TCP_ESTABLISHED) 46762306a36Sopenharmony_ci return false; 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci if (subflow->mp_capable) { 47062306a36Sopenharmony_ci mpext = mptcp_get_ext(skb); 47162306a36Sopenharmony_ci data_len = mpext ? mpext->data_len : 0; 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci /* we will check ops->data_len in mptcp_write_options() to 47462306a36Sopenharmony_ci * discriminate between TCPOLEN_MPTCP_MPC_ACK_DATA and 47562306a36Sopenharmony_ci * TCPOLEN_MPTCP_MPC_ACK 47662306a36Sopenharmony_ci */ 47762306a36Sopenharmony_ci opts->data_len = data_len; 47862306a36Sopenharmony_ci opts->suboptions = OPTION_MPTCP_MPC_ACK; 47962306a36Sopenharmony_ci opts->sndr_key = subflow->local_key; 48062306a36Sopenharmony_ci opts->rcvr_key = subflow->remote_key; 48162306a36Sopenharmony_ci opts->csum_reqd = READ_ONCE(msk->csum_enabled); 48262306a36Sopenharmony_ci opts->allow_join_id0 = mptcp_allow_join_id0(sock_net(sk)); 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_ci /* Section 3.1. 48562306a36Sopenharmony_ci * The MP_CAPABLE option is carried on the SYN, SYN/ACK, and ACK 48662306a36Sopenharmony_ci * packets that start the first subflow of an MPTCP connection, 48762306a36Sopenharmony_ci * as well as the first packet that carries data 48862306a36Sopenharmony_ci */ 48962306a36Sopenharmony_ci if (data_len > 0) { 49062306a36Sopenharmony_ci len = TCPOLEN_MPTCP_MPC_ACK_DATA; 49162306a36Sopenharmony_ci if (opts->csum_reqd) { 49262306a36Sopenharmony_ci /* we need to propagate more info to csum the pseudo hdr */ 49362306a36Sopenharmony_ci opts->data_seq = mpext->data_seq; 49462306a36Sopenharmony_ci opts->subflow_seq = mpext->subflow_seq; 49562306a36Sopenharmony_ci opts->csum = mpext->csum; 49662306a36Sopenharmony_ci len += TCPOLEN_MPTCP_DSS_CHECKSUM; 49762306a36Sopenharmony_ci } 49862306a36Sopenharmony_ci *size = ALIGN(len, 4); 49962306a36Sopenharmony_ci } else { 50062306a36Sopenharmony_ci *size = TCPOLEN_MPTCP_MPC_ACK; 50162306a36Sopenharmony_ci } 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ci pr_debug("subflow=%p, local_key=%llu, remote_key=%llu map_len=%d", 50462306a36Sopenharmony_ci subflow, subflow->local_key, subflow->remote_key, 50562306a36Sopenharmony_ci data_len); 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci return true; 50862306a36Sopenharmony_ci } else if (subflow->mp_join) { 50962306a36Sopenharmony_ci opts->suboptions = OPTION_MPTCP_MPJ_ACK; 51062306a36Sopenharmony_ci memcpy(opts->hmac, subflow->hmac, MPTCPOPT_HMAC_LEN); 51162306a36Sopenharmony_ci *size = TCPOLEN_MPTCP_MPJ_ACK; 51262306a36Sopenharmony_ci pr_debug("subflow=%p", subflow); 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci /* we can use the full delegate action helper only from BH context 51562306a36Sopenharmony_ci * If we are in process context - sk is flushing the backlog at 51662306a36Sopenharmony_ci * socket lock release time - just set the appropriate flag, will 51762306a36Sopenharmony_ci * be handled by the release callback 51862306a36Sopenharmony_ci */ 51962306a36Sopenharmony_ci if (sock_owned_by_user(sk)) 52062306a36Sopenharmony_ci set_bit(MPTCP_DELEGATE_ACK, &subflow->delegated_status); 52162306a36Sopenharmony_ci else 52262306a36Sopenharmony_ci mptcp_subflow_delegate(subflow, MPTCP_DELEGATE_ACK); 52362306a36Sopenharmony_ci return true; 52462306a36Sopenharmony_ci } 52562306a36Sopenharmony_ci return false; 52662306a36Sopenharmony_ci} 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_cistatic void mptcp_write_data_fin(struct mptcp_subflow_context *subflow, 52962306a36Sopenharmony_ci struct sk_buff *skb, struct mptcp_ext *ext) 53062306a36Sopenharmony_ci{ 53162306a36Sopenharmony_ci /* The write_seq value has already been incremented, so the actual 53262306a36Sopenharmony_ci * sequence number for the DATA_FIN is one less. 53362306a36Sopenharmony_ci */ 53462306a36Sopenharmony_ci u64 data_fin_tx_seq = READ_ONCE(mptcp_sk(subflow->conn)->write_seq) - 1; 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci if (!ext->use_map || !skb->len) { 53762306a36Sopenharmony_ci /* RFC6824 requires a DSS mapping with specific values 53862306a36Sopenharmony_ci * if DATA_FIN is set but no data payload is mapped 53962306a36Sopenharmony_ci */ 54062306a36Sopenharmony_ci ext->data_fin = 1; 54162306a36Sopenharmony_ci ext->use_map = 1; 54262306a36Sopenharmony_ci ext->dsn64 = 1; 54362306a36Sopenharmony_ci ext->data_seq = data_fin_tx_seq; 54462306a36Sopenharmony_ci ext->subflow_seq = 0; 54562306a36Sopenharmony_ci ext->data_len = 1; 54662306a36Sopenharmony_ci } else if (ext->data_seq + ext->data_len == data_fin_tx_seq) { 54762306a36Sopenharmony_ci /* If there's an existing DSS mapping and it is the 54862306a36Sopenharmony_ci * final mapping, DATA_FIN consumes 1 additional byte of 54962306a36Sopenharmony_ci * mapping space. 55062306a36Sopenharmony_ci */ 55162306a36Sopenharmony_ci ext->data_fin = 1; 55262306a36Sopenharmony_ci ext->data_len++; 55362306a36Sopenharmony_ci } 55462306a36Sopenharmony_ci} 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_cistatic bool mptcp_established_options_dss(struct sock *sk, struct sk_buff *skb, 55762306a36Sopenharmony_ci bool snd_data_fin_enable, 55862306a36Sopenharmony_ci unsigned int *size, 55962306a36Sopenharmony_ci struct mptcp_out_options *opts) 56062306a36Sopenharmony_ci{ 56162306a36Sopenharmony_ci struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(sk); 56262306a36Sopenharmony_ci struct mptcp_sock *msk = mptcp_sk(subflow->conn); 56362306a36Sopenharmony_ci unsigned int dss_size = 0; 56462306a36Sopenharmony_ci struct mptcp_ext *mpext; 56562306a36Sopenharmony_ci unsigned int ack_size; 56662306a36Sopenharmony_ci bool ret = false; 56762306a36Sopenharmony_ci u64 ack_seq; 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci opts->csum_reqd = READ_ONCE(msk->csum_enabled); 57062306a36Sopenharmony_ci mpext = skb ? mptcp_get_ext(skb) : NULL; 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci if (!skb || (mpext && mpext->use_map) || snd_data_fin_enable) { 57362306a36Sopenharmony_ci unsigned int map_size = TCPOLEN_MPTCP_DSS_BASE + TCPOLEN_MPTCP_DSS_MAP64; 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci if (mpext) { 57662306a36Sopenharmony_ci if (opts->csum_reqd) 57762306a36Sopenharmony_ci map_size += TCPOLEN_MPTCP_DSS_CHECKSUM; 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci opts->ext_copy = *mpext; 58062306a36Sopenharmony_ci } 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_ci dss_size = map_size; 58362306a36Sopenharmony_ci if (skb && snd_data_fin_enable) 58462306a36Sopenharmony_ci mptcp_write_data_fin(subflow, skb, &opts->ext_copy); 58562306a36Sopenharmony_ci opts->suboptions = OPTION_MPTCP_DSS; 58662306a36Sopenharmony_ci ret = true; 58762306a36Sopenharmony_ci } 58862306a36Sopenharmony_ci 58962306a36Sopenharmony_ci /* passive sockets msk will set the 'can_ack' after accept(), even 59062306a36Sopenharmony_ci * if the first subflow may have the already the remote key handy 59162306a36Sopenharmony_ci */ 59262306a36Sopenharmony_ci opts->ext_copy.use_ack = 0; 59362306a36Sopenharmony_ci if (!READ_ONCE(msk->can_ack)) { 59462306a36Sopenharmony_ci *size = ALIGN(dss_size, 4); 59562306a36Sopenharmony_ci return ret; 59662306a36Sopenharmony_ci } 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_ci ack_seq = READ_ONCE(msk->ack_seq); 59962306a36Sopenharmony_ci if (READ_ONCE(msk->use_64bit_ack)) { 60062306a36Sopenharmony_ci ack_size = TCPOLEN_MPTCP_DSS_ACK64; 60162306a36Sopenharmony_ci opts->ext_copy.data_ack = ack_seq; 60262306a36Sopenharmony_ci opts->ext_copy.ack64 = 1; 60362306a36Sopenharmony_ci } else { 60462306a36Sopenharmony_ci ack_size = TCPOLEN_MPTCP_DSS_ACK32; 60562306a36Sopenharmony_ci opts->ext_copy.data_ack32 = (uint32_t)ack_seq; 60662306a36Sopenharmony_ci opts->ext_copy.ack64 = 0; 60762306a36Sopenharmony_ci } 60862306a36Sopenharmony_ci opts->ext_copy.use_ack = 1; 60962306a36Sopenharmony_ci opts->suboptions = OPTION_MPTCP_DSS; 61062306a36Sopenharmony_ci WRITE_ONCE(msk->old_wspace, __mptcp_space((struct sock *)msk)); 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_ci /* Add kind/length/subtype/flag overhead if mapping is not populated */ 61362306a36Sopenharmony_ci if (dss_size == 0) 61462306a36Sopenharmony_ci ack_size += TCPOLEN_MPTCP_DSS_BASE; 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_ci dss_size += ack_size; 61762306a36Sopenharmony_ci 61862306a36Sopenharmony_ci *size = ALIGN(dss_size, 4); 61962306a36Sopenharmony_ci return true; 62062306a36Sopenharmony_ci} 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_cistatic u64 add_addr_generate_hmac(u64 key1, u64 key2, 62362306a36Sopenharmony_ci struct mptcp_addr_info *addr) 62462306a36Sopenharmony_ci{ 62562306a36Sopenharmony_ci u16 port = ntohs(addr->port); 62662306a36Sopenharmony_ci u8 hmac[SHA256_DIGEST_SIZE]; 62762306a36Sopenharmony_ci u8 msg[19]; 62862306a36Sopenharmony_ci int i = 0; 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_ci msg[i++] = addr->id; 63162306a36Sopenharmony_ci if (addr->family == AF_INET) { 63262306a36Sopenharmony_ci memcpy(&msg[i], &addr->addr.s_addr, 4); 63362306a36Sopenharmony_ci i += 4; 63462306a36Sopenharmony_ci } 63562306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_MPTCP_IPV6) 63662306a36Sopenharmony_ci else if (addr->family == AF_INET6) { 63762306a36Sopenharmony_ci memcpy(&msg[i], &addr->addr6.s6_addr, 16); 63862306a36Sopenharmony_ci i += 16; 63962306a36Sopenharmony_ci } 64062306a36Sopenharmony_ci#endif 64162306a36Sopenharmony_ci msg[i++] = port >> 8; 64262306a36Sopenharmony_ci msg[i++] = port & 0xFF; 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci mptcp_crypto_hmac_sha(key1, key2, msg, i, hmac); 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_ci return get_unaligned_be64(&hmac[SHA256_DIGEST_SIZE - sizeof(u64)]); 64762306a36Sopenharmony_ci} 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_cistatic bool mptcp_established_options_add_addr(struct sock *sk, struct sk_buff *skb, 65062306a36Sopenharmony_ci unsigned int *size, 65162306a36Sopenharmony_ci unsigned int remaining, 65262306a36Sopenharmony_ci struct mptcp_out_options *opts) 65362306a36Sopenharmony_ci{ 65462306a36Sopenharmony_ci struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(sk); 65562306a36Sopenharmony_ci struct mptcp_sock *msk = mptcp_sk(subflow->conn); 65662306a36Sopenharmony_ci bool drop_other_suboptions = false; 65762306a36Sopenharmony_ci unsigned int opt_size = *size; 65862306a36Sopenharmony_ci bool echo; 65962306a36Sopenharmony_ci int len; 66062306a36Sopenharmony_ci 66162306a36Sopenharmony_ci /* add addr will strip the existing options, be sure to avoid breaking 66262306a36Sopenharmony_ci * MPC/MPJ handshakes 66362306a36Sopenharmony_ci */ 66462306a36Sopenharmony_ci if (!mptcp_pm_should_add_signal(msk) || 66562306a36Sopenharmony_ci (opts->suboptions & (OPTION_MPTCP_MPJ_ACK | OPTION_MPTCP_MPC_ACK)) || 66662306a36Sopenharmony_ci !mptcp_pm_add_addr_signal(msk, skb, opt_size, remaining, &opts->addr, 66762306a36Sopenharmony_ci &echo, &drop_other_suboptions)) 66862306a36Sopenharmony_ci return false; 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ci if (drop_other_suboptions) 67162306a36Sopenharmony_ci remaining += opt_size; 67262306a36Sopenharmony_ci len = mptcp_add_addr_len(opts->addr.family, echo, !!opts->addr.port); 67362306a36Sopenharmony_ci if (remaining < len) 67462306a36Sopenharmony_ci return false; 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ci *size = len; 67762306a36Sopenharmony_ci if (drop_other_suboptions) { 67862306a36Sopenharmony_ci pr_debug("drop other suboptions"); 67962306a36Sopenharmony_ci opts->suboptions = 0; 68062306a36Sopenharmony_ci 68162306a36Sopenharmony_ci /* note that e.g. DSS could have written into the memory 68262306a36Sopenharmony_ci * aliased by ahmac, we must reset the field here 68362306a36Sopenharmony_ci * to avoid appending the hmac even for ADD_ADDR echo 68462306a36Sopenharmony_ci * options 68562306a36Sopenharmony_ci */ 68662306a36Sopenharmony_ci opts->ahmac = 0; 68762306a36Sopenharmony_ci *size -= opt_size; 68862306a36Sopenharmony_ci } 68962306a36Sopenharmony_ci opts->suboptions |= OPTION_MPTCP_ADD_ADDR; 69062306a36Sopenharmony_ci if (!echo) { 69162306a36Sopenharmony_ci MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_ADDADDRTX); 69262306a36Sopenharmony_ci opts->ahmac = add_addr_generate_hmac(msk->local_key, 69362306a36Sopenharmony_ci msk->remote_key, 69462306a36Sopenharmony_ci &opts->addr); 69562306a36Sopenharmony_ci } else { 69662306a36Sopenharmony_ci MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_ECHOADDTX); 69762306a36Sopenharmony_ci } 69862306a36Sopenharmony_ci pr_debug("addr_id=%d, ahmac=%llu, echo=%d, port=%d", 69962306a36Sopenharmony_ci opts->addr.id, opts->ahmac, echo, ntohs(opts->addr.port)); 70062306a36Sopenharmony_ci 70162306a36Sopenharmony_ci return true; 70262306a36Sopenharmony_ci} 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_cistatic bool mptcp_established_options_rm_addr(struct sock *sk, 70562306a36Sopenharmony_ci unsigned int *size, 70662306a36Sopenharmony_ci unsigned int remaining, 70762306a36Sopenharmony_ci struct mptcp_out_options *opts) 70862306a36Sopenharmony_ci{ 70962306a36Sopenharmony_ci struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(sk); 71062306a36Sopenharmony_ci struct mptcp_sock *msk = mptcp_sk(subflow->conn); 71162306a36Sopenharmony_ci struct mptcp_rm_list rm_list; 71262306a36Sopenharmony_ci int i, len; 71362306a36Sopenharmony_ci 71462306a36Sopenharmony_ci if (!mptcp_pm_should_rm_signal(msk) || 71562306a36Sopenharmony_ci !(mptcp_pm_rm_addr_signal(msk, remaining, &rm_list))) 71662306a36Sopenharmony_ci return false; 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_ci len = mptcp_rm_addr_len(&rm_list); 71962306a36Sopenharmony_ci if (len < 0) 72062306a36Sopenharmony_ci return false; 72162306a36Sopenharmony_ci if (remaining < len) 72262306a36Sopenharmony_ci return false; 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_ci *size = len; 72562306a36Sopenharmony_ci opts->suboptions |= OPTION_MPTCP_RM_ADDR; 72662306a36Sopenharmony_ci opts->rm_list = rm_list; 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_ci for (i = 0; i < opts->rm_list.nr; i++) 72962306a36Sopenharmony_ci pr_debug("rm_list_ids[%d]=%d", i, opts->rm_list.ids[i]); 73062306a36Sopenharmony_ci MPTCP_ADD_STATS(sock_net(sk), MPTCP_MIB_RMADDRTX, opts->rm_list.nr); 73162306a36Sopenharmony_ci return true; 73262306a36Sopenharmony_ci} 73362306a36Sopenharmony_ci 73462306a36Sopenharmony_cistatic bool mptcp_established_options_mp_prio(struct sock *sk, 73562306a36Sopenharmony_ci unsigned int *size, 73662306a36Sopenharmony_ci unsigned int remaining, 73762306a36Sopenharmony_ci struct mptcp_out_options *opts) 73862306a36Sopenharmony_ci{ 73962306a36Sopenharmony_ci struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(sk); 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_ci /* can't send MP_PRIO with MPC, as they share the same option space: 74262306a36Sopenharmony_ci * 'backup'. Also it makes no sense at all 74362306a36Sopenharmony_ci */ 74462306a36Sopenharmony_ci if (!subflow->send_mp_prio || (opts->suboptions & OPTIONS_MPTCP_MPC)) 74562306a36Sopenharmony_ci return false; 74662306a36Sopenharmony_ci 74762306a36Sopenharmony_ci /* account for the trailing 'nop' option */ 74862306a36Sopenharmony_ci if (remaining < TCPOLEN_MPTCP_PRIO_ALIGN) 74962306a36Sopenharmony_ci return false; 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_ci *size = TCPOLEN_MPTCP_PRIO_ALIGN; 75262306a36Sopenharmony_ci opts->suboptions |= OPTION_MPTCP_PRIO; 75362306a36Sopenharmony_ci opts->backup = subflow->request_bkup; 75462306a36Sopenharmony_ci 75562306a36Sopenharmony_ci pr_debug("prio=%d", opts->backup); 75662306a36Sopenharmony_ci 75762306a36Sopenharmony_ci return true; 75862306a36Sopenharmony_ci} 75962306a36Sopenharmony_ci 76062306a36Sopenharmony_cistatic noinline bool mptcp_established_options_rst(struct sock *sk, struct sk_buff *skb, 76162306a36Sopenharmony_ci unsigned int *size, 76262306a36Sopenharmony_ci unsigned int remaining, 76362306a36Sopenharmony_ci struct mptcp_out_options *opts) 76462306a36Sopenharmony_ci{ 76562306a36Sopenharmony_ci const struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(sk); 76662306a36Sopenharmony_ci 76762306a36Sopenharmony_ci if (remaining < TCPOLEN_MPTCP_RST) 76862306a36Sopenharmony_ci return false; 76962306a36Sopenharmony_ci 77062306a36Sopenharmony_ci *size = TCPOLEN_MPTCP_RST; 77162306a36Sopenharmony_ci opts->suboptions |= OPTION_MPTCP_RST; 77262306a36Sopenharmony_ci opts->reset_transient = subflow->reset_transient; 77362306a36Sopenharmony_ci opts->reset_reason = subflow->reset_reason; 77462306a36Sopenharmony_ci MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_MPRSTTX); 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_ci return true; 77762306a36Sopenharmony_ci} 77862306a36Sopenharmony_ci 77962306a36Sopenharmony_cistatic bool mptcp_established_options_fastclose(struct sock *sk, 78062306a36Sopenharmony_ci unsigned int *size, 78162306a36Sopenharmony_ci unsigned int remaining, 78262306a36Sopenharmony_ci struct mptcp_out_options *opts) 78362306a36Sopenharmony_ci{ 78462306a36Sopenharmony_ci struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(sk); 78562306a36Sopenharmony_ci struct mptcp_sock *msk = mptcp_sk(subflow->conn); 78662306a36Sopenharmony_ci 78762306a36Sopenharmony_ci if (likely(!subflow->send_fastclose)) 78862306a36Sopenharmony_ci return false; 78962306a36Sopenharmony_ci 79062306a36Sopenharmony_ci if (remaining < TCPOLEN_MPTCP_FASTCLOSE) 79162306a36Sopenharmony_ci return false; 79262306a36Sopenharmony_ci 79362306a36Sopenharmony_ci *size = TCPOLEN_MPTCP_FASTCLOSE; 79462306a36Sopenharmony_ci opts->suboptions |= OPTION_MPTCP_FASTCLOSE; 79562306a36Sopenharmony_ci opts->rcvr_key = msk->remote_key; 79662306a36Sopenharmony_ci 79762306a36Sopenharmony_ci pr_debug("FASTCLOSE key=%llu", opts->rcvr_key); 79862306a36Sopenharmony_ci MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_MPFASTCLOSETX); 79962306a36Sopenharmony_ci return true; 80062306a36Sopenharmony_ci} 80162306a36Sopenharmony_ci 80262306a36Sopenharmony_cistatic bool mptcp_established_options_mp_fail(struct sock *sk, 80362306a36Sopenharmony_ci unsigned int *size, 80462306a36Sopenharmony_ci unsigned int remaining, 80562306a36Sopenharmony_ci struct mptcp_out_options *opts) 80662306a36Sopenharmony_ci{ 80762306a36Sopenharmony_ci struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(sk); 80862306a36Sopenharmony_ci 80962306a36Sopenharmony_ci if (likely(!subflow->send_mp_fail)) 81062306a36Sopenharmony_ci return false; 81162306a36Sopenharmony_ci 81262306a36Sopenharmony_ci if (remaining < TCPOLEN_MPTCP_FAIL) 81362306a36Sopenharmony_ci return false; 81462306a36Sopenharmony_ci 81562306a36Sopenharmony_ci *size = TCPOLEN_MPTCP_FAIL; 81662306a36Sopenharmony_ci opts->suboptions |= OPTION_MPTCP_FAIL; 81762306a36Sopenharmony_ci opts->fail_seq = subflow->map_seq; 81862306a36Sopenharmony_ci 81962306a36Sopenharmony_ci pr_debug("MP_FAIL fail_seq=%llu", opts->fail_seq); 82062306a36Sopenharmony_ci MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_MPFAILTX); 82162306a36Sopenharmony_ci 82262306a36Sopenharmony_ci return true; 82362306a36Sopenharmony_ci} 82462306a36Sopenharmony_ci 82562306a36Sopenharmony_cibool mptcp_established_options(struct sock *sk, struct sk_buff *skb, 82662306a36Sopenharmony_ci unsigned int *size, unsigned int remaining, 82762306a36Sopenharmony_ci struct mptcp_out_options *opts) 82862306a36Sopenharmony_ci{ 82962306a36Sopenharmony_ci struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(sk); 83062306a36Sopenharmony_ci struct mptcp_sock *msk = mptcp_sk(subflow->conn); 83162306a36Sopenharmony_ci unsigned int opt_size = 0; 83262306a36Sopenharmony_ci bool snd_data_fin; 83362306a36Sopenharmony_ci bool ret = false; 83462306a36Sopenharmony_ci 83562306a36Sopenharmony_ci opts->suboptions = 0; 83662306a36Sopenharmony_ci 83762306a36Sopenharmony_ci if (unlikely(__mptcp_check_fallback(msk) && !mptcp_check_infinite_map(skb))) 83862306a36Sopenharmony_ci return false; 83962306a36Sopenharmony_ci 84062306a36Sopenharmony_ci if (unlikely(skb && TCP_SKB_CB(skb)->tcp_flags & TCPHDR_RST)) { 84162306a36Sopenharmony_ci if (mptcp_established_options_fastclose(sk, &opt_size, remaining, opts) || 84262306a36Sopenharmony_ci mptcp_established_options_mp_fail(sk, &opt_size, remaining, opts)) { 84362306a36Sopenharmony_ci *size += opt_size; 84462306a36Sopenharmony_ci remaining -= opt_size; 84562306a36Sopenharmony_ci } 84662306a36Sopenharmony_ci /* MP_RST can be used with MP_FASTCLOSE and MP_FAIL if there is room */ 84762306a36Sopenharmony_ci if (mptcp_established_options_rst(sk, skb, &opt_size, remaining, opts)) { 84862306a36Sopenharmony_ci *size += opt_size; 84962306a36Sopenharmony_ci remaining -= opt_size; 85062306a36Sopenharmony_ci } 85162306a36Sopenharmony_ci return true; 85262306a36Sopenharmony_ci } 85362306a36Sopenharmony_ci 85462306a36Sopenharmony_ci snd_data_fin = mptcp_data_fin_enabled(msk); 85562306a36Sopenharmony_ci if (mptcp_established_options_mp(sk, skb, snd_data_fin, &opt_size, opts)) 85662306a36Sopenharmony_ci ret = true; 85762306a36Sopenharmony_ci else if (mptcp_established_options_dss(sk, skb, snd_data_fin, &opt_size, opts)) { 85862306a36Sopenharmony_ci unsigned int mp_fail_size; 85962306a36Sopenharmony_ci 86062306a36Sopenharmony_ci ret = true; 86162306a36Sopenharmony_ci if (mptcp_established_options_mp_fail(sk, &mp_fail_size, 86262306a36Sopenharmony_ci remaining - opt_size, opts)) { 86362306a36Sopenharmony_ci *size += opt_size + mp_fail_size; 86462306a36Sopenharmony_ci remaining -= opt_size - mp_fail_size; 86562306a36Sopenharmony_ci return true; 86662306a36Sopenharmony_ci } 86762306a36Sopenharmony_ci } 86862306a36Sopenharmony_ci 86962306a36Sopenharmony_ci /* we reserved enough space for the above options, and exceeding the 87062306a36Sopenharmony_ci * TCP option space would be fatal 87162306a36Sopenharmony_ci */ 87262306a36Sopenharmony_ci if (WARN_ON_ONCE(opt_size > remaining)) 87362306a36Sopenharmony_ci return false; 87462306a36Sopenharmony_ci 87562306a36Sopenharmony_ci *size += opt_size; 87662306a36Sopenharmony_ci remaining -= opt_size; 87762306a36Sopenharmony_ci if (mptcp_established_options_add_addr(sk, skb, &opt_size, remaining, opts)) { 87862306a36Sopenharmony_ci *size += opt_size; 87962306a36Sopenharmony_ci remaining -= opt_size; 88062306a36Sopenharmony_ci ret = true; 88162306a36Sopenharmony_ci } else if (mptcp_established_options_rm_addr(sk, &opt_size, remaining, opts)) { 88262306a36Sopenharmony_ci *size += opt_size; 88362306a36Sopenharmony_ci remaining -= opt_size; 88462306a36Sopenharmony_ci ret = true; 88562306a36Sopenharmony_ci } 88662306a36Sopenharmony_ci 88762306a36Sopenharmony_ci if (mptcp_established_options_mp_prio(sk, &opt_size, remaining, opts)) { 88862306a36Sopenharmony_ci *size += opt_size; 88962306a36Sopenharmony_ci remaining -= opt_size; 89062306a36Sopenharmony_ci ret = true; 89162306a36Sopenharmony_ci } 89262306a36Sopenharmony_ci 89362306a36Sopenharmony_ci return ret; 89462306a36Sopenharmony_ci} 89562306a36Sopenharmony_ci 89662306a36Sopenharmony_cibool mptcp_synack_options(const struct request_sock *req, unsigned int *size, 89762306a36Sopenharmony_ci struct mptcp_out_options *opts) 89862306a36Sopenharmony_ci{ 89962306a36Sopenharmony_ci struct mptcp_subflow_request_sock *subflow_req = mptcp_subflow_rsk(req); 90062306a36Sopenharmony_ci 90162306a36Sopenharmony_ci if (subflow_req->mp_capable) { 90262306a36Sopenharmony_ci opts->suboptions = OPTION_MPTCP_MPC_SYNACK; 90362306a36Sopenharmony_ci opts->sndr_key = subflow_req->local_key; 90462306a36Sopenharmony_ci opts->csum_reqd = subflow_req->csum_reqd; 90562306a36Sopenharmony_ci opts->allow_join_id0 = subflow_req->allow_join_id0; 90662306a36Sopenharmony_ci *size = TCPOLEN_MPTCP_MPC_SYNACK; 90762306a36Sopenharmony_ci pr_debug("subflow_req=%p, local_key=%llu", 90862306a36Sopenharmony_ci subflow_req, subflow_req->local_key); 90962306a36Sopenharmony_ci return true; 91062306a36Sopenharmony_ci } else if (subflow_req->mp_join) { 91162306a36Sopenharmony_ci opts->suboptions = OPTION_MPTCP_MPJ_SYNACK; 91262306a36Sopenharmony_ci opts->backup = subflow_req->backup; 91362306a36Sopenharmony_ci opts->join_id = subflow_req->local_id; 91462306a36Sopenharmony_ci opts->thmac = subflow_req->thmac; 91562306a36Sopenharmony_ci opts->nonce = subflow_req->local_nonce; 91662306a36Sopenharmony_ci pr_debug("req=%p, bkup=%u, id=%u, thmac=%llu, nonce=%u", 91762306a36Sopenharmony_ci subflow_req, opts->backup, opts->join_id, 91862306a36Sopenharmony_ci opts->thmac, opts->nonce); 91962306a36Sopenharmony_ci *size = TCPOLEN_MPTCP_MPJ_SYNACK; 92062306a36Sopenharmony_ci return true; 92162306a36Sopenharmony_ci } 92262306a36Sopenharmony_ci return false; 92362306a36Sopenharmony_ci} 92462306a36Sopenharmony_ci 92562306a36Sopenharmony_cistatic bool check_fully_established(struct mptcp_sock *msk, struct sock *ssk, 92662306a36Sopenharmony_ci struct mptcp_subflow_context *subflow, 92762306a36Sopenharmony_ci struct sk_buff *skb, 92862306a36Sopenharmony_ci struct mptcp_options_received *mp_opt) 92962306a36Sopenharmony_ci{ 93062306a36Sopenharmony_ci /* here we can process OoO, in-window pkts, only in-sequence 4th ack 93162306a36Sopenharmony_ci * will make the subflow fully established 93262306a36Sopenharmony_ci */ 93362306a36Sopenharmony_ci if (likely(subflow->fully_established)) { 93462306a36Sopenharmony_ci /* on passive sockets, check for 3rd ack retransmission 93562306a36Sopenharmony_ci * note that msk is always set by subflow_syn_recv_sock() 93662306a36Sopenharmony_ci * for mp_join subflows 93762306a36Sopenharmony_ci */ 93862306a36Sopenharmony_ci if (TCP_SKB_CB(skb)->seq == subflow->ssn_offset + 1 && 93962306a36Sopenharmony_ci TCP_SKB_CB(skb)->end_seq == TCP_SKB_CB(skb)->seq && 94062306a36Sopenharmony_ci subflow->mp_join && (mp_opt->suboptions & OPTIONS_MPTCP_MPJ) && 94162306a36Sopenharmony_ci !subflow->request_join) 94262306a36Sopenharmony_ci tcp_send_ack(ssk); 94362306a36Sopenharmony_ci goto check_notify; 94462306a36Sopenharmony_ci } 94562306a36Sopenharmony_ci 94662306a36Sopenharmony_ci /* we must process OoO packets before the first subflow is fully 94762306a36Sopenharmony_ci * established. OoO packets are instead a protocol violation 94862306a36Sopenharmony_ci * for MP_JOIN subflows as the peer must not send any data 94962306a36Sopenharmony_ci * before receiving the forth ack - cfr. RFC 8684 section 3.2. 95062306a36Sopenharmony_ci */ 95162306a36Sopenharmony_ci if (TCP_SKB_CB(skb)->seq != subflow->ssn_offset + 1) { 95262306a36Sopenharmony_ci if (subflow->mp_join) 95362306a36Sopenharmony_ci goto reset; 95462306a36Sopenharmony_ci if (subflow->is_mptfo && mp_opt->suboptions & OPTION_MPTCP_MPC_ACK) 95562306a36Sopenharmony_ci goto set_fully_established; 95662306a36Sopenharmony_ci return subflow->mp_capable; 95762306a36Sopenharmony_ci } 95862306a36Sopenharmony_ci 95962306a36Sopenharmony_ci if (subflow->remote_key_valid && 96062306a36Sopenharmony_ci (((mp_opt->suboptions & OPTION_MPTCP_DSS) && mp_opt->use_ack) || 96162306a36Sopenharmony_ci ((mp_opt->suboptions & OPTION_MPTCP_ADD_ADDR) && !mp_opt->echo))) { 96262306a36Sopenharmony_ci /* subflows are fully established as soon as we get any 96362306a36Sopenharmony_ci * additional ack, including ADD_ADDR. 96462306a36Sopenharmony_ci */ 96562306a36Sopenharmony_ci goto set_fully_established; 96662306a36Sopenharmony_ci } 96762306a36Sopenharmony_ci 96862306a36Sopenharmony_ci /* If the first established packet does not contain MP_CAPABLE + data 96962306a36Sopenharmony_ci * then fallback to TCP. Fallback scenarios requires a reset for 97062306a36Sopenharmony_ci * MP_JOIN subflows. 97162306a36Sopenharmony_ci */ 97262306a36Sopenharmony_ci if (!(mp_opt->suboptions & OPTIONS_MPTCP_MPC)) { 97362306a36Sopenharmony_ci if (subflow->mp_join) 97462306a36Sopenharmony_ci goto reset; 97562306a36Sopenharmony_ci subflow->mp_capable = 0; 97662306a36Sopenharmony_ci pr_fallback(msk); 97762306a36Sopenharmony_ci mptcp_do_fallback(ssk); 97862306a36Sopenharmony_ci return false; 97962306a36Sopenharmony_ci } 98062306a36Sopenharmony_ci 98162306a36Sopenharmony_ci if (mp_opt->deny_join_id0) 98262306a36Sopenharmony_ci WRITE_ONCE(msk->pm.remote_deny_join_id0, true); 98362306a36Sopenharmony_ci 98462306a36Sopenharmony_ci if (unlikely(!READ_ONCE(msk->pm.server_side))) 98562306a36Sopenharmony_ci pr_warn_once("bogus mpc option on established client sk"); 98662306a36Sopenharmony_ci 98762306a36Sopenharmony_ciset_fully_established: 98862306a36Sopenharmony_ci mptcp_data_lock((struct sock *)msk); 98962306a36Sopenharmony_ci __mptcp_subflow_fully_established(msk, subflow, mp_opt); 99062306a36Sopenharmony_ci mptcp_data_unlock((struct sock *)msk); 99162306a36Sopenharmony_ci 99262306a36Sopenharmony_cicheck_notify: 99362306a36Sopenharmony_ci /* if the subflow is not already linked into the conn_list, we can't 99462306a36Sopenharmony_ci * notify the PM: this subflow is still on the listener queue 99562306a36Sopenharmony_ci * and the PM possibly acquiring the subflow lock could race with 99662306a36Sopenharmony_ci * the listener close 99762306a36Sopenharmony_ci */ 99862306a36Sopenharmony_ci if (likely(subflow->pm_notified) || list_empty(&subflow->node)) 99962306a36Sopenharmony_ci return true; 100062306a36Sopenharmony_ci 100162306a36Sopenharmony_ci subflow->pm_notified = 1; 100262306a36Sopenharmony_ci if (subflow->mp_join) { 100362306a36Sopenharmony_ci clear_3rdack_retransmission(ssk); 100462306a36Sopenharmony_ci mptcp_pm_subflow_established(msk); 100562306a36Sopenharmony_ci } else { 100662306a36Sopenharmony_ci mptcp_pm_fully_established(msk, ssk); 100762306a36Sopenharmony_ci } 100862306a36Sopenharmony_ci return true; 100962306a36Sopenharmony_ci 101062306a36Sopenharmony_cireset: 101162306a36Sopenharmony_ci mptcp_subflow_reset(ssk); 101262306a36Sopenharmony_ci return false; 101362306a36Sopenharmony_ci} 101462306a36Sopenharmony_ci 101562306a36Sopenharmony_ciu64 __mptcp_expand_seq(u64 old_seq, u64 cur_seq) 101662306a36Sopenharmony_ci{ 101762306a36Sopenharmony_ci u32 old_seq32, cur_seq32; 101862306a36Sopenharmony_ci 101962306a36Sopenharmony_ci old_seq32 = (u32)old_seq; 102062306a36Sopenharmony_ci cur_seq32 = (u32)cur_seq; 102162306a36Sopenharmony_ci cur_seq = (old_seq & GENMASK_ULL(63, 32)) + cur_seq32; 102262306a36Sopenharmony_ci if (unlikely(cur_seq32 < old_seq32 && before(old_seq32, cur_seq32))) 102362306a36Sopenharmony_ci return cur_seq + (1LL << 32); 102462306a36Sopenharmony_ci 102562306a36Sopenharmony_ci /* reverse wrap could happen, too */ 102662306a36Sopenharmony_ci if (unlikely(cur_seq32 > old_seq32 && after(old_seq32, cur_seq32))) 102762306a36Sopenharmony_ci return cur_seq - (1LL << 32); 102862306a36Sopenharmony_ci return cur_seq; 102962306a36Sopenharmony_ci} 103062306a36Sopenharmony_ci 103162306a36Sopenharmony_cistatic void __mptcp_snd_una_update(struct mptcp_sock *msk, u64 new_snd_una) 103262306a36Sopenharmony_ci{ 103362306a36Sopenharmony_ci msk->bytes_acked += new_snd_una - msk->snd_una; 103462306a36Sopenharmony_ci msk->snd_una = new_snd_una; 103562306a36Sopenharmony_ci} 103662306a36Sopenharmony_ci 103762306a36Sopenharmony_cistatic void ack_update_msk(struct mptcp_sock *msk, 103862306a36Sopenharmony_ci struct sock *ssk, 103962306a36Sopenharmony_ci struct mptcp_options_received *mp_opt) 104062306a36Sopenharmony_ci{ 104162306a36Sopenharmony_ci u64 new_wnd_end, new_snd_una, snd_nxt = READ_ONCE(msk->snd_nxt); 104262306a36Sopenharmony_ci struct sock *sk = (struct sock *)msk; 104362306a36Sopenharmony_ci u64 old_snd_una; 104462306a36Sopenharmony_ci 104562306a36Sopenharmony_ci mptcp_data_lock(sk); 104662306a36Sopenharmony_ci 104762306a36Sopenharmony_ci /* avoid ack expansion on update conflict, to reduce the risk of 104862306a36Sopenharmony_ci * wrongly expanding to a future ack sequence number, which is way 104962306a36Sopenharmony_ci * more dangerous than missing an ack 105062306a36Sopenharmony_ci */ 105162306a36Sopenharmony_ci old_snd_una = msk->snd_una; 105262306a36Sopenharmony_ci new_snd_una = mptcp_expand_seq(old_snd_una, mp_opt->data_ack, mp_opt->ack64); 105362306a36Sopenharmony_ci 105462306a36Sopenharmony_ci /* ACK for data not even sent yet? Ignore.*/ 105562306a36Sopenharmony_ci if (unlikely(after64(new_snd_una, snd_nxt))) 105662306a36Sopenharmony_ci new_snd_una = old_snd_una; 105762306a36Sopenharmony_ci 105862306a36Sopenharmony_ci new_wnd_end = new_snd_una + tcp_sk(ssk)->snd_wnd; 105962306a36Sopenharmony_ci 106062306a36Sopenharmony_ci if (after64(new_wnd_end, msk->wnd_end)) 106162306a36Sopenharmony_ci msk->wnd_end = new_wnd_end; 106262306a36Sopenharmony_ci 106362306a36Sopenharmony_ci /* this assumes mptcp_incoming_options() is invoked after tcp_ack() */ 106462306a36Sopenharmony_ci if (after64(msk->wnd_end, READ_ONCE(msk->snd_nxt))) 106562306a36Sopenharmony_ci __mptcp_check_push(sk, ssk); 106662306a36Sopenharmony_ci 106762306a36Sopenharmony_ci if (after64(new_snd_una, old_snd_una)) { 106862306a36Sopenharmony_ci __mptcp_snd_una_update(msk, new_snd_una); 106962306a36Sopenharmony_ci __mptcp_data_acked(sk); 107062306a36Sopenharmony_ci } 107162306a36Sopenharmony_ci mptcp_data_unlock(sk); 107262306a36Sopenharmony_ci 107362306a36Sopenharmony_ci trace_ack_update_msk(mp_opt->data_ack, 107462306a36Sopenharmony_ci old_snd_una, new_snd_una, 107562306a36Sopenharmony_ci new_wnd_end, msk->wnd_end); 107662306a36Sopenharmony_ci} 107762306a36Sopenharmony_ci 107862306a36Sopenharmony_cibool mptcp_update_rcv_data_fin(struct mptcp_sock *msk, u64 data_fin_seq, bool use_64bit) 107962306a36Sopenharmony_ci{ 108062306a36Sopenharmony_ci /* Skip if DATA_FIN was already received. 108162306a36Sopenharmony_ci * If updating simultaneously with the recvmsg loop, values 108262306a36Sopenharmony_ci * should match. If they mismatch, the peer is misbehaving and 108362306a36Sopenharmony_ci * we will prefer the most recent information. 108462306a36Sopenharmony_ci */ 108562306a36Sopenharmony_ci if (READ_ONCE(msk->rcv_data_fin)) 108662306a36Sopenharmony_ci return false; 108762306a36Sopenharmony_ci 108862306a36Sopenharmony_ci WRITE_ONCE(msk->rcv_data_fin_seq, 108962306a36Sopenharmony_ci mptcp_expand_seq(READ_ONCE(msk->ack_seq), data_fin_seq, use_64bit)); 109062306a36Sopenharmony_ci WRITE_ONCE(msk->rcv_data_fin, 1); 109162306a36Sopenharmony_ci 109262306a36Sopenharmony_ci return true; 109362306a36Sopenharmony_ci} 109462306a36Sopenharmony_ci 109562306a36Sopenharmony_cistatic bool add_addr_hmac_valid(struct mptcp_sock *msk, 109662306a36Sopenharmony_ci struct mptcp_options_received *mp_opt) 109762306a36Sopenharmony_ci{ 109862306a36Sopenharmony_ci u64 hmac = 0; 109962306a36Sopenharmony_ci 110062306a36Sopenharmony_ci if (mp_opt->echo) 110162306a36Sopenharmony_ci return true; 110262306a36Sopenharmony_ci 110362306a36Sopenharmony_ci hmac = add_addr_generate_hmac(msk->remote_key, 110462306a36Sopenharmony_ci msk->local_key, 110562306a36Sopenharmony_ci &mp_opt->addr); 110662306a36Sopenharmony_ci 110762306a36Sopenharmony_ci pr_debug("msk=%p, ahmac=%llu, mp_opt->ahmac=%llu\n", 110862306a36Sopenharmony_ci msk, hmac, mp_opt->ahmac); 110962306a36Sopenharmony_ci 111062306a36Sopenharmony_ci return hmac == mp_opt->ahmac; 111162306a36Sopenharmony_ci} 111262306a36Sopenharmony_ci 111362306a36Sopenharmony_ci/* Return false if a subflow has been reset, else return true */ 111462306a36Sopenharmony_cibool mptcp_incoming_options(struct sock *sk, struct sk_buff *skb) 111562306a36Sopenharmony_ci{ 111662306a36Sopenharmony_ci struct mptcp_subflow_context *subflow = mptcp_subflow_ctx(sk); 111762306a36Sopenharmony_ci struct mptcp_sock *msk = mptcp_sk(subflow->conn); 111862306a36Sopenharmony_ci struct mptcp_options_received mp_opt; 111962306a36Sopenharmony_ci struct mptcp_ext *mpext; 112062306a36Sopenharmony_ci 112162306a36Sopenharmony_ci if (__mptcp_check_fallback(msk)) { 112262306a36Sopenharmony_ci /* Keep it simple and unconditionally trigger send data cleanup and 112362306a36Sopenharmony_ci * pending queue spooling. We will need to acquire the data lock 112462306a36Sopenharmony_ci * for more accurate checks, and once the lock is acquired, such 112562306a36Sopenharmony_ci * helpers are cheap. 112662306a36Sopenharmony_ci */ 112762306a36Sopenharmony_ci mptcp_data_lock(subflow->conn); 112862306a36Sopenharmony_ci if (sk_stream_memory_free(sk)) 112962306a36Sopenharmony_ci __mptcp_check_push(subflow->conn, sk); 113062306a36Sopenharmony_ci 113162306a36Sopenharmony_ci /* on fallback we just need to ignore the msk-level snd_una, as 113262306a36Sopenharmony_ci * this is really plain TCP 113362306a36Sopenharmony_ci */ 113462306a36Sopenharmony_ci __mptcp_snd_una_update(msk, READ_ONCE(msk->snd_nxt)); 113562306a36Sopenharmony_ci 113662306a36Sopenharmony_ci __mptcp_data_acked(subflow->conn); 113762306a36Sopenharmony_ci mptcp_data_unlock(subflow->conn); 113862306a36Sopenharmony_ci return true; 113962306a36Sopenharmony_ci } 114062306a36Sopenharmony_ci 114162306a36Sopenharmony_ci mptcp_get_options(skb, &mp_opt); 114262306a36Sopenharmony_ci 114362306a36Sopenharmony_ci /* The subflow can be in close state only if check_fully_established() 114462306a36Sopenharmony_ci * just sent a reset. If so, tell the caller to ignore the current packet. 114562306a36Sopenharmony_ci */ 114662306a36Sopenharmony_ci if (!check_fully_established(msk, sk, subflow, skb, &mp_opt)) 114762306a36Sopenharmony_ci return sk->sk_state != TCP_CLOSE; 114862306a36Sopenharmony_ci 114962306a36Sopenharmony_ci if (unlikely(mp_opt.suboptions != OPTION_MPTCP_DSS)) { 115062306a36Sopenharmony_ci if ((mp_opt.suboptions & OPTION_MPTCP_FASTCLOSE) && 115162306a36Sopenharmony_ci msk->local_key == mp_opt.rcvr_key) { 115262306a36Sopenharmony_ci WRITE_ONCE(msk->rcv_fastclose, true); 115362306a36Sopenharmony_ci mptcp_schedule_work((struct sock *)msk); 115462306a36Sopenharmony_ci MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_MPFASTCLOSERX); 115562306a36Sopenharmony_ci } 115662306a36Sopenharmony_ci 115762306a36Sopenharmony_ci if ((mp_opt.suboptions & OPTION_MPTCP_ADD_ADDR) && 115862306a36Sopenharmony_ci add_addr_hmac_valid(msk, &mp_opt)) { 115962306a36Sopenharmony_ci if (!mp_opt.echo) { 116062306a36Sopenharmony_ci mptcp_pm_add_addr_received(sk, &mp_opt.addr); 116162306a36Sopenharmony_ci MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_ADDADDR); 116262306a36Sopenharmony_ci } else { 116362306a36Sopenharmony_ci mptcp_pm_add_addr_echoed(msk, &mp_opt.addr); 116462306a36Sopenharmony_ci mptcp_pm_del_add_timer(msk, &mp_opt.addr, true); 116562306a36Sopenharmony_ci MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_ECHOADD); 116662306a36Sopenharmony_ci } 116762306a36Sopenharmony_ci 116862306a36Sopenharmony_ci if (mp_opt.addr.port) 116962306a36Sopenharmony_ci MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_PORTADD); 117062306a36Sopenharmony_ci } 117162306a36Sopenharmony_ci 117262306a36Sopenharmony_ci if (mp_opt.suboptions & OPTION_MPTCP_RM_ADDR) 117362306a36Sopenharmony_ci mptcp_pm_rm_addr_received(msk, &mp_opt.rm_list); 117462306a36Sopenharmony_ci 117562306a36Sopenharmony_ci if (mp_opt.suboptions & OPTION_MPTCP_PRIO) { 117662306a36Sopenharmony_ci mptcp_pm_mp_prio_received(sk, mp_opt.backup); 117762306a36Sopenharmony_ci MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_MPPRIORX); 117862306a36Sopenharmony_ci } 117962306a36Sopenharmony_ci 118062306a36Sopenharmony_ci if (mp_opt.suboptions & OPTION_MPTCP_FAIL) { 118162306a36Sopenharmony_ci mptcp_pm_mp_fail_received(sk, mp_opt.fail_seq); 118262306a36Sopenharmony_ci MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_MPFAILRX); 118362306a36Sopenharmony_ci } 118462306a36Sopenharmony_ci 118562306a36Sopenharmony_ci if (mp_opt.suboptions & OPTION_MPTCP_RST) { 118662306a36Sopenharmony_ci subflow->reset_seen = 1; 118762306a36Sopenharmony_ci subflow->reset_reason = mp_opt.reset_reason; 118862306a36Sopenharmony_ci subflow->reset_transient = mp_opt.reset_transient; 118962306a36Sopenharmony_ci MPTCP_INC_STATS(sock_net(sk), MPTCP_MIB_MPRSTRX); 119062306a36Sopenharmony_ci } 119162306a36Sopenharmony_ci 119262306a36Sopenharmony_ci if (!(mp_opt.suboptions & OPTION_MPTCP_DSS)) 119362306a36Sopenharmony_ci return true; 119462306a36Sopenharmony_ci } 119562306a36Sopenharmony_ci 119662306a36Sopenharmony_ci /* we can't wait for recvmsg() to update the ack_seq, otherwise 119762306a36Sopenharmony_ci * monodirectional flows will stuck 119862306a36Sopenharmony_ci */ 119962306a36Sopenharmony_ci if (mp_opt.use_ack) 120062306a36Sopenharmony_ci ack_update_msk(msk, sk, &mp_opt); 120162306a36Sopenharmony_ci 120262306a36Sopenharmony_ci /* Zero-data-length packets are dropped by the caller and not 120362306a36Sopenharmony_ci * propagated to the MPTCP layer, so the skb extension does not 120462306a36Sopenharmony_ci * need to be allocated or populated. DATA_FIN information, if 120562306a36Sopenharmony_ci * present, needs to be updated here before the skb is freed. 120662306a36Sopenharmony_ci */ 120762306a36Sopenharmony_ci if (TCP_SKB_CB(skb)->seq == TCP_SKB_CB(skb)->end_seq) { 120862306a36Sopenharmony_ci if (mp_opt.data_fin && mp_opt.data_len == 1 && 120962306a36Sopenharmony_ci mptcp_update_rcv_data_fin(msk, mp_opt.data_seq, mp_opt.dsn64)) 121062306a36Sopenharmony_ci mptcp_schedule_work((struct sock *)msk); 121162306a36Sopenharmony_ci 121262306a36Sopenharmony_ci return true; 121362306a36Sopenharmony_ci } 121462306a36Sopenharmony_ci 121562306a36Sopenharmony_ci mpext = skb_ext_add(skb, SKB_EXT_MPTCP); 121662306a36Sopenharmony_ci if (!mpext) 121762306a36Sopenharmony_ci return true; 121862306a36Sopenharmony_ci 121962306a36Sopenharmony_ci memset(mpext, 0, sizeof(*mpext)); 122062306a36Sopenharmony_ci 122162306a36Sopenharmony_ci if (likely(mp_opt.use_map)) { 122262306a36Sopenharmony_ci if (mp_opt.mpc_map) { 122362306a36Sopenharmony_ci /* this is an MP_CAPABLE carrying MPTCP data 122462306a36Sopenharmony_ci * we know this map the first chunk of data 122562306a36Sopenharmony_ci */ 122662306a36Sopenharmony_ci mptcp_crypto_key_sha(subflow->remote_key, NULL, 122762306a36Sopenharmony_ci &mpext->data_seq); 122862306a36Sopenharmony_ci mpext->data_seq++; 122962306a36Sopenharmony_ci mpext->subflow_seq = 1; 123062306a36Sopenharmony_ci mpext->dsn64 = 1; 123162306a36Sopenharmony_ci mpext->mpc_map = 1; 123262306a36Sopenharmony_ci mpext->data_fin = 0; 123362306a36Sopenharmony_ci } else { 123462306a36Sopenharmony_ci mpext->data_seq = mp_opt.data_seq; 123562306a36Sopenharmony_ci mpext->subflow_seq = mp_opt.subflow_seq; 123662306a36Sopenharmony_ci mpext->dsn64 = mp_opt.dsn64; 123762306a36Sopenharmony_ci mpext->data_fin = mp_opt.data_fin; 123862306a36Sopenharmony_ci } 123962306a36Sopenharmony_ci mpext->data_len = mp_opt.data_len; 124062306a36Sopenharmony_ci mpext->use_map = 1; 124162306a36Sopenharmony_ci mpext->csum_reqd = !!(mp_opt.suboptions & OPTION_MPTCP_CSUMREQD); 124262306a36Sopenharmony_ci 124362306a36Sopenharmony_ci if (mpext->csum_reqd) 124462306a36Sopenharmony_ci mpext->csum = mp_opt.csum; 124562306a36Sopenharmony_ci } 124662306a36Sopenharmony_ci 124762306a36Sopenharmony_ci return true; 124862306a36Sopenharmony_ci} 124962306a36Sopenharmony_ci 125062306a36Sopenharmony_cistatic void mptcp_set_rwin(struct tcp_sock *tp, struct tcphdr *th) 125162306a36Sopenharmony_ci{ 125262306a36Sopenharmony_ci const struct sock *ssk = (const struct sock *)tp; 125362306a36Sopenharmony_ci struct mptcp_subflow_context *subflow; 125462306a36Sopenharmony_ci u64 ack_seq, rcv_wnd_old, rcv_wnd_new; 125562306a36Sopenharmony_ci struct mptcp_sock *msk; 125662306a36Sopenharmony_ci u32 new_win; 125762306a36Sopenharmony_ci u64 win; 125862306a36Sopenharmony_ci 125962306a36Sopenharmony_ci subflow = mptcp_subflow_ctx(ssk); 126062306a36Sopenharmony_ci msk = mptcp_sk(subflow->conn); 126162306a36Sopenharmony_ci 126262306a36Sopenharmony_ci ack_seq = READ_ONCE(msk->ack_seq); 126362306a36Sopenharmony_ci rcv_wnd_new = ack_seq + tp->rcv_wnd; 126462306a36Sopenharmony_ci 126562306a36Sopenharmony_ci rcv_wnd_old = atomic64_read(&msk->rcv_wnd_sent); 126662306a36Sopenharmony_ci if (after64(rcv_wnd_new, rcv_wnd_old)) { 126762306a36Sopenharmony_ci u64 rcv_wnd; 126862306a36Sopenharmony_ci 126962306a36Sopenharmony_ci for (;;) { 127062306a36Sopenharmony_ci rcv_wnd = atomic64_cmpxchg(&msk->rcv_wnd_sent, rcv_wnd_old, rcv_wnd_new); 127162306a36Sopenharmony_ci 127262306a36Sopenharmony_ci if (rcv_wnd == rcv_wnd_old) 127362306a36Sopenharmony_ci break; 127462306a36Sopenharmony_ci 127562306a36Sopenharmony_ci rcv_wnd_old = rcv_wnd; 127662306a36Sopenharmony_ci if (before64(rcv_wnd_new, rcv_wnd_old)) { 127762306a36Sopenharmony_ci MPTCP_INC_STATS(sock_net(ssk), MPTCP_MIB_RCVWNDCONFLICTUPDATE); 127862306a36Sopenharmony_ci goto raise_win; 127962306a36Sopenharmony_ci } 128062306a36Sopenharmony_ci MPTCP_INC_STATS(sock_net(ssk), MPTCP_MIB_RCVWNDCONFLICT); 128162306a36Sopenharmony_ci } 128262306a36Sopenharmony_ci return; 128362306a36Sopenharmony_ci } 128462306a36Sopenharmony_ci 128562306a36Sopenharmony_ci if (rcv_wnd_new != rcv_wnd_old) { 128662306a36Sopenharmony_ciraise_win: 128762306a36Sopenharmony_ci win = rcv_wnd_old - ack_seq; 128862306a36Sopenharmony_ci tp->rcv_wnd = min_t(u64, win, U32_MAX); 128962306a36Sopenharmony_ci new_win = tp->rcv_wnd; 129062306a36Sopenharmony_ci 129162306a36Sopenharmony_ci /* Make sure we do not exceed the maximum possible 129262306a36Sopenharmony_ci * scaled window. 129362306a36Sopenharmony_ci */ 129462306a36Sopenharmony_ci if (unlikely(th->syn)) 129562306a36Sopenharmony_ci new_win = min(new_win, 65535U) << tp->rx_opt.rcv_wscale; 129662306a36Sopenharmony_ci if (!tp->rx_opt.rcv_wscale && 129762306a36Sopenharmony_ci READ_ONCE(sock_net(ssk)->ipv4.sysctl_tcp_workaround_signed_windows)) 129862306a36Sopenharmony_ci new_win = min(new_win, MAX_TCP_WINDOW); 129962306a36Sopenharmony_ci else 130062306a36Sopenharmony_ci new_win = min(new_win, (65535U << tp->rx_opt.rcv_wscale)); 130162306a36Sopenharmony_ci 130262306a36Sopenharmony_ci /* RFC1323 scaling applied */ 130362306a36Sopenharmony_ci new_win >>= tp->rx_opt.rcv_wscale; 130462306a36Sopenharmony_ci th->window = htons(new_win); 130562306a36Sopenharmony_ci MPTCP_INC_STATS(sock_net(ssk), MPTCP_MIB_RCVWNDSHARED); 130662306a36Sopenharmony_ci } 130762306a36Sopenharmony_ci} 130862306a36Sopenharmony_ci 130962306a36Sopenharmony_ci__sum16 __mptcp_make_csum(u64 data_seq, u32 subflow_seq, u16 data_len, __wsum sum) 131062306a36Sopenharmony_ci{ 131162306a36Sopenharmony_ci struct csum_pseudo_header header; 131262306a36Sopenharmony_ci __wsum csum; 131362306a36Sopenharmony_ci 131462306a36Sopenharmony_ci /* cfr RFC 8684 3.3.1.: 131562306a36Sopenharmony_ci * the data sequence number used in the pseudo-header is 131662306a36Sopenharmony_ci * always the 64-bit value, irrespective of what length is used in the 131762306a36Sopenharmony_ci * DSS option itself. 131862306a36Sopenharmony_ci */ 131962306a36Sopenharmony_ci header.data_seq = cpu_to_be64(data_seq); 132062306a36Sopenharmony_ci header.subflow_seq = htonl(subflow_seq); 132162306a36Sopenharmony_ci header.data_len = htons(data_len); 132262306a36Sopenharmony_ci header.csum = 0; 132362306a36Sopenharmony_ci 132462306a36Sopenharmony_ci csum = csum_partial(&header, sizeof(header), sum); 132562306a36Sopenharmony_ci return csum_fold(csum); 132662306a36Sopenharmony_ci} 132762306a36Sopenharmony_ci 132862306a36Sopenharmony_cistatic __sum16 mptcp_make_csum(const struct mptcp_ext *mpext) 132962306a36Sopenharmony_ci{ 133062306a36Sopenharmony_ci return __mptcp_make_csum(mpext->data_seq, mpext->subflow_seq, mpext->data_len, 133162306a36Sopenharmony_ci ~csum_unfold(mpext->csum)); 133262306a36Sopenharmony_ci} 133362306a36Sopenharmony_ci 133462306a36Sopenharmony_cistatic void put_len_csum(u16 len, __sum16 csum, void *data) 133562306a36Sopenharmony_ci{ 133662306a36Sopenharmony_ci __sum16 *sumptr = data + 2; 133762306a36Sopenharmony_ci __be16 *ptr = data; 133862306a36Sopenharmony_ci 133962306a36Sopenharmony_ci put_unaligned_be16(len, ptr); 134062306a36Sopenharmony_ci 134162306a36Sopenharmony_ci put_unaligned(csum, sumptr); 134262306a36Sopenharmony_ci} 134362306a36Sopenharmony_ci 134462306a36Sopenharmony_civoid mptcp_write_options(struct tcphdr *th, __be32 *ptr, struct tcp_sock *tp, 134562306a36Sopenharmony_ci struct mptcp_out_options *opts) 134662306a36Sopenharmony_ci{ 134762306a36Sopenharmony_ci const struct sock *ssk = (const struct sock *)tp; 134862306a36Sopenharmony_ci struct mptcp_subflow_context *subflow; 134962306a36Sopenharmony_ci 135062306a36Sopenharmony_ci /* Which options can be used together? 135162306a36Sopenharmony_ci * 135262306a36Sopenharmony_ci * X: mutually exclusive 135362306a36Sopenharmony_ci * O: often used together 135462306a36Sopenharmony_ci * C: can be used together in some cases 135562306a36Sopenharmony_ci * P: could be used together but we prefer not to (optimisations) 135662306a36Sopenharmony_ci * 135762306a36Sopenharmony_ci * Opt: | MPC | MPJ | DSS | ADD | RM | PRIO | FAIL | FC | 135862306a36Sopenharmony_ci * ------|------|------|------|------|------|------|------|------| 135962306a36Sopenharmony_ci * MPC |------|------|------|------|------|------|------|------| 136062306a36Sopenharmony_ci * MPJ | X |------|------|------|------|------|------|------| 136162306a36Sopenharmony_ci * DSS | X | X |------|------|------|------|------|------| 136262306a36Sopenharmony_ci * ADD | X | X | P |------|------|------|------|------| 136362306a36Sopenharmony_ci * RM | C | C | C | P |------|------|------|------| 136462306a36Sopenharmony_ci * PRIO | X | C | C | C | C |------|------|------| 136562306a36Sopenharmony_ci * FAIL | X | X | C | X | X | X |------|------| 136662306a36Sopenharmony_ci * FC | X | X | X | X | X | X | X |------| 136762306a36Sopenharmony_ci * RST | X | X | X | X | X | X | O | O | 136862306a36Sopenharmony_ci * ------|------|------|------|------|------|------|------|------| 136962306a36Sopenharmony_ci * 137062306a36Sopenharmony_ci * The same applies in mptcp_established_options() function. 137162306a36Sopenharmony_ci */ 137262306a36Sopenharmony_ci if (likely(OPTION_MPTCP_DSS & opts->suboptions)) { 137362306a36Sopenharmony_ci struct mptcp_ext *mpext = &opts->ext_copy; 137462306a36Sopenharmony_ci u8 len = TCPOLEN_MPTCP_DSS_BASE; 137562306a36Sopenharmony_ci u8 flags = 0; 137662306a36Sopenharmony_ci 137762306a36Sopenharmony_ci if (mpext->use_ack) { 137862306a36Sopenharmony_ci flags = MPTCP_DSS_HAS_ACK; 137962306a36Sopenharmony_ci if (mpext->ack64) { 138062306a36Sopenharmony_ci len += TCPOLEN_MPTCP_DSS_ACK64; 138162306a36Sopenharmony_ci flags |= MPTCP_DSS_ACK64; 138262306a36Sopenharmony_ci } else { 138362306a36Sopenharmony_ci len += TCPOLEN_MPTCP_DSS_ACK32; 138462306a36Sopenharmony_ci } 138562306a36Sopenharmony_ci } 138662306a36Sopenharmony_ci 138762306a36Sopenharmony_ci if (mpext->use_map) { 138862306a36Sopenharmony_ci len += TCPOLEN_MPTCP_DSS_MAP64; 138962306a36Sopenharmony_ci 139062306a36Sopenharmony_ci /* Use only 64-bit mapping flags for now, add 139162306a36Sopenharmony_ci * support for optional 32-bit mappings later. 139262306a36Sopenharmony_ci */ 139362306a36Sopenharmony_ci flags |= MPTCP_DSS_HAS_MAP | MPTCP_DSS_DSN64; 139462306a36Sopenharmony_ci if (mpext->data_fin) 139562306a36Sopenharmony_ci flags |= MPTCP_DSS_DATA_FIN; 139662306a36Sopenharmony_ci 139762306a36Sopenharmony_ci if (opts->csum_reqd) 139862306a36Sopenharmony_ci len += TCPOLEN_MPTCP_DSS_CHECKSUM; 139962306a36Sopenharmony_ci } 140062306a36Sopenharmony_ci 140162306a36Sopenharmony_ci *ptr++ = mptcp_option(MPTCPOPT_DSS, len, 0, flags); 140262306a36Sopenharmony_ci 140362306a36Sopenharmony_ci if (mpext->use_ack) { 140462306a36Sopenharmony_ci if (mpext->ack64) { 140562306a36Sopenharmony_ci put_unaligned_be64(mpext->data_ack, ptr); 140662306a36Sopenharmony_ci ptr += 2; 140762306a36Sopenharmony_ci } else { 140862306a36Sopenharmony_ci put_unaligned_be32(mpext->data_ack32, ptr); 140962306a36Sopenharmony_ci ptr += 1; 141062306a36Sopenharmony_ci } 141162306a36Sopenharmony_ci } 141262306a36Sopenharmony_ci 141362306a36Sopenharmony_ci if (mpext->use_map) { 141462306a36Sopenharmony_ci put_unaligned_be64(mpext->data_seq, ptr); 141562306a36Sopenharmony_ci ptr += 2; 141662306a36Sopenharmony_ci put_unaligned_be32(mpext->subflow_seq, ptr); 141762306a36Sopenharmony_ci ptr += 1; 141862306a36Sopenharmony_ci if (opts->csum_reqd) { 141962306a36Sopenharmony_ci /* data_len == 0 is reserved for the infinite mapping, 142062306a36Sopenharmony_ci * the checksum will also be set to 0. 142162306a36Sopenharmony_ci */ 142262306a36Sopenharmony_ci put_len_csum(mpext->data_len, 142362306a36Sopenharmony_ci (mpext->data_len ? mptcp_make_csum(mpext) : 0), 142462306a36Sopenharmony_ci ptr); 142562306a36Sopenharmony_ci } else { 142662306a36Sopenharmony_ci put_unaligned_be32(mpext->data_len << 16 | 142762306a36Sopenharmony_ci TCPOPT_NOP << 8 | TCPOPT_NOP, ptr); 142862306a36Sopenharmony_ci } 142962306a36Sopenharmony_ci ptr += 1; 143062306a36Sopenharmony_ci } 143162306a36Sopenharmony_ci 143262306a36Sopenharmony_ci /* We might need to add MP_FAIL options in rare cases */ 143362306a36Sopenharmony_ci if (unlikely(OPTION_MPTCP_FAIL & opts->suboptions)) 143462306a36Sopenharmony_ci goto mp_fail; 143562306a36Sopenharmony_ci } else if (OPTIONS_MPTCP_MPC & opts->suboptions) { 143662306a36Sopenharmony_ci u8 len, flag = MPTCP_CAP_HMAC_SHA256; 143762306a36Sopenharmony_ci 143862306a36Sopenharmony_ci if (OPTION_MPTCP_MPC_SYN & opts->suboptions) { 143962306a36Sopenharmony_ci len = TCPOLEN_MPTCP_MPC_SYN; 144062306a36Sopenharmony_ci } else if (OPTION_MPTCP_MPC_SYNACK & opts->suboptions) { 144162306a36Sopenharmony_ci len = TCPOLEN_MPTCP_MPC_SYNACK; 144262306a36Sopenharmony_ci } else if (opts->data_len) { 144362306a36Sopenharmony_ci len = TCPOLEN_MPTCP_MPC_ACK_DATA; 144462306a36Sopenharmony_ci if (opts->csum_reqd) 144562306a36Sopenharmony_ci len += TCPOLEN_MPTCP_DSS_CHECKSUM; 144662306a36Sopenharmony_ci } else { 144762306a36Sopenharmony_ci len = TCPOLEN_MPTCP_MPC_ACK; 144862306a36Sopenharmony_ci } 144962306a36Sopenharmony_ci 145062306a36Sopenharmony_ci if (opts->csum_reqd) 145162306a36Sopenharmony_ci flag |= MPTCP_CAP_CHECKSUM_REQD; 145262306a36Sopenharmony_ci 145362306a36Sopenharmony_ci if (!opts->allow_join_id0) 145462306a36Sopenharmony_ci flag |= MPTCP_CAP_DENY_JOIN_ID0; 145562306a36Sopenharmony_ci 145662306a36Sopenharmony_ci *ptr++ = mptcp_option(MPTCPOPT_MP_CAPABLE, len, 145762306a36Sopenharmony_ci MPTCP_SUPPORTED_VERSION, 145862306a36Sopenharmony_ci flag); 145962306a36Sopenharmony_ci 146062306a36Sopenharmony_ci if (!((OPTION_MPTCP_MPC_SYNACK | OPTION_MPTCP_MPC_ACK) & 146162306a36Sopenharmony_ci opts->suboptions)) 146262306a36Sopenharmony_ci goto mp_capable_done; 146362306a36Sopenharmony_ci 146462306a36Sopenharmony_ci put_unaligned_be64(opts->sndr_key, ptr); 146562306a36Sopenharmony_ci ptr += 2; 146662306a36Sopenharmony_ci if (!((OPTION_MPTCP_MPC_ACK) & opts->suboptions)) 146762306a36Sopenharmony_ci goto mp_capable_done; 146862306a36Sopenharmony_ci 146962306a36Sopenharmony_ci put_unaligned_be64(opts->rcvr_key, ptr); 147062306a36Sopenharmony_ci ptr += 2; 147162306a36Sopenharmony_ci if (!opts->data_len) 147262306a36Sopenharmony_ci goto mp_capable_done; 147362306a36Sopenharmony_ci 147462306a36Sopenharmony_ci if (opts->csum_reqd) { 147562306a36Sopenharmony_ci put_len_csum(opts->data_len, 147662306a36Sopenharmony_ci __mptcp_make_csum(opts->data_seq, 147762306a36Sopenharmony_ci opts->subflow_seq, 147862306a36Sopenharmony_ci opts->data_len, 147962306a36Sopenharmony_ci ~csum_unfold(opts->csum)), 148062306a36Sopenharmony_ci ptr); 148162306a36Sopenharmony_ci } else { 148262306a36Sopenharmony_ci put_unaligned_be32(opts->data_len << 16 | 148362306a36Sopenharmony_ci TCPOPT_NOP << 8 | TCPOPT_NOP, ptr); 148462306a36Sopenharmony_ci } 148562306a36Sopenharmony_ci ptr += 1; 148662306a36Sopenharmony_ci 148762306a36Sopenharmony_ci /* MPC is additionally mutually exclusive with MP_PRIO */ 148862306a36Sopenharmony_ci goto mp_capable_done; 148962306a36Sopenharmony_ci } else if (OPTIONS_MPTCP_MPJ & opts->suboptions) { 149062306a36Sopenharmony_ci if (OPTION_MPTCP_MPJ_SYN & opts->suboptions) { 149162306a36Sopenharmony_ci *ptr++ = mptcp_option(MPTCPOPT_MP_JOIN, 149262306a36Sopenharmony_ci TCPOLEN_MPTCP_MPJ_SYN, 149362306a36Sopenharmony_ci opts->backup, opts->join_id); 149462306a36Sopenharmony_ci put_unaligned_be32(opts->token, ptr); 149562306a36Sopenharmony_ci ptr += 1; 149662306a36Sopenharmony_ci put_unaligned_be32(opts->nonce, ptr); 149762306a36Sopenharmony_ci ptr += 1; 149862306a36Sopenharmony_ci } else if (OPTION_MPTCP_MPJ_SYNACK & opts->suboptions) { 149962306a36Sopenharmony_ci *ptr++ = mptcp_option(MPTCPOPT_MP_JOIN, 150062306a36Sopenharmony_ci TCPOLEN_MPTCP_MPJ_SYNACK, 150162306a36Sopenharmony_ci opts->backup, opts->join_id); 150262306a36Sopenharmony_ci put_unaligned_be64(opts->thmac, ptr); 150362306a36Sopenharmony_ci ptr += 2; 150462306a36Sopenharmony_ci put_unaligned_be32(opts->nonce, ptr); 150562306a36Sopenharmony_ci ptr += 1; 150662306a36Sopenharmony_ci } else { 150762306a36Sopenharmony_ci *ptr++ = mptcp_option(MPTCPOPT_MP_JOIN, 150862306a36Sopenharmony_ci TCPOLEN_MPTCP_MPJ_ACK, 0, 0); 150962306a36Sopenharmony_ci memcpy(ptr, opts->hmac, MPTCPOPT_HMAC_LEN); 151062306a36Sopenharmony_ci ptr += 5; 151162306a36Sopenharmony_ci } 151262306a36Sopenharmony_ci } else if (OPTION_MPTCP_ADD_ADDR & opts->suboptions) { 151362306a36Sopenharmony_ci u8 len = TCPOLEN_MPTCP_ADD_ADDR_BASE; 151462306a36Sopenharmony_ci u8 echo = MPTCP_ADDR_ECHO; 151562306a36Sopenharmony_ci 151662306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_MPTCP_IPV6) 151762306a36Sopenharmony_ci if (opts->addr.family == AF_INET6) 151862306a36Sopenharmony_ci len = TCPOLEN_MPTCP_ADD_ADDR6_BASE; 151962306a36Sopenharmony_ci#endif 152062306a36Sopenharmony_ci 152162306a36Sopenharmony_ci if (opts->addr.port) 152262306a36Sopenharmony_ci len += TCPOLEN_MPTCP_PORT_LEN; 152362306a36Sopenharmony_ci 152462306a36Sopenharmony_ci if (opts->ahmac) { 152562306a36Sopenharmony_ci len += sizeof(opts->ahmac); 152662306a36Sopenharmony_ci echo = 0; 152762306a36Sopenharmony_ci } 152862306a36Sopenharmony_ci 152962306a36Sopenharmony_ci *ptr++ = mptcp_option(MPTCPOPT_ADD_ADDR, 153062306a36Sopenharmony_ci len, echo, opts->addr.id); 153162306a36Sopenharmony_ci if (opts->addr.family == AF_INET) { 153262306a36Sopenharmony_ci memcpy((u8 *)ptr, (u8 *)&opts->addr.addr.s_addr, 4); 153362306a36Sopenharmony_ci ptr += 1; 153462306a36Sopenharmony_ci } 153562306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_MPTCP_IPV6) 153662306a36Sopenharmony_ci else if (opts->addr.family == AF_INET6) { 153762306a36Sopenharmony_ci memcpy((u8 *)ptr, opts->addr.addr6.s6_addr, 16); 153862306a36Sopenharmony_ci ptr += 4; 153962306a36Sopenharmony_ci } 154062306a36Sopenharmony_ci#endif 154162306a36Sopenharmony_ci 154262306a36Sopenharmony_ci if (!opts->addr.port) { 154362306a36Sopenharmony_ci if (opts->ahmac) { 154462306a36Sopenharmony_ci put_unaligned_be64(opts->ahmac, ptr); 154562306a36Sopenharmony_ci ptr += 2; 154662306a36Sopenharmony_ci } 154762306a36Sopenharmony_ci } else { 154862306a36Sopenharmony_ci u16 port = ntohs(opts->addr.port); 154962306a36Sopenharmony_ci 155062306a36Sopenharmony_ci if (opts->ahmac) { 155162306a36Sopenharmony_ci u8 *bptr = (u8 *)ptr; 155262306a36Sopenharmony_ci 155362306a36Sopenharmony_ci put_unaligned_be16(port, bptr); 155462306a36Sopenharmony_ci bptr += 2; 155562306a36Sopenharmony_ci put_unaligned_be64(opts->ahmac, bptr); 155662306a36Sopenharmony_ci bptr += 8; 155762306a36Sopenharmony_ci put_unaligned_be16(TCPOPT_NOP << 8 | 155862306a36Sopenharmony_ci TCPOPT_NOP, bptr); 155962306a36Sopenharmony_ci 156062306a36Sopenharmony_ci ptr += 3; 156162306a36Sopenharmony_ci } else { 156262306a36Sopenharmony_ci put_unaligned_be32(port << 16 | 156362306a36Sopenharmony_ci TCPOPT_NOP << 8 | 156462306a36Sopenharmony_ci TCPOPT_NOP, ptr); 156562306a36Sopenharmony_ci ptr += 1; 156662306a36Sopenharmony_ci } 156762306a36Sopenharmony_ci } 156862306a36Sopenharmony_ci } else if (unlikely(OPTION_MPTCP_FASTCLOSE & opts->suboptions)) { 156962306a36Sopenharmony_ci /* FASTCLOSE is mutually exclusive with others except RST */ 157062306a36Sopenharmony_ci *ptr++ = mptcp_option(MPTCPOPT_MP_FASTCLOSE, 157162306a36Sopenharmony_ci TCPOLEN_MPTCP_FASTCLOSE, 157262306a36Sopenharmony_ci 0, 0); 157362306a36Sopenharmony_ci put_unaligned_be64(opts->rcvr_key, ptr); 157462306a36Sopenharmony_ci ptr += 2; 157562306a36Sopenharmony_ci 157662306a36Sopenharmony_ci if (OPTION_MPTCP_RST & opts->suboptions) 157762306a36Sopenharmony_ci goto mp_rst; 157862306a36Sopenharmony_ci return; 157962306a36Sopenharmony_ci } else if (unlikely(OPTION_MPTCP_FAIL & opts->suboptions)) { 158062306a36Sopenharmony_cimp_fail: 158162306a36Sopenharmony_ci /* MP_FAIL is mutually exclusive with others except RST */ 158262306a36Sopenharmony_ci subflow = mptcp_subflow_ctx(ssk); 158362306a36Sopenharmony_ci subflow->send_mp_fail = 0; 158462306a36Sopenharmony_ci 158562306a36Sopenharmony_ci *ptr++ = mptcp_option(MPTCPOPT_MP_FAIL, 158662306a36Sopenharmony_ci TCPOLEN_MPTCP_FAIL, 158762306a36Sopenharmony_ci 0, 0); 158862306a36Sopenharmony_ci put_unaligned_be64(opts->fail_seq, ptr); 158962306a36Sopenharmony_ci ptr += 2; 159062306a36Sopenharmony_ci 159162306a36Sopenharmony_ci if (OPTION_MPTCP_RST & opts->suboptions) 159262306a36Sopenharmony_ci goto mp_rst; 159362306a36Sopenharmony_ci return; 159462306a36Sopenharmony_ci } else if (unlikely(OPTION_MPTCP_RST & opts->suboptions)) { 159562306a36Sopenharmony_cimp_rst: 159662306a36Sopenharmony_ci *ptr++ = mptcp_option(MPTCPOPT_RST, 159762306a36Sopenharmony_ci TCPOLEN_MPTCP_RST, 159862306a36Sopenharmony_ci opts->reset_transient, 159962306a36Sopenharmony_ci opts->reset_reason); 160062306a36Sopenharmony_ci return; 160162306a36Sopenharmony_ci } 160262306a36Sopenharmony_ci 160362306a36Sopenharmony_ci if (OPTION_MPTCP_PRIO & opts->suboptions) { 160462306a36Sopenharmony_ci subflow = mptcp_subflow_ctx(ssk); 160562306a36Sopenharmony_ci subflow->send_mp_prio = 0; 160662306a36Sopenharmony_ci 160762306a36Sopenharmony_ci *ptr++ = mptcp_option(MPTCPOPT_MP_PRIO, 160862306a36Sopenharmony_ci TCPOLEN_MPTCP_PRIO, 160962306a36Sopenharmony_ci opts->backup, TCPOPT_NOP); 161062306a36Sopenharmony_ci 161162306a36Sopenharmony_ci MPTCP_INC_STATS(sock_net(ssk), MPTCP_MIB_MPPRIOTX); 161262306a36Sopenharmony_ci } 161362306a36Sopenharmony_ci 161462306a36Sopenharmony_cimp_capable_done: 161562306a36Sopenharmony_ci if (OPTION_MPTCP_RM_ADDR & opts->suboptions) { 161662306a36Sopenharmony_ci u8 i = 1; 161762306a36Sopenharmony_ci 161862306a36Sopenharmony_ci *ptr++ = mptcp_option(MPTCPOPT_RM_ADDR, 161962306a36Sopenharmony_ci TCPOLEN_MPTCP_RM_ADDR_BASE + opts->rm_list.nr, 162062306a36Sopenharmony_ci 0, opts->rm_list.ids[0]); 162162306a36Sopenharmony_ci 162262306a36Sopenharmony_ci while (i < opts->rm_list.nr) { 162362306a36Sopenharmony_ci u8 id1, id2, id3, id4; 162462306a36Sopenharmony_ci 162562306a36Sopenharmony_ci id1 = opts->rm_list.ids[i]; 162662306a36Sopenharmony_ci id2 = i + 1 < opts->rm_list.nr ? opts->rm_list.ids[i + 1] : TCPOPT_NOP; 162762306a36Sopenharmony_ci id3 = i + 2 < opts->rm_list.nr ? opts->rm_list.ids[i + 2] : TCPOPT_NOP; 162862306a36Sopenharmony_ci id4 = i + 3 < opts->rm_list.nr ? opts->rm_list.ids[i + 3] : TCPOPT_NOP; 162962306a36Sopenharmony_ci put_unaligned_be32(id1 << 24 | id2 << 16 | id3 << 8 | id4, ptr); 163062306a36Sopenharmony_ci ptr += 1; 163162306a36Sopenharmony_ci i += 4; 163262306a36Sopenharmony_ci } 163362306a36Sopenharmony_ci } 163462306a36Sopenharmony_ci 163562306a36Sopenharmony_ci if (tp) 163662306a36Sopenharmony_ci mptcp_set_rwin(tp, th); 163762306a36Sopenharmony_ci} 163862306a36Sopenharmony_ci 163962306a36Sopenharmony_ci__be32 mptcp_get_reset_option(const struct sk_buff *skb) 164062306a36Sopenharmony_ci{ 164162306a36Sopenharmony_ci const struct mptcp_ext *ext = mptcp_get_ext(skb); 164262306a36Sopenharmony_ci u8 flags, reason; 164362306a36Sopenharmony_ci 164462306a36Sopenharmony_ci if (ext) { 164562306a36Sopenharmony_ci flags = ext->reset_transient; 164662306a36Sopenharmony_ci reason = ext->reset_reason; 164762306a36Sopenharmony_ci 164862306a36Sopenharmony_ci return mptcp_option(MPTCPOPT_RST, TCPOLEN_MPTCP_RST, 164962306a36Sopenharmony_ci flags, reason); 165062306a36Sopenharmony_ci } 165162306a36Sopenharmony_ci 165262306a36Sopenharmony_ci return htonl(0u); 165362306a36Sopenharmony_ci} 165462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mptcp_get_reset_option); 1655