James Kuszmaul | 4cb043c | 2021-01-17 11:25:51 -0800 | [diff] [blame^] | 1 | /*- |
| 2 | * Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved. |
| 3 | * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved. |
| 4 | * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved. |
| 5 | * |
| 6 | * Redistribution and use in source and binary forms, with or without |
| 7 | * modification, are permitted provided that the following conditions are met: |
| 8 | * |
| 9 | * a) Redistributions of source code must retain the above copyright notice, |
| 10 | * this list of conditions and the following disclaimer. |
| 11 | * |
| 12 | * b) Redistributions in binary form must reproduce the above copyright |
| 13 | * notice, this list of conditions and the following disclaimer in |
| 14 | * the documentation and/or other materials provided with the distribution. |
| 15 | * |
| 16 | * c) Neither the name of Cisco Systems, Inc. nor the names of its |
| 17 | * contributors may be used to endorse or promote products derived |
| 18 | * from this software without specific prior written permission. |
| 19 | * |
| 20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| 21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, |
| 22 | * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| 23 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE |
| 24 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| 25 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
| 26 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
| 27 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
| 28 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
| 29 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF |
| 30 | * THE POSSIBILITY OF SUCH DAMAGE. |
| 31 | */ |
| 32 | |
| 33 | #ifdef __FreeBSD__ |
| 34 | #include <sys/cdefs.h> |
| 35 | __FBSDID("$FreeBSD: head/sys/netinet/sctp_timer.c 310590 2016-12-26 11:06:41Z tuexen $"); |
| 36 | #endif |
| 37 | |
| 38 | #define _IP_VHL |
| 39 | #include <netinet/sctp_os.h> |
| 40 | #include <netinet/sctp_pcb.h> |
| 41 | #ifdef INET6 |
| 42 | #if defined(__Userspace_os_FreeBSD) |
| 43 | #include <netinet6/sctp6_var.h> |
| 44 | #endif |
| 45 | #endif |
| 46 | #include <netinet/sctp_var.h> |
| 47 | #include <netinet/sctp_sysctl.h> |
| 48 | #include <netinet/sctp_timer.h> |
| 49 | #include <netinet/sctputil.h> |
| 50 | #include <netinet/sctp_output.h> |
| 51 | #include <netinet/sctp_header.h> |
| 52 | #include <netinet/sctp_indata.h> |
| 53 | #include <netinet/sctp_asconf.h> |
| 54 | #include <netinet/sctp_input.h> |
| 55 | #include <netinet/sctp.h> |
| 56 | #include <netinet/sctp_uio.h> |
| 57 | #if defined(INET) || defined(INET6) |
| 58 | #if !defined(__Userspace_os_Windows) |
| 59 | #include <netinet/udp.h> |
| 60 | #endif |
| 61 | #endif |
| 62 | |
| 63 | #if defined(__APPLE__) |
| 64 | #define APPLE_FILE_NO 6 |
| 65 | #endif |
| 66 | |
| 67 | void |
| 68 | sctp_audit_retranmission_queue(struct sctp_association *asoc) |
| 69 | { |
| 70 | struct sctp_tmit_chunk *chk; |
| 71 | |
| 72 | SCTPDBG(SCTP_DEBUG_TIMER4, "Audit invoked on send queue cnt:%d onqueue:%d\n", |
| 73 | asoc->sent_queue_retran_cnt, |
| 74 | asoc->sent_queue_cnt); |
| 75 | asoc->sent_queue_retran_cnt = 0; |
| 76 | asoc->sent_queue_cnt = 0; |
| 77 | TAILQ_FOREACH(chk, &asoc->sent_queue, sctp_next) { |
| 78 | if (chk->sent == SCTP_DATAGRAM_RESEND) { |
| 79 | sctp_ucount_incr(asoc->sent_queue_retran_cnt); |
| 80 | } |
| 81 | asoc->sent_queue_cnt++; |
| 82 | } |
| 83 | TAILQ_FOREACH(chk, &asoc->control_send_queue, sctp_next) { |
| 84 | if (chk->sent == SCTP_DATAGRAM_RESEND) { |
| 85 | sctp_ucount_incr(asoc->sent_queue_retran_cnt); |
| 86 | } |
| 87 | } |
| 88 | TAILQ_FOREACH(chk, &asoc->asconf_send_queue, sctp_next) { |
| 89 | if (chk->sent == SCTP_DATAGRAM_RESEND) { |
| 90 | sctp_ucount_incr(asoc->sent_queue_retran_cnt); |
| 91 | } |
| 92 | } |
| 93 | SCTPDBG(SCTP_DEBUG_TIMER4, "Audit completes retran:%d onqueue:%d\n", |
| 94 | asoc->sent_queue_retran_cnt, |
| 95 | asoc->sent_queue_cnt); |
| 96 | } |
| 97 | |
| 98 | static int |
| 99 | sctp_threshold_management(struct sctp_inpcb *inp, struct sctp_tcb *stcb, |
| 100 | struct sctp_nets *net, uint16_t threshold) |
| 101 | { |
| 102 | if (net) { |
| 103 | net->error_count++; |
| 104 | SCTPDBG(SCTP_DEBUG_TIMER4, "Error count for %p now %d thresh:%d\n", |
| 105 | (void *)net, net->error_count, |
| 106 | net->failure_threshold); |
| 107 | if (net->error_count > net->failure_threshold) { |
| 108 | /* We had a threshold failure */ |
| 109 | if (net->dest_state & SCTP_ADDR_REACHABLE) { |
| 110 | net->dest_state &= ~SCTP_ADDR_REACHABLE; |
| 111 | net->dest_state &= ~SCTP_ADDR_REQ_PRIMARY; |
| 112 | net->dest_state &= ~SCTP_ADDR_PF; |
| 113 | sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN, |
| 114 | stcb, 0, |
| 115 | (void *)net, SCTP_SO_NOT_LOCKED); |
| 116 | } |
| 117 | } else if ((net->pf_threshold < net->failure_threshold) && |
| 118 | (net->error_count > net->pf_threshold)) { |
| 119 | if (!(net->dest_state & SCTP_ADDR_PF)) { |
| 120 | net->dest_state |= SCTP_ADDR_PF; |
| 121 | net->last_active = sctp_get_tick_count(); |
| 122 | sctp_send_hb(stcb, net, SCTP_SO_NOT_LOCKED); |
| 123 | sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, |
| 124 | inp, stcb, net, |
| 125 | SCTP_FROM_SCTP_TIMER + SCTP_LOC_1); |
| 126 | sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net); |
| 127 | } |
| 128 | } |
| 129 | } |
| 130 | if (stcb == NULL) |
| 131 | return (0); |
| 132 | |
| 133 | if (net) { |
| 134 | if ((net->dest_state & SCTP_ADDR_UNCONFIRMED) == 0) { |
| 135 | if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_THRESHOLD_LOGGING) { |
| 136 | sctp_misc_ints(SCTP_THRESHOLD_INCR, |
| 137 | stcb->asoc.overall_error_count, |
| 138 | (stcb->asoc.overall_error_count+1), |
| 139 | SCTP_FROM_SCTP_TIMER, |
| 140 | __LINE__); |
| 141 | } |
| 142 | stcb->asoc.overall_error_count++; |
| 143 | } |
| 144 | } else { |
| 145 | if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_THRESHOLD_LOGGING) { |
| 146 | sctp_misc_ints(SCTP_THRESHOLD_INCR, |
| 147 | stcb->asoc.overall_error_count, |
| 148 | (stcb->asoc.overall_error_count+1), |
| 149 | SCTP_FROM_SCTP_TIMER, |
| 150 | __LINE__); |
| 151 | } |
| 152 | stcb->asoc.overall_error_count++; |
| 153 | } |
| 154 | SCTPDBG(SCTP_DEBUG_TIMER4, "Overall error count for %p now %d thresh:%u state:%x\n", |
| 155 | (void *)&stcb->asoc, stcb->asoc.overall_error_count, |
| 156 | (uint32_t)threshold, |
| 157 | ((net == NULL) ? (uint32_t) 0 : (uint32_t) net->dest_state)); |
| 158 | /* |
| 159 | * We specifically do not do >= to give the assoc one more change |
| 160 | * before we fail it. |
| 161 | */ |
| 162 | if (stcb->asoc.overall_error_count > threshold) { |
| 163 | /* Abort notification sends a ULP notify */ |
| 164 | struct mbuf *op_err; |
| 165 | |
| 166 | op_err = sctp_generate_cause(SCTP_BASE_SYSCTL(sctp_diag_info_code), |
| 167 | "Association error counter exceeded"); |
| 168 | inp->last_abort_code = SCTP_FROM_SCTP_TIMER + SCTP_LOC_2; |
| 169 | sctp_abort_an_association(inp, stcb, op_err, SCTP_SO_NOT_LOCKED); |
| 170 | return (1); |
| 171 | } |
| 172 | return (0); |
| 173 | } |
| 174 | |
| 175 | /* |
| 176 | * sctp_find_alternate_net() returns a non-NULL pointer as long |
| 177 | * the argument net is non-NULL. |
| 178 | */ |
| 179 | struct sctp_nets * |
| 180 | sctp_find_alternate_net(struct sctp_tcb *stcb, |
| 181 | struct sctp_nets *net, |
| 182 | int mode) |
| 183 | { |
| 184 | /* Find and return an alternate network if possible */ |
| 185 | struct sctp_nets *alt, *mnet, *min_errors_net = NULL , *max_cwnd_net = NULL; |
| 186 | int once; |
| 187 | /* JRS 5/14/07 - Initialize min_errors to an impossible value. */ |
| 188 | int min_errors = -1; |
| 189 | uint32_t max_cwnd = 0; |
| 190 | |
| 191 | if (stcb->asoc.numnets == 1) { |
| 192 | /* No others but net */ |
| 193 | return (TAILQ_FIRST(&stcb->asoc.nets)); |
| 194 | } |
| 195 | /* |
| 196 | * JRS 5/14/07 - If mode is set to 2, use the CMT PF find alternate net algorithm. |
| 197 | * This algorithm chooses the active destination (not in PF state) with the largest |
| 198 | * cwnd value. If all destinations are in PF state, unreachable, or unconfirmed, choose |
| 199 | * the desination that is in PF state with the lowest error count. In case of a tie, |
| 200 | * choose the destination that was most recently active. |
| 201 | */ |
| 202 | if (mode == 2) { |
| 203 | TAILQ_FOREACH(mnet, &stcb->asoc.nets, sctp_next) { |
| 204 | /* JRS 5/14/07 - If the destination is unreachable or unconfirmed, skip it. */ |
| 205 | if (((mnet->dest_state & SCTP_ADDR_REACHABLE) != SCTP_ADDR_REACHABLE) || |
| 206 | (mnet->dest_state & SCTP_ADDR_UNCONFIRMED)) { |
| 207 | continue; |
| 208 | } |
| 209 | /* |
| 210 | * JRS 5/14/07 - If the destination is reachable but in PF state, compare |
| 211 | * the error count of the destination to the minimum error count seen thus far. |
| 212 | * Store the destination with the lower error count. If the error counts are |
| 213 | * equal, store the destination that was most recently active. |
| 214 | */ |
| 215 | if (mnet->dest_state & SCTP_ADDR_PF) { |
| 216 | /* |
| 217 | * JRS 5/14/07 - If the destination under consideration is the current |
| 218 | * destination, work as if the error count is one higher. The |
| 219 | * actual error count will not be incremented until later in the |
| 220 | * t3 handler. |
| 221 | */ |
| 222 | if (mnet == net) { |
| 223 | if (min_errors == -1) { |
| 224 | min_errors = mnet->error_count + 1; |
| 225 | min_errors_net = mnet; |
| 226 | } else if (mnet->error_count + 1 < min_errors) { |
| 227 | min_errors = mnet->error_count + 1; |
| 228 | min_errors_net = mnet; |
| 229 | } else if (mnet->error_count + 1 == min_errors |
| 230 | && mnet->last_active > min_errors_net->last_active) { |
| 231 | min_errors_net = mnet; |
| 232 | min_errors = mnet->error_count + 1; |
| 233 | } |
| 234 | continue; |
| 235 | } else { |
| 236 | if (min_errors == -1) { |
| 237 | min_errors = mnet->error_count; |
| 238 | min_errors_net = mnet; |
| 239 | } else if (mnet->error_count < min_errors) { |
| 240 | min_errors = mnet->error_count; |
| 241 | min_errors_net = mnet; |
| 242 | } else if (mnet->error_count == min_errors |
| 243 | && mnet->last_active > min_errors_net->last_active) { |
| 244 | min_errors_net = mnet; |
| 245 | min_errors = mnet->error_count; |
| 246 | } |
| 247 | continue; |
| 248 | } |
| 249 | } |
| 250 | /* |
| 251 | * JRS 5/14/07 - If the destination is reachable and not in PF state, compare the |
| 252 | * cwnd of the destination to the highest cwnd seen thus far. Store the |
| 253 | * destination with the higher cwnd value. If the cwnd values are equal, |
| 254 | * randomly choose one of the two destinations. |
| 255 | */ |
| 256 | if (max_cwnd < mnet->cwnd) { |
| 257 | max_cwnd_net = mnet; |
| 258 | max_cwnd = mnet->cwnd; |
| 259 | } else if (max_cwnd == mnet->cwnd) { |
| 260 | uint32_t rndval; |
| 261 | uint8_t this_random; |
| 262 | |
| 263 | if (stcb->asoc.hb_random_idx > 3) { |
| 264 | rndval = sctp_select_initial_TSN(&stcb->sctp_ep->sctp_ep); |
| 265 | memcpy(stcb->asoc.hb_random_values, &rndval, sizeof(stcb->asoc.hb_random_values)); |
| 266 | this_random = stcb->asoc.hb_random_values[0]; |
| 267 | stcb->asoc.hb_random_idx++; |
| 268 | stcb->asoc.hb_ect_randombit = 0; |
| 269 | } else { |
| 270 | this_random = stcb->asoc.hb_random_values[stcb->asoc.hb_random_idx]; |
| 271 | stcb->asoc.hb_random_idx++; |
| 272 | stcb->asoc.hb_ect_randombit = 0; |
| 273 | } |
| 274 | if (this_random % 2 == 1) { |
| 275 | max_cwnd_net = mnet; |
| 276 | max_cwnd = mnet->cwnd; /* Useless? */ |
| 277 | } |
| 278 | } |
| 279 | } |
| 280 | if (max_cwnd_net == NULL) { |
| 281 | if (min_errors_net == NULL) { |
| 282 | return (net); |
| 283 | } |
| 284 | return (min_errors_net); |
| 285 | } else { |
| 286 | return (max_cwnd_net); |
| 287 | } |
| 288 | } /* JRS 5/14/07 - If mode is set to 1, use the CMT policy for choosing an alternate net. */ |
| 289 | else if (mode == 1) { |
| 290 | TAILQ_FOREACH(mnet, &stcb->asoc.nets, sctp_next) { |
| 291 | if (((mnet->dest_state & SCTP_ADDR_REACHABLE) != SCTP_ADDR_REACHABLE) || |
| 292 | (mnet->dest_state & SCTP_ADDR_UNCONFIRMED)) { |
| 293 | /* |
| 294 | * will skip ones that are not-reachable or |
| 295 | * unconfirmed |
| 296 | */ |
| 297 | continue; |
| 298 | } |
| 299 | if (max_cwnd < mnet->cwnd) { |
| 300 | max_cwnd_net = mnet; |
| 301 | max_cwnd = mnet->cwnd; |
| 302 | } else if (max_cwnd == mnet->cwnd) { |
| 303 | uint32_t rndval; |
| 304 | uint8_t this_random; |
| 305 | |
| 306 | if (stcb->asoc.hb_random_idx > 3) { |
| 307 | rndval = sctp_select_initial_TSN(&stcb->sctp_ep->sctp_ep); |
| 308 | memcpy(stcb->asoc.hb_random_values, &rndval, |
| 309 | sizeof(stcb->asoc.hb_random_values)); |
| 310 | this_random = stcb->asoc.hb_random_values[0]; |
| 311 | stcb->asoc.hb_random_idx = 0; |
| 312 | stcb->asoc.hb_ect_randombit = 0; |
| 313 | } else { |
| 314 | this_random = stcb->asoc.hb_random_values[stcb->asoc.hb_random_idx]; |
| 315 | stcb->asoc.hb_random_idx++; |
| 316 | stcb->asoc.hb_ect_randombit = 0; |
| 317 | } |
| 318 | if (this_random % 2) { |
| 319 | max_cwnd_net = mnet; |
| 320 | max_cwnd = mnet->cwnd; |
| 321 | } |
| 322 | } |
| 323 | } |
| 324 | if (max_cwnd_net) { |
| 325 | return (max_cwnd_net); |
| 326 | } |
| 327 | } |
| 328 | mnet = net; |
| 329 | once = 0; |
| 330 | |
| 331 | if (mnet == NULL) { |
| 332 | mnet = TAILQ_FIRST(&stcb->asoc.nets); |
| 333 | if (mnet == NULL) { |
| 334 | return (NULL); |
| 335 | } |
| 336 | } |
| 337 | for (;;) { |
| 338 | alt = TAILQ_NEXT(mnet, sctp_next); |
| 339 | if (alt == NULL) { |
| 340 | once++; |
| 341 | if (once > 1) { |
| 342 | break; |
| 343 | } |
| 344 | alt = TAILQ_FIRST(&stcb->asoc.nets); |
| 345 | if (alt == NULL) { |
| 346 | return (NULL); |
| 347 | } |
| 348 | } |
| 349 | if (alt->ro.ro_rt == NULL) { |
| 350 | if (alt->ro._s_addr) { |
| 351 | sctp_free_ifa(alt->ro._s_addr); |
| 352 | alt->ro._s_addr = NULL; |
| 353 | } |
| 354 | alt->src_addr_selected = 0; |
| 355 | } |
| 356 | if (((alt->dest_state & SCTP_ADDR_REACHABLE) == SCTP_ADDR_REACHABLE) && |
| 357 | (alt->ro.ro_rt != NULL) && |
| 358 | (!(alt->dest_state & SCTP_ADDR_UNCONFIRMED))) { |
| 359 | /* Found a reachable address */ |
| 360 | break; |
| 361 | } |
| 362 | mnet = alt; |
| 363 | } |
| 364 | |
| 365 | if (alt == NULL) { |
| 366 | /* Case where NO insv network exists (dormant state) */ |
| 367 | /* we rotate destinations */ |
| 368 | once = 0; |
| 369 | mnet = net; |
| 370 | for (;;) { |
| 371 | if (mnet == NULL) { |
| 372 | return (TAILQ_FIRST(&stcb->asoc.nets)); |
| 373 | } |
| 374 | alt = TAILQ_NEXT(mnet, sctp_next); |
| 375 | if (alt == NULL) { |
| 376 | once++; |
| 377 | if (once > 1) { |
| 378 | break; |
| 379 | } |
| 380 | alt = TAILQ_FIRST(&stcb->asoc.nets); |
| 381 | if (alt == NULL) { |
| 382 | break; |
| 383 | } |
| 384 | } |
| 385 | if ((!(alt->dest_state & SCTP_ADDR_UNCONFIRMED)) && |
| 386 | (alt != net)) { |
| 387 | /* Found an alternate address */ |
| 388 | break; |
| 389 | } |
| 390 | mnet = alt; |
| 391 | } |
| 392 | } |
| 393 | if (alt == NULL) { |
| 394 | return (net); |
| 395 | } |
| 396 | return (alt); |
| 397 | } |
| 398 | |
| 399 | static void |
| 400 | sctp_backoff_on_timeout(struct sctp_tcb *stcb, |
| 401 | struct sctp_nets *net, |
| 402 | int win_probe, |
| 403 | int num_marked, int num_abandoned) |
| 404 | { |
| 405 | if (net->RTO == 0) { |
| 406 | if (net->RTO_measured) { |
| 407 | net->RTO = stcb->asoc.minrto; |
| 408 | } else { |
| 409 | net->RTO = stcb->asoc.initial_rto; |
| 410 | } |
| 411 | } |
| 412 | net->RTO <<= 1; |
| 413 | if (net->RTO > stcb->asoc.maxrto) { |
| 414 | net->RTO = stcb->asoc.maxrto; |
| 415 | } |
| 416 | if ((win_probe == 0) && (num_marked || num_abandoned)) { |
| 417 | /* We don't apply penalty to window probe scenarios */ |
| 418 | /* JRS - Use the congestion control given in the CC module */ |
| 419 | stcb->asoc.cc_functions.sctp_cwnd_update_after_timeout(stcb, net); |
| 420 | } |
| 421 | } |
| 422 | |
| 423 | #ifndef INVARIANTS |
| 424 | static void |
| 425 | sctp_recover_sent_list(struct sctp_tcb *stcb) |
| 426 | { |
| 427 | struct sctp_tmit_chunk *chk, *nchk; |
| 428 | struct sctp_association *asoc; |
| 429 | |
| 430 | asoc = &stcb->asoc; |
| 431 | TAILQ_FOREACH_SAFE(chk, &asoc->sent_queue, sctp_next, nchk) { |
| 432 | if (SCTP_TSN_GE(asoc->last_acked_seq, chk->rec.data.tsn)) { |
| 433 | SCTP_PRINTF("Found chk:%p tsn:%x <= last_acked_seq:%x\n", |
| 434 | (void *)chk, chk->rec.data.tsn, asoc->last_acked_seq); |
| 435 | if (chk->sent != SCTP_DATAGRAM_NR_ACKED) { |
| 436 | if (asoc->strmout[chk->rec.data.sid].chunks_on_queues > 0) { |
| 437 | asoc->strmout[chk->rec.data.sid].chunks_on_queues--; |
| 438 | } |
| 439 | } |
| 440 | if ((asoc->strmout[chk->rec.data.sid].chunks_on_queues == 0) && |
| 441 | (asoc->strmout[chk->rec.data.sid].state == SCTP_STREAM_RESET_PENDING) && |
| 442 | TAILQ_EMPTY(&asoc->strmout[chk->rec.data.sid].outqueue)) { |
| 443 | asoc->trigger_reset = 1; |
| 444 | } |
| 445 | TAILQ_REMOVE(&asoc->sent_queue, chk, sctp_next); |
| 446 | if (PR_SCTP_ENABLED(chk->flags)) { |
| 447 | if (asoc->pr_sctp_cnt != 0) |
| 448 | asoc->pr_sctp_cnt--; |
| 449 | } |
| 450 | if (chk->data) { |
| 451 | /*sa_ignore NO_NULL_CHK*/ |
| 452 | sctp_free_bufspace(stcb, asoc, chk, 1); |
| 453 | sctp_m_freem(chk->data); |
| 454 | chk->data = NULL; |
| 455 | if (asoc->prsctp_supported && PR_SCTP_BUF_ENABLED(chk->flags)) { |
| 456 | asoc->sent_queue_cnt_removeable--; |
| 457 | } |
| 458 | } |
| 459 | asoc->sent_queue_cnt--; |
| 460 | sctp_free_a_chunk(stcb, chk, SCTP_SO_NOT_LOCKED); |
| 461 | } |
| 462 | } |
| 463 | SCTP_PRINTF("after recover order is as follows\n"); |
| 464 | TAILQ_FOREACH(chk, &asoc->sent_queue, sctp_next) { |
| 465 | SCTP_PRINTF("chk:%p TSN:%x\n", (void *)chk, chk->rec.data.tsn); |
| 466 | } |
| 467 | } |
| 468 | #endif |
| 469 | |
| 470 | static int |
| 471 | sctp_mark_all_for_resend(struct sctp_tcb *stcb, |
| 472 | struct sctp_nets *net, |
| 473 | struct sctp_nets *alt, |
| 474 | int window_probe, |
| 475 | int *num_marked, |
| 476 | int *num_abandoned) |
| 477 | { |
| 478 | |
| 479 | /* |
| 480 | * Mark all chunks (well not all) that were sent to *net for |
| 481 | * retransmission. Move them to alt for there destination as well... |
| 482 | * We only mark chunks that have been outstanding long enough to |
| 483 | * have received feed-back. |
| 484 | */ |
| 485 | struct sctp_tmit_chunk *chk, *nchk; |
| 486 | struct sctp_nets *lnets; |
| 487 | struct timeval now, min_wait, tv; |
| 488 | int cur_rto; |
| 489 | int cnt_abandoned; |
| 490 | int audit_tf, num_mk, fir; |
| 491 | unsigned int cnt_mk; |
| 492 | uint32_t orig_flight, orig_tf; |
| 493 | uint32_t tsnlast, tsnfirst; |
| 494 | int recovery_cnt = 0; |
| 495 | |
| 496 | |
| 497 | /* none in flight now */ |
| 498 | audit_tf = 0; |
| 499 | fir = 0; |
| 500 | /* |
| 501 | * figure out how long a data chunk must be pending before we can |
| 502 | * mark it .. |
| 503 | */ |
| 504 | (void)SCTP_GETTIME_TIMEVAL(&now); |
| 505 | /* get cur rto in micro-seconds */ |
| 506 | cur_rto = (net->lastsa >> SCTP_RTT_SHIFT) + net->lastsv; |
| 507 | cur_rto *= 1000; |
| 508 | if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FR_LOGGING_ENABLE) { |
| 509 | sctp_log_fr(cur_rto, |
| 510 | stcb->asoc.peers_rwnd, |
| 511 | window_probe, |
| 512 | SCTP_FR_T3_MARK_TIME); |
| 513 | sctp_log_fr(net->flight_size, 0, 0, SCTP_FR_CWND_REPORT); |
| 514 | sctp_log_fr(net->flight_size, net->cwnd, stcb->asoc.total_flight, SCTP_FR_CWND_REPORT); |
| 515 | } |
| 516 | tv.tv_sec = cur_rto / 1000000; |
| 517 | tv.tv_usec = cur_rto % 1000000; |
| 518 | #ifndef __FreeBSD__ |
| 519 | timersub(&now, &tv, &min_wait); |
| 520 | #else |
| 521 | min_wait = now; |
| 522 | timevalsub(&min_wait, &tv); |
| 523 | #endif |
| 524 | if (min_wait.tv_sec < 0 || min_wait.tv_usec < 0) { |
| 525 | /* |
| 526 | * if we hit here, we don't have enough seconds on the clock |
| 527 | * to account for the RTO. We just let the lower seconds be |
| 528 | * the bounds and don't worry about it. This may mean we |
| 529 | * will mark a lot more than we should. |
| 530 | */ |
| 531 | min_wait.tv_sec = min_wait.tv_usec = 0; |
| 532 | } |
| 533 | if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FR_LOGGING_ENABLE) { |
| 534 | sctp_log_fr(cur_rto, now.tv_sec, now.tv_usec, SCTP_FR_T3_MARK_TIME); |
| 535 | sctp_log_fr(0, min_wait.tv_sec, min_wait.tv_usec, SCTP_FR_T3_MARK_TIME); |
| 536 | } |
| 537 | /* |
| 538 | * Our rwnd will be incorrect here since we are not adding back the |
| 539 | * cnt * mbuf but we will fix that down below. |
| 540 | */ |
| 541 | orig_flight = net->flight_size; |
| 542 | orig_tf = stcb->asoc.total_flight; |
| 543 | |
| 544 | net->fast_retran_ip = 0; |
| 545 | /* Now on to each chunk */ |
| 546 | cnt_abandoned = 0; |
| 547 | num_mk = cnt_mk = 0; |
| 548 | tsnfirst = tsnlast = 0; |
| 549 | #ifndef INVARIANTS |
| 550 | start_again: |
| 551 | #endif |
| 552 | TAILQ_FOREACH_SAFE(chk, &stcb->asoc.sent_queue, sctp_next, nchk) { |
| 553 | if (SCTP_TSN_GE(stcb->asoc.last_acked_seq, chk->rec.data.tsn)) { |
| 554 | /* Strange case our list got out of order? */ |
| 555 | SCTP_PRINTF("Our list is out of order? last_acked:%x chk:%x\n", |
| 556 | (unsigned int)stcb->asoc.last_acked_seq, (unsigned int)chk->rec.data.tsn); |
| 557 | recovery_cnt++; |
| 558 | #ifdef INVARIANTS |
| 559 | panic("last acked >= chk on sent-Q"); |
| 560 | #else |
| 561 | SCTP_PRINTF("Recover attempts a restart cnt:%d\n", recovery_cnt); |
| 562 | sctp_recover_sent_list(stcb); |
| 563 | if (recovery_cnt < 10) { |
| 564 | goto start_again; |
| 565 | } else { |
| 566 | SCTP_PRINTF("Recovery fails %d times??\n", recovery_cnt); |
| 567 | } |
| 568 | #endif |
| 569 | } |
| 570 | if ((chk->whoTo == net) && (chk->sent < SCTP_DATAGRAM_ACKED)) { |
| 571 | /* |
| 572 | * found one to mark: If it is less than |
| 573 | * DATAGRAM_ACKED it MUST not be a skipped or marked |
| 574 | * TSN but instead one that is either already set |
| 575 | * for retransmission OR one that needs |
| 576 | * retransmission. |
| 577 | */ |
| 578 | |
| 579 | /* validate its been outstanding long enough */ |
| 580 | if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FR_LOGGING_ENABLE) { |
| 581 | sctp_log_fr(chk->rec.data.tsn, |
| 582 | chk->sent_rcv_time.tv_sec, |
| 583 | chk->sent_rcv_time.tv_usec, |
| 584 | SCTP_FR_T3_MARK_TIME); |
| 585 | } |
| 586 | if ((chk->sent_rcv_time.tv_sec > min_wait.tv_sec) && (window_probe == 0)) { |
| 587 | /* |
| 588 | * we have reached a chunk that was sent |
| 589 | * some seconds past our min.. forget it we |
| 590 | * will find no more to send. |
| 591 | */ |
| 592 | if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FR_LOGGING_ENABLE) { |
| 593 | sctp_log_fr(0, |
| 594 | chk->sent_rcv_time.tv_sec, |
| 595 | chk->sent_rcv_time.tv_usec, |
| 596 | SCTP_FR_T3_STOPPED); |
| 597 | } |
| 598 | continue; |
| 599 | } else if ((chk->sent_rcv_time.tv_sec == min_wait.tv_sec) && |
| 600 | (window_probe == 0)) { |
| 601 | /* |
| 602 | * we must look at the micro seconds to |
| 603 | * know. |
| 604 | */ |
| 605 | if (chk->sent_rcv_time.tv_usec >= min_wait.tv_usec) { |
| 606 | /* |
| 607 | * ok it was sent after our boundary |
| 608 | * time. |
| 609 | */ |
| 610 | continue; |
| 611 | } |
| 612 | } |
| 613 | if (stcb->asoc.prsctp_supported && PR_SCTP_TTL_ENABLED(chk->flags)) { |
| 614 | /* Is it expired? */ |
| 615 | #ifndef __FreeBSD__ |
| 616 | if (timercmp(&now, &chk->rec.data.timetodrop, >)) { |
| 617 | #else |
| 618 | if (timevalcmp(&now, &chk->rec.data.timetodrop, >)) { |
| 619 | #endif |
| 620 | /* Yes so drop it */ |
| 621 | if (chk->data) { |
| 622 | (void)sctp_release_pr_sctp_chunk(stcb, |
| 623 | chk, |
| 624 | 1, |
| 625 | SCTP_SO_NOT_LOCKED); |
| 626 | cnt_abandoned++; |
| 627 | } |
| 628 | continue; |
| 629 | } |
| 630 | } |
| 631 | if (stcb->asoc.prsctp_supported && PR_SCTP_RTX_ENABLED(chk->flags)) { |
| 632 | /* Has it been retransmitted tv_sec times? */ |
| 633 | if (chk->snd_count > chk->rec.data.timetodrop.tv_sec) { |
| 634 | if (chk->data) { |
| 635 | (void)sctp_release_pr_sctp_chunk(stcb, |
| 636 | chk, |
| 637 | 1, |
| 638 | SCTP_SO_NOT_LOCKED); |
| 639 | cnt_abandoned++; |
| 640 | } |
| 641 | continue; |
| 642 | } |
| 643 | } |
| 644 | if (chk->sent < SCTP_DATAGRAM_RESEND) { |
| 645 | sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt); |
| 646 | num_mk++; |
| 647 | if (fir == 0) { |
| 648 | fir = 1; |
| 649 | tsnfirst = chk->rec.data.tsn; |
| 650 | } |
| 651 | tsnlast = chk->rec.data.tsn; |
| 652 | if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FR_LOGGING_ENABLE) { |
| 653 | sctp_log_fr(chk->rec.data.tsn, chk->snd_count, |
| 654 | 0, SCTP_FR_T3_MARKED); |
| 655 | } |
| 656 | |
| 657 | if (chk->rec.data.chunk_was_revoked) { |
| 658 | /* deflate the cwnd */ |
| 659 | chk->whoTo->cwnd -= chk->book_size; |
| 660 | chk->rec.data.chunk_was_revoked = 0; |
| 661 | } |
| 662 | net->marked_retrans++; |
| 663 | stcb->asoc.marked_retrans++; |
| 664 | if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FLIGHT_LOGGING_ENABLE) { |
| 665 | sctp_misc_ints(SCTP_FLIGHT_LOG_DOWN_RSND_TO, |
| 666 | chk->whoTo->flight_size, |
| 667 | chk->book_size, |
| 668 | (uint32_t)(uintptr_t)chk->whoTo, |
| 669 | chk->rec.data.tsn); |
| 670 | } |
| 671 | sctp_flight_size_decrease(chk); |
| 672 | sctp_total_flight_decrease(stcb, chk); |
| 673 | stcb->asoc.peers_rwnd += chk->send_size; |
| 674 | stcb->asoc.peers_rwnd += SCTP_BASE_SYSCTL(sctp_peer_chunk_oh); |
| 675 | } |
| 676 | chk->sent = SCTP_DATAGRAM_RESEND; |
| 677 | SCTP_STAT_INCR(sctps_markedretrans); |
| 678 | |
| 679 | /* reset the TSN for striking and other FR stuff */ |
| 680 | chk->rec.data.doing_fast_retransmit = 0; |
| 681 | /* Clear any time so NO RTT is being done */ |
| 682 | |
| 683 | if (chk->do_rtt) { |
| 684 | if (chk->whoTo->rto_needed == 0) { |
| 685 | chk->whoTo->rto_needed = 1; |
| 686 | } |
| 687 | } |
| 688 | chk->do_rtt = 0; |
| 689 | if (alt != net) { |
| 690 | sctp_free_remote_addr(chk->whoTo); |
| 691 | chk->no_fr_allowed = 1; |
| 692 | chk->whoTo = alt; |
| 693 | atomic_add_int(&alt->ref_count, 1); |
| 694 | } else { |
| 695 | chk->no_fr_allowed = 0; |
| 696 | if (TAILQ_EMPTY(&stcb->asoc.send_queue)) { |
| 697 | chk->rec.data.fast_retran_tsn = stcb->asoc.sending_seq; |
| 698 | } else { |
| 699 | chk->rec.data.fast_retran_tsn = (TAILQ_FIRST(&stcb->asoc.send_queue))->rec.data.tsn; |
| 700 | } |
| 701 | } |
| 702 | /* CMT: Do not allow FRs on retransmitted TSNs. |
| 703 | */ |
| 704 | if (stcb->asoc.sctp_cmt_on_off > 0) { |
| 705 | chk->no_fr_allowed = 1; |
| 706 | } |
| 707 | #ifdef THIS_SHOULD_NOT_BE_DONE |
| 708 | } else if (chk->sent == SCTP_DATAGRAM_ACKED) { |
| 709 | /* remember highest acked one */ |
| 710 | could_be_sent = chk; |
| 711 | #endif |
| 712 | } |
| 713 | if (chk->sent == SCTP_DATAGRAM_RESEND) { |
| 714 | cnt_mk++; |
| 715 | } |
| 716 | } |
| 717 | if ((orig_flight - net->flight_size) != (orig_tf - stcb->asoc.total_flight)) { |
| 718 | /* we did not subtract the same things? */ |
| 719 | audit_tf = 1; |
| 720 | } |
| 721 | |
| 722 | if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FR_LOGGING_ENABLE) { |
| 723 | sctp_log_fr(tsnfirst, tsnlast, num_mk, SCTP_FR_T3_TIMEOUT); |
| 724 | } |
| 725 | #ifdef SCTP_DEBUG |
| 726 | if (num_mk) { |
| 727 | SCTPDBG(SCTP_DEBUG_TIMER1, "LAST TSN marked was %x\n", |
| 728 | tsnlast); |
| 729 | SCTPDBG(SCTP_DEBUG_TIMER1, "Num marked for retransmission was %d peer-rwd:%ld\n", |
| 730 | num_mk, (u_long)stcb->asoc.peers_rwnd); |
| 731 | SCTPDBG(SCTP_DEBUG_TIMER1, "LAST TSN marked was %x\n", |
| 732 | tsnlast); |
| 733 | SCTPDBG(SCTP_DEBUG_TIMER1, "Num marked for retransmission was %d peer-rwd:%d\n", |
| 734 | num_mk, |
| 735 | (int)stcb->asoc.peers_rwnd); |
| 736 | } |
| 737 | #endif |
| 738 | *num_marked = num_mk; |
| 739 | *num_abandoned = cnt_abandoned; |
| 740 | /* Now check for a ECN Echo that may be stranded And |
| 741 | * include the cnt_mk'd to have all resends in the |
| 742 | * control queue. |
| 743 | */ |
| 744 | TAILQ_FOREACH(chk, &stcb->asoc.control_send_queue, sctp_next) { |
| 745 | if (chk->sent == SCTP_DATAGRAM_RESEND) { |
| 746 | cnt_mk++; |
| 747 | } |
| 748 | if ((chk->whoTo == net) && |
| 749 | (chk->rec.chunk_id.id == SCTP_ECN_ECHO)) { |
| 750 | sctp_free_remote_addr(chk->whoTo); |
| 751 | chk->whoTo = alt; |
| 752 | if (chk->sent != SCTP_DATAGRAM_RESEND) { |
| 753 | chk->sent = SCTP_DATAGRAM_RESEND; |
| 754 | sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt); |
| 755 | cnt_mk++; |
| 756 | } |
| 757 | atomic_add_int(&alt->ref_count, 1); |
| 758 | } |
| 759 | } |
| 760 | #ifdef THIS_SHOULD_NOT_BE_DONE |
| 761 | if ((stcb->asoc.sent_queue_retran_cnt == 0) && (could_be_sent)) { |
| 762 | /* fix it so we retransmit the highest acked anyway */ |
| 763 | sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt); |
| 764 | cnt_mk++; |
| 765 | could_be_sent->sent = SCTP_DATAGRAM_RESEND; |
| 766 | } |
| 767 | #endif |
| 768 | if (stcb->asoc.sent_queue_retran_cnt != cnt_mk) { |
| 769 | #ifdef INVARIANTS |
| 770 | SCTP_PRINTF("Local Audit says there are %d for retran asoc cnt:%d we marked:%d this time\n", |
| 771 | cnt_mk, stcb->asoc.sent_queue_retran_cnt, num_mk); |
| 772 | #endif |
| 773 | #ifndef SCTP_AUDITING_ENABLED |
| 774 | stcb->asoc.sent_queue_retran_cnt = cnt_mk; |
| 775 | #endif |
| 776 | } |
| 777 | if (audit_tf) { |
| 778 | SCTPDBG(SCTP_DEBUG_TIMER4, |
| 779 | "Audit total flight due to negative value net:%p\n", |
| 780 | (void *)net); |
| 781 | stcb->asoc.total_flight = 0; |
| 782 | stcb->asoc.total_flight_count = 0; |
| 783 | /* Clear all networks flight size */ |
| 784 | TAILQ_FOREACH(lnets, &stcb->asoc.nets, sctp_next) { |
| 785 | lnets->flight_size = 0; |
| 786 | SCTPDBG(SCTP_DEBUG_TIMER4, |
| 787 | "Net:%p c-f cwnd:%d ssthresh:%d\n", |
| 788 | (void *)lnets, lnets->cwnd, lnets->ssthresh); |
| 789 | } |
| 790 | TAILQ_FOREACH(chk, &stcb->asoc.sent_queue, sctp_next) { |
| 791 | if (chk->sent < SCTP_DATAGRAM_RESEND) { |
| 792 | if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FLIGHT_LOGGING_ENABLE) { |
| 793 | sctp_misc_ints(SCTP_FLIGHT_LOG_UP, |
| 794 | chk->whoTo->flight_size, |
| 795 | chk->book_size, |
| 796 | (uint32_t)(uintptr_t)chk->whoTo, |
| 797 | chk->rec.data.tsn); |
| 798 | } |
| 799 | |
| 800 | sctp_flight_size_increase(chk); |
| 801 | sctp_total_flight_increase(stcb, chk); |
| 802 | } |
| 803 | } |
| 804 | } |
| 805 | /* We return 1 if we only have a window probe outstanding */ |
| 806 | return (0); |
| 807 | } |
| 808 | |
| 809 | |
| 810 | int |
| 811 | sctp_t3rxt_timer(struct sctp_inpcb *inp, |
| 812 | struct sctp_tcb *stcb, |
| 813 | struct sctp_nets *net) |
| 814 | { |
| 815 | struct sctp_nets *alt; |
| 816 | int win_probe, num_mk, num_abandoned; |
| 817 | |
| 818 | if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FR_LOGGING_ENABLE) { |
| 819 | sctp_log_fr(0, 0, 0, SCTP_FR_T3_TIMEOUT); |
| 820 | } |
| 821 | if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { |
| 822 | struct sctp_nets *lnet; |
| 823 | |
| 824 | TAILQ_FOREACH(lnet, &stcb->asoc.nets, sctp_next) { |
| 825 | if (net == lnet) { |
| 826 | sctp_log_cwnd(stcb, lnet, 1, SCTP_CWND_LOG_FROM_T3); |
| 827 | } else { |
| 828 | sctp_log_cwnd(stcb, lnet, 0, SCTP_CWND_LOG_FROM_T3); |
| 829 | } |
| 830 | } |
| 831 | } |
| 832 | /* Find an alternate and mark those for retransmission */ |
| 833 | if ((stcb->asoc.peers_rwnd == 0) && |
| 834 | (stcb->asoc.total_flight < net->mtu)) { |
| 835 | SCTP_STAT_INCR(sctps_timowindowprobe); |
| 836 | win_probe = 1; |
| 837 | } else { |
| 838 | win_probe = 0; |
| 839 | } |
| 840 | |
| 841 | if (win_probe == 0) { |
| 842 | /* We don't do normal threshold management on window probes */ |
| 843 | if (sctp_threshold_management(inp, stcb, net, |
| 844 | stcb->asoc.max_send_times)) { |
| 845 | /* Association was destroyed */ |
| 846 | return (1); |
| 847 | } else { |
| 848 | if (net != stcb->asoc.primary_destination) { |
| 849 | /* send a immediate HB if our RTO is stale */ |
| 850 | struct timeval now; |
| 851 | unsigned int ms_goneby; |
| 852 | |
| 853 | (void)SCTP_GETTIME_TIMEVAL(&now); |
| 854 | if (net->last_sent_time.tv_sec) { |
| 855 | ms_goneby = (now.tv_sec - net->last_sent_time.tv_sec) * 1000; |
| 856 | } else { |
| 857 | ms_goneby = 0; |
| 858 | } |
| 859 | if ((net->dest_state & SCTP_ADDR_PF) == 0) { |
| 860 | if ((ms_goneby > net->RTO) || (net->RTO == 0)) { |
| 861 | /* |
| 862 | * no recent feed back in an RTO or |
| 863 | * more, request a RTT update |
| 864 | */ |
| 865 | sctp_send_hb(stcb, net, SCTP_SO_NOT_LOCKED); |
| 866 | } |
| 867 | } |
| 868 | } |
| 869 | } |
| 870 | } else { |
| 871 | /* |
| 872 | * For a window probe we don't penalize the net's but only |
| 873 | * the association. This may fail it if SACKs are not coming |
| 874 | * back. If sack's are coming with rwnd locked at 0, we will |
| 875 | * continue to hold things waiting for rwnd to raise |
| 876 | */ |
| 877 | if (sctp_threshold_management(inp, stcb, NULL, |
| 878 | stcb->asoc.max_send_times)) { |
| 879 | /* Association was destroyed */ |
| 880 | return (1); |
| 881 | } |
| 882 | } |
| 883 | if (stcb->asoc.sctp_cmt_on_off > 0) { |
| 884 | if (net->pf_threshold < net->failure_threshold) { |
| 885 | alt = sctp_find_alternate_net(stcb, net, 2); |
| 886 | } else { |
| 887 | /* |
| 888 | * CMT: Using RTX_SSTHRESH policy for CMT. |
| 889 | * If CMT is being used, then pick dest with |
| 890 | * largest ssthresh for any retransmission. |
| 891 | */ |
| 892 | alt = sctp_find_alternate_net(stcb, net, 1); |
| 893 | /* |
| 894 | * CUCv2: If a different dest is picked for |
| 895 | * the retransmission, then new |
| 896 | * (rtx-)pseudo_cumack needs to be tracked |
| 897 | * for orig dest. Let CUCv2 track new (rtx-) |
| 898 | * pseudo-cumack always. |
| 899 | */ |
| 900 | net->find_pseudo_cumack = 1; |
| 901 | net->find_rtx_pseudo_cumack = 1; |
| 902 | } |
| 903 | } else { |
| 904 | alt = sctp_find_alternate_net(stcb, net, 0); |
| 905 | } |
| 906 | |
| 907 | num_mk = 0; |
| 908 | num_abandoned = 0; |
| 909 | (void)sctp_mark_all_for_resend(stcb, net, alt, win_probe, |
| 910 | &num_mk, &num_abandoned); |
| 911 | /* FR Loss recovery just ended with the T3. */ |
| 912 | stcb->asoc.fast_retran_loss_recovery = 0; |
| 913 | |
| 914 | /* CMT FR loss recovery ended with the T3 */ |
| 915 | net->fast_retran_loss_recovery = 0; |
| 916 | if ((stcb->asoc.cc_functions.sctp_cwnd_new_transmission_begins) && |
| 917 | (net->flight_size == 0)) { |
| 918 | (*stcb->asoc.cc_functions.sctp_cwnd_new_transmission_begins)(stcb, net); |
| 919 | } |
| 920 | |
| 921 | /* |
| 922 | * setup the sat loss recovery that prevents satellite cwnd advance. |
| 923 | */ |
| 924 | stcb->asoc.sat_t3_loss_recovery = 1; |
| 925 | stcb->asoc.sat_t3_recovery_tsn = stcb->asoc.sending_seq; |
| 926 | |
| 927 | /* Backoff the timer and cwnd */ |
| 928 | sctp_backoff_on_timeout(stcb, net, win_probe, num_mk, num_abandoned); |
| 929 | if ((!(net->dest_state & SCTP_ADDR_REACHABLE)) || |
| 930 | (net->dest_state & SCTP_ADDR_PF)) { |
| 931 | /* Move all pending over too */ |
| 932 | sctp_move_chunks_from_net(stcb, net); |
| 933 | |
| 934 | /* Get the address that failed, to |
| 935 | * force a new src address selecton and |
| 936 | * a route allocation. |
| 937 | */ |
| 938 | if (net->ro._s_addr) { |
| 939 | sctp_free_ifa(net->ro._s_addr); |
| 940 | net->ro._s_addr = NULL; |
| 941 | } |
| 942 | net->src_addr_selected = 0; |
| 943 | |
| 944 | /* Force a route allocation too */ |
| 945 | if (net->ro.ro_rt) { |
| 946 | RTFREE(net->ro.ro_rt); |
| 947 | net->ro.ro_rt = NULL; |
| 948 | } |
| 949 | |
| 950 | /* Was it our primary? */ |
| 951 | if ((stcb->asoc.primary_destination == net) && (alt != net)) { |
| 952 | /* |
| 953 | * Yes, note it as such and find an alternate note: |
| 954 | * this means HB code must use this to resent the |
| 955 | * primary if it goes active AND if someone does a |
| 956 | * change-primary then this flag must be cleared |
| 957 | * from any net structures. |
| 958 | */ |
| 959 | if (stcb->asoc.alternate) { |
| 960 | sctp_free_remote_addr(stcb->asoc.alternate); |
| 961 | } |
| 962 | stcb->asoc.alternate = alt; |
| 963 | atomic_add_int(&stcb->asoc.alternate->ref_count, 1); |
| 964 | } |
| 965 | } |
| 966 | /* |
| 967 | * Special case for cookie-echo'ed case, we don't do output but must |
| 968 | * await the COOKIE-ACK before retransmission |
| 969 | */ |
| 970 | if (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_COOKIE_ECHOED) { |
| 971 | /* |
| 972 | * Here we just reset the timer and start again since we |
| 973 | * have not established the asoc |
| 974 | */ |
| 975 | sctp_timer_start(SCTP_TIMER_TYPE_SEND, inp, stcb, net); |
| 976 | return (0); |
| 977 | } |
| 978 | if (stcb->asoc.prsctp_supported) { |
| 979 | struct sctp_tmit_chunk *lchk; |
| 980 | |
| 981 | lchk = sctp_try_advance_peer_ack_point(stcb, &stcb->asoc); |
| 982 | /* C3. See if we need to send a Fwd-TSN */ |
| 983 | if (SCTP_TSN_GT(stcb->asoc.advanced_peer_ack_point, stcb->asoc.last_acked_seq)) { |
| 984 | send_forward_tsn(stcb, &stcb->asoc); |
| 985 | if (lchk) { |
| 986 | /* Assure a timer is up */ |
| 987 | sctp_timer_start(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, stcb, lchk->whoTo); |
| 988 | } |
| 989 | } |
| 990 | } |
| 991 | if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_MONITOR_ENABLE) { |
| 992 | sctp_log_cwnd(stcb, net, net->cwnd, SCTP_CWND_LOG_FROM_RTX); |
| 993 | } |
| 994 | return (0); |
| 995 | } |
| 996 | |
| 997 | int |
| 998 | sctp_t1init_timer(struct sctp_inpcb *inp, |
| 999 | struct sctp_tcb *stcb, |
| 1000 | struct sctp_nets *net) |
| 1001 | { |
| 1002 | /* bump the thresholds */ |
| 1003 | if (stcb->asoc.delayed_connection) { |
| 1004 | /* |
| 1005 | * special hook for delayed connection. The library did NOT |
| 1006 | * complete the rest of its sends. |
| 1007 | */ |
| 1008 | stcb->asoc.delayed_connection = 0; |
| 1009 | sctp_send_initiate(inp, stcb, SCTP_SO_NOT_LOCKED); |
| 1010 | return (0); |
| 1011 | } |
| 1012 | if (SCTP_GET_STATE((&stcb->asoc)) != SCTP_STATE_COOKIE_WAIT) { |
| 1013 | return (0); |
| 1014 | } |
| 1015 | if (sctp_threshold_management(inp, stcb, net, |
| 1016 | stcb->asoc.max_init_times)) { |
| 1017 | /* Association was destroyed */ |
| 1018 | return (1); |
| 1019 | } |
| 1020 | stcb->asoc.dropped_special_cnt = 0; |
| 1021 | sctp_backoff_on_timeout(stcb, stcb->asoc.primary_destination, 1, 0, 0); |
| 1022 | if (stcb->asoc.initial_init_rto_max < net->RTO) { |
| 1023 | net->RTO = stcb->asoc.initial_init_rto_max; |
| 1024 | } |
| 1025 | if (stcb->asoc.numnets > 1) { |
| 1026 | /* If we have more than one addr use it */ |
| 1027 | struct sctp_nets *alt; |
| 1028 | |
| 1029 | alt = sctp_find_alternate_net(stcb, stcb->asoc.primary_destination, 0); |
| 1030 | if (alt != stcb->asoc.primary_destination) { |
| 1031 | sctp_move_chunks_from_net(stcb, stcb->asoc.primary_destination); |
| 1032 | stcb->asoc.primary_destination = alt; |
| 1033 | } |
| 1034 | } |
| 1035 | /* Send out a new init */ |
| 1036 | sctp_send_initiate(inp, stcb, SCTP_SO_NOT_LOCKED); |
| 1037 | return (0); |
| 1038 | } |
| 1039 | |
| 1040 | /* |
| 1041 | * For cookie and asconf we actually need to find and mark for resend, then |
| 1042 | * increment the resend counter (after all the threshold management stuff of |
| 1043 | * course). |
| 1044 | */ |
| 1045 | int |
| 1046 | sctp_cookie_timer(struct sctp_inpcb *inp, |
| 1047 | struct sctp_tcb *stcb, |
| 1048 | struct sctp_nets *net SCTP_UNUSED) |
| 1049 | { |
| 1050 | struct sctp_nets *alt; |
| 1051 | struct sctp_tmit_chunk *cookie; |
| 1052 | |
| 1053 | /* first before all else we must find the cookie */ |
| 1054 | TAILQ_FOREACH(cookie, &stcb->asoc.control_send_queue, sctp_next) { |
| 1055 | if (cookie->rec.chunk_id.id == SCTP_COOKIE_ECHO) { |
| 1056 | break; |
| 1057 | } |
| 1058 | } |
| 1059 | if (cookie == NULL) { |
| 1060 | if (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_COOKIE_ECHOED) { |
| 1061 | /* FOOBAR! */ |
| 1062 | struct mbuf *op_err; |
| 1063 | |
| 1064 | op_err = sctp_generate_cause(SCTP_BASE_SYSCTL(sctp_diag_info_code), |
| 1065 | "Cookie timer expired, but no cookie"); |
| 1066 | inp->last_abort_code = SCTP_FROM_SCTP_TIMER + SCTP_LOC_3; |
| 1067 | sctp_abort_an_association(inp, stcb, op_err, SCTP_SO_NOT_LOCKED); |
| 1068 | } else { |
| 1069 | #ifdef INVARIANTS |
| 1070 | panic("Cookie timer expires in wrong state?"); |
| 1071 | #else |
| 1072 | SCTP_PRINTF("Strange in state %d not cookie-echoed yet c-e timer expires?\n", SCTP_GET_STATE(&stcb->asoc)); |
| 1073 | return (0); |
| 1074 | #endif |
| 1075 | } |
| 1076 | return (0); |
| 1077 | } |
| 1078 | /* Ok we found the cookie, threshold management next */ |
| 1079 | if (sctp_threshold_management(inp, stcb, cookie->whoTo, |
| 1080 | stcb->asoc.max_init_times)) { |
| 1081 | /* Assoc is over */ |
| 1082 | return (1); |
| 1083 | } |
| 1084 | /* |
| 1085 | * Cleared threshold management, now lets backoff the address |
| 1086 | * and select an alternate |
| 1087 | */ |
| 1088 | stcb->asoc.dropped_special_cnt = 0; |
| 1089 | sctp_backoff_on_timeout(stcb, cookie->whoTo, 1, 0, 0); |
| 1090 | alt = sctp_find_alternate_net(stcb, cookie->whoTo, 0); |
| 1091 | if (alt != cookie->whoTo) { |
| 1092 | sctp_free_remote_addr(cookie->whoTo); |
| 1093 | cookie->whoTo = alt; |
| 1094 | atomic_add_int(&alt->ref_count, 1); |
| 1095 | } |
| 1096 | /* Now mark the retran info */ |
| 1097 | if (cookie->sent != SCTP_DATAGRAM_RESEND) { |
| 1098 | sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt); |
| 1099 | } |
| 1100 | cookie->sent = SCTP_DATAGRAM_RESEND; |
| 1101 | /* |
| 1102 | * Now call the output routine to kick out the cookie again, Note we |
| 1103 | * don't mark any chunks for retran so that FR will need to kick in |
| 1104 | * to move these (or a send timer). |
| 1105 | */ |
| 1106 | return (0); |
| 1107 | } |
| 1108 | |
| 1109 | int |
| 1110 | sctp_strreset_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb, |
| 1111 | struct sctp_nets *net) |
| 1112 | { |
| 1113 | struct sctp_nets *alt; |
| 1114 | struct sctp_tmit_chunk *strrst = NULL, *chk = NULL; |
| 1115 | |
| 1116 | if (stcb->asoc.stream_reset_outstanding == 0) { |
| 1117 | return (0); |
| 1118 | } |
| 1119 | /* find the existing STRRESET, we use the seq number we sent out on */ |
| 1120 | (void)sctp_find_stream_reset(stcb, stcb->asoc.str_reset_seq_out, &strrst); |
| 1121 | if (strrst == NULL) { |
| 1122 | return (0); |
| 1123 | } |
| 1124 | /* do threshold management */ |
| 1125 | if (sctp_threshold_management(inp, stcb, strrst->whoTo, |
| 1126 | stcb->asoc.max_send_times)) { |
| 1127 | /* Assoc is over */ |
| 1128 | return (1); |
| 1129 | } |
| 1130 | /* |
| 1131 | * Cleared threshold management, now lets backoff the address |
| 1132 | * and select an alternate |
| 1133 | */ |
| 1134 | sctp_backoff_on_timeout(stcb, strrst->whoTo, 1, 0, 0); |
| 1135 | alt = sctp_find_alternate_net(stcb, strrst->whoTo, 0); |
| 1136 | sctp_free_remote_addr(strrst->whoTo); |
| 1137 | strrst->whoTo = alt; |
| 1138 | atomic_add_int(&alt->ref_count, 1); |
| 1139 | |
| 1140 | /* See if a ECN Echo is also stranded */ |
| 1141 | TAILQ_FOREACH(chk, &stcb->asoc.control_send_queue, sctp_next) { |
| 1142 | if ((chk->whoTo == net) && |
| 1143 | (chk->rec.chunk_id.id == SCTP_ECN_ECHO)) { |
| 1144 | sctp_free_remote_addr(chk->whoTo); |
| 1145 | if (chk->sent != SCTP_DATAGRAM_RESEND) { |
| 1146 | chk->sent = SCTP_DATAGRAM_RESEND; |
| 1147 | sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt); |
| 1148 | } |
| 1149 | chk->whoTo = alt; |
| 1150 | atomic_add_int(&alt->ref_count, 1); |
| 1151 | } |
| 1152 | } |
| 1153 | if (!(net->dest_state & SCTP_ADDR_REACHABLE)) { |
| 1154 | /* |
| 1155 | * If the address went un-reachable, we need to move to |
| 1156 | * alternates for ALL chk's in queue |
| 1157 | */ |
| 1158 | sctp_move_chunks_from_net(stcb, net); |
| 1159 | } |
| 1160 | /* mark the retran info */ |
| 1161 | if (strrst->sent != SCTP_DATAGRAM_RESEND) |
| 1162 | sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt); |
| 1163 | strrst->sent = SCTP_DATAGRAM_RESEND; |
| 1164 | |
| 1165 | /* restart the timer */ |
| 1166 | sctp_timer_start(SCTP_TIMER_TYPE_STRRESET, inp, stcb, strrst->whoTo); |
| 1167 | return (0); |
| 1168 | } |
| 1169 | |
| 1170 | int |
| 1171 | sctp_asconf_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb, |
| 1172 | struct sctp_nets *net) |
| 1173 | { |
| 1174 | struct sctp_nets *alt; |
| 1175 | struct sctp_tmit_chunk *asconf, *chk; |
| 1176 | |
| 1177 | /* is this a first send, or a retransmission? */ |
| 1178 | if (TAILQ_EMPTY(&stcb->asoc.asconf_send_queue)) { |
| 1179 | /* compose a new ASCONF chunk and send it */ |
| 1180 | sctp_send_asconf(stcb, net, SCTP_ADDR_NOT_LOCKED); |
| 1181 | } else { |
| 1182 | /* |
| 1183 | * Retransmission of the existing ASCONF is needed |
| 1184 | */ |
| 1185 | |
| 1186 | /* find the existing ASCONF */ |
| 1187 | asconf = TAILQ_FIRST(&stcb->asoc.asconf_send_queue); |
| 1188 | if (asconf == NULL) { |
| 1189 | return (0); |
| 1190 | } |
| 1191 | /* do threshold management */ |
| 1192 | if (sctp_threshold_management(inp, stcb, asconf->whoTo, |
| 1193 | stcb->asoc.max_send_times)) { |
| 1194 | /* Assoc is over */ |
| 1195 | return (1); |
| 1196 | } |
| 1197 | if (asconf->snd_count > stcb->asoc.max_send_times) { |
| 1198 | /* |
| 1199 | * Something is rotten: our peer is not responding to |
| 1200 | * ASCONFs but apparently is to other chunks. i.e. it |
| 1201 | * is not properly handling the chunk type upper bits. |
| 1202 | * Mark this peer as ASCONF incapable and cleanup. |
| 1203 | */ |
| 1204 | SCTPDBG(SCTP_DEBUG_TIMER1, "asconf_timer: Peer has not responded to our repeated ASCONFs\n"); |
| 1205 | sctp_asconf_cleanup(stcb, net); |
| 1206 | return (0); |
| 1207 | } |
| 1208 | /* |
| 1209 | * cleared threshold management, so now backoff the net and |
| 1210 | * select an alternate |
| 1211 | */ |
| 1212 | sctp_backoff_on_timeout(stcb, asconf->whoTo, 1, 0, 0); |
| 1213 | alt = sctp_find_alternate_net(stcb, asconf->whoTo, 0); |
| 1214 | if (asconf->whoTo != alt) { |
| 1215 | sctp_free_remote_addr(asconf->whoTo); |
| 1216 | asconf->whoTo = alt; |
| 1217 | atomic_add_int(&alt->ref_count, 1); |
| 1218 | } |
| 1219 | |
| 1220 | /* See if an ECN Echo is also stranded */ |
| 1221 | TAILQ_FOREACH(chk, &stcb->asoc.control_send_queue, sctp_next) { |
| 1222 | if ((chk->whoTo == net) && |
| 1223 | (chk->rec.chunk_id.id == SCTP_ECN_ECHO)) { |
| 1224 | sctp_free_remote_addr(chk->whoTo); |
| 1225 | chk->whoTo = alt; |
| 1226 | if (chk->sent != SCTP_DATAGRAM_RESEND) { |
| 1227 | chk->sent = SCTP_DATAGRAM_RESEND; |
| 1228 | sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt); |
| 1229 | } |
| 1230 | atomic_add_int(&alt->ref_count, 1); |
| 1231 | } |
| 1232 | } |
| 1233 | TAILQ_FOREACH(chk, &stcb->asoc.asconf_send_queue, sctp_next) { |
| 1234 | if (chk->whoTo != alt) { |
| 1235 | sctp_free_remote_addr(chk->whoTo); |
| 1236 | chk->whoTo = alt; |
| 1237 | atomic_add_int(&alt->ref_count, 1); |
| 1238 | } |
| 1239 | if (asconf->sent != SCTP_DATAGRAM_RESEND && chk->sent != SCTP_DATAGRAM_UNSENT) |
| 1240 | sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt); |
| 1241 | chk->sent = SCTP_DATAGRAM_RESEND; |
| 1242 | } |
| 1243 | if (!(net->dest_state & SCTP_ADDR_REACHABLE)) { |
| 1244 | /* |
| 1245 | * If the address went un-reachable, we need to move |
| 1246 | * to the alternate for ALL chunks in queue |
| 1247 | */ |
| 1248 | sctp_move_chunks_from_net(stcb, net); |
| 1249 | } |
| 1250 | /* mark the retran info */ |
| 1251 | if (asconf->sent != SCTP_DATAGRAM_RESEND) |
| 1252 | sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt); |
| 1253 | asconf->sent = SCTP_DATAGRAM_RESEND; |
| 1254 | |
| 1255 | /* send another ASCONF if any and we can do */ |
| 1256 | sctp_send_asconf(stcb, alt, SCTP_ADDR_NOT_LOCKED); |
| 1257 | } |
| 1258 | return (0); |
| 1259 | } |
| 1260 | |
| 1261 | /* Mobility adaptation */ |
| 1262 | void |
| 1263 | sctp_delete_prim_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb, |
| 1264 | struct sctp_nets *net SCTP_UNUSED) |
| 1265 | { |
| 1266 | if (stcb->asoc.deleted_primary == NULL) { |
| 1267 | SCTPDBG(SCTP_DEBUG_ASCONF1, "delete_prim_timer: deleted_primary is not stored...\n"); |
| 1268 | sctp_mobility_feature_off(inp, SCTP_MOBILITY_PRIM_DELETED); |
| 1269 | return; |
| 1270 | } |
| 1271 | SCTPDBG(SCTP_DEBUG_ASCONF1, "delete_prim_timer: finished to keep deleted primary "); |
| 1272 | SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, &stcb->asoc.deleted_primary->ro._l_addr.sa); |
| 1273 | sctp_free_remote_addr(stcb->asoc.deleted_primary); |
| 1274 | stcb->asoc.deleted_primary = NULL; |
| 1275 | sctp_mobility_feature_off(inp, SCTP_MOBILITY_PRIM_DELETED); |
| 1276 | return; |
| 1277 | } |
| 1278 | |
| 1279 | /* |
| 1280 | * For the shutdown and shutdown-ack, we do not keep one around on the |
| 1281 | * control queue. This means we must generate a new one and call the general |
| 1282 | * chunk output routine, AFTER having done threshold management. |
| 1283 | * It is assumed that net is non-NULL. |
| 1284 | */ |
| 1285 | int |
| 1286 | sctp_shutdown_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb, |
| 1287 | struct sctp_nets *net) |
| 1288 | { |
| 1289 | struct sctp_nets *alt; |
| 1290 | |
| 1291 | /* first threshold management */ |
| 1292 | if (sctp_threshold_management(inp, stcb, net, stcb->asoc.max_send_times)) { |
| 1293 | /* Assoc is over */ |
| 1294 | return (1); |
| 1295 | } |
| 1296 | sctp_backoff_on_timeout(stcb, net, 1, 0, 0); |
| 1297 | /* second select an alternative */ |
| 1298 | alt = sctp_find_alternate_net(stcb, net, 0); |
| 1299 | |
| 1300 | /* third generate a shutdown into the queue for out net */ |
| 1301 | sctp_send_shutdown(stcb, alt); |
| 1302 | |
| 1303 | /* fourth restart timer */ |
| 1304 | sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN, inp, stcb, alt); |
| 1305 | return (0); |
| 1306 | } |
| 1307 | |
| 1308 | int |
| 1309 | sctp_shutdownack_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb, |
| 1310 | struct sctp_nets *net) |
| 1311 | { |
| 1312 | struct sctp_nets *alt; |
| 1313 | |
| 1314 | /* first threshold management */ |
| 1315 | if (sctp_threshold_management(inp, stcb, net, stcb->asoc.max_send_times)) { |
| 1316 | /* Assoc is over */ |
| 1317 | return (1); |
| 1318 | } |
| 1319 | sctp_backoff_on_timeout(stcb, net, 1, 0, 0); |
| 1320 | /* second select an alternative */ |
| 1321 | alt = sctp_find_alternate_net(stcb, net, 0); |
| 1322 | |
| 1323 | /* third generate a shutdown into the queue for out net */ |
| 1324 | sctp_send_shutdown_ack(stcb, alt); |
| 1325 | |
| 1326 | /* fourth restart timer */ |
| 1327 | sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNACK, inp, stcb, alt); |
| 1328 | return (0); |
| 1329 | } |
| 1330 | |
| 1331 | static void |
| 1332 | sctp_audit_stream_queues_for_size(struct sctp_inpcb *inp, |
| 1333 | struct sctp_tcb *stcb) |
| 1334 | { |
| 1335 | struct sctp_stream_queue_pending *sp; |
| 1336 | unsigned int i, chks_in_queue = 0; |
| 1337 | int being_filled = 0; |
| 1338 | /* |
| 1339 | * This function is ONLY called when the send/sent queues are empty. |
| 1340 | */ |
| 1341 | if ((stcb == NULL) || (inp == NULL)) |
| 1342 | return; |
| 1343 | |
| 1344 | if (stcb->asoc.sent_queue_retran_cnt) { |
| 1345 | SCTP_PRINTF("Hmm, sent_queue_retran_cnt is non-zero %d\n", |
| 1346 | stcb->asoc.sent_queue_retran_cnt); |
| 1347 | stcb->asoc.sent_queue_retran_cnt = 0; |
| 1348 | } |
| 1349 | if (stcb->asoc.ss_functions.sctp_ss_is_empty(stcb, &stcb->asoc)) { |
| 1350 | /* No stream scheduler information, initialize scheduler */ |
| 1351 | stcb->asoc.ss_functions.sctp_ss_init(stcb, &stcb->asoc, 0); |
| 1352 | if (!stcb->asoc.ss_functions.sctp_ss_is_empty(stcb, &stcb->asoc)) { |
| 1353 | /* yep, we lost a stream or two */ |
| 1354 | SCTP_PRINTF("Found additional streams NOT managed by scheduler, corrected\n"); |
| 1355 | } else { |
| 1356 | /* no streams lost */ |
| 1357 | stcb->asoc.total_output_queue_size = 0; |
| 1358 | } |
| 1359 | } |
| 1360 | /* Check to see if some data queued, if so report it */ |
| 1361 | for (i = 0; i < stcb->asoc.streamoutcnt; i++) { |
| 1362 | if (!TAILQ_EMPTY(&stcb->asoc.strmout[i].outqueue)) { |
| 1363 | TAILQ_FOREACH(sp, &stcb->asoc.strmout[i].outqueue, next) { |
| 1364 | if (sp->msg_is_complete) |
| 1365 | being_filled++; |
| 1366 | chks_in_queue++; |
| 1367 | } |
| 1368 | } |
| 1369 | } |
| 1370 | if (chks_in_queue != stcb->asoc.stream_queue_cnt) { |
| 1371 | SCTP_PRINTF("Hmm, stream queue cnt at %d I counted %d in stream out wheel\n", |
| 1372 | stcb->asoc.stream_queue_cnt, chks_in_queue); |
| 1373 | } |
| 1374 | if (chks_in_queue) { |
| 1375 | /* call the output queue function */ |
| 1376 | sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_T3, SCTP_SO_NOT_LOCKED); |
| 1377 | if ((TAILQ_EMPTY(&stcb->asoc.send_queue)) && |
| 1378 | (TAILQ_EMPTY(&stcb->asoc.sent_queue))) { |
| 1379 | /* |
| 1380 | * Probably should go in and make it go back through |
| 1381 | * and add fragments allowed |
| 1382 | */ |
| 1383 | if (being_filled == 0) { |
| 1384 | SCTP_PRINTF("Still nothing moved %d chunks are stuck\n", |
| 1385 | chks_in_queue); |
| 1386 | } |
| 1387 | } |
| 1388 | } else { |
| 1389 | SCTP_PRINTF("Found no chunks on any queue tot:%lu\n", |
| 1390 | (u_long)stcb->asoc.total_output_queue_size); |
| 1391 | stcb->asoc.total_output_queue_size = 0; |
| 1392 | } |
| 1393 | } |
| 1394 | |
| 1395 | int |
| 1396 | sctp_heartbeat_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb, |
| 1397 | struct sctp_nets *net) |
| 1398 | { |
| 1399 | uint8_t net_was_pf; |
| 1400 | |
| 1401 | if (net->dest_state & SCTP_ADDR_PF) { |
| 1402 | net_was_pf = 1; |
| 1403 | } else { |
| 1404 | net_was_pf = 0; |
| 1405 | } |
| 1406 | if (net->hb_responded == 0) { |
| 1407 | if (net->ro._s_addr) { |
| 1408 | /* Invalidate the src address if we did not get |
| 1409 | * a response last time. |
| 1410 | */ |
| 1411 | sctp_free_ifa(net->ro._s_addr); |
| 1412 | net->ro._s_addr = NULL; |
| 1413 | net->src_addr_selected = 0; |
| 1414 | } |
| 1415 | sctp_backoff_on_timeout(stcb, net, 1, 0, 0); |
| 1416 | if (sctp_threshold_management(inp, stcb, net, stcb->asoc.max_send_times)) { |
| 1417 | /* Assoc is over */ |
| 1418 | return (1); |
| 1419 | } |
| 1420 | } |
| 1421 | /* Zero PBA, if it needs it */ |
| 1422 | if (net->partial_bytes_acked) { |
| 1423 | net->partial_bytes_acked = 0; |
| 1424 | } |
| 1425 | if ((stcb->asoc.total_output_queue_size > 0) && |
| 1426 | (TAILQ_EMPTY(&stcb->asoc.send_queue)) && |
| 1427 | (TAILQ_EMPTY(&stcb->asoc.sent_queue))) { |
| 1428 | sctp_audit_stream_queues_for_size(inp, stcb); |
| 1429 | } |
| 1430 | if (!(net->dest_state & SCTP_ADDR_NOHB) && |
| 1431 | !((net_was_pf == 0) && (net->dest_state & SCTP_ADDR_PF))) { |
| 1432 | /* when move to PF during threshold mangement, a HB has been |
| 1433 | queued in that routine */ |
| 1434 | uint32_t ms_gone_by; |
| 1435 | |
| 1436 | if ((net->last_sent_time.tv_sec > 0) || |
| 1437 | (net->last_sent_time.tv_usec > 0)) { |
| 1438 | #ifdef __FreeBSD__ |
| 1439 | struct timeval diff; |
| 1440 | |
| 1441 | SCTP_GETTIME_TIMEVAL(&diff); |
| 1442 | timevalsub(&diff, &net->last_sent_time); |
| 1443 | #else |
| 1444 | struct timeval diff, now; |
| 1445 | |
| 1446 | SCTP_GETTIME_TIMEVAL(&now); |
| 1447 | timersub(&now, &net->last_sent_time, &diff); |
| 1448 | #endif |
| 1449 | ms_gone_by = (uint32_t)(diff.tv_sec * 1000) + |
| 1450 | (uint32_t)(diff.tv_usec / 1000); |
| 1451 | } else { |
| 1452 | ms_gone_by = 0xffffffff; |
| 1453 | } |
| 1454 | if ((ms_gone_by >= net->heart_beat_delay) || |
| 1455 | (net->dest_state & SCTP_ADDR_PF)) { |
| 1456 | sctp_send_hb(stcb, net, SCTP_SO_NOT_LOCKED); |
| 1457 | } |
| 1458 | } |
| 1459 | return (0); |
| 1460 | } |
| 1461 | |
| 1462 | void |
| 1463 | sctp_pathmtu_timer(struct sctp_inpcb *inp, |
| 1464 | struct sctp_tcb *stcb, |
| 1465 | struct sctp_nets *net) |
| 1466 | { |
| 1467 | uint32_t next_mtu, mtu; |
| 1468 | |
| 1469 | next_mtu = sctp_get_next_mtu(net->mtu); |
| 1470 | |
| 1471 | if ((next_mtu > net->mtu) && (net->port == 0)) { |
| 1472 | if ((net->src_addr_selected == 0) || |
| 1473 | (net->ro._s_addr == NULL) || |
| 1474 | (net->ro._s_addr->localifa_flags & SCTP_BEING_DELETED)) { |
| 1475 | if ((net->ro._s_addr != NULL) && (net->ro._s_addr->localifa_flags & SCTP_BEING_DELETED)) { |
| 1476 | sctp_free_ifa(net->ro._s_addr); |
| 1477 | net->ro._s_addr = NULL; |
| 1478 | net->src_addr_selected = 0; |
| 1479 | } else if (net->ro._s_addr == NULL) { |
| 1480 | #if defined(INET6) && defined(SCTP_EMBEDDED_V6_SCOPE) |
| 1481 | if (net->ro._l_addr.sa.sa_family == AF_INET6) { |
| 1482 | struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&net->ro._l_addr; |
| 1483 | /* KAME hack: embed scopeid */ |
| 1484 | #if defined(__APPLE__) |
| 1485 | #if defined(APPLE_LEOPARD) || defined(APPLE_SNOWLEOPARD) |
| 1486 | (void)in6_embedscope(&sin6->sin6_addr, sin6, NULL, NULL); |
| 1487 | #else |
| 1488 | (void)in6_embedscope(&sin6->sin6_addr, sin6, NULL, NULL, NULL); |
| 1489 | #endif |
| 1490 | #elif defined(SCTP_KAME) |
| 1491 | (void)sa6_embedscope(sin6, MODULE_GLOBAL(ip6_use_defzone)); |
| 1492 | #else |
| 1493 | (void)in6_embedscope(&sin6->sin6_addr, sin6); |
| 1494 | #endif |
| 1495 | } |
| 1496 | #endif |
| 1497 | |
| 1498 | net->ro._s_addr = sctp_source_address_selection(inp, |
| 1499 | stcb, |
| 1500 | (sctp_route_t *)&net->ro, |
| 1501 | net, 0, stcb->asoc.vrf_id); |
| 1502 | #if defined(INET6) && defined(SCTP_EMBEDDED_V6_SCOPE) |
| 1503 | if (net->ro._l_addr.sa.sa_family == AF_INET6) { |
| 1504 | struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&net->ro._l_addr; |
| 1505 | #ifdef SCTP_KAME |
| 1506 | (void)sa6_recoverscope(sin6); |
| 1507 | #else |
| 1508 | (void)in6_recoverscope(sin6, &sin6->sin6_addr, NULL); |
| 1509 | #endif /* SCTP_KAME */ |
| 1510 | } |
| 1511 | #endif /* INET6 */ |
| 1512 | } |
| 1513 | if (net->ro._s_addr) |
| 1514 | net->src_addr_selected = 1; |
| 1515 | } |
| 1516 | if (net->ro._s_addr) { |
| 1517 | mtu = SCTP_GATHER_MTU_FROM_ROUTE(net->ro._s_addr, &net->ro._s_addr.sa, net->ro.ro_rt); |
| 1518 | #if defined(INET) || defined(INET6) |
| 1519 | if (net->port) { |
| 1520 | mtu -= sizeof(struct udphdr); |
| 1521 | } |
| 1522 | #endif |
| 1523 | if (mtu > next_mtu) { |
| 1524 | net->mtu = next_mtu; |
| 1525 | } else { |
| 1526 | net->mtu = mtu; |
| 1527 | } |
| 1528 | } |
| 1529 | } |
| 1530 | /* restart the timer */ |
| 1531 | sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net); |
| 1532 | } |
| 1533 | |
| 1534 | void |
| 1535 | sctp_autoclose_timer(struct sctp_inpcb *inp, |
| 1536 | struct sctp_tcb *stcb, |
| 1537 | struct sctp_nets *net) |
| 1538 | { |
| 1539 | struct timeval tn, *tim_touse; |
| 1540 | struct sctp_association *asoc; |
| 1541 | int ticks_gone_by; |
| 1542 | |
| 1543 | (void)SCTP_GETTIME_TIMEVAL(&tn); |
| 1544 | if (stcb->asoc.sctp_autoclose_ticks && |
| 1545 | sctp_is_feature_on(inp, SCTP_PCB_FLAGS_AUTOCLOSE)) { |
| 1546 | /* Auto close is on */ |
| 1547 | asoc = &stcb->asoc; |
| 1548 | /* pick the time to use */ |
| 1549 | if (asoc->time_last_rcvd.tv_sec > |
| 1550 | asoc->time_last_sent.tv_sec) { |
| 1551 | tim_touse = &asoc->time_last_rcvd; |
| 1552 | } else { |
| 1553 | tim_touse = &asoc->time_last_sent; |
| 1554 | } |
| 1555 | /* Now has long enough transpired to autoclose? */ |
| 1556 | ticks_gone_by = SEC_TO_TICKS(tn.tv_sec - tim_touse->tv_sec); |
| 1557 | if ((ticks_gone_by > 0) && |
| 1558 | (ticks_gone_by >= (int)asoc->sctp_autoclose_ticks)) { |
| 1559 | /* |
| 1560 | * autoclose time has hit, call the output routine, |
| 1561 | * which should do nothing just to be SURE we don't |
| 1562 | * have hanging data. We can then safely check the |
| 1563 | * queues and know that we are clear to send |
| 1564 | * shutdown |
| 1565 | */ |
| 1566 | sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_AUTOCLOSE_TMR, SCTP_SO_NOT_LOCKED); |
| 1567 | /* Are we clean? */ |
| 1568 | if (TAILQ_EMPTY(&asoc->send_queue) && |
| 1569 | TAILQ_EMPTY(&asoc->sent_queue)) { |
| 1570 | /* |
| 1571 | * there is nothing queued to send, so I'm |
| 1572 | * done... |
| 1573 | */ |
| 1574 | if (SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_SENT) { |
| 1575 | /* only send SHUTDOWN 1st time thru */ |
| 1576 | struct sctp_nets *netp; |
| 1577 | |
| 1578 | if ((SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) || |
| 1579 | (SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) { |
| 1580 | SCTP_STAT_DECR_GAUGE32(sctps_currestab); |
| 1581 | } |
| 1582 | SCTP_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_SENT); |
| 1583 | SCTP_CLEAR_SUBSTATE(asoc, SCTP_STATE_SHUTDOWN_PENDING); |
| 1584 | sctp_stop_timers_for_shutdown(stcb); |
| 1585 | if (stcb->asoc.alternate) { |
| 1586 | netp = stcb->asoc.alternate; |
| 1587 | } else { |
| 1588 | netp = stcb->asoc.primary_destination; |
| 1589 | } |
| 1590 | sctp_send_shutdown(stcb, netp); |
| 1591 | sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN, |
| 1592 | stcb->sctp_ep, stcb, |
| 1593 | netp); |
| 1594 | sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, |
| 1595 | stcb->sctp_ep, stcb, |
| 1596 | netp); |
| 1597 | } |
| 1598 | } |
| 1599 | } else { |
| 1600 | /* |
| 1601 | * No auto close at this time, reset t-o to check |
| 1602 | * later |
| 1603 | */ |
| 1604 | int tmp; |
| 1605 | |
| 1606 | /* fool the timer startup to use the time left */ |
| 1607 | tmp = asoc->sctp_autoclose_ticks; |
| 1608 | asoc->sctp_autoclose_ticks -= ticks_gone_by; |
| 1609 | sctp_timer_start(SCTP_TIMER_TYPE_AUTOCLOSE, inp, stcb, |
| 1610 | net); |
| 1611 | /* restore the real tick value */ |
| 1612 | asoc->sctp_autoclose_ticks = tmp; |
| 1613 | } |
| 1614 | } |
| 1615 | } |
| 1616 | |