721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon/*
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * CDDL HEADER START
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon *
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * The contents of this file are subject to the terms of the
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * Common Development and Distribution License (the "License").
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * You may not use this file except in compliance with the License.
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon *
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * or http://www.opensolaris.org/os/licensing.
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * See the License for the specific language governing permissions
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * and limitations under the License.
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon *
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * When distributing Covered Code, include this CDDL HEADER in each
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * If applicable, add the following below this CDDL HEADER, with the
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * fields enclosed by brackets "[]" replaced with your own identifying
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * information: Portions Copyright [yyyy] [name of copyright owner]
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon *
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * CDDL HEADER END
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon */
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon/*
66cd0f60c3182913d379abb730ae755bf6367126Kacheong Poon * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney * Copyright 2016 Joyent, Inc.
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon */
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon/*
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * This file contains functions related to TCP time wait processing. Also
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * refer to the time wait handling comments in tcp_impl.h.
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon */
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon#include <sys/types.h>
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon#include <sys/strsun.h>
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon#include <sys/squeue_impl.h>
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon#include <sys/squeue.h>
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon#include <sys/callo.h>
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon#include <inet/common.h>
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon#include <inet/ip.h>
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon#include <inet/tcp.h>
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon#include <inet/tcp_impl.h>
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon#include <inet/tcp_cluster.h>
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooneystatic void tcp_time_wait_purge(tcp_t *, tcp_squeue_priv_t *);
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney#define TW_BUCKET(t) \
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney (((t) / MSEC_TO_TICK(TCP_TIME_WAIT_DELAY)) % TCP_TIME_WAIT_BUCKETS)
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney#define TW_BUCKET_NEXT(b) (((b) + 1) % TCP_TIME_WAIT_BUCKETS)
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon/*
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * Remove a connection from the list of detached TIME_WAIT connections.
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * It returns B_FALSE if it can't remove the connection from the list
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * as the connection has already been removed from the list due to an
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * earlier call to tcp_time_wait_remove(); otherwise it returns B_TRUE.
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon */
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poonboolean_t
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooneytcp_time_wait_remove(tcp_t *tcp, tcp_squeue_priv_t *tsp)
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon{
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon boolean_t locked = B_FALSE;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney if (tsp == NULL) {
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney tsp = *((tcp_squeue_priv_t **)
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon squeue_getprivate(tcp->tcp_connp->conn_sqp, SQPRIVATE_TCP));
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney mutex_enter(&tsp->tcp_time_wait_lock);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon locked = B_TRUE;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon } else {
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney ASSERT(MUTEX_HELD(&tsp->tcp_time_wait_lock));
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon }
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon /* 0 means that the tcp_t has not been added to the time wait list. */
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (tcp->tcp_time_wait_expire == 0) {
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon ASSERT(tcp->tcp_time_wait_next == NULL);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon ASSERT(tcp->tcp_time_wait_prev == NULL);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (locked)
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney mutex_exit(&tsp->tcp_time_wait_lock);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon return (B_FALSE);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon }
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon ASSERT(TCP_IS_DETACHED(tcp));
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon ASSERT(tcp->tcp_state == TCPS_TIME_WAIT);
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney ASSERT(tsp->tcp_time_wait_cnt > 0);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney if (tcp->tcp_time_wait_next != NULL) {
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcp->tcp_time_wait_next->tcp_time_wait_prev =
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcp->tcp_time_wait_prev;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon }
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney if (tcp->tcp_time_wait_prev != NULL) {
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney tcp->tcp_time_wait_prev->tcp_time_wait_next =
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney tcp->tcp_time_wait_next;
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney } else {
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney unsigned int bucket;
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney bucket = TW_BUCKET(tcp->tcp_time_wait_expire);
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney ASSERT(tsp->tcp_time_wait_bucket[bucket] == tcp);
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney tsp->tcp_time_wait_bucket[bucket] = tcp->tcp_time_wait_next;
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney }
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcp->tcp_time_wait_next = NULL;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcp->tcp_time_wait_prev = NULL;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcp->tcp_time_wait_expire = 0;
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney tsp->tcp_time_wait_cnt--;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (locked)
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney mutex_exit(&tsp->tcp_time_wait_lock);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon return (B_TRUE);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon}
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
81b60dac72578dc6fa8b5be0b69548c8ebba1da8Jerry Jelinek/* Constants used for fast checking of a localhost address */
81b60dac72578dc6fa8b5be0b69548c8ebba1da8Jerry Jelinek#if defined(_BIG_ENDIAN)
81b60dac72578dc6fa8b5be0b69548c8ebba1da8Jerry Jelinek#define IPv4_LOCALHOST 0x7f000000U
81b60dac72578dc6fa8b5be0b69548c8ebba1da8Jerry Jelinek#define IPv4_LH_MASK 0xffffff00U
81b60dac72578dc6fa8b5be0b69548c8ebba1da8Jerry Jelinek#else
81b60dac72578dc6fa8b5be0b69548c8ebba1da8Jerry Jelinek#define IPv4_LOCALHOST 0x0000007fU
81b60dac72578dc6fa8b5be0b69548c8ebba1da8Jerry Jelinek#define IPv4_LH_MASK 0x00ffffffU
81b60dac72578dc6fa8b5be0b69548c8ebba1da8Jerry Jelinek#endif
81b60dac72578dc6fa8b5be0b69548c8ebba1da8Jerry Jelinek
81b60dac72578dc6fa8b5be0b69548c8ebba1da8Jerry Jelinek#define IS_LOCAL_HOST(x) ( \
81b60dac72578dc6fa8b5be0b69548c8ebba1da8Jerry Jelinek ((x)->tcp_connp->conn_ipversion == IPV4_VERSION && \
81b60dac72578dc6fa8b5be0b69548c8ebba1da8Jerry Jelinek ((x)->tcp_connp->conn_laddr_v4 & IPv4_LH_MASK) == IPv4_LOCALHOST) || \
81b60dac72578dc6fa8b5be0b69548c8ebba1da8Jerry Jelinek ((x)->tcp_connp->conn_ipversion == IPV6_VERSION && \
81b60dac72578dc6fa8b5be0b69548c8ebba1da8Jerry Jelinek IN6_IS_ADDR_LOOPBACK(&(x)->tcp_connp->conn_laddr_v6)))
81b60dac72578dc6fa8b5be0b69548c8ebba1da8Jerry Jelinek
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon/*
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * Add a connection to the list of detached TIME_WAIT connections
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * and set its time to expire.
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon */
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poonvoid
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poontcp_time_wait_append(tcp_t *tcp)
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon{
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcp_stack_t *tcps = tcp->tcp_tcps;
66cd0f60c3182913d379abb730ae755bf6367126Kacheong Poon squeue_t *sqp = tcp->tcp_connp->conn_sqp;
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney tcp_squeue_priv_t *tsp =
66cd0f60c3182913d379abb730ae755bf6367126Kacheong Poon *((tcp_squeue_priv_t **)squeue_getprivate(sqp, SQPRIVATE_TCP));
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney int64_t now, schedule;
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney unsigned int bucket;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcp_timers_stop(tcp);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon /* Freed above */
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon ASSERT(tcp->tcp_timer_tid == 0);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon ASSERT(tcp->tcp_ack_tid == 0);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon /* must have happened at the time of detaching the tcp */
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney ASSERT(TCP_IS_DETACHED(tcp));
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney ASSERT(tcp->tcp_state == TCPS_TIME_WAIT);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon ASSERT(tcp->tcp_ptpahn == NULL);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon ASSERT(tcp->tcp_flow_stopped == 0);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon ASSERT(tcp->tcp_time_wait_next == NULL);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon ASSERT(tcp->tcp_time_wait_prev == NULL);
66cd0f60c3182913d379abb730ae755bf6367126Kacheong Poon ASSERT(tcp->tcp_time_wait_expire == 0);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon ASSERT(tcp->tcp_listener == NULL);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney TCP_DBGSTAT(tcps, tcp_time_wait);
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney mutex_enter(&tsp->tcp_time_wait_lock);
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney /*
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney * Immediately expire loopback connections. Since there is no worry
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney * about packets on the local host showing up after a long network
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney * delay, this is safe and allows much higher rates of connection churn
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney * for applications operating locally.
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney *
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney * This typically bypasses the tcp_free_list fast path due to squeue
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney * re-entry for the loopback close operation.
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney */
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney if (tcp->tcp_loopback) {
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney tcp_time_wait_purge(tcp, tsp);
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney mutex_exit(&tsp->tcp_time_wait_lock);
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney return;
81b60dac72578dc6fa8b5be0b69548c8ebba1da8Jerry Jelinek }
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney /*
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney * In order to reap TIME_WAITs reliably, we should use a source of time
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney * that is not adjustable by the user. While it would be more accurate
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney * to grab this timestamp before (potentially) sleeping on the
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney * tcp_time_wait_lock, doing so complicates bucket addressing later.
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney */
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney now = ddi_get_lbolt64();
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney /*
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney * Each squeue uses an arbitrary time offset when scheduling
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney * expiration timers. This prevents the bucketing from forcing
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney * tcp_time_wait_collector to run in locksetup across squeues.
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney *
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney * This offset is (re)initialized when a new TIME_WAIT connection is
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney * added to an squeue which has no connections waiting to expire.
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney */
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney if (tsp->tcp_time_wait_tid == 0) {
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney ASSERT(tsp->tcp_time_wait_cnt == 0);
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney tsp->tcp_time_wait_offset =
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney now % MSEC_TO_TICK(TCP_TIME_WAIT_DELAY);
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney }
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney now -= tsp->tcp_time_wait_offset;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney /*
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney * Use the netstack-defined timeout, rounded up to the minimum
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney * time_wait_collector interval.
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney */
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney schedule = now + MSEC_TO_TICK(tcps->tcps_time_wait_interval);
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney tcp->tcp_time_wait_expire = schedule;
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney /*
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney * Append the connection into the appropriate bucket.
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney */
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney bucket = TW_BUCKET(tcp->tcp_time_wait_expire);
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney tcp->tcp_time_wait_next = tsp->tcp_time_wait_bucket[bucket];
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney tsp->tcp_time_wait_bucket[bucket] = tcp;
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney if (tcp->tcp_time_wait_next != NULL) {
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney ASSERT(tcp->tcp_time_wait_next->tcp_time_wait_prev == NULL);
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney tcp->tcp_time_wait_next->tcp_time_wait_prev = tcp;
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney }
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney tsp->tcp_time_wait_cnt++;
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney /*
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney * Round delay up to the nearest bucket boundary.
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney */
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney schedule += MSEC_TO_TICK(TCP_TIME_WAIT_DELAY);
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney schedule -= schedule % MSEC_TO_TICK(TCP_TIME_WAIT_DELAY);
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney /*
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney * The newly inserted entry may require a tighter schedule for the
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney * expiration timer.
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney */
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney if (schedule < tsp->tcp_time_wait_schedule) {
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney callout_id_t old_tid = tsp->tcp_time_wait_tid;
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney tsp->tcp_time_wait_schedule = schedule;
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney tsp->tcp_time_wait_tid =
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney timeout_generic(CALLOUT_NORMAL,
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney tcp_time_wait_collector, sqp,
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney TICK_TO_NSEC(schedule - now),
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney CALLOUT_TCP_RESOLUTION, CALLOUT_FLAG_ROUNDUP);
66cd0f60c3182913d379abb730ae755bf6367126Kacheong Poon
66cd0f60c3182913d379abb730ae755bf6367126Kacheong Poon /*
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney * It is possible for the timer to fire before the untimeout
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney * action is able to complete. In that case, the exclusion
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney * offered by the tcp_time_wait_collector_active flag will
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney * prevent multiple collector threads from processing records
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney * simultaneously from the same squeue.
0870f17b1158eef95a9cbc509c015c6467c7cdecKacheong Poon */
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney mutex_exit(&tsp->tcp_time_wait_lock);
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney (void) untimeout_default(old_tid, 0);
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney return;
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney }
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney /*
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney * Start a fresh timer if none exists.
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney */
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney if (tsp->tcp_time_wait_schedule == 0) {
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney ASSERT(tsp->tcp_time_wait_tid == 0);
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney tsp->tcp_time_wait_schedule = schedule;
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney tsp->tcp_time_wait_tid =
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney timeout_generic(CALLOUT_NORMAL,
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney tcp_time_wait_collector, sqp,
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney TICK_TO_NSEC(schedule - now),
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney CALLOUT_TCP_RESOLUTION, CALLOUT_FLAG_ROUNDUP);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon }
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney mutex_exit(&tsp->tcp_time_wait_lock);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon}
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon/*
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * Wrapper to call tcp_close_detached() via squeue to clean up TIME-WAIT
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * tcp_t. Used in tcp_time_wait_collector().
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon */
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon/* ARGSUSED */
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poonstatic void
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poontcp_timewait_close(void *arg, mblk_t *mp, void *arg2, ip_recv_attr_t *dummy)
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon{
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon conn_t *connp = (conn_t *)arg;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcp_t *tcp = connp->conn_tcp;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon ASSERT(tcp != NULL);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (tcp->tcp_state == TCPS_CLOSED) {
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon return;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon }
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon ASSERT((connp->conn_family == AF_INET &&
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon connp->conn_ipversion == IPV4_VERSION) ||
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon (connp->conn_family == AF_INET6 &&
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon (connp->conn_ipversion == IPV4_VERSION ||
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon connp->conn_ipversion == IPV6_VERSION)));
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon ASSERT(!tcp->tcp_listener);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon ASSERT(TCP_IS_DETACHED(tcp));
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon /*
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * Because they have no upstream client to rebind or tcp_close()
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * them later, we axe the connection here and now.
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon */
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcp_close_detached(tcp);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon}
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooneystatic void
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooneytcp_time_wait_purge(tcp_t *tcp, tcp_squeue_priv_t *tsp)
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney{
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney mblk_t *mp;
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney conn_t *connp = tcp->tcp_connp;
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney kmutex_t *lock;
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney ASSERT(MUTEX_HELD(&tsp->tcp_time_wait_lock));
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney ASSERT(connp->conn_fanout != NULL);
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney lock = &connp->conn_fanout->connf_lock;
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney /*
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney * This is essentially a TIME_WAIT reclaim fast path optimization for
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney * performance where the connection is checked under the fanout lock
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney * (so that no one else can get access to the conn_t) that the refcnt
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney * is 2 (one each for TCP and the classifier hash list). That is the
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney * case and clustering callbacks are not enabled, the conn can be
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney * removed under the fanout lock and avoid clean-up under the squeue.
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney *
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney * This optimization is forgone when clustering is enabled since the
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney * clustering callback must be made before setting the CONDEMNED flag
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney * and after dropping all locks
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney *
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney * See the comments in tcp_closei_local for additional information
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney * regarding the refcnt logic.
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney */
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney if (mutex_tryenter(lock)) {
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney mutex_enter(&connp->conn_lock);
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney if (connp->conn_ref == 2 && cl_inet_disconnect == NULL) {
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney ipcl_hash_remove_locked(connp, connp->conn_fanout);
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney /*
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney * Set the CONDEMNED flag now itself so that the refcnt
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney * cannot increase due to any walker.
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney */
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney connp->conn_state_flags |= CONN_CONDEMNED;
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney mutex_exit(&connp->conn_lock);
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney mutex_exit(lock);
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney if (tsp->tcp_free_list_cnt < tcp_free_list_max_cnt) {
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney /*
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney * Add to head of tcp_free_list
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney */
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney tcp_cleanup(tcp);
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney ASSERT(connp->conn_latch == NULL);
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney ASSERT(connp->conn_policy == NULL);
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney ASSERT(tcp->tcp_tcps == NULL);
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney ASSERT(connp->conn_netstack == NULL);
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney tcp->tcp_time_wait_next = tsp->tcp_free_list;
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney tcp->tcp_in_free_list = B_TRUE;
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney tsp->tcp_free_list = tcp;
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney tsp->tcp_free_list_cnt++;
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney } else {
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney /*
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney * Do not add to tcp_free_list
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney */
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney tcp_bind_hash_remove(tcp);
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney ixa_cleanup(tcp->tcp_connp->conn_ixa);
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney tcp_ipsec_cleanup(tcp);
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney CONN_DEC_REF(tcp->tcp_connp);
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney }
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney /*
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney * With the fast-path complete, we can bail.
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney */
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney return;
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney } else {
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney /*
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney * Fall back to slow path.
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney */
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney CONN_INC_REF_LOCKED(connp);
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney mutex_exit(&connp->conn_lock);
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney mutex_exit(lock);
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney }
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney } else {
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney CONN_INC_REF(connp);
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney }
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney /*
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney * We can reuse the closemp here since conn has detached (otherwise we
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney * wouldn't even be in time_wait list). It is safe to change
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney * tcp_closemp_used without taking a lock as no other thread can
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney * concurrently access it at this point in the connection lifecycle.
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney */
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney if (tcp->tcp_closemp.b_prev == NULL) {
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney tcp->tcp_closemp_used = B_TRUE;
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney } else {
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney cmn_err(CE_PANIC,
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney "tcp_timewait_collector: concurrent use of tcp_closemp: "
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney "connp %p tcp %p\n", (void *)connp, (void *)tcp);
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney }
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney TCP_DEBUG_GETPCSTACK(tcp->tcmp_stk, 15);
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney mp = &tcp->tcp_closemp;
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney mutex_exit(&tsp->tcp_time_wait_lock);
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney SQUEUE_ENTER_ONE(connp->conn_sqp, mp, tcp_timewait_close, connp, NULL,
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney SQ_FILL, SQTAG_TCP_TIMEWAIT);
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney mutex_enter(&tsp->tcp_time_wait_lock);
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney}
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon/*
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney * Purge any tcp_t instances associated with this squeue which have expired
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney * from the TIME_WAIT state.
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon */
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poonvoid
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poontcp_time_wait_collector(void *arg)
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon{
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcp_t *tcp;
c79a72d7e59c9ff493d8dde8b462cca0445f51c8Patrick Mooney int64_t now, sched_active, sched_cur, sched_new;
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney unsigned int idx;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon squeue_t *sqp = (squeue_t *)arg;
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney tcp_squeue_priv_t *tsp =
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon *((tcp_squeue_priv_t **)squeue_getprivate(sqp, SQPRIVATE_TCP));
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney mutex_enter(&tsp->tcp_time_wait_lock);
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney /*
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney * Because of timer scheduling complexity and the fact that the
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney * tcp_time_wait_lock is dropped during tcp_time_wait_purge, it is
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney * possible for multiple tcp_time_wait_collector threads to run against
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney * the same squeue. This flag is used to exclude other collectors from
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney * the squeue during execution.
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney */
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney if (tsp->tcp_time_wait_collector_active) {
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney mutex_exit(&tsp->tcp_time_wait_lock);
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney return;
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney }
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney tsp->tcp_time_wait_collector_active = B_TRUE;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
c79a72d7e59c9ff493d8dde8b462cca0445f51c8Patrick Mooney /*
c79a72d7e59c9ff493d8dde8b462cca0445f51c8Patrick Mooney * After its assignment here, the value of sched_active must not be
c79a72d7e59c9ff493d8dde8b462cca0445f51c8Patrick Mooney * altered as it is used to validate the state of the
c79a72d7e59c9ff493d8dde8b462cca0445f51c8Patrick Mooney * tcp_time_wait_collector callout schedule for this squeue.
c79a72d7e59c9ff493d8dde8b462cca0445f51c8Patrick Mooney *
c79a72d7e59c9ff493d8dde8b462cca0445f51c8Patrick Mooney * The same does not hold true of sched_cur, which holds the timestamp
c79a72d7e59c9ff493d8dde8b462cca0445f51c8Patrick Mooney * of the bucket undergoing processing. While it is initially equal to
c79a72d7e59c9ff493d8dde8b462cca0445f51c8Patrick Mooney * sched_active, certain conditions below can walk it forward,
c79a72d7e59c9ff493d8dde8b462cca0445f51c8Patrick Mooney * triggering the retry loop.
c79a72d7e59c9ff493d8dde8b462cca0445f51c8Patrick Mooney */
c79a72d7e59c9ff493d8dde8b462cca0445f51c8Patrick Mooney sched_cur = sched_active = tsp->tcp_time_wait_schedule;
c79a72d7e59c9ff493d8dde8b462cca0445f51c8Patrick Mooney
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney /*
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney * Purge the free list if necessary
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney */
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney if (tsp->tcp_free_list != NULL) {
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon TCP_G_STAT(tcp_freelist_cleanup);
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney while ((tcp = tsp->tcp_free_list) != NULL) {
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney tsp->tcp_free_list = tcp->tcp_time_wait_next;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcp->tcp_time_wait_next = NULL;
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney tsp->tcp_free_list_cnt--;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon ASSERT(tcp->tcp_tcps == NULL);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon CONN_DEC_REF(tcp->tcp_connp);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon }
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney ASSERT(tsp->tcp_free_list_cnt == 0);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon }
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon /*
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney * If there are no connections pending, clear timer-related state to be
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney * reinitialized by the next caller.
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon */
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney if (tsp->tcp_time_wait_cnt == 0) {
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney tsp->tcp_time_wait_offset = 0;
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney tsp->tcp_time_wait_schedule = 0;
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney tsp->tcp_time_wait_tid = 0;
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney tsp->tcp_time_wait_collector_active = B_FALSE;
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney mutex_exit(&tsp->tcp_time_wait_lock);
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney return;
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney }
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney
c79a72d7e59c9ff493d8dde8b462cca0445f51c8Patrick Mooneyretry:
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney /*
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney * Grab the bucket which we were scheduled to cleanse.
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney */
c79a72d7e59c9ff493d8dde8b462cca0445f51c8Patrick Mooney idx = TW_BUCKET(sched_cur - 1);
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney now = ddi_get_lbolt64() - tsp->tcp_time_wait_offset;
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney tcp = tsp->tcp_time_wait_bucket[idx];
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney while (tcp != NULL) {
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon /*
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney * Since the bucket count is sized to prevent wrap-around
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney * during typical operation and timers are schedule to process
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney * buckets with only expired connections, there is only one
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney * reason to encounter a connection expiring in the future:
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney * The tcp_time_wait_collector thread has been so delayed in
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney * its processing that connections have wrapped around the
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney * timing wheel into this bucket.
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney *
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney * In that case, the remaining entires in the bucket can be
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney * ignored since, being appended sequentially, they should all
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney * expire in the future.
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon */
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney if (now < tcp->tcp_time_wait_expire) {
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon break;
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney }
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney /*
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney * Pull the connection out of the bucket.
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney */
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney VERIFY(tcp_time_wait_remove(tcp, tsp));
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon /*
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney * Purge the connection.
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon *
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney * While tcp_time_wait_lock will be temporarily dropped as part
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney * of the process, there is no risk of the timer being
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney * (re)scheduled while the collector is running since a value
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney * corresponding to the past is left in tcp_time_wait_schedule.
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon */
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney tcp_time_wait_purge(tcp, tsp);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney /*
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney * Because tcp_time_wait_remove clears the tcp_time_wait_next
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney * field, the next item must be grabbed directly from the
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney * bucket itself.
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney */
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney tcp = tsp->tcp_time_wait_bucket[idx];
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney }
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney if (tsp->tcp_time_wait_cnt == 0) {
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney /*
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney * There is not a need for the collector to schedule a new
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney * timer if no pending items remain. The timer state can be
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney * cleared only if it was untouched while the collector dropped
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney * its locks during tcp_time_wait_purge.
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney */
c79a72d7e59c9ff493d8dde8b462cca0445f51c8Patrick Mooney if (tsp->tcp_time_wait_schedule == sched_active) {
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney tsp->tcp_time_wait_offset = 0;
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney tsp->tcp_time_wait_schedule = 0;
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney tsp->tcp_time_wait_tid = 0;
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney }
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney tsp->tcp_time_wait_collector_active = B_FALSE;
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney mutex_exit(&tsp->tcp_time_wait_lock);
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney return;
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney } else {
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney unsigned int nidx;
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney /*
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney * Locate the next bucket containing entries.
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney */
c79a72d7e59c9ff493d8dde8b462cca0445f51c8Patrick Mooney sched_new = sched_cur + MSEC_TO_TICK(TCP_TIME_WAIT_DELAY);
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney nidx = TW_BUCKET_NEXT(idx);
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney while (tsp->tcp_time_wait_bucket[nidx] == NULL) {
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney if (nidx == idx) {
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney break;
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney }
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney nidx = TW_BUCKET_NEXT(nidx);
c79a72d7e59c9ff493d8dde8b462cca0445f51c8Patrick Mooney sched_new += MSEC_TO_TICK(TCP_TIME_WAIT_DELAY);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon }
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney ASSERT(tsp->tcp_time_wait_bucket[nidx] != NULL);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon }
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney /*
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney * It is possible that the system is under such dire load that between
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney * the timer scheduling and TIME_WAIT processing delay, execution
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney * overran the interval allocated to this bucket.
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney */
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney now = ddi_get_lbolt64() - tsp->tcp_time_wait_offset;
c79a72d7e59c9ff493d8dde8b462cca0445f51c8Patrick Mooney if (sched_new <= now) {
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney /*
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney * Attempt to right the situation by immediately performing a
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney * purge on the next bucket. This loop will continue as needed
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney * until the schedule can be pushed out ahead of the clock.
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney */
c79a72d7e59c9ff493d8dde8b462cca0445f51c8Patrick Mooney sched_cur = sched_new;
c79a72d7e59c9ff493d8dde8b462cca0445f51c8Patrick Mooney DTRACE_PROBE3(tcp__time__wait__overrun,
c79a72d7e59c9ff493d8dde8b462cca0445f51c8Patrick Mooney tcp_squeue_priv_t *, tsp, int64_t, sched_new, int64_t, now);
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney goto retry;
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney }
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
66cd0f60c3182913d379abb730ae755bf6367126Kacheong Poon /*
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney * Another thread may have snuck in to reschedule the timer while locks
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney * were dropped during tcp_time_wait_purge. Defer to the running timer
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney * if that is the case.
66cd0f60c3182913d379abb730ae755bf6367126Kacheong Poon */
c79a72d7e59c9ff493d8dde8b462cca0445f51c8Patrick Mooney if (tsp->tcp_time_wait_schedule != sched_active) {
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney tsp->tcp_time_wait_collector_active = B_FALSE;
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney mutex_exit(&tsp->tcp_time_wait_lock);
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney return;
66cd0f60c3182913d379abb730ae755bf6367126Kacheong Poon }
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney /*
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney * Schedule the next timer.
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney */
c79a72d7e59c9ff493d8dde8b462cca0445f51c8Patrick Mooney tsp->tcp_time_wait_schedule = sched_new;
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney tsp->tcp_time_wait_tid =
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney timeout_generic(CALLOUT_NORMAL,
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney tcp_time_wait_collector, sqp,
c79a72d7e59c9ff493d8dde8b462cca0445f51c8Patrick Mooney TICK_TO_NSEC(sched_new - now),
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney CALLOUT_TCP_RESOLUTION, CALLOUT_FLAG_ROUNDUP);
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney tsp->tcp_time_wait_collector_active = B_FALSE;
2404c9e6b54f427b32dd0a2d46940d6a4c5299bcPatrick Mooney mutex_exit(&tsp->tcp_time_wait_lock);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon}
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon/*
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * tcp_time_wait_processing() handles processing of incoming packets when
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * the tcp_t is in the TIME_WAIT state.
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon *
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * A TIME_WAIT tcp_t that has an associated open TCP end point (not in
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * detached state) is never put on the time wait list.
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon */
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poonvoid
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poontcp_time_wait_processing(tcp_t *tcp, mblk_t *mp, uint32_t seg_seq,
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon uint32_t seg_ack, int seg_len, tcpha_t *tcpha, ip_recv_attr_t *ira)
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon{
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon int32_t bytes_acked;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon int32_t gap;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon int32_t rgap;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcp_opt_t tcpopt;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon uint_t flags;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon uint32_t new_swnd = 0;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon conn_t *nconnp;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon conn_t *connp = tcp->tcp_connp;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcp_stack_t *tcps = tcp->tcp_tcps;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon BUMP_LOCAL(tcp->tcp_ibsegs);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon DTRACE_PROBE2(tcp__trace__recv, mblk_t *, mp, tcp_t *, tcp);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon flags = (unsigned int)tcpha->tha_flags & 0xFF;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon new_swnd = ntohs(tcpha->tha_win) <<
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon ((tcpha->tha_flags & TH_SYN) ? 0 : tcp->tcp_snd_ws);
1f183ba0b0be3e10202501aa3740753df6512804Lauri Tirkkonen
1f183ba0b0be3e10202501aa3740753df6512804Lauri Tirkkonen if (tcp->tcp_snd_ts_ok && !(tcpha->tha_flags & TH_RST)) {
1f183ba0b0be3e10202501aa3740753df6512804Lauri Tirkkonen int options;
1f183ba0b0be3e10202501aa3740753df6512804Lauri Tirkkonen if (tcp->tcp_snd_sack_ok)
1f183ba0b0be3e10202501aa3740753df6512804Lauri Tirkkonen tcpopt.tcp = tcp;
1f183ba0b0be3e10202501aa3740753df6512804Lauri Tirkkonen else
1f183ba0b0be3e10202501aa3740753df6512804Lauri Tirkkonen tcpopt.tcp = NULL;
1f183ba0b0be3e10202501aa3740753df6512804Lauri Tirkkonen options = tcp_parse_options(tcpha, &tcpopt);
1f183ba0b0be3e10202501aa3740753df6512804Lauri Tirkkonen if (!(options & TCP_OPT_TSTAMP_PRESENT)) {
1f183ba0b0be3e10202501aa3740753df6512804Lauri Tirkkonen DTRACE_TCP1(droppedtimestamp, tcp_t *, tcp);
1f183ba0b0be3e10202501aa3740753df6512804Lauri Tirkkonen goto done;
1f183ba0b0be3e10202501aa3740753df6512804Lauri Tirkkonen } else if (!tcp_paws_check(tcp, &tcpopt)) {
1f183ba0b0be3e10202501aa3740753df6512804Lauri Tirkkonen tcp_xmit_ctl(NULL, tcp, tcp->tcp_snxt, tcp->tcp_rnxt,
1f183ba0b0be3e10202501aa3740753df6512804Lauri Tirkkonen TH_ACK);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon goto done;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon }
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon }
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon gap = seg_seq - tcp->tcp_rnxt;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon rgap = tcp->tcp_rwnd - (gap + seg_len);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (gap < 0) {
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon TCPS_BUMP_MIB(tcps, tcpInDataDupSegs);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon TCPS_UPDATE_MIB(tcps, tcpInDataDupBytes,
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon (seg_len > -gap ? -gap : seg_len));
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon seg_len += gap;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (seg_len < 0 || (seg_len == 0 && !(flags & TH_FIN))) {
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (flags & TH_RST) {
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon goto done;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon }
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if ((flags & TH_FIN) && seg_len == -1) {
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon /*
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * When TCP receives a duplicate FIN in
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * TIME_WAIT state, restart the 2 MSL timer.
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * See page 73 in RFC 793. Make sure this TCP
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * is already on the TIME_WAIT list. If not,
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * just restart the timer.
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon */
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (TCP_IS_DETACHED(tcp)) {
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (tcp_time_wait_remove(tcp, NULL) ==
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon B_TRUE) {
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcp_time_wait_append(tcp);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon TCP_DBGSTAT(tcps,
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcp_rput_time_wait);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon }
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon } else {
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon ASSERT(tcp != NULL);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon TCP_TIMER_RESTART(tcp,
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcps->tcps_time_wait_interval);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon }
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcp_xmit_ctl(NULL, tcp, tcp->tcp_snxt,
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcp->tcp_rnxt, TH_ACK);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon goto done;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon }
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon flags |= TH_ACK_NEEDED;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon seg_len = 0;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon goto process_ack;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon }
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon /* Fix seg_seq, and chew the gap off the front. */
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon seg_seq = tcp->tcp_rnxt;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon }
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if ((flags & TH_SYN) && gap > 0 && rgap < 0) {
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon /*
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * Make sure that when we accept the connection, pick
c0e6663fe828dc0e5313994c7ac7527654f066f9Jerry Jelinek * an ISS greater than (tcp_snxt + tcp_iss_incr/2) for the
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * old connection.
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon *
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * The next ISS generated is equal to tcp_iss_incr_extra
c0e6663fe828dc0e5313994c7ac7527654f066f9Jerry Jelinek * + tcp_iss_incr/2 + other components depending on the
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * value of tcp_strong_iss. We pre-calculate the new
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * ISS here and compare with tcp_snxt to determine if
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * we need to make adjustment to tcp_iss_incr_extra.
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon *
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * The above calculation is ugly and is a
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * waste of CPU cycles...
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon */
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon uint32_t new_iss = tcps->tcps_iss_incr_extra;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon int32_t adj;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon ip_stack_t *ipst = tcps->tcps_netstack->netstack_ip;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon switch (tcps->tcps_strong_iss) {
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon case 2: {
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon /* Add time and MD5 components. */
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon uint32_t answer[4];
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon struct {
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon uint32_t ports;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon in6_addr_t src;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon in6_addr_t dst;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon } arg;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon MD5_CTX context;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon mutex_enter(&tcps->tcps_iss_key_lock);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon context = tcps->tcps_iss_key;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon mutex_exit(&tcps->tcps_iss_key_lock);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon arg.ports = connp->conn_ports;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon /* We use MAPPED addresses in tcp_iss_init */
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon arg.src = connp->conn_laddr_v6;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon arg.dst = connp->conn_faddr_v6;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon MD5Update(&context, (uchar_t *)&arg,
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon sizeof (arg));
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon MD5Final((uchar_t *)answer, &context);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon answer[0] ^= answer[1] ^ answer[2] ^ answer[3];
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon new_iss += (gethrtime() >> ISS_NSEC_SHT) + answer[0];
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon break;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon }
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon case 1:
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon /* Add time component and min random (i.e. 1). */
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon new_iss += (gethrtime() >> ISS_NSEC_SHT) + 1;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon break;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon default:
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon /* Add only time component. */
c0e6663fe828dc0e5313994c7ac7527654f066f9Jerry Jelinek new_iss += (uint32_t)gethrestime_sec() *
c0e6663fe828dc0e5313994c7ac7527654f066f9Jerry Jelinek tcps->tcps_iss_incr;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon break;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon }
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if ((adj = (int32_t)(tcp->tcp_snxt - new_iss)) > 0) {
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon /*
c0e6663fe828dc0e5313994c7ac7527654f066f9Jerry Jelinek * New ISS not guaranteed to be tcp_iss_incr/2
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * ahead of the current tcp_snxt, so add the
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * difference to tcp_iss_incr_extra.
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon */
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcps->tcps_iss_incr_extra += adj;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon }
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon /*
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * If tcp_clean_death() can not perform the task now,
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * drop the SYN packet and let the other side re-xmit.
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * Otherwise pass the SYN packet back in, since the
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * old tcp state has been cleaned up or freed.
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon */
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (tcp_clean_death(tcp, 0) == -1)
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon goto done;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon nconnp = ipcl_classify(mp, ira, ipst);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (nconnp != NULL) {
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon TCP_STAT(tcps, tcp_time_wait_syn_success);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon /* Drops ref on nconnp */
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcp_reinput(nconnp, mp, ira, ipst);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon return;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon }
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon goto done;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon }
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon /*
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * rgap is the amount of stuff received out of window. A negative
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * value is the amount out of window.
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon */
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (rgap < 0) {
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon TCPS_BUMP_MIB(tcps, tcpInDataPastWinSegs);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon TCPS_UPDATE_MIB(tcps, tcpInDataPastWinBytes, -rgap);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon /* Fix seg_len and make sure there is something left. */
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon seg_len += rgap;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (seg_len <= 0) {
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (flags & TH_RST) {
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon goto done;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon }
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon flags |= TH_ACK_NEEDED;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon seg_len = 0;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon goto process_ack;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon }
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon }
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon /*
1f183ba0b0be3e10202501aa3740753df6512804Lauri Tirkkonen * Check whether we can update tcp_ts_recent. This test is from RFC
1f183ba0b0be3e10202501aa3740753df6512804Lauri Tirkkonen * 7323, section 5.3.
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon */
1f183ba0b0be3e10202501aa3740753df6512804Lauri Tirkkonen if (tcp->tcp_snd_ts_ok && !(flags & TH_RST) &&
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon TSTMP_GEQ(tcpopt.tcp_opt_ts_val, tcp->tcp_ts_recent) &&
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon SEQ_LEQ(seg_seq, tcp->tcp_rack)) {
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcp->tcp_ts_recent = tcpopt.tcp_opt_ts_val;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcp->tcp_last_rcv_lbolt = ddi_get_lbolt64();
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon }
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (seg_seq != tcp->tcp_rnxt && seg_len > 0) {
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon /* Always ack out of order packets */
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon flags |= TH_ACK_NEEDED;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon seg_len = 0;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon } else if (seg_len > 0) {
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon TCPS_BUMP_MIB(tcps, tcpInClosed);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon TCPS_BUMP_MIB(tcps, tcpInDataInorderSegs);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon TCPS_UPDATE_MIB(tcps, tcpInDataInorderBytes, seg_len);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon }
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (flags & TH_RST) {
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon (void) tcp_clean_death(tcp, 0);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon goto done;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon }
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (flags & TH_SYN) {
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcp_xmit_ctl("TH_SYN", tcp, seg_ack, seg_seq + 1,
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon TH_RST|TH_ACK);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon /*
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * Do not delete the TCP structure if it is in
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * TIME_WAIT state. Refer to RFC 1122, 4.2.2.13.
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon */
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon goto done;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon }
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poonprocess_ack:
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (flags & TH_ACK) {
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon bytes_acked = (int)(seg_ack - tcp->tcp_suna);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (bytes_acked <= 0) {
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (bytes_acked == 0 && seg_len == 0 &&
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon new_swnd == tcp->tcp_swnd)
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon TCPS_BUMP_MIB(tcps, tcpInDupAck);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon } else {
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon /* Acks something not sent */
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon flags |= TH_ACK_NEEDED;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon }
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon }
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (flags & TH_ACK_NEEDED) {
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon /*
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * Time to send an ack for some reason.
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon */
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcp_xmit_ctl(NULL, tcp, tcp->tcp_snxt,
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcp->tcp_rnxt, TH_ACK);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon }
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poondone:
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon freemsg(mp);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon}