+ case TCP_NOTSENT_LOWAT:
+ /* record at MPTCP level */
+ error = sooptcopyin(sopt, &optval, sizeof(optval),
+ sizeof(optval));
+ if (error) {
+ goto err_out;
+ }
+ if (optval < 0) {
+ error = EINVAL;
+ goto err_out;
+ } else {
+ if (optval == 0) {
+ mp_so->so_flags &= ~SOF_NOTSENT_LOWAT;
+ error = mptcp_set_notsent_lowat(mpte, 0);
+ } else {
+ mp_so->so_flags |= SOF_NOTSENT_LOWAT;
+ error = mptcp_set_notsent_lowat(mpte,
+ optval);
+ }
+
+ if (error) {
+ goto err_out;
+ }
+ }
+ goto out;
+ case MPTCP_SERVICE_TYPE:
+ /* record at MPTCP level */
+ error = sooptcopyin(sopt, &optval, sizeof(optval),
+ sizeof(optval));
+ if (error) {
+ goto err_out;
+ }
+ if (optval < 0 || optval >= MPTCP_SVCTYPE_MAX) {
+ error = EINVAL;
+ goto err_out;
+ }
+
+ mpte->mpte_svctype = optval;
+
+ if (mptcp_entitlement_check(mp_so) < 0) {
+ error = EACCES;
+ goto err_out;
+ }
+
+ mpte->mpte_flags |= MPTE_SVCTYPE_CHECKED;
+
+ goto out;
+ case MPTCP_ALTERNATE_PORT:
+ /* record at MPTCP level */
+ error = sooptcopyin(sopt, &optval, sizeof(optval),
+ sizeof(optval));
+ if (error) {
+ goto err_out;
+ }
+
+ if (optval < 0 || optval > UINT16_MAX) {
+ error = EINVAL;
+ goto err_out;
+ }
+
+ mpte->mpte_alternate_port = optval;
+
+ goto out;
+ case MPTCP_FORCE_ENABLE:
+ /* record at MPTCP level */
+ error = sooptcopyin(sopt, &optval, sizeof(optval),
+ sizeof(optval));
+ if (error) {
+ goto err_out;
+ }
+
+ if (optval < 0 || optval > 1) {
+ error = EINVAL;
+ goto err_out;
+ }
+
+ if (optval) {
+ mpte->mpte_flags |= MPTE_FORCE_ENABLE;
+ } else {
+ mpte->mpte_flags &= ~MPTE_FORCE_ENABLE;
+ }
+
+ goto out;
+ case MPTCP_EXPECTED_PROGRESS_TARGET:
+ {
+ struct mptcb *mp_tp = mpte->mpte_mptcb;
+ uint64_t mach_time_target;
+ uint64_t nanoseconds;
+
+ if (mpte->mpte_svctype != MPTCP_SVCTYPE_TARGET_BASED) {
+ os_log(mptcp_log_handle, "%s - %lx: Can't set urgent activity when svctype is %u\n",
+ __func__, (unsigned long)VM_KERNEL_ADDRPERM(mpte), mpte->mpte_svctype);
+ error = EINVAL;
+ goto err_out;
+ }
+
+ error = sooptcopyin(sopt, &mach_time_target, sizeof(mach_time_target), sizeof(mach_time_target));
+ if (error) {
+ goto err_out;
+ }
+
+ if (!mptcp_ok_to_create_subflows(mp_tp)) {
+ os_log(mptcp_log_handle, "%s - %lx: Not ok to create subflows, state %u flags %#x\n",
+ __func__, (unsigned long)VM_KERNEL_ADDRPERM(mpte), mp_tp->mpt_state, mp_tp->mpt_flags);
+ error = EINVAL;
+ goto err_out;
+ }
+
+ if (mach_time_target) {
+ uint64_t time_now = 0;
+ uint64_t time_now_nanoseconds;
+
+ absolutetime_to_nanoseconds(mach_time_target, &nanoseconds);
+ nanoseconds = nanoseconds - (mptcp_expected_progress_headstart * NSEC_PER_MSEC);
+
+ time_now = mach_continuous_time();
+ absolutetime_to_nanoseconds(time_now, &time_now_nanoseconds);
+
+ nanoseconds_to_absolutetime(nanoseconds, &mach_time_target);
+ /* If the timer is already running and it would
+ * fire in less than mptcp_expected_progress_headstart
+ * seconds, then it's not worth canceling it.
+ */
+ if (mpte->mpte_time_target &&
+ mpte->mpte_time_target < time_now &&
+ time_now_nanoseconds > nanoseconds - (mptcp_expected_progress_headstart * NSEC_PER_MSEC)) {
+ os_log(mptcp_log_handle, "%s - %lx: Not rescheduling timer %llu now %llu target %llu\n",
+ __func__, (unsigned long)VM_KERNEL_ADDRPERM(mpte),
+ mpte->mpte_time_target,
+ time_now,
+ mach_time_target);
+ goto out;
+ }
+ }
+
+ mpte->mpte_time_target = mach_time_target;
+ mptcp_set_urgency_timer(mpte);
+
+ goto out;
+ }