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.
3d0a255c417cf2e7b69e770de43f195b0eeffacbGarrett D'Amore * Copyright (c) 2011 Nexenta Systems, Inc. All rights reserved.
7f2dc2cf1a1245bdd505d658a1dbcbda218daed1Bryan Cantrill * Copyright 2011 Joyent, Inc. All rights reserved.
633fc3a6eed35d918db16925b7048d7a2e28064aSebastien Roy * Copyright (c) 2014 by Delphix. All rights reserved.
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon */
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon#include <sys/types.h>
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon#include <sys/strlog.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#include <sys/strsubr.h>
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon#include <inet/common.h>
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon#include <inet/ip.h>
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon#include <inet/ip_ire.h>
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon#include <inet/ip_rts.h>
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon#include <inet/tcp.h>
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon#include <inet/tcp_impl.h>
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon/*
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * Implementation of TCP Timers.
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * =============================
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon *
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * INTERFACE:
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon *
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * There are two basic functions dealing with tcp timers:
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon *
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * timeout_id_t tcp_timeout(connp, func, time)
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * clock_t tcp_timeout_cancel(connp, timeout_id)
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * TCP_TIMER_RESTART(tcp, intvl)
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon *
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * tcp_timeout() starts a timer for the 'tcp' instance arranging to call 'func'
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * after 'time' ticks passed. The function called by timeout() must adhere to
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * the same restrictions as a driver soft interrupt handler - it must not sleep
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * or call other functions that might sleep. The value returned is the opaque
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * non-zero timeout identifier that can be passed to tcp_timeout_cancel() to
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * cancel the request. The call to tcp_timeout() may fail in which case it
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * returns zero. This is different from the timeout(9F) function which never
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * fails.
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon *
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * The call-back function 'func' always receives 'connp' as its single
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * argument. It is always executed in the squeue corresponding to the tcp
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * structure. The tcp structure is guaranteed to be present at the time the
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * call-back is called.
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon *
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * NOTE: The call-back function 'func' is never called if tcp is in
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * the TCPS_CLOSED state.
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon *
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * tcp_timeout_cancel() attempts to cancel a pending tcp_timeout()
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * request. locks acquired by the call-back routine should not be held across
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * the call to tcp_timeout_cancel() or a deadlock may result.
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon *
7f2dc2cf1a1245bdd505d658a1dbcbda218daed1Bryan Cantrill * tcp_timeout_cancel() returns -1 if the timeout request is invalid.
7f2dc2cf1a1245bdd505d658a1dbcbda218daed1Bryan Cantrill * Otherwise, it returns an integer value greater than or equal to 0.
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon *
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * NOTE: both tcp_timeout() and tcp_timeout_cancel() should always be called
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * within squeue context corresponding to the tcp instance. Since the
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * call-back is also called via the same squeue, there are no race
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * conditions described in untimeout(9F) manual page since all calls are
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * strictly serialized.
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon *
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * TCP_TIMER_RESTART() is a macro that attempts to cancel a pending timeout
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * stored in tcp_timer_tid and starts a new one using
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * MSEC_TO_TICK(intvl). It always uses tcp_timer() function as a call-back
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * and stores the return value of tcp_timeout() in the tcp->tcp_timer_tid
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * field.
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon *
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * IMPLEMENTATION:
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon *
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * TCP timers are implemented using three-stage process. The call to
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * tcp_timeout() uses timeout(9F) function to call tcp_timer_callback() function
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * when the timer expires. The tcp_timer_callback() arranges the call of the
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * tcp_timer_handler() function via squeue corresponding to the tcp
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * instance. The tcp_timer_handler() calls actual requested timeout call-back
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * and passes tcp instance as an argument to it. Information is passed between
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * stages using the tcp_timer_t structure which contains the connp pointer, the
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * tcp call-back to call and the timeout id returned by the timeout(9F).
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon *
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * The tcp_timer_t structure is not used directly, it is embedded in an mblk_t -
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * like structure that is used to enter an squeue. The mp->b_rptr of this pseudo
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * mblk points to the beginning of tcp_timer_t structure. The tcp_timeout()
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * returns the pointer to this mblk.
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon *
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * The pseudo mblk is allocated from a special tcp_timer_cache kmem cache. It
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * looks like a normal mblk without actual dblk attached to it.
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon *
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * To optimize performance each tcp instance holds a small cache of timer
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * mblocks. In the current implementation it caches up to two timer mblocks per
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * tcp instance. The cache is preserved over tcp frees and is only freed when
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * the whole tcp structure is destroyed by its kmem destructor. Since all tcp
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * timer processing happens on a corresponding squeue, the cache manipulation
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * does not require any locks. Experiments show that majority of timer mblocks
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * allocations are satisfied from the tcp cache and do not involve kmem calls.
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon *
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * The tcp_timeout() places a refhold on the connp instance which guarantees
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * that it will be present at the time the call-back function fires. The
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * tcp_timer_handler() drops the reference after calling the call-back, so the
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * call-back function does not need to manipulate the references explicitly.
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon */
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poonkmem_cache_t *tcp_timercache;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poonstatic void tcp_ip_notify(tcp_t *);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poonstatic void tcp_timer_callback(void *);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poonstatic void tcp_timer_free(tcp_t *, mblk_t *);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poonstatic void tcp_timer_handler(void *, mblk_t *, void *, ip_recv_attr_t *);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
66cd0f60c3182913d379abb730ae755bf6367126Kacheong Poon/*
66cd0f60c3182913d379abb730ae755bf6367126Kacheong Poon * tim is in millisec.
66cd0f60c3182913d379abb730ae755bf6367126Kacheong Poon */
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poontimeout_id_t
66cd0f60c3182913d379abb730ae755bf6367126Kacheong Poontcp_timeout(conn_t *connp, void (*f)(void *), hrtime_t tim)
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon{
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon mblk_t *mp;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcp_timer_t *tcpt;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcp_t *tcp = connp->conn_tcp;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon ASSERT(connp->conn_sqp != NULL);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon TCP_DBGSTAT(tcp->tcp_tcps, tcp_timeout_calls);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (tcp->tcp_timercache == NULL) {
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon mp = tcp_timermp_alloc(KM_NOSLEEP | KM_PANIC);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon } else {
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon TCP_DBGSTAT(tcp->tcp_tcps, tcp_timeout_cached_alloc);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon mp = tcp->tcp_timercache;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcp->tcp_timercache = mp->b_next;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon mp->b_next = NULL;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon ASSERT(mp->b_wptr == NULL);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon }
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon CONN_INC_REF(connp);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcpt = (tcp_timer_t *)mp->b_rptr;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcpt->connp = connp;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcpt->tcpt_proc = f;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon /*
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * TCP timers are normal timeouts. Plus, they do not require more than
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * a 10 millisecond resolution. By choosing a coarser resolution and by
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * rounding up the expiration to the next resolution boundary, we can
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * batch timers in the callout subsystem to make TCP timers more
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * efficient. The roundup also protects short timers from expiring too
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * early before they have a chance to be cancelled.
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon */
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcpt->tcpt_tid = timeout_generic(CALLOUT_NORMAL, tcp_timer_callback, mp,
66cd0f60c3182913d379abb730ae755bf6367126Kacheong Poon tim * MICROSEC, CALLOUT_TCP_RESOLUTION, CALLOUT_FLAG_ROUNDUP);
7f2dc2cf1a1245bdd505d658a1dbcbda218daed1Bryan Cantrill VERIFY(!(tcpt->tcpt_tid & CALLOUT_ID_FREE));
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon return ((timeout_id_t)mp);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon}
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poonstatic void
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poontcp_timer_callback(void *arg)
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon{
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon mblk_t *mp = (mblk_t *)arg;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcp_timer_t *tcpt;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon conn_t *connp;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcpt = (tcp_timer_t *)mp->b_rptr;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon connp = tcpt->connp;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon SQUEUE_ENTER_ONE(connp->conn_sqp, mp, tcp_timer_handler, connp,
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon NULL, SQ_FILL, SQTAG_TCP_TIMER);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon}
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon/* ARGSUSED */
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poonstatic void
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poontcp_timer_handler(void *arg, mblk_t *mp, void *arg2, ip_recv_attr_t *dummy)
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon{
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcp_timer_t *tcpt;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon conn_t *connp = (conn_t *)arg;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcp_t *tcp = connp->conn_tcp;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcpt = (tcp_timer_t *)mp->b_rptr;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon ASSERT(connp == tcpt->connp);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon ASSERT((squeue_t *)arg2 == connp->conn_sqp);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
7f2dc2cf1a1245bdd505d658a1dbcbda218daed1Bryan Cantrill if (tcpt->tcpt_tid & CALLOUT_ID_FREE) {
7f2dc2cf1a1245bdd505d658a1dbcbda218daed1Bryan Cantrill /*
7f2dc2cf1a1245bdd505d658a1dbcbda218daed1Bryan Cantrill * This timeout was cancelled after it was enqueued to the
7f2dc2cf1a1245bdd505d658a1dbcbda218daed1Bryan Cantrill * squeue; free the timer and return.
7f2dc2cf1a1245bdd505d658a1dbcbda218daed1Bryan Cantrill */
7f2dc2cf1a1245bdd505d658a1dbcbda218daed1Bryan Cantrill tcp_timer_free(connp->conn_tcp, mp);
7f2dc2cf1a1245bdd505d658a1dbcbda218daed1Bryan Cantrill return;
7f2dc2cf1a1245bdd505d658a1dbcbda218daed1Bryan Cantrill }
7f2dc2cf1a1245bdd505d658a1dbcbda218daed1Bryan Cantrill
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon /*
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * If the TCP has reached the closed state, don't proceed any
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * further. This TCP logically does not exist on the system.
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * tcpt_proc could for example access queues, that have already
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * been qprocoff'ed off.
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon */
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (tcp->tcp_state != TCPS_CLOSED) {
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon (*tcpt->tcpt_proc)(connp);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon } else {
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcp->tcp_timer_tid = 0;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon }
7f2dc2cf1a1245bdd505d658a1dbcbda218daed1Bryan Cantrill
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcp_timer_free(connp->conn_tcp, mp);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon}
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon/*
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * There is potential race with untimeout and the handler firing at the same
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * time. The mblock may be freed by the handler while we are trying to use
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * it. But since both should execute on the same squeue, this race should not
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * occur.
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon */
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poonclock_t
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poontcp_timeout_cancel(conn_t *connp, timeout_id_t id)
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon{
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon mblk_t *mp = (mblk_t *)id;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcp_timer_t *tcpt;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon clock_t delta;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon TCP_DBGSTAT(connp->conn_tcp->tcp_tcps, tcp_timeout_cancel_reqs);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (mp == NULL)
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon return (-1);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcpt = (tcp_timer_t *)mp->b_rptr;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon ASSERT(tcpt->connp == connp);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon delta = untimeout_default(tcpt->tcpt_tid, 0);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (delta >= 0) {
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon TCP_DBGSTAT(connp->conn_tcp->tcp_tcps, tcp_timeout_canceled);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcp_timer_free(connp->conn_tcp, mp);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon CONN_DEC_REF(connp);
7f2dc2cf1a1245bdd505d658a1dbcbda218daed1Bryan Cantrill } else {
7f2dc2cf1a1245bdd505d658a1dbcbda218daed1Bryan Cantrill /*
7f2dc2cf1a1245bdd505d658a1dbcbda218daed1Bryan Cantrill * If we were unable to untimeout successfully, it has already
7f2dc2cf1a1245bdd505d658a1dbcbda218daed1Bryan Cantrill * been enqueued on the squeue; mark the ID with the free
7f2dc2cf1a1245bdd505d658a1dbcbda218daed1Bryan Cantrill * bit. This bit can never be set in a valid identifier, and
7f2dc2cf1a1245bdd505d658a1dbcbda218daed1Bryan Cantrill * we'll use it to prevent the timeout from being executed.
7f2dc2cf1a1245bdd505d658a1dbcbda218daed1Bryan Cantrill * And note that we're within the squeue perimeter here, so
7f2dc2cf1a1245bdd505d658a1dbcbda218daed1Bryan Cantrill * we don't need to worry about racing with timer handling
7f2dc2cf1a1245bdd505d658a1dbcbda218daed1Bryan Cantrill * (which also executes within the perimeter).
7f2dc2cf1a1245bdd505d658a1dbcbda218daed1Bryan Cantrill */
7f2dc2cf1a1245bdd505d658a1dbcbda218daed1Bryan Cantrill tcpt->tcpt_tid |= CALLOUT_ID_FREE;
7f2dc2cf1a1245bdd505d658a1dbcbda218daed1Bryan Cantrill delta = 0;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon }
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
66cd0f60c3182913d379abb730ae755bf6367126Kacheong Poon return (TICK_TO_MSEC(delta));
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon}
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon/*
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * Allocate space for the timer event. The allocation looks like mblk, but it is
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * not a proper mblk. To avoid confusion we set b_wptr to NULL.
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon *
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * Dealing with failures: If we can't allocate from the timer cache we try
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * allocating from dblock caches using allocb_tryhard(). In this case b_wptr
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * points to b_rptr.
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * If we can't allocate anything using allocb_tryhard(), we perform a last
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * attempt and use kmem_alloc_tryhard(). In this case we set b_wptr to -1 and
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * save the actual allocation size in b_datap.
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon */
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poonmblk_t *
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poontcp_timermp_alloc(int kmflags)
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon{
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon mblk_t *mp = (mblk_t *)kmem_cache_alloc(tcp_timercache,
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon kmflags & ~KM_PANIC);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (mp != NULL) {
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon mp->b_next = mp->b_prev = NULL;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon mp->b_rptr = (uchar_t *)(&mp[1]);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon mp->b_wptr = NULL;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon mp->b_datap = NULL;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon mp->b_queue = NULL;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon mp->b_cont = NULL;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon } else if (kmflags & KM_PANIC) {
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon /*
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * Failed to allocate memory for the timer. Try allocating from
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * dblock caches.
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon */
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon /* ipclassifier calls this from a constructor - hence no tcps */
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon TCP_G_STAT(tcp_timermp_allocfail);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon mp = allocb_tryhard(sizeof (tcp_timer_t));
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (mp == NULL) {
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon size_t size = 0;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon /*
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * Memory is really low. Try tryhard allocation.
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon *
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * ipclassifier calls this from a constructor -
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * hence no tcps
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon */
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon TCP_G_STAT(tcp_timermp_allocdblfail);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon mp = kmem_alloc_tryhard(sizeof (mblk_t) +
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon sizeof (tcp_timer_t), &size, kmflags);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon mp->b_rptr = (uchar_t *)(&mp[1]);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon mp->b_next = mp->b_prev = NULL;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon mp->b_wptr = (uchar_t *)-1;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon mp->b_datap = (dblk_t *)size;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon mp->b_queue = NULL;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon mp->b_cont = NULL;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon }
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon ASSERT(mp->b_wptr != NULL);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon }
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon /* ipclassifier calls this from a constructor - hence no tcps */
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon TCP_G_DBGSTAT(tcp_timermp_alloced);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon return (mp);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon}
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon/*
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * Free per-tcp timer cache.
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * It can only contain entries from tcp_timercache.
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon */
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poonvoid
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poontcp_timermp_free(tcp_t *tcp)
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon{
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon mblk_t *mp;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon while ((mp = tcp->tcp_timercache) != NULL) {
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon ASSERT(mp->b_wptr == NULL);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcp->tcp_timercache = tcp->tcp_timercache->b_next;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon kmem_cache_free(tcp_timercache, mp);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon }
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon}
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon/*
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * Free timer event. Put it on the per-tcp timer cache if there is not too many
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * events there already (currently at most two events are cached).
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * If the event is not allocated from the timer cache, free it right away.
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon */
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poonstatic void
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poontcp_timer_free(tcp_t *tcp, mblk_t *mp)
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon{
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon mblk_t *mp1 = tcp->tcp_timercache;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (mp->b_wptr != NULL) {
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon /*
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * This allocation is not from a timer cache, free it right
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * away.
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon */
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (mp->b_wptr != (uchar_t *)-1)
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon freeb(mp);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon else
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon kmem_free(mp, (size_t)mp->b_datap);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon } else if (mp1 == NULL || mp1->b_next == NULL) {
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon /* Cache this timer block for future allocations */
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon mp->b_rptr = (uchar_t *)(&mp[1]);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon mp->b_next = mp1;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcp->tcp_timercache = mp;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon } else {
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon kmem_cache_free(tcp_timercache, mp);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon TCP_DBGSTAT(tcp->tcp_tcps, tcp_timermp_freed);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon }
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon}
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon/*
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * Stop all TCP timers.
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon */
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poonvoid
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poontcp_timers_stop(tcp_t *tcp)
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon{
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (tcp->tcp_timer_tid != 0) {
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon (void) TCP_TIMER_CANCEL(tcp, tcp->tcp_timer_tid);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcp->tcp_timer_tid = 0;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon }
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (tcp->tcp_ka_tid != 0) {
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon (void) TCP_TIMER_CANCEL(tcp, tcp->tcp_ka_tid);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcp->tcp_ka_tid = 0;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon }
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (tcp->tcp_ack_tid != 0) {
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon (void) TCP_TIMER_CANCEL(tcp, tcp->tcp_ack_tid);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcp->tcp_ack_tid = 0;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon }
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (tcp->tcp_push_tid != 0) {
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon (void) TCP_TIMER_CANCEL(tcp, tcp->tcp_push_tid);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcp->tcp_push_tid = 0;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon }
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (tcp->tcp_reass_tid != 0) {
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon (void) TCP_TIMER_CANCEL(tcp, tcp->tcp_reass_tid);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcp->tcp_reass_tid = 0;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon }
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon}
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon/*
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * Timer callback routine for keepalive probe. We do a fake resend of
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * last ACKed byte. Then set a timer using RTO. When the timer expires,
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * check to see if we have heard anything from the other end for the last
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * RTO period. If we have, set the timer to expire for another
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * tcp_keepalive_intrvl and check again. If we have not, set a timer using
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * RTO << 1 and check again when it expires. Keep exponentially increasing
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * the timeout if we have not heard from the other side. If for more than
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * (tcp_ka_interval + tcp_ka_abort_thres) we have not heard anything,
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * kill the connection unless the keepalive abort threshold is 0. In
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * that case, we will probe "forever."
3d0a255c417cf2e7b69e770de43f195b0eeffacbGarrett D'Amore * If tcp_ka_cnt and tcp_ka_rinterval are non-zero, then we do not follow
3d0a255c417cf2e7b69e770de43f195b0eeffacbGarrett D'Amore * the exponential backoff, but send probes tcp_ka_cnt times in regular
3d0a255c417cf2e7b69e770de43f195b0eeffacbGarrett D'Amore * intervals of tcp_ka_rinterval milliseconds until we hear back from peer.
3d0a255c417cf2e7b69e770de43f195b0eeffacbGarrett D'Amore * Kill the connection if we don't hear back from peer after tcp_ka_cnt
3d0a255c417cf2e7b69e770de43f195b0eeffacbGarrett D'Amore * probes are sent.
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon */
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poonvoid
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poontcp_keepalive_timer(void *arg)
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon{
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon mblk_t *mp;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon conn_t *connp = (conn_t *)arg;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcp_t *tcp = connp->conn_tcp;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon int32_t firetime;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon int32_t idletime;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon int32_t ka_intrvl;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcp_stack_t *tcps = tcp->tcp_tcps;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcp->tcp_ka_tid = 0;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (tcp->tcp_fused)
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon return;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon TCPS_BUMP_MIB(tcps, tcpTimKeepalive);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon ka_intrvl = tcp->tcp_ka_interval;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon /*
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * Keepalive probe should only be sent if the application has not
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * done a close on the connection.
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon */
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (tcp->tcp_state > TCPS_CLOSE_WAIT) {
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon return;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon }
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon /* Timer fired too early, restart it. */
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (tcp->tcp_state < TCPS_ESTABLISHED) {
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcp->tcp_ka_tid = TCP_TIMER(tcp, tcp_keepalive_timer,
66cd0f60c3182913d379abb730ae755bf6367126Kacheong Poon ka_intrvl);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon return;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon }
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon idletime = TICK_TO_MSEC(ddi_get_lbolt() - tcp->tcp_last_recv_time);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon /*
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * If we have not heard from the other side for a long
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * time, kill the connection unless the keepalive abort
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * threshold is 0. In that case, we will probe "forever."
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon */
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (tcp->tcp_ka_abort_thres != 0 &&
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon idletime > (ka_intrvl + tcp->tcp_ka_abort_thres)) {
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon TCPS_BUMP_MIB(tcps, tcpTimKeepaliveDrop);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon (void) tcp_clean_death(tcp, tcp->tcp_client_errno ?
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcp->tcp_client_errno : ETIMEDOUT);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon return;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon }
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (tcp->tcp_snxt == tcp->tcp_suna &&
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon idletime >= ka_intrvl) {
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon /* Fake resend of last ACKed byte. */
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon mblk_t *mp1 = allocb(1, BPRI_LO);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (mp1 != NULL) {
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon *mp1->b_wptr++ = '\0';
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon mp = tcp_xmit_mp(tcp, mp1, 1, NULL, NULL,
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcp->tcp_suna - 1, B_FALSE, NULL, B_TRUE);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon freeb(mp1);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon /*
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * if allocation failed, fall through to start the
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * timer back.
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon */
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (mp != NULL) {
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcp_send_data(tcp, mp);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon TCPS_BUMP_MIB(tcps, tcpTimKeepaliveProbe);
3d0a255c417cf2e7b69e770de43f195b0eeffacbGarrett D'Amore if (tcp->tcp_ka_rinterval) {
3d0a255c417cf2e7b69e770de43f195b0eeffacbGarrett D'Amore firetime = tcp->tcp_ka_rinterval;
3d0a255c417cf2e7b69e770de43f195b0eeffacbGarrett D'Amore } else if (tcp->tcp_ka_last_intrvl != 0) {
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon int max;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon /*
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * We should probe again at least
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * in ka_intrvl, but not more than
707e74bc53cd429bcd731df722227c7dc2de47c6Kacheong Poon * tcp_rto_max.
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon */
707e74bc53cd429bcd731df722227c7dc2de47c6Kacheong Poon max = tcp->tcp_rto_max;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon firetime = MIN(ka_intrvl - 1,
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcp->tcp_ka_last_intrvl << 1);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (firetime > max)
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon firetime = max;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon } else {
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon firetime = tcp->tcp_rto;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon }
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcp->tcp_ka_tid = TCP_TIMER(tcp,
66cd0f60c3182913d379abb730ae755bf6367126Kacheong Poon tcp_keepalive_timer, firetime);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcp->tcp_ka_last_intrvl = firetime;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon return;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon }
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon }
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon } else {
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcp->tcp_ka_last_intrvl = 0;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon }
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon /* firetime can be negative if (mp1 == NULL || mp == NULL) */
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if ((firetime = ka_intrvl - idletime) < 0) {
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon firetime = ka_intrvl;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon }
66cd0f60c3182913d379abb730ae755bf6367126Kacheong Poon tcp->tcp_ka_tid = TCP_TIMER(tcp, tcp_keepalive_timer, firetime);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon}
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poonvoid
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poontcp_reass_timer(void *arg)
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon{
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon conn_t *connp = (conn_t *)arg;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcp_t *tcp = connp->conn_tcp;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcp->tcp_reass_tid = 0;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (tcp->tcp_reass_head == NULL)
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon return;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon ASSERT(tcp->tcp_reass_tail != NULL);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (tcp->tcp_snd_sack_ok && tcp->tcp_num_sack_blk > 0) {
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcp_sack_remove(tcp->tcp_sack_list,
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon TCP_REASS_END(tcp->tcp_reass_tail), &tcp->tcp_num_sack_blk);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon }
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcp_close_mpp(&tcp->tcp_reass_head);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcp->tcp_reass_tail = NULL;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon TCP_STAT(tcp->tcp_tcps, tcp_reass_timeout);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon}
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon/* This function handles the push timeout. */
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poonvoid
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poontcp_push_timer(void *arg)
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon{
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon conn_t *connp = (conn_t *)arg;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcp_t *tcp = connp->conn_tcp;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon TCP_DBGSTAT(tcp->tcp_tcps, tcp_push_timer_cnt);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon ASSERT(tcp->tcp_listener == NULL);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon ASSERT(!IPCL_IS_NONSTR(connp));
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcp->tcp_push_tid = 0;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (tcp->tcp_rcv_list != NULL &&
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcp_rcv_drain(tcp) == TH_ACK_NEEDED)
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcp_xmit_ctl(NULL, tcp, tcp->tcp_snxt, tcp->tcp_rnxt, TH_ACK);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon}
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon/*
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * This function handles delayed ACK timeout.
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon */
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poonvoid
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poontcp_ack_timer(void *arg)
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon{
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon conn_t *connp = (conn_t *)arg;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcp_t *tcp = connp->conn_tcp;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon mblk_t *mp;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcp_stack_t *tcps = tcp->tcp_tcps;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon TCP_DBGSTAT(tcps, tcp_ack_timer_cnt);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcp->tcp_ack_tid = 0;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (tcp->tcp_fused)
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon return;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon /*
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * Do not send ACK if there is no outstanding unack'ed data.
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon */
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (tcp->tcp_rnxt == tcp->tcp_rack) {
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon return;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon }
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if ((tcp->tcp_rnxt - tcp->tcp_rack) > tcp->tcp_mss) {
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon /*
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * Make sure we don't allow deferred ACKs to result in
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * timer-based ACKing. If we have held off an ACK
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * when there was more than an mss here, and the timer
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * goes off, we have to worry about the possibility
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * that the sender isn't doing slow-start, or is out
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * of step with us for some other reason. We fall
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * permanently back in the direction of
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * ACK-every-other-packet as suggested in RFC 1122.
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon */
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (tcp->tcp_rack_abs_max > 2)
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcp->tcp_rack_abs_max--;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcp->tcp_rack_cur_max = 2;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon }
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon mp = tcp_ack_mp(tcp);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (mp != NULL) {
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon BUMP_LOCAL(tcp->tcp_obsegs);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon TCPS_BUMP_MIB(tcps, tcpOutAck);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon TCPS_BUMP_MIB(tcps, tcpOutAckDelayed);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcp_send_data(tcp, mp);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon }
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon}
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon/*
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * Notify IP that we are having trouble with this connection. IP should
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * make note so it can potentially use a different IRE.
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon */
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poonstatic void
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poontcp_ip_notify(tcp_t *tcp)
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon{
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon conn_t *connp = tcp->tcp_connp;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon ire_t *ire;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon /*
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * Note: in the case of source routing we want to blow away the
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * route to the first source route hop.
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon */
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon ire = connp->conn_ixa->ixa_ire;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (ire != NULL && !(ire->ire_flags & (RTF_REJECT|RTF_BLACKHOLE))) {
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (ire->ire_ipversion == IPV4_VERSION) {
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon /*
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * As per RFC 1122, we send an RTM_LOSING to inform
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * routing protocols.
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon */
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon ip_rts_change(RTM_LOSING, ire->ire_addr,
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon ire->ire_gateway_addr, ire->ire_mask,
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon connp->conn_laddr_v4, 0, 0, 0,
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon (RTA_DST | RTA_GATEWAY | RTA_NETMASK | RTA_IFA),
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon ire->ire_ipst);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon }
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon (void) ire_no_good(ire);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon }
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon}
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon/*
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * tcp_timer is the timer service routine. It handles the retransmission,
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * FIN_WAIT_2 flush, and zero window probe timeout events. It figures out
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * from the state of the tcp instance what kind of action needs to be done
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * at the time it is called.
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon */
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poonvoid
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poontcp_timer(void *arg)
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon{
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon mblk_t *mp;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon clock_t first_threshold;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon clock_t second_threshold;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon clock_t ms;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon uint32_t mss;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon conn_t *connp = (conn_t *)arg;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcp_t *tcp = connp->conn_tcp;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcp_stack_t *tcps = tcp->tcp_tcps;
707e74bc53cd429bcd731df722227c7dc2de47c6Kacheong Poon boolean_t dont_timeout = B_FALSE;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcp->tcp_timer_tid = 0;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (tcp->tcp_fused)
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon return;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon first_threshold = tcp->tcp_first_timer_threshold;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon second_threshold = tcp->tcp_second_timer_threshold;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon switch (tcp->tcp_state) {
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon case TCPS_IDLE:
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon case TCPS_BOUND:
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon case TCPS_LISTEN:
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon return;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon case TCPS_SYN_RCVD: {
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcp_t *listener = tcp->tcp_listener;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (tcp->tcp_syn_rcvd_timeout == 0 && (listener != NULL)) {
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon /* it's our first timeout */
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcp->tcp_syn_rcvd_timeout = 1;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon mutex_enter(&listener->tcp_eager_lock);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon listener->tcp_syn_rcvd_timeout++;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (!tcp->tcp_dontdrop && !tcp->tcp_closemp_used) {
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon /*
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * Make this eager available for drop if we
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * need to drop one to accomodate a new
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * incoming SYN request.
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon */
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon MAKE_DROPPABLE(listener, tcp);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon }
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (!listener->tcp_syn_defense &&
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon (listener->tcp_syn_rcvd_timeout >
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon (tcps->tcps_conn_req_max_q0 >> 2)) &&
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon (tcps->tcps_conn_req_max_q0 > 200)) {
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon /* We may be under attack. Put on a defense. */
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon listener->tcp_syn_defense = B_TRUE;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon cmn_err(CE_WARN, "High TCP connect timeout "
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon "rate! System (port %d) may be under a "
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon "SYN flood attack!",
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon ntohs(listener->tcp_connp->conn_lport));
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon listener->tcp_ip_addr_cache = kmem_zalloc(
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon IP_ADDR_CACHE_SIZE * sizeof (ipaddr_t),
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon KM_NOSLEEP);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon }
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon mutex_exit(&listener->tcp_eager_lock);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon } else if (listener != NULL) {
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon mutex_enter(&listener->tcp_eager_lock);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcp->tcp_syn_rcvd_timeout++;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (tcp->tcp_syn_rcvd_timeout > 1 &&
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon !tcp->tcp_closemp_used) {
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon /*
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * This is our second timeout. Put the tcp in
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * the list of droppable eagers to allow it to
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * be dropped, if needed. We don't check
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * whether tcp_dontdrop is set or not to
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * protect ourselve from a SYN attack where a
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * remote host can spoof itself as one of the
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * good IP source and continue to hold
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * resources too long.
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon */
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon MAKE_DROPPABLE(listener, tcp);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon }
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon mutex_exit(&listener->tcp_eager_lock);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon }
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon }
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon /* FALLTHRU */
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon case TCPS_SYN_SENT:
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon first_threshold = tcp->tcp_first_ctimer_threshold;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon second_threshold = tcp->tcp_second_ctimer_threshold;
707e74bc53cd429bcd731df722227c7dc2de47c6Kacheong Poon
5dd46ab5742d7db1cbb08dec7b64fa14930c02f7Kacheong Poon /*
5dd46ab5742d7db1cbb08dec7b64fa14930c02f7Kacheong Poon * If an app has set the second_threshold to 0, it means that
5dd46ab5742d7db1cbb08dec7b64fa14930c02f7Kacheong Poon * we need to retransmit forever, unless this is a passive
5dd46ab5742d7db1cbb08dec7b64fa14930c02f7Kacheong Poon * open. We need to set second_threshold back to a normal
5dd46ab5742d7db1cbb08dec7b64fa14930c02f7Kacheong Poon * value such that later comparison with it still makes
5dd46ab5742d7db1cbb08dec7b64fa14930c02f7Kacheong Poon * sense. But we set dont_timeout to B_TRUE so that we will
5dd46ab5742d7db1cbb08dec7b64fa14930c02f7Kacheong Poon * never time out.
5dd46ab5742d7db1cbb08dec7b64fa14930c02f7Kacheong Poon */
707e74bc53cd429bcd731df722227c7dc2de47c6Kacheong Poon if (second_threshold == 0) {
5dd46ab5742d7db1cbb08dec7b64fa14930c02f7Kacheong Poon second_threshold = tcps->tcps_ip_abort_linterval;
5dd46ab5742d7db1cbb08dec7b64fa14930c02f7Kacheong Poon if (tcp->tcp_active_open)
707e74bc53cd429bcd731df722227c7dc2de47c6Kacheong Poon dont_timeout = B_TRUE;
707e74bc53cd429bcd731df722227c7dc2de47c6Kacheong Poon }
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon break;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon case TCPS_ESTABLISHED:
707e74bc53cd429bcd731df722227c7dc2de47c6Kacheong Poon case TCPS_CLOSE_WAIT:
707e74bc53cd429bcd731df722227c7dc2de47c6Kacheong Poon /*
707e74bc53cd429bcd731df722227c7dc2de47c6Kacheong Poon * If the end point has not been closed, TCP can retransmit
707e74bc53cd429bcd731df722227c7dc2de47c6Kacheong Poon * forever. But if the end point is closed, the normal
707e74bc53cd429bcd731df722227c7dc2de47c6Kacheong Poon * timeout applies.
707e74bc53cd429bcd731df722227c7dc2de47c6Kacheong Poon */
5dd46ab5742d7db1cbb08dec7b64fa14930c02f7Kacheong Poon if (second_threshold == 0) {
5dd46ab5742d7db1cbb08dec7b64fa14930c02f7Kacheong Poon second_threshold = tcps->tcps_ip_abort_linterval;
707e74bc53cd429bcd731df722227c7dc2de47c6Kacheong Poon dont_timeout = B_TRUE;
5dd46ab5742d7db1cbb08dec7b64fa14930c02f7Kacheong Poon }
707e74bc53cd429bcd731df722227c7dc2de47c6Kacheong Poon /* FALLTHRU */
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon case TCPS_FIN_WAIT_1:
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon case TCPS_CLOSING:
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon case TCPS_LAST_ACK:
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon /* If we have data to rexmit */
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (tcp->tcp_suna != tcp->tcp_snxt) {
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon clock_t time_to_wait;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon TCPS_BUMP_MIB(tcps, tcpTimRetrans);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (!tcp->tcp_xmit_head)
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon break;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon time_to_wait = ddi_get_lbolt() -
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon (clock_t)tcp->tcp_xmit_head->b_prev;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon time_to_wait = tcp->tcp_rto -
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon TICK_TO_MSEC(time_to_wait);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon /*
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * If the timer fires too early, 1 clock tick earlier,
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * restart the timer.
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon */
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (time_to_wait > msec_per_tick) {
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon TCP_STAT(tcps, tcp_timer_fire_early);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon TCP_TIMER_RESTART(tcp, time_to_wait);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon return;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon }
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon /*
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * When we probe zero windows, we force the swnd open.
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * If our peer acks with a closed window swnd will be
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * set to zero by tcp_rput(). As long as we are
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * receiving acks tcp_rput will
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * reset 'tcp_ms_we_have_waited' so as not to trip the
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * first and second interval actions. NOTE: the timer
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * interval is allowed to continue its exponential
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * backoff.
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon */
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (tcp->tcp_swnd == 0 || tcp->tcp_zero_win_probe) {
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (connp->conn_debug) {
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon (void) strlog(TCP_MOD_ID, 0, 1,
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon SL_TRACE, "tcp_timer: zero win");
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon }
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon } else {
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon /*
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * After retransmission, we need to do
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * slow start. Set the ssthresh to one
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * half of current effective window and
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * cwnd to one MSS. Also reset
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * tcp_cwnd_cnt.
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon *
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * Note that if tcp_ssthresh is reduced because
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * of ECN, do not reduce it again unless it is
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * already one window of data away (tcp_cwr
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * should then be cleared) or this is a
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * timeout for a retransmitted segment.
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon */
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon uint32_t npkt;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (!tcp->tcp_cwr || tcp->tcp_rexmit) {
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon npkt = ((tcp->tcp_timer_backoff ?
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcp->tcp_cwnd_ssthresh :
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcp->tcp_snxt -
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcp->tcp_suna) >> 1) / tcp->tcp_mss;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcp->tcp_cwnd_ssthresh = MAX(npkt, 2) *
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcp->tcp_mss;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon }
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcp->tcp_cwnd = tcp->tcp_mss;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcp->tcp_cwnd_cnt = 0;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (tcp->tcp_ecn_ok) {
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcp->tcp_cwr = B_TRUE;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcp->tcp_cwr_snd_max = tcp->tcp_snxt;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcp->tcp_ecn_cwr_sent = B_FALSE;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon }
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon }
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon break;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon }
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon /*
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * We have something to send yet we cannot send. The
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * reason can be:
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon *
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * 1. Zero send window: we need to do zero window probe.
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * 2. Zero cwnd: because of ECN, we need to "clock out
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * segments.
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * 3. SWS avoidance: receiver may have shrunk window,
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * reset our knowledge.
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon *
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * Note that condition 2 can happen with either 1 or
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * 3. But 1 and 3 are exclusive.
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon */
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (tcp->tcp_unsent != 0) {
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon /*
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * Should not hold the zero-copy messages for too long.
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon */
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (tcp->tcp_snd_zcopy_aware && !tcp->tcp_xmit_zc_clean)
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcp->tcp_xmit_head = tcp_zcopy_backoff(tcp,
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcp->tcp_xmit_head, B_TRUE);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (tcp->tcp_cwnd == 0) {
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon /*
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * Set tcp_cwnd to 1 MSS so that a
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * new segment can be sent out. We
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * are "clocking out" new data when
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * the network is really congested.
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon */
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon ASSERT(tcp->tcp_ecn_ok);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcp->tcp_cwnd = tcp->tcp_mss;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon }
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (tcp->tcp_swnd == 0) {
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon /* Extend window for zero window probe */
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcp->tcp_swnd++;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcp->tcp_zero_win_probe = B_TRUE;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon TCPS_BUMP_MIB(tcps, tcpOutWinProbe);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon } else {
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon /*
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * Handle timeout from sender SWS avoidance.
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * Reset our knowledge of the max send window
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * since the receiver might have reduced its
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * receive buffer. Avoid setting tcp_max_swnd
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * to one since that will essentially disable
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * the SWS checks.
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon *
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * Note that since we don't have a SWS
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * state variable, if the timeout is set
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * for ECN but not for SWS, this
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * code will also be executed. This is
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * fine as tcp_max_swnd is updated
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * constantly and it will not affect
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * anything.
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon */
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcp->tcp_max_swnd = MAX(tcp->tcp_swnd, 2);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon }
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcp_wput_data(tcp, NULL, B_FALSE);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon return;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon }
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon /* Is there a FIN that needs to be to re retransmitted? */
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if ((tcp->tcp_valid_bits & TCP_FSS_VALID) &&
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon !tcp->tcp_fin_acked)
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon break;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon /* Nothing to do, return without restarting timer. */
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon TCP_STAT(tcps, tcp_timer_fire_miss);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon return;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon case TCPS_FIN_WAIT_2:
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon /*
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * User closed the TCP endpoint and peer ACK'ed our FIN.
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * We waited some time for for peer's FIN, but it hasn't
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * arrived. We flush the connection now to avoid
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * case where the peer has rebooted.
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon */
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (TCP_IS_DETACHED(tcp)) {
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon (void) tcp_clean_death(tcp, 0);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon } else {
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon TCP_TIMER_RESTART(tcp,
707e74bc53cd429bcd731df722227c7dc2de47c6Kacheong Poon tcp->tcp_fin_wait_2_flush_interval);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon }
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon return;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon case TCPS_TIME_WAIT:
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon (void) tcp_clean_death(tcp, 0);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon return;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon default:
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (connp->conn_debug) {
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon (void) strlog(TCP_MOD_ID, 0, 1, SL_TRACE|SL_ERROR,
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon "tcp_timer: strange state (%d) %s",
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcp->tcp_state, tcp_display(tcp, NULL,
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon DISP_PORT_ONLY));
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon }
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon return;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon }
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon /*
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * If the system is under memory pressure or the max number of
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * connections have been established for the listener, be more
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * aggressive in aborting connections.
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon */
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (tcps->tcps_reclaim || (tcp->tcp_listen_cnt != NULL &&
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcp->tcp_listen_cnt->tlc_cnt > tcp->tcp_listen_cnt->tlc_max)) {
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon second_threshold = tcp_early_abort * SECONDS;
707e74bc53cd429bcd731df722227c7dc2de47c6Kacheong Poon
707e74bc53cd429bcd731df722227c7dc2de47c6Kacheong Poon /* We will ignore the never timeout promise in this case... */
707e74bc53cd429bcd731df722227c7dc2de47c6Kacheong Poon dont_timeout = B_FALSE;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon }
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
5dd46ab5742d7db1cbb08dec7b64fa14930c02f7Kacheong Poon ASSERT(second_threshold != 0);
707e74bc53cd429bcd731df722227c7dc2de47c6Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if ((ms = tcp->tcp_ms_we_have_waited) > second_threshold) {
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon /*
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * Should not hold the zero-copy messages for too long.
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon */
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (tcp->tcp_snd_zcopy_aware && !tcp->tcp_xmit_zc_clean)
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcp->tcp_xmit_head = tcp_zcopy_backoff(tcp,
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcp->tcp_xmit_head, B_TRUE);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
5dd46ab5742d7db1cbb08dec7b64fa14930c02f7Kacheong Poon if (dont_timeout) {
5dd46ab5742d7db1cbb08dec7b64fa14930c02f7Kacheong Poon /*
5dd46ab5742d7db1cbb08dec7b64fa14930c02f7Kacheong Poon * Reset tcp_ms_we_have_waited to avoid overflow since
5dd46ab5742d7db1cbb08dec7b64fa14930c02f7Kacheong Poon * we are going to retransmit forever.
5dd46ab5742d7db1cbb08dec7b64fa14930c02f7Kacheong Poon */
5dd46ab5742d7db1cbb08dec7b64fa14930c02f7Kacheong Poon tcp->tcp_ms_we_have_waited = second_threshold;
707e74bc53cd429bcd731df722227c7dc2de47c6Kacheong Poon goto timer_rexmit;
5dd46ab5742d7db1cbb08dec7b64fa14930c02f7Kacheong Poon }
707e74bc53cd429bcd731df722227c7dc2de47c6Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon /*
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * For zero window probe, we need to send indefinitely,
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * unless we have not heard from the other side for some
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * time...
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon */
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if ((tcp->tcp_zero_win_probe == 0) ||
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon (TICK_TO_MSEC(ddi_get_lbolt() - tcp->tcp_last_recv_time) >
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon second_threshold)) {
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon TCPS_BUMP_MIB(tcps, tcpTimRetransDrop);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon /*
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * If TCP is in SYN_RCVD state, send back a
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * RST|ACK as BSD does. Note that tcp_zero_win_probe
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * should be zero in TCPS_SYN_RCVD state.
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon */
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (tcp->tcp_state == TCPS_SYN_RCVD) {
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcp_xmit_ctl("tcp_timer: RST sent on timeout "
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon "in SYN_RCVD",
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcp, tcp->tcp_snxt,
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcp->tcp_rnxt, TH_RST | TH_ACK);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon }
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon (void) tcp_clean_death(tcp,
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcp->tcp_client_errno ?
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcp->tcp_client_errno : ETIMEDOUT);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon return;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon } else {
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon /*
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * If the system is under memory pressure, we also
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * abort connection in zero window probing.
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon */
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (tcps->tcps_reclaim) {
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon (void) tcp_clean_death(tcp,
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcp->tcp_client_errno ?
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcp->tcp_client_errno : ETIMEDOUT);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon TCP_STAT(tcps, tcp_zwin_mem_drop);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon return;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon }
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon /*
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * Set tcp_ms_we_have_waited to second_threshold
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * so that in next timeout, we will do the above
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * check (ddi_get_lbolt() - tcp_last_recv_time).
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * This is also to avoid overflow.
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon *
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * We don't need to decrement tcp_timer_backoff
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * to avoid overflow because it will be decremented
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * later if new timeout value is greater than
707e74bc53cd429bcd731df722227c7dc2de47c6Kacheong Poon * tcp_rto_max. In the case when tcp_rto_max is
707e74bc53cd429bcd731df722227c7dc2de47c6Kacheong Poon * greater than second_threshold, it means that we
707e74bc53cd429bcd731df722227c7dc2de47c6Kacheong Poon * will wait longer than second_threshold to send
707e74bc53cd429bcd731df722227c7dc2de47c6Kacheong Poon * the next
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * window probe.
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon */
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcp->tcp_ms_we_have_waited = second_threshold;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon }
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon } else if (ms > first_threshold) {
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon /*
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * Should not hold the zero-copy messages for too long.
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon */
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (tcp->tcp_snd_zcopy_aware && !tcp->tcp_xmit_zc_clean)
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcp->tcp_xmit_head = tcp_zcopy_backoff(tcp,
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcp->tcp_xmit_head, B_TRUE);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon /*
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * We have been retransmitting for too long... The RTT
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * we calculated is probably incorrect. Reinitialize it.
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * Need to compensate for 0 tcp_rtt_sa. Reset
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * tcp_rtt_update so that we won't accidentally cache a
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * bad value. But only do this if this is not a zero
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * window probe.
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon */
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (tcp->tcp_rtt_sa != 0 && tcp->tcp_zero_win_probe == 0) {
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcp->tcp_rtt_sd += (tcp->tcp_rtt_sa >> 3) +
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon (tcp->tcp_rtt_sa >> 5);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcp->tcp_rtt_sa = 0;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcp_ip_notify(tcp);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcp->tcp_rtt_update = 0;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon }
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon }
707e74bc53cd429bcd731df722227c7dc2de47c6Kacheong Poon
707e74bc53cd429bcd731df722227c7dc2de47c6Kacheong Poontimer_rexmit:
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcp->tcp_timer_backoff++;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if ((ms = (tcp->tcp_rtt_sa >> 3) + tcp->tcp_rtt_sd +
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcps->tcps_rexmit_interval_extra + (tcp->tcp_rtt_sa >> 5)) <
707e74bc53cd429bcd731df722227c7dc2de47c6Kacheong Poon tcp->tcp_rto_min) {
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon /*
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * This means the original RTO is tcp_rexmit_interval_min.
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * So we will use tcp_rexmit_interval_min as the RTO value
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * and do the backoff.
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon */
707e74bc53cd429bcd731df722227c7dc2de47c6Kacheong Poon ms = tcp->tcp_rto_min << tcp->tcp_timer_backoff;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon } else {
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon ms <<= tcp->tcp_timer_backoff;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon }
707e74bc53cd429bcd731df722227c7dc2de47c6Kacheong Poon if (ms > tcp->tcp_rto_max) {
707e74bc53cd429bcd731df722227c7dc2de47c6Kacheong Poon ms = tcp->tcp_rto_max;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon /*
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * ms is at max, decrement tcp_timer_backoff to avoid
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * overflow.
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon */
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcp->tcp_timer_backoff--;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon }
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcp->tcp_ms_we_have_waited += ms;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (tcp->tcp_zero_win_probe == 0) {
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcp->tcp_rto = ms;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon }
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon TCP_TIMER_RESTART(tcp, ms);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon /*
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * This is after a timeout and tcp_rto is backed off. Set
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * tcp_set_timer to 1 so that next time RTO is updated, we will
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * restart the timer with a correct value.
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon */
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcp->tcp_set_timer = 1;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon mss = tcp->tcp_snxt - tcp->tcp_suna;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (mss > tcp->tcp_mss)
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon mss = tcp->tcp_mss;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (mss > tcp->tcp_swnd && tcp->tcp_swnd != 0)
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon mss = tcp->tcp_swnd;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if ((mp = tcp->tcp_xmit_head) != NULL)
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon mp->b_prev = (mblk_t *)ddi_get_lbolt();
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon mp = tcp_xmit_mp(tcp, mp, mss, NULL, NULL, tcp->tcp_suna, B_TRUE, &mss,
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon B_TRUE);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon /*
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * When slow start after retransmission begins, start with
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * this seq no. tcp_rexmit_max marks the end of special slow
633fc3a6eed35d918db16925b7048d7a2e28064aSebastien Roy * start phase.
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon */
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcp->tcp_rexmit_nxt = tcp->tcp_suna;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if ((tcp->tcp_valid_bits & TCP_FSS_VALID) &&
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon (tcp->tcp_unsent == 0)) {
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcp->tcp_rexmit_max = tcp->tcp_fss;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon } else {
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcp->tcp_rexmit_max = tcp->tcp_snxt;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon }
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcp->tcp_rexmit = B_TRUE;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcp->tcp_dupack_cnt = 0;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon /*
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * Remove all rexmit SACK blk to start from fresh.
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon */
66cd0f60c3182913d379abb730ae755bf6367126Kacheong Poon if (tcp->tcp_snd_sack_ok)
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon TCP_NOTSACK_REMOVE_ALL(tcp->tcp_notsack_list, tcp);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon if (mp == NULL) {
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon return;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon }
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcp->tcp_csuna = tcp->tcp_snxt;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon TCPS_BUMP_MIB(tcps, tcpRetransSegs);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon TCPS_UPDATE_MIB(tcps, tcpRetransBytes, mss);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcp_send_data(tcp, mp);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon}
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon/*
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * Handle lingering timeouts. This function is called when the SO_LINGER timeout
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon * expires.
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon */
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poonvoid
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poontcp_close_linger_timeout(void *arg)
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon{
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon conn_t *connp = (conn_t *)arg;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcp_t *tcp = connp->conn_tcp;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcp->tcp_client_errno = ETIMEDOUT;
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon tcp_stop_lingering(tcp);
721fffe35d40e548a5a58dc53a2ec9c6762172d9Kacheong Poon}