/* Create a new IPv4 subflow. * * We are in user-context and meta-sock-lock is hold. */ int mptcp_init4_subsockets(struct sock *meta_sk, const struct mptcp_loc4 *loc, struct mptcp_rem4 *rem) { struct tcp_sock *tp; struct sock *sk; struct sockaddr_in loc_in, rem_in; struct socket_alloc sock_full; struct socket *sock = (struct socket *)&sock_full; int ret; /** First, create and prepare the new socket */ memcpy(&sock_full, meta_sk->sk_socket, sizeof(sock_full)); sock->state = SS_UNCONNECTED; sock->ops = NULL; ret = inet_create(sock_net(meta_sk), sock, IPPROTO_TCP, 1); if (unlikely(ret < 0)) { net_err_ratelimited("%s inet_create failed ret: %d\n", __func__, ret); return ret; } sk = sock->sk; tp = tcp_sk(sk); /* All subsockets need the MPTCP-lock-class */ lockdep_set_class_and_name(&(sk)->sk_lock.slock, &meta_slock_key, meta_slock_key_name); lockdep_init_map(&(sk)->sk_lock.dep_map, meta_key_name, &meta_key, 0); ret = mptcp_add_sock(meta_sk, sk, loc->loc4_id, rem->rem4_id, GFP_KERNEL); if (ret) { net_err_ratelimited("%s mptcp_add_sock failed ret: %d\n", __func__, ret); goto error; } tp->mptcp->slave_sk = 1; /* Initializing the timer for an MPTCP subflow */ timer_setup(&tp->mptcp->mptcp_ack_timer, mptcp_ack_handler, 0); /** Then, connect the socket to the peer */ loc_in.sin_family = AF_INET; rem_in.sin_family = AF_INET; loc_in.sin_port = 0; if (rem->port) rem_in.sin_port = rem->port; else rem_in.sin_port = inet_sk(meta_sk)->inet_dport; loc_in.sin_addr = loc->addr; rem_in.sin_addr = rem->addr; if (loc->if_idx) sk->sk_bound_dev_if = loc->if_idx; ret = kernel_bind(sock, (struct sockaddr *)&loc_in, sizeof(struct sockaddr_in)); if (ret < 0) { net_err_ratelimited("%s: token %#x bind() to %pI4 index %d failed, error %d\n", __func__, tcp_sk(meta_sk)->mpcb->mptcp_loc_token, &loc_in.sin_addr, loc->if_idx, ret); goto error; } mptcp_debug("%s: token %#x pi %d src_addr:%pI4:%d dst_addr:%pI4:%d ifidx: %d\n", __func__, tcp_sk(meta_sk)->mpcb->mptcp_loc_token, tp->mptcp->path_index, &loc_in.sin_addr, ntohs(loc_in.sin_port), &rem_in.sin_addr, ntohs(rem_in.sin_port), loc->if_idx); ret = kernel_connect(sock, (struct sockaddr *)&rem_in, sizeof(struct sockaddr_in), O_NONBLOCK); if (ret < 0 && ret != -EINPROGRESS) { net_err_ratelimited("%s: MPTCP subsocket connect() failed, error %d\n", __func__, ret); goto error; } MPTCP_INC_STATS(sock_net(meta_sk), MPTCP_MIB_JOINSYNTX); sk_set_socket(sk, meta_sk->sk_socket); sk->sk_wq = meta_sk->sk_wq; return 0; error: /* May happen if mptcp_add_sock fails first */ if (!mptcp(tp)) { tcp_close(sk, 0); } else { local_bh_disable(); mptcp_sub_force_close(sk); local_bh_enable(); } return ret; }
struct sock *mptcp_select_ack_sock(const struct mptcp_cb *mpcb, int copied) { struct sock *sk, *subsk = NULL; struct tcp_sock *meta_tp = mpcb_meta_tp(mpcb); u32 max_data_seq = 0; /* max_data_seq initialized to correct compiler-warning. * But the initialization is handled by max_data_seq_set */ short max_data_seq_set = 0; u32 min_time = 0xffffffff; /* How do we select the subflow to send the window-update on? * * 1. He has to be in a state where he can send an ack. * 2. He has to be one of those subflow who recently * contributed to the received stream * (this guarantees a working subflow) * a) its latest data_seq received is after the original * copied_seq. * We select the one with the lowest rtt, so that the * window-update reaches our peer the fastest. * b) if no subflow has this kind of data_seq (e.g., very * strange meta-level retransmissions going on), we take * the subflow who last sent the highest data_seq. */ mptcp_for_each_sk(mpcb, sk) { struct tcp_sock *tp = tcp_sk(sk); if ((1 << sk->sk_state) & (TCPF_SYN_SENT | TCPF_SYN_RECV | TCPF_CLOSE | TCPF_LISTEN)) continue; /* Select among those who contributed to the * current receive-queue. */ if (copied && after(tp->mptcp->last_data_seq, meta_tp->copied_seq - copied)) { if (tp->srtt < min_time) { min_time = tp->srtt; subsk = sk; max_data_seq_set = 0; } continue; } if (!subsk && !max_data_seq_set) { max_data_seq = tp->mptcp->last_data_seq; max_data_seq_set = 1; subsk = sk; } /* Otherwise, take the one with the highest data_seq */ if ((!subsk || max_data_seq_set) && after(tp->mptcp->last_data_seq, max_data_seq)) { max_data_seq = tp->mptcp->last_data_seq; subsk = sk; } } if (!subsk) { mptcp_debug("%s subsk is null, copied %d, cseq %u\n", __func__, copied, meta_tp->copied_seq); mptcp_for_each_sk(mpcb, sk) { struct tcp_sock *tp = tcp_sk(sk); mptcp_debug("%s pi %d state %u last_dseq %u\n", __func__, tp->mptcp->path_index, sk->sk_state, tp->mptcp->last_data_seq); } }