18c2654abSrjs /* $KAME: sctp_timer.c,v 1.30 2005/06/16 18:29:25 jinmei Exp $ */
2*7f459241Sandvar /* $NetBSD: sctp_timer.c,v 1.6 2022/02/16 22:00:56 andvar Exp $ */
38c2654abSrjs
48c2654abSrjs /*
58c2654abSrjs * Copyright (C) 2002, 2003, 2004 Cisco Systems Inc,
68c2654abSrjs * All rights reserved.
78c2654abSrjs *
88c2654abSrjs * Redistribution and use in source and binary forms, with or without
98c2654abSrjs * modification, are permitted provided that the following conditions
108c2654abSrjs * are met:
118c2654abSrjs * 1. Redistributions of source code must retain the above copyright
128c2654abSrjs * notice, this list of conditions and the following disclaimer.
138c2654abSrjs * 2. Redistributions in binary form must reproduce the above copyright
148c2654abSrjs * notice, this list of conditions and the following disclaimer in the
158c2654abSrjs * documentation and/or other materials provided with the distribution.
168c2654abSrjs * 3. Neither the name of the project nor the names of its contributors
178c2654abSrjs * may be used to endorse or promote products derived from this software
188c2654abSrjs * without specific prior written permission.
198c2654abSrjs *
208c2654abSrjs * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
218c2654abSrjs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
228c2654abSrjs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
238c2654abSrjs * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
248c2654abSrjs * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
258c2654abSrjs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
268c2654abSrjs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
278c2654abSrjs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
288c2654abSrjs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
298c2654abSrjs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
308c2654abSrjs * SUCH DAMAGE.
318c2654abSrjs */
328c2654abSrjs #include <sys/cdefs.h>
33*7f459241Sandvar __KERNEL_RCSID(0, "$NetBSD: sctp_timer.c,v 1.6 2022/02/16 22:00:56 andvar Exp $");
348c2654abSrjs
358c2654abSrjs #ifdef _KERNEL_OPT
368c2654abSrjs #include "opt_inet.h"
378c2654abSrjs #include "opt_sctp.h"
38a12c401aSrjs #include "opt_ipsec.h"
398c2654abSrjs #endif /* _KERNEL_OPT */
408c2654abSrjs
418c2654abSrjs #include <sys/param.h>
428c2654abSrjs #include <sys/systm.h>
438c2654abSrjs #include <sys/malloc.h>
448c2654abSrjs #include <sys/mbuf.h>
458c2654abSrjs #include <sys/domain.h>
468c2654abSrjs #include <sys/protosw.h>
478c2654abSrjs #include <sys/socket.h>
488c2654abSrjs #include <sys/socketvar.h>
498c2654abSrjs #include <sys/proc.h>
508c2654abSrjs #include <sys/kernel.h>
518c2654abSrjs #include <sys/sysctl.h>
528c2654abSrjs #ifdef INET6
538c2654abSrjs #include <sys/domain.h>
548c2654abSrjs #endif
558c2654abSrjs
568c2654abSrjs #include <machine/limits.h>
578c2654abSrjs
588c2654abSrjs #include <net/if.h>
598c2654abSrjs #include <net/if_types.h>
608c2654abSrjs #include <net/route.h>
618c2654abSrjs #include <netinet/in.h>
628c2654abSrjs #include <netinet/in_systm.h>
638c2654abSrjs #define _IP_VHL
648c2654abSrjs #include <netinet/ip.h>
658c2654abSrjs #include <netinet/in_pcb.h>
668c2654abSrjs #include <netinet/in_var.h>
678c2654abSrjs #include <netinet/ip_var.h>
688c2654abSrjs
698c2654abSrjs #ifdef INET6
708c2654abSrjs #include <netinet/ip6.h>
718c2654abSrjs #include <netinet6/ip6_var.h>
728c2654abSrjs #endif /* INET6 */
738c2654abSrjs
748c2654abSrjs #include <netinet/sctp_pcb.h>
758c2654abSrjs
768c2654abSrjs #ifdef IPSEC
77505ea976Srjs #include <netipsec/ipsec.h>
78505ea976Srjs #include <netipsec/key.h>
798c2654abSrjs #endif /* IPSEC */
808c2654abSrjs #ifdef INET6
818c2654abSrjs #include <netinet6/sctp6_var.h>
828c2654abSrjs #endif
838c2654abSrjs #include <netinet/sctp_var.h>
848c2654abSrjs #include <netinet/sctp_timer.h>
858c2654abSrjs #include <netinet/sctputil.h>
868c2654abSrjs #include <netinet/sctp_output.h>
878c2654abSrjs #include <netinet/sctp_hashdriver.h>
888c2654abSrjs #include <netinet/sctp_header.h>
898c2654abSrjs #include <netinet/sctp_indata.h>
908c2654abSrjs #include <netinet/sctp_asconf.h>
918c2654abSrjs
928c2654abSrjs #include <netinet/sctp.h>
938c2654abSrjs #include <netinet/sctp_uio.h>
948c2654abSrjs
958c2654abSrjs #ifdef SCTP_DEBUG
968c2654abSrjs extern u_int32_t sctp_debug_on;
978c2654abSrjs #endif /* SCTP_DEBUG */
988c2654abSrjs
998c2654abSrjs void
sctp_audit_retranmission_queue(struct sctp_association * asoc)1008c2654abSrjs sctp_audit_retranmission_queue(struct sctp_association *asoc)
1018c2654abSrjs {
1028c2654abSrjs struct sctp_tmit_chunk *chk;
1038c2654abSrjs
1048c2654abSrjs #ifdef SCTP_DEBUG
1058c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_TIMER4) {
1068c2654abSrjs printf("Audit invoked on send queue cnt:%d onqueue:%d\n",
1078c2654abSrjs asoc->sent_queue_retran_cnt,
1088c2654abSrjs asoc->sent_queue_cnt);
1098c2654abSrjs }
1108c2654abSrjs #endif /* SCTP_DEBUG */
1118c2654abSrjs asoc->sent_queue_retran_cnt = 0;
1128c2654abSrjs asoc->sent_queue_cnt = 0;
1138c2654abSrjs TAILQ_FOREACH(chk, &asoc->sent_queue, sctp_next) {
1148c2654abSrjs if (chk->sent == SCTP_DATAGRAM_RESEND) {
1158c2654abSrjs asoc->sent_queue_retran_cnt++;
1168c2654abSrjs }
1178c2654abSrjs asoc->sent_queue_cnt++;
1188c2654abSrjs }
1198c2654abSrjs TAILQ_FOREACH(chk, &asoc->control_send_queue, sctp_next) {
1208c2654abSrjs if (chk->sent == SCTP_DATAGRAM_RESEND) {
1218c2654abSrjs asoc->sent_queue_retran_cnt++;
1228c2654abSrjs }
1238c2654abSrjs }
1248c2654abSrjs #ifdef SCTP_DEBUG
1258c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_TIMER4) {
1268c2654abSrjs printf("Audit completes retran:%d onqueue:%d\n",
1278c2654abSrjs asoc->sent_queue_retran_cnt,
1288c2654abSrjs asoc->sent_queue_cnt);
1298c2654abSrjs }
1308c2654abSrjs #endif /* SCTP_DEBUG */
1318c2654abSrjs }
1328c2654abSrjs
1338c2654abSrjs int
sctp_threshold_management(struct sctp_inpcb * inp,struct sctp_tcb * stcb,struct sctp_nets * net,uint16_t threshold)1348c2654abSrjs sctp_threshold_management(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
1358c2654abSrjs struct sctp_nets *net, uint16_t threshold)
1368c2654abSrjs {
1378c2654abSrjs if (net) {
1388c2654abSrjs net->error_count++;
1398c2654abSrjs #ifdef SCTP_DEBUG
1408c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_TIMER4) {
1418c2654abSrjs printf("Error count for %p now %d thresh:%d\n",
1428c2654abSrjs net, net->error_count,
1438c2654abSrjs net->failure_threshold);
1448c2654abSrjs }
1458c2654abSrjs #endif /* SCTP_DEBUG */
1468c2654abSrjs if (net->error_count >= net->failure_threshold) {
1478c2654abSrjs /* We had a threshold failure */
1488c2654abSrjs if (net->dest_state & SCTP_ADDR_REACHABLE) {
1498c2654abSrjs net->dest_state &= ~SCTP_ADDR_REACHABLE;
1508c2654abSrjs net->dest_state |= SCTP_ADDR_NOT_REACHABLE;
1518c2654abSrjs if (net == stcb->asoc.primary_destination) {
1528c2654abSrjs net->dest_state |= SCTP_ADDR_WAS_PRIMARY;
1538c2654abSrjs }
1548c2654abSrjs sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN,
1558c2654abSrjs stcb,
1568c2654abSrjs SCTP_FAILED_THRESHOLD,
1578c2654abSrjs (void *)net);
1588c2654abSrjs }
1598c2654abSrjs }
1608c2654abSrjs /*********HOLD THIS COMMENT FOR PATCH OF ALTERNATE
1618c2654abSrjs *********ROUTING CODE
1628c2654abSrjs */
1638c2654abSrjs /*********HOLD THIS COMMENT FOR END OF PATCH OF ALTERNATE
1648c2654abSrjs *********ROUTING CODE
1658c2654abSrjs */
1668c2654abSrjs }
1678c2654abSrjs if (stcb == NULL)
1688c2654abSrjs return (0);
1698c2654abSrjs
1708c2654abSrjs if (net) {
1718c2654abSrjs if ((net->dest_state & SCTP_ADDR_UNCONFIRMED) == 0) {
1728c2654abSrjs stcb->asoc.overall_error_count++;
1738c2654abSrjs }
1748c2654abSrjs } else {
1758c2654abSrjs stcb->asoc.overall_error_count++;
1768c2654abSrjs }
1778c2654abSrjs #ifdef SCTP_DEBUG
1788c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_TIMER4) {
1798c2654abSrjs printf("Overall error count for %p now %d thresh:%u state:%x\n",
1808c2654abSrjs &stcb->asoc,
1818c2654abSrjs stcb->asoc.overall_error_count,
1828c2654abSrjs (u_int)threshold,
1838c2654abSrjs ((net == NULL) ? (u_int)0 : (u_int)net->dest_state));
1848c2654abSrjs }
1858c2654abSrjs #endif /* SCTP_DEBUG */
1868c2654abSrjs /* We specifically do not do >= to give the assoc one more
1878c2654abSrjs * change before we fail it.
1888c2654abSrjs */
1898c2654abSrjs if (stcb->asoc.overall_error_count > threshold) {
1908c2654abSrjs /* Abort notification sends a ULP notify */
1918c2654abSrjs struct mbuf *oper;
1928c2654abSrjs MGET(oper, M_DONTWAIT, MT_DATA);
1938c2654abSrjs if (oper) {
1948c2654abSrjs struct sctp_paramhdr *ph;
1958c2654abSrjs u_int32_t *ippp;
1968c2654abSrjs
1978c2654abSrjs oper->m_len = sizeof(struct sctp_paramhdr) +
1988c2654abSrjs sizeof(*ippp);
1998c2654abSrjs ph = mtod(oper, struct sctp_paramhdr *);
2008c2654abSrjs ph->param_type = htons(SCTP_CAUSE_PROTOCOL_VIOLATION);
2018c2654abSrjs ph->param_length = htons(oper->m_len);
2028c2654abSrjs ippp = (u_int32_t *)(ph + 1);
2038c2654abSrjs *ippp = htonl(0x40000001);
2048c2654abSrjs }
2058c2654abSrjs sctp_abort_an_association(inp, stcb, SCTP_FAILED_THRESHOLD, oper);
2068c2654abSrjs return (1);
2078c2654abSrjs }
2088c2654abSrjs return (0);
2098c2654abSrjs }
2108c2654abSrjs
2118c2654abSrjs struct sctp_nets *
sctp_find_alternate_net(struct sctp_tcb * stcb,struct sctp_nets * net)2128c2654abSrjs sctp_find_alternate_net(struct sctp_tcb *stcb,
2138c2654abSrjs struct sctp_nets *net)
2148c2654abSrjs {
2158c2654abSrjs /* Find and return an alternate network if possible */
2168c2654abSrjs struct sctp_nets *alt, *mnet;
2178c2654abSrjs struct rtentry *rt;
2188c2654abSrjs int once;
2198c2654abSrjs
2208c2654abSrjs if (stcb->asoc.numnets == 1) {
2218c2654abSrjs /* No others but net */
2228c2654abSrjs return (TAILQ_FIRST(&stcb->asoc.nets));
2238c2654abSrjs }
2248c2654abSrjs mnet = net;
2258c2654abSrjs once = 0;
2268c2654abSrjs
2278c2654abSrjs if (mnet == NULL) {
2288c2654abSrjs mnet = TAILQ_FIRST(&stcb->asoc.nets);
2298c2654abSrjs }
2308c2654abSrjs do {
2318c2654abSrjs alt = TAILQ_NEXT(mnet, sctp_next);
2328c2654abSrjs if (alt == NULL) {
2338c2654abSrjs once++;
2348c2654abSrjs if (once > 1) {
2358c2654abSrjs break;
2368c2654abSrjs }
2378c2654abSrjs alt = TAILQ_FIRST(&stcb->asoc.nets);
2388c2654abSrjs }
2398c2654abSrjs rt = rtcache_validate(&alt->ro);
2408c2654abSrjs if (rt == NULL) {
2418c2654abSrjs alt->src_addr_selected = 0;
2428c2654abSrjs }
2438c2654abSrjs if (
2448c2654abSrjs ((alt->dest_state & SCTP_ADDR_REACHABLE) == SCTP_ADDR_REACHABLE) &&
2458c2654abSrjs (rt != NULL) &&
2468c2654abSrjs (!(alt->dest_state & SCTP_ADDR_UNCONFIRMED))
2478c2654abSrjs ) {
2488c2654abSrjs /* Found a reachable address */
2494c25fb2fSozaki-r rtcache_unref(rt, &alt->ro);
2508c2654abSrjs break;
2518c2654abSrjs }
2524c25fb2fSozaki-r rtcache_unref(rt, &alt->ro);
2538c2654abSrjs mnet = alt;
2548c2654abSrjs } while (alt != NULL);
2558c2654abSrjs
2568c2654abSrjs if (alt == NULL) {
2578c2654abSrjs /* Case where NO insv network exists (dormant state) */
2588c2654abSrjs /* we rotate destinations */
2598c2654abSrjs once = 0;
2608c2654abSrjs mnet = net;
2618c2654abSrjs do {
2628c2654abSrjs alt = TAILQ_NEXT(mnet, sctp_next);
2638c2654abSrjs if (alt == NULL) {
2648c2654abSrjs once++;
2658c2654abSrjs if (once > 1) {
2668c2654abSrjs break;
2678c2654abSrjs }
2688c2654abSrjs alt = TAILQ_FIRST(&stcb->asoc.nets);
2698c2654abSrjs }
2708c2654abSrjs if ((!(alt->dest_state & SCTP_ADDR_UNCONFIRMED)) &&
2718c2654abSrjs (alt != net)) {
2728c2654abSrjs /* Found an alternate address */
2738c2654abSrjs break;
2748c2654abSrjs }
2758c2654abSrjs mnet = alt;
2768c2654abSrjs } while (alt != NULL);
2778c2654abSrjs }
2788c2654abSrjs if (alt == NULL) {
2798c2654abSrjs return (net);
2808c2654abSrjs }
2818c2654abSrjs return (alt);
2828c2654abSrjs }
2838c2654abSrjs
2848c2654abSrjs static void
sctp_backoff_on_timeout(struct sctp_tcb * stcb,struct sctp_nets * net,int win_probe,int num_marked)2858c2654abSrjs sctp_backoff_on_timeout(struct sctp_tcb *stcb,
2868c2654abSrjs struct sctp_nets *net,
2878c2654abSrjs int win_probe,
2888c2654abSrjs int num_marked)
2898c2654abSrjs {
2908c2654abSrjs #ifdef SCTP_DEBUG
2918c2654abSrjs int oldRTO;
2928c2654abSrjs
2938c2654abSrjs oldRTO = net->RTO;
2948c2654abSrjs #endif /* SCTP_DEBUG */
2958c2654abSrjs net->RTO <<= 1;
2968c2654abSrjs #ifdef SCTP_DEBUG
2978c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_TIMER2) {
2988c2654abSrjs printf("Timer doubles from %d ms -to-> %d ms\n",
2998c2654abSrjs oldRTO, net->RTO);
3008c2654abSrjs }
3018c2654abSrjs #endif /* SCTP_DEBUG */
3028c2654abSrjs
3038c2654abSrjs if (net->RTO > stcb->asoc.maxrto) {
3048c2654abSrjs net->RTO = stcb->asoc.maxrto;
3058c2654abSrjs #ifdef SCTP_DEBUG
3068c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_TIMER2) {
3078c2654abSrjs printf("Growth capped by maxrto %d\n",
3088c2654abSrjs net->RTO);
3098c2654abSrjs }
3108c2654abSrjs #endif /* SCTP_DEBUG */
3118c2654abSrjs }
3128c2654abSrjs
3138c2654abSrjs
3148c2654abSrjs if ((win_probe == 0) && num_marked) {
3158c2654abSrjs /* We don't apply penalty to window probe scenarios */
3168c2654abSrjs #ifdef SCTP_CWND_LOGGING
3178c2654abSrjs int old_cwnd=net->cwnd;
3188c2654abSrjs #endif
3198c2654abSrjs net->ssthresh = net->cwnd >> 1;
3208c2654abSrjs if (net->ssthresh < (net->mtu << 1)) {
3218c2654abSrjs net->ssthresh = (net->mtu << 1);
3228c2654abSrjs }
3238c2654abSrjs net->cwnd = net->mtu;
3248c2654abSrjs /* floor of 1 mtu */
3258c2654abSrjs if (net->cwnd < net->mtu)
3268c2654abSrjs net->cwnd = net->mtu;
3278c2654abSrjs #ifdef SCTP_CWND_LOGGING
3288c2654abSrjs sctp_log_cwnd(net, net->cwnd-old_cwnd, SCTP_CWND_LOG_FROM_RTX);
3298c2654abSrjs #endif
3308c2654abSrjs
3318c2654abSrjs net->partial_bytes_acked = 0;
3328c2654abSrjs #ifdef SCTP_DEBUG
3338c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_TIMER1) {
3348c2654abSrjs printf("collapse cwnd to 1MTU ssthresh to %d\n",
3358c2654abSrjs net->ssthresh);
3368c2654abSrjs }
3378c2654abSrjs #endif
3388c2654abSrjs
3398c2654abSrjs }
3408c2654abSrjs }
3418c2654abSrjs
3428c2654abSrjs
3438c2654abSrjs static int
sctp_mark_all_for_resend(struct sctp_tcb * stcb,struct sctp_nets * net,struct sctp_nets * alt,int * num_marked)3448c2654abSrjs sctp_mark_all_for_resend(struct sctp_tcb *stcb,
3458c2654abSrjs struct sctp_nets *net,
3468c2654abSrjs struct sctp_nets *alt,
3478c2654abSrjs int *num_marked)
3488c2654abSrjs {
3498c2654abSrjs
3508c2654abSrjs /*
3518c2654abSrjs * Mark all chunks (well not all) that were sent to *net for retransmission.
3528c2654abSrjs * Move them to alt for there destination as well... We only
3538c2654abSrjs * mark chunks that have been outstanding long enough to have
3548c2654abSrjs * received feed-back.
3558c2654abSrjs */
3568c2654abSrjs struct sctp_tmit_chunk *chk, *tp2;
3578c2654abSrjs struct sctp_nets *lnets;
3588c2654abSrjs struct timeval now, min_wait, tv;
3598c2654abSrjs int cur_rto;
3608c2654abSrjs int win_probes, non_win_probes, orig_rwnd, audit_tf, num_mk, fir;
3618c2654abSrjs unsigned int cnt_mk;
3628c2654abSrjs u_int32_t orig_flight;
3638c2654abSrjs #ifdef SCTP_FR_LOGGING
3648c2654abSrjs u_int32_t tsnfirst, tsnlast;
3658c2654abSrjs #endif
3668c2654abSrjs
3678c2654abSrjs /* none in flight now */
3688c2654abSrjs audit_tf = 0;
3698c2654abSrjs fir=0;
3708c2654abSrjs /* figure out how long a data chunk must be pending
3718c2654abSrjs * before we can mark it ..
3728c2654abSrjs */
3738c2654abSrjs SCTP_GETTIME_TIMEVAL(&now);
3748c2654abSrjs /* get cur rto in micro-seconds */
3758c2654abSrjs cur_rto = (((net->lastsa >> 2) + net->lastsv) >> 1);
3768c2654abSrjs #ifdef SCTP_FR_LOGGING
3778c2654abSrjs sctp_log_fr(cur_rto, 0, 0, SCTP_FR_T3_MARK_TIME);
3788c2654abSrjs #endif
3798c2654abSrjs cur_rto *= 1000;
3808c2654abSrjs #ifdef SCTP_FR_LOGGING
3818c2654abSrjs sctp_log_fr(cur_rto, 0, 0, SCTP_FR_T3_MARK_TIME);
3828c2654abSrjs #endif
3838c2654abSrjs tv.tv_sec = cur_rto / 1000000;
3848c2654abSrjs tv.tv_usec = cur_rto % 1000000;
3858c2654abSrjs #ifndef __FreeBSD__
3868c2654abSrjs timersub(&now, &tv, &min_wait);
3878c2654abSrjs #else
3888c2654abSrjs min_wait = now;
3898c2654abSrjs timevalsub(&min_wait, &tv);
3908c2654abSrjs #endif
3918c2654abSrjs if (min_wait.tv_sec < 0 || min_wait.tv_usec < 0) {
3928c2654abSrjs /*
3938c2654abSrjs * if we hit here, we don't
3948c2654abSrjs * have enough seconds on the clock to account
3958c2654abSrjs * for the RTO. We just let the lower seconds
3968c2654abSrjs * be the bounds and don't worry about it. This
3978c2654abSrjs * may mean we will mark a lot more than we should.
3988c2654abSrjs */
3998c2654abSrjs min_wait.tv_sec = min_wait.tv_usec = 0;
4008c2654abSrjs }
4018c2654abSrjs #ifdef SCTP_FR_LOGGING
4028c2654abSrjs sctp_log_fr(cur_rto, now.tv_sec, now.tv_usec, SCTP_FR_T3_MARK_TIME);
4038c2654abSrjs sctp_log_fr(0, min_wait.tv_sec, min_wait.tv_usec, SCTP_FR_T3_MARK_TIME);
4048c2654abSrjs #endif
4058c2654abSrjs if (stcb->asoc.total_flight >= net->flight_size) {
4068c2654abSrjs stcb->asoc.total_flight -= net->flight_size;
4078c2654abSrjs } else {
4088c2654abSrjs audit_tf = 1;
4098c2654abSrjs stcb->asoc.total_flight = 0;
4108c2654abSrjs }
4118c2654abSrjs /* Our rwnd will be incorrect here since we are not adding
4128c2654abSrjs * back the cnt * mbuf but we will fix that down below.
4138c2654abSrjs */
4148c2654abSrjs orig_rwnd = stcb->asoc.peers_rwnd;
4158c2654abSrjs orig_flight = net->flight_size;
4168c2654abSrjs stcb->asoc.peers_rwnd += net->flight_size;
4178c2654abSrjs net->flight_size = 0;
4188c2654abSrjs net->rto_pending = 0;
4198c2654abSrjs net->fast_retran_ip= 0;
4208c2654abSrjs win_probes = non_win_probes = 0;
4218c2654abSrjs #ifdef SCTP_DEBUG
4228c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_TIMER2) {
4238c2654abSrjs printf("Marking ALL un-acked for retransmission at t3-timeout\n");
4248c2654abSrjs }
4258c2654abSrjs #endif /* SCTP_DEBUG */
4268c2654abSrjs /* Now on to each chunk */
4278c2654abSrjs num_mk = cnt_mk = 0;
4288c2654abSrjs #ifdef SCTP_FR_LOGGING
4298c2654abSrjs tsnlast = tsnfirst = 0;
4308c2654abSrjs #endif
4318c2654abSrjs chk = TAILQ_FIRST(&stcb->asoc.sent_queue);
4328c2654abSrjs for (;chk != NULL; chk = tp2) {
4338c2654abSrjs tp2 = TAILQ_NEXT(chk, sctp_next);
4348c2654abSrjs if ((compare_with_wrap(stcb->asoc.last_acked_seq,
4358c2654abSrjs chk->rec.data.TSN_seq,
4368c2654abSrjs MAX_TSN)) ||
4378c2654abSrjs (stcb->asoc.last_acked_seq == chk->rec.data.TSN_seq)) {
4388c2654abSrjs /* Strange case our list got out of order? */
4398c2654abSrjs printf("Our list is out of order?\n");
4408c2654abSrjs TAILQ_REMOVE(&stcb->asoc.sent_queue, chk, sctp_next);
4418c2654abSrjs if (chk->data) {
4428c2654abSrjs sctp_release_pr_sctp_chunk(stcb, chk, 0xffff,
4438c2654abSrjs &stcb->asoc.sent_queue);
4448c2654abSrjs if (chk->flags & SCTP_PR_SCTP_BUFFER) {
4458c2654abSrjs stcb->asoc.sent_queue_cnt_removeable--;
4468c2654abSrjs }
4478c2654abSrjs }
4488c2654abSrjs stcb->asoc.sent_queue_cnt--;
4498c2654abSrjs sctp_free_remote_addr(chk->whoTo);
4508c2654abSrjs sctppcbinfo.ipi_count_chunk--;
4518c2654abSrjs if ((int)sctppcbinfo.ipi_count_chunk < 0) {
4528c2654abSrjs panic("Chunk count is going negative");
4538c2654abSrjs }
4548c2654abSrjs SCTP_ZONE_FREE(sctppcbinfo.ipi_zone_chunk, chk);
4558c2654abSrjs sctppcbinfo.ipi_gencnt_chunk++;
4568c2654abSrjs continue;
4578c2654abSrjs }
4588c2654abSrjs if ((chk->whoTo == net) && (chk->sent < SCTP_DATAGRAM_ACKED)) {
4598c2654abSrjs /* found one to mark:
4608c2654abSrjs * If it is less than DATAGRAM_ACKED it MUST
4618c2654abSrjs * not be a skipped or marked TSN but instead
4628c2654abSrjs * one that is either already set for retransmission OR
4638c2654abSrjs * one that needs retransmission.
4648c2654abSrjs */
4658c2654abSrjs
4668c2654abSrjs /* validate its been outstanding long enough */
4678c2654abSrjs #ifdef SCTP_FR_LOGGING
4688c2654abSrjs sctp_log_fr(chk->rec.data.TSN_seq,
4698c2654abSrjs chk->sent_rcv_time.tv_sec,
4708c2654abSrjs chk->sent_rcv_time.tv_usec,
4718c2654abSrjs SCTP_FR_T3_MARK_TIME);
4728c2654abSrjs #endif
4738c2654abSrjs if (chk->sent_rcv_time.tv_sec > min_wait.tv_sec) {
4748c2654abSrjs /* we have reached a chunk that was sent some
4758c2654abSrjs * seconds past our min.. forget it we will
4768c2654abSrjs * find no more to send.
4778c2654abSrjs */
4788c2654abSrjs #ifdef SCTP_FR_LOGGING
4798c2654abSrjs sctp_log_fr(0,
4808c2654abSrjs chk->sent_rcv_time.tv_sec,
4818c2654abSrjs chk->sent_rcv_time.tv_usec,
4828c2654abSrjs SCTP_FR_T3_STOPPED);
4838c2654abSrjs #endif
4848c2654abSrjs continue;
4858c2654abSrjs } else if (chk->sent_rcv_time.tv_sec == min_wait.tv_sec) {
4868c2654abSrjs /* we must look at the micro seconds to know.
4878c2654abSrjs */
4888c2654abSrjs if (chk->sent_rcv_time.tv_usec >= min_wait.tv_usec) {
4898c2654abSrjs /* ok it was sent after our boundary time. */
4908c2654abSrjs #ifdef SCTP_FR_LOGGING
4918c2654abSrjs sctp_log_fr(0,
4928c2654abSrjs chk->sent_rcv_time.tv_sec,
4938c2654abSrjs chk->sent_rcv_time.tv_usec,
4948c2654abSrjs SCTP_FR_T3_STOPPED);
4958c2654abSrjs #endif
4968c2654abSrjs continue;
4978c2654abSrjs }
4988c2654abSrjs }
4998c2654abSrjs if (stcb->asoc.total_flight_count > 0) {
5008c2654abSrjs stcb->asoc.total_flight_count--;
5018c2654abSrjs }
5028c2654abSrjs if ((chk->flags & (SCTP_PR_SCTP_ENABLED|SCTP_PR_SCTP_BUFFER)) == SCTP_PR_SCTP_ENABLED) {
5038c2654abSrjs /* Is it expired? */
5048c2654abSrjs if ((now.tv_sec > chk->rec.data.timetodrop.tv_sec) ||
5058c2654abSrjs ((chk->rec.data.timetodrop.tv_sec == now.tv_sec) &&
5068c2654abSrjs (now.tv_usec > chk->rec.data.timetodrop.tv_usec))) {
5078c2654abSrjs /* Yes so drop it */
5088c2654abSrjs if (chk->data) {
5098c2654abSrjs sctp_release_pr_sctp_chunk(stcb,
5108c2654abSrjs chk,
5118c2654abSrjs (SCTP_RESPONSE_TO_USER_REQ|SCTP_NOTIFY_DATAGRAM_SENT),
5128c2654abSrjs &stcb->asoc.sent_queue);
5138c2654abSrjs }
5148c2654abSrjs }
5158c2654abSrjs continue;
5168c2654abSrjs }
5178c2654abSrjs if (chk->sent != SCTP_DATAGRAM_RESEND) {
5188c2654abSrjs stcb->asoc.sent_queue_retran_cnt++;
5198c2654abSrjs num_mk++;
5208c2654abSrjs if (fir == 0) {
5218c2654abSrjs fir = 1;
5228c2654abSrjs #ifdef SCTP_DEBUG
5238c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_TIMER1) {
5248c2654abSrjs printf("First TSN marked was %x\n",
5258c2654abSrjs chk->rec.data.TSN_seq);
5268c2654abSrjs }
5278c2654abSrjs #endif
5288c2654abSrjs #ifdef SCTP_FR_LOGGING
5298c2654abSrjs tsnfirst = chk->rec.data.TSN_seq;
5308c2654abSrjs #endif
5318c2654abSrjs }
5328c2654abSrjs #ifdef SCTP_FR_LOGGING
5338c2654abSrjs tsnlast = chk->rec.data.TSN_seq;
5348c2654abSrjs sctp_log_fr(chk->rec.data.TSN_seq, chk->snd_count,
5358c2654abSrjs 0, SCTP_FR_T3_MARKED);
5368c2654abSrjs
5378c2654abSrjs #endif
5388c2654abSrjs }
5398c2654abSrjs chk->sent = SCTP_DATAGRAM_RESEND;
5408c2654abSrjs /* reset the TSN for striking and other FR stuff */
5418c2654abSrjs chk->rec.data.doing_fast_retransmit = 0;
5428c2654abSrjs #ifdef SCTP_DEBUG
5438c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_TIMER3) {
5448c2654abSrjs printf("mark TSN:%x for retransmission\n", chk->rec.data.TSN_seq);
5458c2654abSrjs }
5468c2654abSrjs #endif /* SCTP_DEBUG */
5478c2654abSrjs /* Clear any time so NO RTT is being done */
5488c2654abSrjs chk->do_rtt = 0;
5498c2654abSrjs /* Bump up the count */
5508c2654abSrjs if (compare_with_wrap(chk->rec.data.TSN_seq,
5518c2654abSrjs stcb->asoc.t3timeout_highest_marked,
5528c2654abSrjs MAX_TSN)) {
5538c2654abSrjs /* TSN_seq > than t3timeout so update */
5548c2654abSrjs stcb->asoc.t3timeout_highest_marked = chk->rec.data.TSN_seq;
5558c2654abSrjs }
5568c2654abSrjs if (alt != net) {
5578c2654abSrjs sctp_free_remote_addr(chk->whoTo);
5588c2654abSrjs chk->whoTo = alt;
5598c2654abSrjs alt->ref_count++;
5608c2654abSrjs }
5618c2654abSrjs if ((chk->rec.data.state_flags & SCTP_WINDOW_PROBE) !=
5628c2654abSrjs SCTP_WINDOW_PROBE) {
5638c2654abSrjs non_win_probes++;
5648c2654abSrjs } else {
5658c2654abSrjs chk->rec.data.state_flags &= ~SCTP_WINDOW_PROBE;
5668c2654abSrjs win_probes++;
5678c2654abSrjs }
5688c2654abSrjs }
5698c2654abSrjs if (chk->sent == SCTP_DATAGRAM_RESEND) {
5708c2654abSrjs cnt_mk++;
5718c2654abSrjs }
5728c2654abSrjs }
5738c2654abSrjs
5748c2654abSrjs #ifdef SCTP_FR_LOGGING
5758c2654abSrjs sctp_log_fr(tsnfirst, tsnlast, num_mk, SCTP_FR_T3_TIMEOUT);
5768c2654abSrjs #endif
5778c2654abSrjs /* compensate for the number we marked */
5788c2654abSrjs stcb->asoc.peers_rwnd += (num_mk /* * sizeof(struct mbuf)*/);
5798c2654abSrjs
5808c2654abSrjs #ifdef SCTP_DEBUG
5818c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_TIMER1) {
5828c2654abSrjs if (num_mk) {
5838c2654abSrjs #ifdef SCTP_FR_LOGGING
5848c2654abSrjs printf("LAST TSN marked was %x\n", tsnlast);
5858c2654abSrjs #endif
5868c2654abSrjs printf("Num marked for retransmission was %d peer-rwd:%ld\n",
5878c2654abSrjs num_mk, (u_long)stcb->asoc.peers_rwnd);
5888c2654abSrjs #ifdef SCTP_FR_LOGGING
5898c2654abSrjs printf("LAST TSN marked was %x\n", tsnlast);
5908c2654abSrjs #endif
5918c2654abSrjs printf("Num marked for retransmission was %d peer-rwd:%d\n",
5928c2654abSrjs num_mk,
5938c2654abSrjs (int)stcb->asoc.peers_rwnd
5948c2654abSrjs );
5958c2654abSrjs }
5968c2654abSrjs }
5978c2654abSrjs #endif
5988c2654abSrjs *num_marked = num_mk;
5998c2654abSrjs if (stcb->asoc.sent_queue_retran_cnt != cnt_mk) {
6008c2654abSrjs printf("Local Audit says there are %d for retran asoc cnt:%d\n",
6018c2654abSrjs cnt_mk, stcb->asoc.sent_queue_retran_cnt);
6028c2654abSrjs #ifndef SCTP_AUDITING_ENABLED
6038c2654abSrjs stcb->asoc.sent_queue_retran_cnt = cnt_mk;
6048c2654abSrjs #endif
6058c2654abSrjs }
6068c2654abSrjs #ifdef SCTP_DEBUG
6078c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_TIMER3) {
6088c2654abSrjs printf("**************************\n");
6098c2654abSrjs }
6108c2654abSrjs #endif /* SCTP_DEBUG */
6118c2654abSrjs
6128c2654abSrjs /* Now check for a ECN Echo that may be stranded */
6138c2654abSrjs TAILQ_FOREACH(chk, &stcb->asoc.control_send_queue, sctp_next) {
6148c2654abSrjs if ((chk->whoTo == net) &&
6158c2654abSrjs (chk->rec.chunk_id == SCTP_ECN_ECHO)) {
6168c2654abSrjs sctp_free_remote_addr(chk->whoTo);
6178c2654abSrjs chk->whoTo = alt;
6188c2654abSrjs if (chk->sent != SCTP_DATAGRAM_RESEND) {
6198c2654abSrjs chk->sent = SCTP_DATAGRAM_RESEND;
6208c2654abSrjs stcb->asoc.sent_queue_retran_cnt++;
6218c2654abSrjs }
6228c2654abSrjs alt->ref_count++;
6238c2654abSrjs }
6248c2654abSrjs }
6258c2654abSrjs if ((orig_rwnd == 0) && (stcb->asoc.total_flight == 0) &&
6268c2654abSrjs (orig_flight <= net->mtu)) {
6278c2654abSrjs /*
6288c2654abSrjs * If the LAST packet sent was not acked and our rwnd is 0
6298c2654abSrjs * then we are in a win-probe state.
6308c2654abSrjs */
6318c2654abSrjs win_probes = 1;
6328c2654abSrjs non_win_probes = 0;
6338c2654abSrjs #ifdef SCTP_DEBUG
6348c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_TIMER1) {
6358c2654abSrjs printf("WIN_PROBE set via o_rwnd=0 tf=0 and all:%d fit in mtu:%d\n",
6368c2654abSrjs orig_flight, net->mtu);
6378c2654abSrjs }
6388c2654abSrjs #endif
6398c2654abSrjs }
6408c2654abSrjs
6418c2654abSrjs if (audit_tf) {
6428c2654abSrjs #ifdef SCTP_DEBUG
6438c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_TIMER4) {
6448c2654abSrjs printf("Audit total flight due to negative value net:%p\n",
6458c2654abSrjs net);
6468c2654abSrjs }
6478c2654abSrjs #endif /* SCTP_DEBUG */
6488c2654abSrjs stcb->asoc.total_flight = 0;
6498c2654abSrjs stcb->asoc.total_flight_count = 0;
6508c2654abSrjs /* Clear all networks flight size */
6518c2654abSrjs TAILQ_FOREACH(lnets, &stcb->asoc.nets, sctp_next) {
6528c2654abSrjs lnets->flight_size = 0;
6538c2654abSrjs #ifdef SCTP_DEBUG
6548c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_TIMER4) {
6558c2654abSrjs printf("Net:%p c-f cwnd:%d ssthresh:%d\n",
6568c2654abSrjs lnets, lnets->cwnd, lnets->ssthresh);
6578c2654abSrjs }
6588c2654abSrjs #endif /* SCTP_DEBUG */
6598c2654abSrjs }
6608c2654abSrjs TAILQ_FOREACH(chk, &stcb->asoc.sent_queue, sctp_next) {
6618c2654abSrjs if (chk->sent < SCTP_DATAGRAM_RESEND) {
6628c2654abSrjs stcb->asoc.total_flight += chk->book_size;
6638c2654abSrjs chk->whoTo->flight_size += chk->book_size;
6648c2654abSrjs stcb->asoc.total_flight_count++;
6658c2654abSrjs }
6668c2654abSrjs }
6678c2654abSrjs }
6688c2654abSrjs /* Setup the ecn nonce re-sync point. We
6698c2654abSrjs * do this since retranmissions are NOT
6708c2654abSrjs * setup for ECN. This means that do to
6718c2654abSrjs * Karn's rule, we don't know the total
6728c2654abSrjs * of the peers ecn bits.
6738c2654abSrjs */
6748c2654abSrjs chk = TAILQ_FIRST(&stcb->asoc.send_queue);
6758c2654abSrjs if (chk == NULL) {
6768c2654abSrjs stcb->asoc.nonce_resync_tsn = stcb->asoc.sending_seq;
6778c2654abSrjs } else {
6788c2654abSrjs stcb->asoc.nonce_resync_tsn = chk->rec.data.TSN_seq;
6798c2654abSrjs }
6808c2654abSrjs stcb->asoc.nonce_wait_for_ecne = 0;
6818c2654abSrjs stcb->asoc.nonce_sum_check = 0;
6828c2654abSrjs /* We return 1 if we only have a window probe outstanding */
6838c2654abSrjs if (win_probes && (non_win_probes == 0)) {
6848c2654abSrjs return (1);
6858c2654abSrjs }
6868c2654abSrjs return (0);
6878c2654abSrjs }
6888c2654abSrjs
6898c2654abSrjs static void
sctp_move_all_chunks_to_alt(struct sctp_tcb * stcb,struct sctp_nets * net,struct sctp_nets * alt)6908c2654abSrjs sctp_move_all_chunks_to_alt(struct sctp_tcb *stcb,
6918c2654abSrjs struct sctp_nets *net,
6928c2654abSrjs struct sctp_nets *alt)
6938c2654abSrjs {
6948c2654abSrjs struct sctp_association *asoc;
6958c2654abSrjs struct sctp_stream_out *outs;
6968c2654abSrjs struct sctp_tmit_chunk *chk;
6978c2654abSrjs
6988c2654abSrjs if (net == alt)
6998c2654abSrjs /* nothing to do */
7008c2654abSrjs return;
7018c2654abSrjs
7028c2654abSrjs asoc = &stcb->asoc;
7038c2654abSrjs
7048c2654abSrjs /*
7058c2654abSrjs * now through all the streams checking for chunks sent to our
7068c2654abSrjs * bad network.
7078c2654abSrjs */
7088c2654abSrjs TAILQ_FOREACH(outs, &asoc->out_wheel, next_spoke) {
7098c2654abSrjs /* now clean up any chunks here */
7108c2654abSrjs TAILQ_FOREACH(chk, &outs->outqueue, sctp_next) {
7118c2654abSrjs if (chk->whoTo == net) {
7128c2654abSrjs sctp_free_remote_addr(chk->whoTo);
7138c2654abSrjs chk->whoTo = alt;
7148c2654abSrjs alt->ref_count++;
7158c2654abSrjs }
7168c2654abSrjs }
7178c2654abSrjs }
7188c2654abSrjs /* Now check the pending queue */
7198c2654abSrjs TAILQ_FOREACH(chk, &asoc->send_queue, sctp_next) {
7208c2654abSrjs if (chk->whoTo == net) {
7218c2654abSrjs sctp_free_remote_addr(chk->whoTo);
7228c2654abSrjs chk->whoTo = alt;
7238c2654abSrjs alt->ref_count++;
7248c2654abSrjs }
7258c2654abSrjs }
7268c2654abSrjs
7278c2654abSrjs }
7288c2654abSrjs
7298c2654abSrjs int
sctp_t3rxt_timer(struct sctp_inpcb * inp,struct sctp_tcb * stcb,struct sctp_nets * net)7308c2654abSrjs sctp_t3rxt_timer(struct sctp_inpcb *inp,
7318c2654abSrjs struct sctp_tcb *stcb,
7328c2654abSrjs struct sctp_nets *net)
7338c2654abSrjs {
7348c2654abSrjs struct sctp_nets *alt;
7358c2654abSrjs int win_probe, num_mk;
7368c2654abSrjs
7378c2654abSrjs
7388c2654abSrjs #ifdef SCTP_FR_LOGGING
7398c2654abSrjs sctp_log_fr(0, 0, 0, SCTP_FR_T3_TIMEOUT);
7408c2654abSrjs #endif
7418c2654abSrjs /* Find an alternate and mark those for retransmission */
7428c2654abSrjs alt = sctp_find_alternate_net(stcb, net);
7438c2654abSrjs win_probe = sctp_mark_all_for_resend(stcb, net, alt, &num_mk);
7448c2654abSrjs
7458c2654abSrjs /* FR Loss recovery just ended with the T3. */
7468c2654abSrjs stcb->asoc.fast_retran_loss_recovery = 0;
7478c2654abSrjs
7488c2654abSrjs /* setup the sat loss recovery that prevents
7498c2654abSrjs * satellite cwnd advance.
7508c2654abSrjs */
7518c2654abSrjs stcb->asoc.sat_t3_loss_recovery = 1;
7528c2654abSrjs stcb->asoc.sat_t3_recovery_tsn = stcb->asoc.sending_seq;
7538c2654abSrjs
7548c2654abSrjs /* Backoff the timer and cwnd */
7558c2654abSrjs sctp_backoff_on_timeout(stcb, net, win_probe, num_mk);
7568c2654abSrjs if (win_probe == 0) {
7578c2654abSrjs /* We don't do normal threshold management on window probes */
7588c2654abSrjs if (sctp_threshold_management(inp, stcb, net,
7598c2654abSrjs stcb->asoc.max_send_times)) {
7608c2654abSrjs /* Association was destroyed */
7618c2654abSrjs return (1);
7628c2654abSrjs } else {
7638c2654abSrjs if (net != stcb->asoc.primary_destination) {
7648c2654abSrjs /* send a immediate HB if our RTO is stale */
7658c2654abSrjs struct timeval now;
7668c2654abSrjs unsigned int ms_goneby;
7678c2654abSrjs SCTP_GETTIME_TIMEVAL(&now);
7688c2654abSrjs if (net->last_sent_time.tv_sec) {
7698c2654abSrjs ms_goneby = (now.tv_sec - net->last_sent_time.tv_sec) * 1000;
7708c2654abSrjs } else {
7718c2654abSrjs ms_goneby = 0;
7728c2654abSrjs }
7738c2654abSrjs if ((ms_goneby > net->RTO) || (net->RTO == 0)) {
7748c2654abSrjs /* no recent feed back in an RTO or more, request a RTT update */
7758c2654abSrjs sctp_send_hb(stcb, 1, net);
7768c2654abSrjs }
7778c2654abSrjs }
7788c2654abSrjs }
7798c2654abSrjs } else {
7808c2654abSrjs /*
7818c2654abSrjs * For a window probe we don't penalize the net's but only
7828c2654abSrjs * the association. This may fail it if SACKs are not coming
7838c2654abSrjs * back. If sack's are coming with rwnd locked at 0, we will
7848c2654abSrjs * continue to hold things waiting for rwnd to raise
7858c2654abSrjs */
7868c2654abSrjs if (sctp_threshold_management(inp, stcb, NULL,
7878c2654abSrjs stcb->asoc.max_send_times)) {
7888c2654abSrjs /* Association was destroyed */
7898c2654abSrjs return (1);
7908c2654abSrjs }
7918c2654abSrjs }
7928c2654abSrjs if (net->dest_state & SCTP_ADDR_NOT_REACHABLE) {
7938c2654abSrjs /* Move all pending over too */
7948c2654abSrjs sctp_move_all_chunks_to_alt(stcb, net, alt);
7958c2654abSrjs /* Was it our primary? */
7968c2654abSrjs if ((stcb->asoc.primary_destination == net) && (alt != net)) {
7978c2654abSrjs /*
7988c2654abSrjs * Yes, note it as such and find an alternate
7998c2654abSrjs * note: this means HB code must use this to resent
8008c2654abSrjs * the primary if it goes active AND if someone does
8018c2654abSrjs * a change-primary then this flag must be cleared
8028c2654abSrjs * from any net structures.
8038c2654abSrjs */
8048c2654abSrjs if (sctp_set_primary_addr(stcb,
8058c2654abSrjs (struct sockaddr *)NULL,
8068c2654abSrjs alt) == 0) {
8078c2654abSrjs net->dest_state |= SCTP_ADDR_WAS_PRIMARY;
8088c2654abSrjs net->src_addr_selected = 0;
8098c2654abSrjs }
8108c2654abSrjs }
8118c2654abSrjs }
8128c2654abSrjs /*
8138c2654abSrjs * Special case for cookie-echo'ed case, we don't do output
8148c2654abSrjs * but must await the COOKIE-ACK before retransmission
8158c2654abSrjs */
8168c2654abSrjs if (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_COOKIE_ECHOED) {
8178c2654abSrjs /*
8188c2654abSrjs * Here we just reset the timer and start again since we
8198c2654abSrjs * have not established the asoc
8208c2654abSrjs */
8218c2654abSrjs #ifdef SCTP_DEBUG
8228c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_TIMER1) {
8238c2654abSrjs printf("Special cookie case return\n");
8248c2654abSrjs }
8258c2654abSrjs #endif /* SCTP_DEBUG */
8268c2654abSrjs sctp_timer_start(SCTP_TIMER_TYPE_SEND, inp, stcb, net);
8278c2654abSrjs return (0);
8288c2654abSrjs }
8298c2654abSrjs if (stcb->asoc.peer_supports_prsctp) {
8308c2654abSrjs struct sctp_tmit_chunk *lchk;
8318c2654abSrjs lchk = sctp_try_advance_peer_ack_point(stcb, &stcb->asoc);
8328c2654abSrjs /* C3. See if we need to send a Fwd-TSN */
8338c2654abSrjs if (compare_with_wrap(stcb->asoc.advanced_peer_ack_point,
8348c2654abSrjs stcb->asoc.last_acked_seq, MAX_TSN)) {
8358c2654abSrjs /*
8368c2654abSrjs * ISSUE with ECN, see FWD-TSN processing for notes
8378c2654abSrjs * on issues that will occur when the ECN NONCE stuff
8388c2654abSrjs * is put into SCTP for cross checking.
8398c2654abSrjs */
8408c2654abSrjs #ifdef SCTP_DEBUG
8418c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_TIMER1) {
8428c2654abSrjs printf("Forward TSN time\n");
8438c2654abSrjs }
8448c2654abSrjs #endif /* SCTP_DEBUG */
8458c2654abSrjs send_forward_tsn(stcb, &stcb->asoc);
8468c2654abSrjs if (lchk) {
8478c2654abSrjs /* Assure a timer is up */
8488c2654abSrjs sctp_timer_start(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, stcb, lchk->whoTo);
8498c2654abSrjs }
8508c2654abSrjs }
8518c2654abSrjs }
8528c2654abSrjs return (0);
8538c2654abSrjs }
8548c2654abSrjs
8558c2654abSrjs int
sctp_t1init_timer(struct sctp_inpcb * inp,struct sctp_tcb * stcb,struct sctp_nets * net)8568c2654abSrjs sctp_t1init_timer(struct sctp_inpcb *inp,
8578c2654abSrjs struct sctp_tcb *stcb,
8588c2654abSrjs struct sctp_nets *net)
8598c2654abSrjs {
8608c2654abSrjs /* bump the thresholds */
8618c2654abSrjs if (stcb->asoc.delayed_connection) {
8628c2654abSrjs /* special hook for delayed connection. The
8638c2654abSrjs * library did NOT complete the rest of its
8648c2654abSrjs * sends.
8658c2654abSrjs */
8668c2654abSrjs stcb->asoc.delayed_connection = 0;
8678c2654abSrjs sctp_send_initiate(inp, stcb);
8688c2654abSrjs return (0);
8698c2654abSrjs }
8708c2654abSrjs if (sctp_threshold_management(inp, stcb, net,
8718c2654abSrjs stcb->asoc.max_init_times)) {
8728c2654abSrjs /* Association was destroyed */
8738c2654abSrjs return (1);
8748c2654abSrjs }
8758c2654abSrjs stcb->asoc.dropped_special_cnt = 0;
8768c2654abSrjs sctp_backoff_on_timeout(stcb, stcb->asoc.primary_destination, 1, 0);
8778c2654abSrjs if (stcb->asoc.initial_init_rto_max < net->RTO) {
8788c2654abSrjs net->RTO = stcb->asoc.initial_init_rto_max;
8798c2654abSrjs }
8808c2654abSrjs if (stcb->asoc.numnets > 1) {
8818c2654abSrjs /* If we have more than one addr use it */
8828c2654abSrjs struct sctp_nets *alt;
8838c2654abSrjs alt = sctp_find_alternate_net(stcb, stcb->asoc.primary_destination);
8848c2654abSrjs if ((alt != NULL) && (alt != stcb->asoc.primary_destination)) {
8858c2654abSrjs sctp_move_all_chunks_to_alt(stcb, stcb->asoc.primary_destination, alt);
8868c2654abSrjs stcb->asoc.primary_destination = alt;
8878c2654abSrjs }
8888c2654abSrjs }
8898c2654abSrjs /* Send out a new init */
8908c2654abSrjs sctp_send_initiate(inp, stcb);
8918c2654abSrjs return (0);
8928c2654abSrjs }
8938c2654abSrjs
8948c2654abSrjs /*
8958c2654abSrjs * For cookie and asconf we actually need to find and mark for resend,
8968c2654abSrjs * then increment the resend counter (after all the threshold management
8978c2654abSrjs * stuff of course).
8988c2654abSrjs */
sctp_cookie_timer(struct sctp_inpcb * inp,struct sctp_tcb * stcb,struct sctp_nets * net)8998c2654abSrjs int sctp_cookie_timer(struct sctp_inpcb *inp,
9008c2654abSrjs struct sctp_tcb *stcb,
9018c2654abSrjs struct sctp_nets *net)
9028c2654abSrjs {
9038c2654abSrjs struct sctp_nets *alt;
9048c2654abSrjs struct sctp_tmit_chunk *cookie;
9058c2654abSrjs /* first before all else we must find the cookie */
9068c2654abSrjs TAILQ_FOREACH(cookie, &stcb->asoc.control_send_queue, sctp_next) {
9078c2654abSrjs if (cookie->rec.chunk_id == SCTP_COOKIE_ECHO) {
9088c2654abSrjs break;
9098c2654abSrjs }
9108c2654abSrjs }
9118c2654abSrjs if (cookie == NULL) {
9128c2654abSrjs if (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_COOKIE_ECHOED) {
9138c2654abSrjs /* FOOBAR! */
9148c2654abSrjs struct mbuf *oper;
9158c2654abSrjs MGET(oper, M_DONTWAIT, MT_DATA);
9168c2654abSrjs if (oper) {
9178c2654abSrjs struct sctp_paramhdr *ph;
9188c2654abSrjs u_int32_t *ippp;
9198c2654abSrjs
9208c2654abSrjs oper->m_len = sizeof(struct sctp_paramhdr) +
9218c2654abSrjs sizeof(*ippp);
9228c2654abSrjs ph = mtod(oper, struct sctp_paramhdr *);
9238c2654abSrjs ph->param_type = htons(SCTP_CAUSE_PROTOCOL_VIOLATION);
9248c2654abSrjs ph->param_length = htons(oper->m_len);
9258c2654abSrjs ippp = (u_int32_t *)(ph + 1);
9268c2654abSrjs *ippp = htonl(0x40000002);
9278c2654abSrjs }
9288c2654abSrjs sctp_abort_an_association(inp, stcb, SCTP_INTERNAL_ERROR,
9298c2654abSrjs oper);
9308c2654abSrjs }
9318c2654abSrjs return (1);
9328c2654abSrjs }
9338c2654abSrjs /* Ok we found the cookie, threshold management next */
9348c2654abSrjs if (sctp_threshold_management(inp, stcb, cookie->whoTo,
9358c2654abSrjs stcb->asoc.max_init_times)) {
9368c2654abSrjs /* Assoc is over */
9378c2654abSrjs return (1);
9388c2654abSrjs }
9398c2654abSrjs /*
9408c2654abSrjs * cleared theshold management now lets backoff the address &
9418c2654abSrjs * select an alternate
9428c2654abSrjs */
9438c2654abSrjs stcb->asoc.dropped_special_cnt = 0;
9448c2654abSrjs sctp_backoff_on_timeout(stcb, cookie->whoTo, 1, 0);
9458c2654abSrjs alt = sctp_find_alternate_net(stcb, cookie->whoTo);
9468c2654abSrjs if (alt != cookie->whoTo) {
9478c2654abSrjs sctp_free_remote_addr(cookie->whoTo);
9488c2654abSrjs cookie->whoTo = alt;
9498c2654abSrjs alt->ref_count++;
9508c2654abSrjs }
9518c2654abSrjs /* Now mark the retran info */
9528c2654abSrjs if (cookie->sent != SCTP_DATAGRAM_RESEND) {
9538c2654abSrjs stcb->asoc.sent_queue_retran_cnt++;
9548c2654abSrjs }
9558c2654abSrjs cookie->sent = SCTP_DATAGRAM_RESEND;
9568c2654abSrjs /*
9578c2654abSrjs * Now call the output routine to kick out the cookie again, Note we
9588c2654abSrjs * don't mark any chunks for retran so that FR will need to kick in
9598c2654abSrjs * to move these (or a send timer).
9608c2654abSrjs */
9618c2654abSrjs return (0);
9628c2654abSrjs }
9638c2654abSrjs
sctp_strreset_timer(struct sctp_inpcb * inp,struct sctp_tcb * stcb,struct sctp_nets * net)9648c2654abSrjs int sctp_strreset_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
9658c2654abSrjs struct sctp_nets *net)
9668c2654abSrjs {
9678c2654abSrjs struct sctp_nets *alt;
9688c2654abSrjs struct sctp_tmit_chunk *strrst, *chk;
9698c2654abSrjs struct sctp_stream_reset_req *strreq;
9708c2654abSrjs /* find the existing STRRESET */
9718c2654abSrjs TAILQ_FOREACH(strrst, &stcb->asoc.control_send_queue,
9728c2654abSrjs sctp_next) {
9738c2654abSrjs if (strrst->rec.chunk_id == SCTP_STREAM_RESET) {
9748c2654abSrjs /* is it what we want */
9758c2654abSrjs strreq = mtod(strrst->data, struct sctp_stream_reset_req *);
9768c2654abSrjs if (strreq->sr_req.ph.param_type == ntohs(SCTP_STR_RESET_REQUEST)) {
9778c2654abSrjs break;
9788c2654abSrjs }
9798c2654abSrjs }
9808c2654abSrjs }
9818c2654abSrjs if (strrst == NULL) {
9828c2654abSrjs #ifdef SCTP_DEBUG
9838c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_TIMER1) {
9848c2654abSrjs printf("Strange, strreset timer fires, but I can't find an str-reset?\n");
9858c2654abSrjs }
9868c2654abSrjs #endif /* SCTP_DEBUG */
9878c2654abSrjs return (0);
9888c2654abSrjs }
9898c2654abSrjs /* do threshold management */
9908c2654abSrjs if (sctp_threshold_management(inp, stcb, strrst->whoTo,
9918c2654abSrjs stcb->asoc.max_send_times)) {
9928c2654abSrjs /* Assoc is over */
9938c2654abSrjs return (1);
9948c2654abSrjs }
9958c2654abSrjs
9968c2654abSrjs /*
9978c2654abSrjs * cleared theshold management
9988c2654abSrjs * now lets backoff the address & select an alternate
9998c2654abSrjs */
10008c2654abSrjs sctp_backoff_on_timeout(stcb, strrst->whoTo, 1, 0);
10018c2654abSrjs alt = sctp_find_alternate_net(stcb, strrst->whoTo);
10028c2654abSrjs sctp_free_remote_addr(strrst->whoTo);
10038c2654abSrjs strrst->whoTo = alt;
10048c2654abSrjs alt->ref_count++;
10058c2654abSrjs
10068c2654abSrjs /* See if a ECN Echo is also stranded */
10078c2654abSrjs TAILQ_FOREACH(chk, &stcb->asoc.control_send_queue, sctp_next) {
10088c2654abSrjs if ((chk->whoTo == net) &&
10098c2654abSrjs (chk->rec.chunk_id == SCTP_ECN_ECHO)) {
10108c2654abSrjs sctp_free_remote_addr(chk->whoTo);
10118c2654abSrjs if (chk->sent != SCTP_DATAGRAM_RESEND) {
10128c2654abSrjs chk->sent = SCTP_DATAGRAM_RESEND;
10138c2654abSrjs stcb->asoc.sent_queue_retran_cnt++;
10148c2654abSrjs }
10158c2654abSrjs chk->whoTo = alt;
10168c2654abSrjs alt->ref_count++;
10178c2654abSrjs }
10188c2654abSrjs }
10198c2654abSrjs if (net->dest_state & SCTP_ADDR_NOT_REACHABLE) {
10208c2654abSrjs /*
10218c2654abSrjs * If the address went un-reachable, we need to move
10228c2654abSrjs * to alternates for ALL chk's in queue
10238c2654abSrjs */
10248c2654abSrjs sctp_move_all_chunks_to_alt(stcb, net, alt);
10258c2654abSrjs }
10268c2654abSrjs /* mark the retran info */
10278c2654abSrjs if (strrst->sent != SCTP_DATAGRAM_RESEND)
10288c2654abSrjs stcb->asoc.sent_queue_retran_cnt++;
10298c2654abSrjs strrst->sent = SCTP_DATAGRAM_RESEND;
10308c2654abSrjs
10318c2654abSrjs /* restart the timer */
10328c2654abSrjs sctp_timer_start(SCTP_TIMER_TYPE_STRRESET, inp, stcb, strrst->whoTo);
10338c2654abSrjs return (0);
10348c2654abSrjs }
10358c2654abSrjs
sctp_asconf_timer(struct sctp_inpcb * inp,struct sctp_tcb * stcb,struct sctp_nets * net)10368c2654abSrjs int sctp_asconf_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
10378c2654abSrjs struct sctp_nets *net)
10388c2654abSrjs {
10398c2654abSrjs struct sctp_nets *alt;
10408c2654abSrjs struct sctp_tmit_chunk *asconf, *chk;
10418c2654abSrjs
10428c2654abSrjs /* is this the first send, or a retransmission? */
10438c2654abSrjs if (stcb->asoc.asconf_sent == 0) {
10448c2654abSrjs /* compose a new ASCONF chunk and send it */
10458c2654abSrjs sctp_send_asconf(stcb, net);
10468c2654abSrjs } else {
10478c2654abSrjs /* Retransmission of the existing ASCONF needed... */
10488c2654abSrjs
10498c2654abSrjs /* find the existing ASCONF */
10508c2654abSrjs TAILQ_FOREACH(asconf, &stcb->asoc.control_send_queue,
10518c2654abSrjs sctp_next) {
10528c2654abSrjs if (asconf->rec.chunk_id == SCTP_ASCONF) {
10538c2654abSrjs break;
10548c2654abSrjs }
10558c2654abSrjs }
10568c2654abSrjs if (asconf == NULL) {
10578c2654abSrjs #ifdef SCTP_DEBUG
10588c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_TIMER1) {
10598c2654abSrjs printf("Strange, asconf timer fires, but I can't find an asconf?\n");
10608c2654abSrjs }
10618c2654abSrjs #endif /* SCTP_DEBUG */
10628c2654abSrjs return (0);
10638c2654abSrjs }
10648c2654abSrjs /* do threshold management */
10658c2654abSrjs if (sctp_threshold_management(inp, stcb, asconf->whoTo,
10668c2654abSrjs stcb->asoc.max_send_times)) {
10678c2654abSrjs /* Assoc is over */
10688c2654abSrjs return (1);
10698c2654abSrjs }
10708c2654abSrjs
10718c2654abSrjs /* PETER? FIX? How will the following code ever run? If
1072*7f459241Sandvar * the max_send_times is hit, threshold management will
10738c2654abSrjs * blow away the association?
10748c2654abSrjs */
10758c2654abSrjs if (asconf->snd_count > stcb->asoc.max_send_times) {
10768c2654abSrjs /*
10778c2654abSrjs * Something is rotten, peer is not responding to
10788c2654abSrjs * ASCONFs but maybe is to data etc. e.g. it is not
10798c2654abSrjs * properly handling the chunk type upper bits
10808c2654abSrjs * Mark this peer as ASCONF incapable and cleanup
10818c2654abSrjs */
10828c2654abSrjs #ifdef SCTP_DEBUG
10838c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_TIMER1) {
10848c2654abSrjs printf("asconf_timer: Peer has not responded to our repeated ASCONFs\n");
10858c2654abSrjs }
10868c2654abSrjs #endif /* SCTP_DEBUG */
10878c2654abSrjs sctp_asconf_cleanup(stcb, net);
10888c2654abSrjs return (0);
10898c2654abSrjs }
10908c2654abSrjs /*
10918c2654abSrjs * cleared theshold management
10928c2654abSrjs * now lets backoff the address & select an alternate
10938c2654abSrjs */
10948c2654abSrjs sctp_backoff_on_timeout(stcb, asconf->whoTo, 1, 0);
10958c2654abSrjs alt = sctp_find_alternate_net(stcb, asconf->whoTo);
10968c2654abSrjs sctp_free_remote_addr(asconf->whoTo);
10978c2654abSrjs asconf->whoTo = alt;
10988c2654abSrjs alt->ref_count++;
10998c2654abSrjs
11008c2654abSrjs /* See if a ECN Echo is also stranded */
11018c2654abSrjs TAILQ_FOREACH(chk, &stcb->asoc.control_send_queue, sctp_next) {
11028c2654abSrjs if ((chk->whoTo == net) &&
11038c2654abSrjs (chk->rec.chunk_id == SCTP_ECN_ECHO)) {
11048c2654abSrjs sctp_free_remote_addr(chk->whoTo);
11058c2654abSrjs chk->whoTo = alt;
11068c2654abSrjs if (chk->sent != SCTP_DATAGRAM_RESEND) {
11078c2654abSrjs chk->sent = SCTP_DATAGRAM_RESEND;
11088c2654abSrjs stcb->asoc.sent_queue_retran_cnt++;
11098c2654abSrjs }
11108c2654abSrjs alt->ref_count++;
11118c2654abSrjs
11128c2654abSrjs }
11138c2654abSrjs }
11148c2654abSrjs if (net->dest_state & SCTP_ADDR_NOT_REACHABLE) {
11158c2654abSrjs /*
11168c2654abSrjs * If the address went un-reachable, we need to move
11178c2654abSrjs * to alternates for ALL chk's in queue
11188c2654abSrjs */
11198c2654abSrjs sctp_move_all_chunks_to_alt(stcb, net, alt);
11208c2654abSrjs }
11218c2654abSrjs /* mark the retran info */
11228c2654abSrjs if (asconf->sent != SCTP_DATAGRAM_RESEND)
11238c2654abSrjs stcb->asoc.sent_queue_retran_cnt++;
11248c2654abSrjs asconf->sent = SCTP_DATAGRAM_RESEND;
11258c2654abSrjs }
11268c2654abSrjs return (0);
11278c2654abSrjs }
11288c2654abSrjs
11298c2654abSrjs /*
11308c2654abSrjs * For the shutdown and shutdown-ack, we do not keep one around on the
11318c2654abSrjs * control queue. This means we must generate a new one and call the general
11328c2654abSrjs * chunk output routine, AFTER having done threshold
11338c2654abSrjs * management.
11348c2654abSrjs */
11358c2654abSrjs int
sctp_shutdown_timer(struct sctp_inpcb * inp,struct sctp_tcb * stcb,struct sctp_nets * net)11368c2654abSrjs sctp_shutdown_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
11378c2654abSrjs struct sctp_nets *net)
11388c2654abSrjs {
11398c2654abSrjs struct sctp_nets *alt;
1140*7f459241Sandvar /* first threshold management */
11418c2654abSrjs if (sctp_threshold_management(inp, stcb, net, stcb->asoc.max_send_times)) {
11428c2654abSrjs /* Assoc is over */
11438c2654abSrjs return (1);
11448c2654abSrjs }
11458c2654abSrjs /* second select an alternative */
11468c2654abSrjs alt = sctp_find_alternate_net(stcb, net);
11478c2654abSrjs
11488c2654abSrjs /* third generate a shutdown into the queue for out net */
11498c2654abSrjs #ifdef SCTP_DEBUG
11508c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_OUTPUT4) {
11518c2654abSrjs printf("%s:%d sends a shutdown\n",
11528c2654abSrjs __FILE__,
11538c2654abSrjs __LINE__
11548c2654abSrjs );
11558c2654abSrjs }
11568c2654abSrjs #endif
11578c2654abSrjs if (alt) {
11588c2654abSrjs sctp_send_shutdown(stcb, alt);
11598c2654abSrjs } else {
11608c2654abSrjs /* if alt is NULL, there is no dest
11618c2654abSrjs * to send to??
11628c2654abSrjs */
11638c2654abSrjs return (0);
11648c2654abSrjs }
11658c2654abSrjs /* fourth restart timer */
11668c2654abSrjs sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN, inp, stcb, alt);
11678c2654abSrjs return (0);
11688c2654abSrjs }
11698c2654abSrjs
sctp_shutdownack_timer(struct sctp_inpcb * inp,struct sctp_tcb * stcb,struct sctp_nets * net)11708c2654abSrjs int sctp_shutdownack_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
11718c2654abSrjs struct sctp_nets *net)
11728c2654abSrjs {
11738c2654abSrjs struct sctp_nets *alt;
1174*7f459241Sandvar /* first threshold management */
11758c2654abSrjs if (sctp_threshold_management(inp, stcb, net, stcb->asoc.max_send_times)) {
11768c2654abSrjs /* Assoc is over */
11778c2654abSrjs return (1);
11788c2654abSrjs }
11798c2654abSrjs /* second select an alternative */
11808c2654abSrjs alt = sctp_find_alternate_net(stcb, net);
11818c2654abSrjs
11828c2654abSrjs /* third generate a shutdown into the queue for out net */
11838c2654abSrjs sctp_send_shutdown_ack(stcb, alt);
11848c2654abSrjs
11858c2654abSrjs /* fourth restart timer */
11868c2654abSrjs sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNACK, inp, stcb, alt);
11878c2654abSrjs return (0);
11888c2654abSrjs }
11898c2654abSrjs
11908c2654abSrjs static void
sctp_audit_stream_queues_for_size(struct sctp_inpcb * inp,struct sctp_tcb * stcb)11918c2654abSrjs sctp_audit_stream_queues_for_size(struct sctp_inpcb *inp,
11928c2654abSrjs struct sctp_tcb *stcb)
11938c2654abSrjs {
11948c2654abSrjs struct sctp_stream_out *outs;
11958c2654abSrjs struct sctp_tmit_chunk *chk;
11968c2654abSrjs unsigned int chks_in_queue=0;
11978c2654abSrjs
11988c2654abSrjs if ((stcb == NULL) || (inp == NULL))
11998c2654abSrjs return;
12008c2654abSrjs if (TAILQ_EMPTY(&stcb->asoc.out_wheel)) {
12018c2654abSrjs printf("Strange, out_wheel empty nothing on sent/send and tot=%lu?\n",
12028c2654abSrjs (u_long)stcb->asoc.total_output_queue_size);
12038c2654abSrjs stcb->asoc.total_output_queue_size = 0;
12048c2654abSrjs return;
12058c2654abSrjs }
12068c2654abSrjs if (stcb->asoc.sent_queue_retran_cnt) {
12078c2654abSrjs printf("Hmm, sent_queue_retran_cnt is non-zero %d\n",
12088c2654abSrjs stcb->asoc.sent_queue_retran_cnt);
12098c2654abSrjs stcb->asoc.sent_queue_retran_cnt = 0;
12108c2654abSrjs }
12118c2654abSrjs /* Check to see if some data queued, if so report it */
12128c2654abSrjs TAILQ_FOREACH(outs, &stcb->asoc.out_wheel, next_spoke) {
12138c2654abSrjs if (!TAILQ_EMPTY(&outs->outqueue)) {
12148c2654abSrjs TAILQ_FOREACH(chk, &outs->outqueue, sctp_next) {
12158c2654abSrjs chks_in_queue++;
12168c2654abSrjs }
12178c2654abSrjs }
12188c2654abSrjs }
12198c2654abSrjs if (chks_in_queue != stcb->asoc.stream_queue_cnt) {
12208c2654abSrjs printf("Hmm, stream queue cnt at %d I counted %d in stream out wheel\n",
12218c2654abSrjs stcb->asoc.stream_queue_cnt, chks_in_queue);
12228c2654abSrjs }
12238c2654abSrjs if (chks_in_queue) {
12248c2654abSrjs /* call the output queue function */
12258c2654abSrjs sctp_chunk_output(inp, stcb, 1);
12268c2654abSrjs if ((TAILQ_EMPTY(&stcb->asoc.send_queue)) &&
12278c2654abSrjs (TAILQ_EMPTY(&stcb->asoc.sent_queue))) {
12288c2654abSrjs /* Probably should go in and make it go back through and add fragments allowed */
12298c2654abSrjs printf("Still nothing moved %d chunks are stuck\n", chks_in_queue);
12308c2654abSrjs }
12318c2654abSrjs } else {
12328c2654abSrjs printf("Found no chunks on any queue tot:%lu\n",
12338c2654abSrjs (u_long)stcb->asoc.total_output_queue_size);
12348c2654abSrjs stcb->asoc.total_output_queue_size = 0;
12358c2654abSrjs }
12368c2654abSrjs }
12378c2654abSrjs
12388c2654abSrjs int
sctp_heartbeat_timer(struct sctp_inpcb * inp,struct sctp_tcb * stcb,struct sctp_nets * net)12398c2654abSrjs sctp_heartbeat_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
12408c2654abSrjs struct sctp_nets *net)
12418c2654abSrjs {
12428c2654abSrjs int cnt_of_unconf=0;
12438c2654abSrjs
12448c2654abSrjs if (net) {
12458c2654abSrjs if (net->hb_responded == 0) {
12468c2654abSrjs sctp_backoff_on_timeout(stcb, net, 1, 0);
12478c2654abSrjs }
12488c2654abSrjs /* Zero PBA, if it needs it */
12498c2654abSrjs if (net->partial_bytes_acked) {
12508c2654abSrjs net->partial_bytes_acked = 0;
12518c2654abSrjs }
12528c2654abSrjs }
12538c2654abSrjs TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
12548c2654abSrjs if ((net->dest_state & SCTP_ADDR_UNCONFIRMED) &&
12558c2654abSrjs (net->dest_state & SCTP_ADDR_REACHABLE)) {
12568c2654abSrjs cnt_of_unconf++;
12578c2654abSrjs }
12588c2654abSrjs }
12598c2654abSrjs if ((stcb->asoc.total_output_queue_size > 0) &&
12608c2654abSrjs (TAILQ_EMPTY(&stcb->asoc.send_queue)) &&
12618c2654abSrjs (TAILQ_EMPTY(&stcb->asoc.sent_queue))) {
12628c2654abSrjs sctp_audit_stream_queues_for_size(inp, stcb);
12638c2654abSrjs }
1264*7f459241Sandvar /* Send a new HB, this will do threshold management, pick a new dest */
12658c2654abSrjs if (sctp_send_hb(stcb, 0, NULL) < 0) {
12668c2654abSrjs return (1);
12678c2654abSrjs }
12688c2654abSrjs if (cnt_of_unconf > 1) {
12698c2654abSrjs /*
12708c2654abSrjs * this will send out extra hb's up to maxburst if
12718c2654abSrjs * there are any unconfirmed addresses.
12728c2654abSrjs */
12738c2654abSrjs int cnt_sent = 1;
12748c2654abSrjs while ((cnt_sent < stcb->asoc.max_burst) && (cnt_of_unconf > 1)) {
12758c2654abSrjs if (sctp_send_hb(stcb, 0, NULL) == 0)
12768c2654abSrjs break;
12778c2654abSrjs cnt_of_unconf--;
12788c2654abSrjs cnt_sent++;
12798c2654abSrjs }
12808c2654abSrjs }
12818c2654abSrjs return (0);
12828c2654abSrjs }
12838c2654abSrjs
12848c2654abSrjs #define SCTP_NUMBER_OF_MTU_SIZES 18
12858c2654abSrjs static u_int32_t mtu_sizes[]={
12868c2654abSrjs 68,
12878c2654abSrjs 296,
12888c2654abSrjs 508,
12898c2654abSrjs 512,
12908c2654abSrjs 544,
12918c2654abSrjs 576,
12928c2654abSrjs 1006,
12938c2654abSrjs 1492,
12948c2654abSrjs 1500,
12958c2654abSrjs 1536,
12968c2654abSrjs 2002,
12978c2654abSrjs 2048,
12988c2654abSrjs 4352,
12998c2654abSrjs 4464,
13008c2654abSrjs 8166,
13018c2654abSrjs 17914,
13028c2654abSrjs 32000,
13038c2654abSrjs 65535
13048c2654abSrjs };
13058c2654abSrjs
13068c2654abSrjs
13078c2654abSrjs static u_int32_t
sctp_getnext_mtu(struct sctp_inpcb * inp,u_int32_t cur_mtu)13088c2654abSrjs sctp_getnext_mtu(struct sctp_inpcb *inp, u_int32_t cur_mtu)
13098c2654abSrjs {
13108c2654abSrjs /* select another MTU that is just bigger than this one */
13118c2654abSrjs int i;
13128c2654abSrjs
13138c2654abSrjs for (i = 0; i < SCTP_NUMBER_OF_MTU_SIZES; i++) {
13148c2654abSrjs if (cur_mtu < mtu_sizes[i]) {
13158c2654abSrjs /* no max_mtu is bigger than this one */
13168c2654abSrjs return (mtu_sizes[i]);
13178c2654abSrjs }
13188c2654abSrjs }
13198c2654abSrjs /* here return the highest allowable */
13208c2654abSrjs return (cur_mtu);
13218c2654abSrjs }
13228c2654abSrjs
13238c2654abSrjs
sctp_pathmtu_timer(struct sctp_inpcb * inp,struct sctp_tcb * stcb,struct sctp_nets * net)13248c2654abSrjs void sctp_pathmtu_timer(struct sctp_inpcb *inp,
13258c2654abSrjs struct sctp_tcb *stcb,
13268c2654abSrjs struct sctp_nets *net)
13278c2654abSrjs {
13288c2654abSrjs u_int32_t next_mtu;
13298c2654abSrjs struct rtentry *rt;
13308c2654abSrjs
13318c2654abSrjs /* restart the timer in any case */
13328c2654abSrjs next_mtu = sctp_getnext_mtu(inp, net->mtu);
13338c2654abSrjs if (next_mtu <= net->mtu) {
13348c2654abSrjs /* nothing to do */
13358c2654abSrjs return;
13368c2654abSrjs }
13378c2654abSrjs rt = rtcache_validate(&net->ro);
13388c2654abSrjs if (rt != NULL) {
13398c2654abSrjs /* only if we have a route and interface do we
13408c2654abSrjs * set anything. Note we always restart
13418c2654abSrjs * the timer though just in case it is updated
13428c2654abSrjs * (i.e. the ifp) or route/ifp is populated.
13438c2654abSrjs */
13448c2654abSrjs if (rt->rt_ifp != NULL) {
13458c2654abSrjs if (rt->rt_ifp->if_mtu > next_mtu) {
13468c2654abSrjs /* ok it will fit out the door */
13478c2654abSrjs net->mtu = next_mtu;
13488c2654abSrjs }
13498c2654abSrjs }
13504c25fb2fSozaki-r rtcache_unref(rt, &net->ro);
13518c2654abSrjs }
13528c2654abSrjs /* restart the timer */
13538c2654abSrjs sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net);
13548c2654abSrjs }
13558c2654abSrjs
sctp_autoclose_timer(struct sctp_inpcb * inp,struct sctp_tcb * stcb,struct sctp_nets * net)13568c2654abSrjs void sctp_autoclose_timer(struct sctp_inpcb *inp,
13578c2654abSrjs struct sctp_tcb *stcb,
13588c2654abSrjs struct sctp_nets *net)
13598c2654abSrjs {
13608c2654abSrjs struct timeval tn, *tim_touse;
13618c2654abSrjs struct sctp_association *asoc;
13628c2654abSrjs int ticks_gone_by;
13638c2654abSrjs
13648c2654abSrjs SCTP_GETTIME_TIMEVAL(&tn);
13658c2654abSrjs if (stcb->asoc.sctp_autoclose_ticks &&
13668c2654abSrjs (inp->sctp_flags & SCTP_PCB_FLAGS_AUTOCLOSE)) {
13678c2654abSrjs /* Auto close is on */
13688c2654abSrjs asoc = &stcb->asoc;
13698c2654abSrjs /* pick the time to use */
13708c2654abSrjs if (asoc->time_last_rcvd.tv_sec >
13718c2654abSrjs asoc->time_last_sent.tv_sec) {
13728c2654abSrjs tim_touse = &asoc->time_last_rcvd;
13738c2654abSrjs } else {
13748c2654abSrjs tim_touse = &asoc->time_last_sent;
13758c2654abSrjs }
13768c2654abSrjs /* Now has long enough transpired to autoclose? */
13778c2654abSrjs ticks_gone_by = ((tn.tv_sec - tim_touse->tv_sec) * hz);
13788c2654abSrjs if ((ticks_gone_by > 0) &&
13798c2654abSrjs (ticks_gone_by >= (int)asoc->sctp_autoclose_ticks)) {
13808c2654abSrjs /*
13818c2654abSrjs * autoclose time has hit, call the output routine,
13828c2654abSrjs * which should do nothing just to be SURE we don't
13838c2654abSrjs * have hanging data. We can then safely check the
13848c2654abSrjs * queues and know that we are clear to send shutdown
13858c2654abSrjs */
13868c2654abSrjs sctp_chunk_output(inp, stcb, 9);
13878c2654abSrjs /* Are we clean? */
13888c2654abSrjs if (TAILQ_EMPTY(&asoc->send_queue) &&
13898c2654abSrjs TAILQ_EMPTY(&asoc->sent_queue)) {
13908c2654abSrjs /*
13918c2654abSrjs * there is nothing queued to send,
13928c2654abSrjs * so I'm done...
13938c2654abSrjs */
13948c2654abSrjs if (SCTP_GET_STATE(asoc) !=
13958c2654abSrjs SCTP_STATE_SHUTDOWN_SENT) {
13968c2654abSrjs /* only send SHUTDOWN 1st time thru */
13978c2654abSrjs #ifdef SCTP_DEBUG
13988c2654abSrjs if (sctp_debug_on & SCTP_DEBUG_OUTPUT4) {
13998c2654abSrjs printf("%s:%d sends a shutdown\n",
14008c2654abSrjs __FILE__,
14018c2654abSrjs __LINE__
14028c2654abSrjs );
14038c2654abSrjs }
14048c2654abSrjs #endif
14058c2654abSrjs sctp_send_shutdown(stcb, stcb->asoc.primary_destination);
14068c2654abSrjs asoc->state = SCTP_STATE_SHUTDOWN_SENT;
14078c2654abSrjs sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN,
14088c2654abSrjs stcb->sctp_ep, stcb,
14098c2654abSrjs asoc->primary_destination);
14108c2654abSrjs sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD,
14118c2654abSrjs stcb->sctp_ep, stcb,
14128c2654abSrjs asoc->primary_destination);
14138c2654abSrjs }
14148c2654abSrjs }
14158c2654abSrjs } else {
14168c2654abSrjs /*
14178c2654abSrjs * No auto close at this time, reset t-o to
14188c2654abSrjs * check later
14198c2654abSrjs */
14208c2654abSrjs int tmp;
14218c2654abSrjs /* fool the timer startup to use the time left */
14228c2654abSrjs tmp = asoc->sctp_autoclose_ticks;
14238c2654abSrjs asoc->sctp_autoclose_ticks -= ticks_gone_by;
14248c2654abSrjs sctp_timer_start(SCTP_TIMER_TYPE_AUTOCLOSE, inp, stcb,
14258c2654abSrjs net);
14268c2654abSrjs /* restore the real tick value */
14278c2654abSrjs asoc->sctp_autoclose_ticks = tmp;
14288c2654abSrjs }
14298c2654abSrjs }
14308c2654abSrjs }
14318c2654abSrjs
14328c2654abSrjs void
sctp_iterator_timer(struct sctp_iterator * it)14338c2654abSrjs sctp_iterator_timer(struct sctp_iterator *it)
14348c2654abSrjs {
14358c2654abSrjs int cnt= 0;
14368c2654abSrjs /* only one iterator can run at a
14378c2654abSrjs * time. This is the only way we
14388c2654abSrjs * can cleanly pull ep's from underneath
14398c2654abSrjs * all the running interators when a
14408c2654abSrjs * ep is freed.
14418c2654abSrjs */
14428c2654abSrjs SCTP_ITERATOR_LOCK();
14438c2654abSrjs if (it->inp == NULL) {
14448c2654abSrjs /* iterator is complete */
14458c2654abSrjs done_with_iterator:
14468c2654abSrjs SCTP_ITERATOR_UNLOCK();
14478c2654abSrjs SCTP_INP_INFO_WLOCK();
14488c2654abSrjs LIST_REMOVE(it, sctp_nxt_itr);
14498c2654abSrjs /* stopping the callout is not needed, in theory,
14508c2654abSrjs * but I am paranoid.
14518c2654abSrjs */
14528c2654abSrjs SCTP_INP_INFO_WUNLOCK();
14538c2654abSrjs callout_stop(&it->tmr.timer);
14548c2654abSrjs if (it->function_atend != NULL) {
14558c2654abSrjs (*it->function_atend)(it->pointer, it->val);
14568c2654abSrjs }
14578c2654abSrjs callout_destroy(&it->tmr.timer);
14588c2654abSrjs free(it, M_PCB);
14598c2654abSrjs return;
14608c2654abSrjs }
14618c2654abSrjs select_a_new_ep:
14628c2654abSrjs SCTP_INP_WLOCK(it->inp);
14638c2654abSrjs while ((it->pcb_flags) && ((it->inp->sctp_flags & it->pcb_flags) != it->pcb_flags)) {
14648c2654abSrjs /* we do not like this ep */
14658c2654abSrjs if (it->iterator_flags & SCTP_ITERATOR_DO_SINGLE_INP) {
14668c2654abSrjs SCTP_INP_WUNLOCK(it->inp);
14678c2654abSrjs goto done_with_iterator;
14688c2654abSrjs }
14698c2654abSrjs SCTP_INP_WUNLOCK(it->inp);
14708c2654abSrjs it->inp = LIST_NEXT(it->inp, sctp_list);
14718c2654abSrjs if (it->inp == NULL) {
14728c2654abSrjs goto done_with_iterator;
14738c2654abSrjs }
14748c2654abSrjs SCTP_INP_WLOCK(it->inp);
14758c2654abSrjs }
14768c2654abSrjs if ((it->inp->inp_starting_point_for_iterator != NULL) &&
14778c2654abSrjs (it->inp->inp_starting_point_for_iterator != it)) {
14788c2654abSrjs printf("Iterator collision, we must wait for other iterator at %p\n",
14798c2654abSrjs it->inp);
14808c2654abSrjs SCTP_INP_WUNLOCK(it->inp);
14818c2654abSrjs goto start_timer_return;
14828c2654abSrjs }
14838c2654abSrjs /* now we do the actual write to this guy */
14848c2654abSrjs it->inp->inp_starting_point_for_iterator = it;
14858c2654abSrjs SCTP_INP_WUNLOCK(it->inp);
14868c2654abSrjs SCTP_INP_RLOCK(it->inp);
14878c2654abSrjs /* if we reach here we found a inp acceptable, now through each
14888c2654abSrjs * one that has the association in the right state
14898c2654abSrjs */
14908c2654abSrjs if (it->stcb == NULL) {
14918c2654abSrjs it->stcb = LIST_FIRST(&it->inp->sctp_asoc_list);
14928c2654abSrjs }
14938c2654abSrjs if (it->stcb->asoc.stcb_starting_point_for_iterator == it) {
14948c2654abSrjs it->stcb->asoc.stcb_starting_point_for_iterator = NULL;
14958c2654abSrjs }
14968c2654abSrjs while (it->stcb) {
14978c2654abSrjs SCTP_TCB_LOCK(it->stcb);
14988c2654abSrjs if (it->asoc_state && ((it->stcb->asoc.state & it->asoc_state) != it->asoc_state)) {
14998c2654abSrjs SCTP_TCB_UNLOCK(it->stcb);
15008c2654abSrjs it->stcb = LIST_NEXT(it->stcb, sctp_tcblist);
15018c2654abSrjs continue;
15028c2654abSrjs }
15038c2654abSrjs cnt++;
15048c2654abSrjs /* run function on this one */
15058c2654abSrjs SCTP_INP_RUNLOCK(it->inp);
15068c2654abSrjs (*it->function_toapply)(it->inp, it->stcb, it->pointer, it->val);
15078c2654abSrjs sctp_chunk_output(it->inp, it->stcb, 1);
15088c2654abSrjs SCTP_TCB_UNLOCK(it->stcb);
15098c2654abSrjs /* see if we have limited out */
15108c2654abSrjs if (cnt > SCTP_MAX_ITERATOR_AT_ONCE) {
15118c2654abSrjs it->stcb->asoc.stcb_starting_point_for_iterator = it;
15128c2654abSrjs start_timer_return:
15138c2654abSrjs SCTP_ITERATOR_UNLOCK();
15148c2654abSrjs sctp_timer_start(SCTP_TIMER_TYPE_ITERATOR, (struct sctp_inpcb *)it, NULL, NULL);
15158c2654abSrjs return;
15168c2654abSrjs }
15178c2654abSrjs SCTP_INP_RLOCK(it->inp);
15188c2654abSrjs it->stcb = LIST_NEXT(it->stcb, sctp_tcblist);
15198c2654abSrjs }
15208c2654abSrjs /* if we reach here, we ran out of stcb's in the inp we are looking at */
15218c2654abSrjs SCTP_INP_RUNLOCK(it->inp);
15228c2654abSrjs SCTP_INP_WLOCK(it->inp);
15238c2654abSrjs it->inp->inp_starting_point_for_iterator = NULL;
15248c2654abSrjs SCTP_INP_WUNLOCK(it->inp);
15258c2654abSrjs if (it->iterator_flags & SCTP_ITERATOR_DO_SINGLE_INP) {
15268c2654abSrjs it->inp = NULL;
15278c2654abSrjs } else {
15288c2654abSrjs SCTP_INP_INFO_RLOCK();
15298c2654abSrjs it->inp = LIST_NEXT(it->inp, sctp_list);
15308c2654abSrjs SCTP_INP_INFO_RUNLOCK();
15318c2654abSrjs }
15328c2654abSrjs if (it->inp == NULL) {
15338c2654abSrjs goto done_with_iterator;
15348c2654abSrjs }
15358c2654abSrjs goto select_a_new_ep;
15368c2654abSrjs }
1537