diff options
Diffstat (limited to 'sys/netinet/sctp_output.c')
-rw-r--r-- | sys/netinet/sctp_output.c | 458 |
1 files changed, 159 insertions, 299 deletions
diff --git a/sys/netinet/sctp_output.c b/sys/netinet/sctp_output.c index 043b3b274c34..803c30945738 100644 --- a/sys/netinet/sctp_output.c +++ b/sys/netinet/sctp_output.c @@ -3543,7 +3543,8 @@ sctp_process_cmsgs_for_init(struct sctp_tcb *stcb, struct mbuf *control, int *er *error = EINVAL; return (-1); } - if (sctp_add_remote_addr(stcb, (struct sockaddr *)&sin, SCTP_DONOT_SETSCOPE, SCTP_ADDR_IS_CONFIRMED)) { + if (sctp_add_remote_addr(stcb, (struct sockaddr *)&sin, NULL, + SCTP_DONOT_SETSCOPE, SCTP_ADDR_IS_CONFIRMED)) { *error = ENOBUFS; return (1); } @@ -3574,13 +3575,15 @@ sctp_process_cmsgs_for_init(struct sctp_tcb *stcb, struct mbuf *control, int *er *error = EINVAL; return (-1); } - if (sctp_add_remote_addr(stcb, (struct sockaddr *)&sin, SCTP_DONOT_SETSCOPE, SCTP_ADDR_IS_CONFIRMED)) { + if (sctp_add_remote_addr(stcb, (struct sockaddr *)&sin, NULL, + SCTP_DONOT_SETSCOPE, SCTP_ADDR_IS_CONFIRMED)) { *error = ENOBUFS; return (1); } } else #endif - if (sctp_add_remote_addr(stcb, (struct sockaddr *)&sin6, SCTP_DONOT_SETSCOPE, SCTP_ADDR_IS_CONFIRMED)) { + if (sctp_add_remote_addr(stcb, (struct sockaddr *)&sin6, NULL, + SCTP_DONOT_SETSCOPE, SCTP_ADDR_IS_CONFIRMED)) { *error = ENOBUFS; return (1); } @@ -3828,28 +3831,7 @@ sctp_handle_no_route(struct sctp_tcb *stcb, (void *)net, so_locked); net->dest_state &= ~SCTP_ADDR_REACHABLE; - net->dest_state |= SCTP_ADDR_NOT_REACHABLE; - /* - * JRS 5/14/07 - If a destination is - * unreachable, the PF bit is turned off. - * This allows an unambiguous use of the PF - * bit for destinations that are reachable - * but potentially failed. If the - * destination is set to the unreachable - * state, also set the destination to the PF - * state. - */ - /* - * Add debug message here if destination is - * not in PF state. - */ - /* Stop any running T3 timers here? */ - if ((stcb->asoc.sctp_cmt_on_off > 0) && - (stcb->asoc.sctp_cmt_pf > 0)) { - net->dest_state &= ~SCTP_ADDR_PF; - SCTPDBG(SCTP_DEBUG_OUTPUT1, "Destination %p moved from PF to unreachable.\n", - net); - } + net->dest_state &= ~SCTP_ADDR_PF; } } if (stcb) { @@ -3859,14 +3841,16 @@ sctp_handle_no_route(struct sctp_tcb *stcb, alt = sctp_find_alternate_net(stcb, net, 0); if (alt != net) { - if (sctp_set_primary_addr(stcb, (struct sockaddr *)NULL, alt) == 0) { - net->dest_state |= SCTP_ADDR_WAS_PRIMARY; - if (net->ro._s_addr) { - sctp_free_ifa(net->ro._s_addr); - net->ro._s_addr = NULL; - } - net->src_addr_selected = 0; + if (stcb->asoc.alternate) { + sctp_free_remote_addr(stcb->asoc.alternate); } + stcb->asoc.alternate = alt; + atomic_add_int(&stcb->asoc.alternate->ref_count, 1); + if (net->ro._s_addr) { + sctp_free_ifa(net->ro._s_addr); + net->ro._s_addr = NULL; + } + net->src_addr_selected = 0; } } } @@ -6498,6 +6482,7 @@ sctp_sendall_iterator(struct sctp_inpcb *inp, struct sctp_tcb *stcb, void *ptr, int added_control = 0; int un_sent, do_chunk_output = 1; struct sctp_association *asoc; + struct sctp_nets *net; ca = (struct sctp_copy_all *)ptr; if (ca->m == NULL) { @@ -6531,6 +6516,11 @@ sctp_sendall_iterator(struct sctp_inpcb *inp, struct sctp_tcb *stcb, void *ptr, m = NULL; } SCTP_TCB_LOCK_ASSERT(stcb); + if (stcb->asoc.alternate) { + net = stcb->asoc.alternate; + } else { + net = stcb->asoc.primary_destination; + } if (ca->sndrcv.sinfo_flags & SCTP_ABORT) { /* Abort this assoc with m as the user defined reason */ if (m) { @@ -6569,7 +6559,7 @@ sctp_sendall_iterator(struct sctp_inpcb *inp, struct sctp_tcb *stcb, void *ptr, } } else { if (m) { - ret = sctp_msg_append(stcb, stcb->asoc.primary_destination, m, + ret = sctp_msg_append(stcb, net, m, &ca->sndrcv, 1); } asoc = &stcb->asoc; @@ -6596,14 +6586,14 @@ sctp_sendall_iterator(struct sctp_inpcb *inp, struct sctp_tcb *stcb, void *ptr, * only send SHUTDOWN the first time * through */ - sctp_send_shutdown(stcb, stcb->asoc.primary_destination); + sctp_send_shutdown(stcb, net); if (SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) { SCTP_STAT_DECR_GAUGE32(sctps_currestab); } SCTP_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_SENT); SCTP_CLEAR_SUBSTATE(asoc, SCTP_STATE_SHUTDOWN_PENDING); sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN, stcb->sctp_ep, stcb, - asoc->primary_destination); + net); sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, stcb->sctp_ep, stcb, asoc->primary_destination); added_control = 1; @@ -7733,13 +7723,13 @@ sctp_med_chunk_output(struct sctp_inpcb *inp, struct sctp_auth_chunk *auth = NULL; uint16_t auth_keyid; int override_ok = 1; + int skip_fill_up = 0; int data_auth_reqd = 0; /* * JRS 5/14/07 - Add flag for whether a heartbeat is sent to the * destination. */ - int pf_hbflag = 0; int quit_now = 0; *num_out = 0; @@ -7806,7 +7796,22 @@ nothing_to_send: max_send_per_dest = SCTP_SB_LIMIT_SND(stcb->sctp_socket) / asoc->numnets; else max_send_per_dest = 0; + if (no_data_chunks == 0) { + /* How many non-directed chunks are there? */ + TAILQ_FOREACH(chk, &asoc->send_queue, sctp_next) { + if (chk->whoTo == NULL) { + /* + * We already have non-directed chunks on + * the queue, no need to do a fill-up. + */ + skip_fill_up = 1; + break; + } + } + + } if ((no_data_chunks == 0) && + (skip_fill_up == 0) && (!stcb->asoc.ss_functions.sctp_ss_is_empty(stcb, asoc))) { TAILQ_FOREACH(net, &asoc->nets, sctp_next) { /* @@ -7821,8 +7826,10 @@ nothing_to_send: * copy by reference (we hope). */ net->window_probe = 0; - if ((net->dest_state & SCTP_ADDR_NOT_REACHABLE) || - (net->dest_state & SCTP_ADDR_UNCONFIRMED)) { + if ((net != stcb->asoc.alternate) && + ((net->dest_state & SCTP_ADDR_PF) || + (!(net->dest_state & SCTP_ADDR_REACHABLE)) || + (net->dest_state & SCTP_ADDR_UNCONFIRMED))) { if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { sctp_log_cwnd(stcb, net, 1, SCTP_CWND_LOG_FILL_OUTQ_CALLED); @@ -7833,16 +7840,6 @@ nothing_to_send: (net->flight_size == 0)) { (*stcb->asoc.cc_functions.sctp_cwnd_new_transmission_begins) (stcb, net); } - if ((asoc->sctp_cmt_on_off == 0) && - (asoc->primary_destination != net) && - (net->ref_count < 2)) { - /* nothing can be in queue for this guy */ - if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { - sctp_log_cwnd(stcb, net, 2, - SCTP_CWND_LOG_FILL_OUTQ_CALLED); - } - continue; - } if (net->flight_size >= net->cwnd) { /* skip this network, no room - can't fill */ if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_CWND_LOGGING_ENABLE) { @@ -7886,6 +7883,16 @@ nothing_to_send: } else { start_at = TAILQ_FIRST(&asoc->nets); } + TAILQ_FOREACH(chk, &asoc->control_send_queue, sctp_next) { + if (chk->whoTo == NULL) { + if (asoc->alternate) { + chk->whoTo = asoc->alternate; + } else { + chk->whoTo = asoc->primary_destination; + } + atomic_add_int(&chk->whoTo->ref_count, 1); + } + } old_start_at = NULL; again_one_more_time: for (net = start_at; net != NULL; net = TAILQ_NEXT(net, sctp_next)) { @@ -7896,15 +7903,6 @@ again_one_more_time: break; } tsns_sent = 0xa; - if ((asoc->sctp_cmt_on_off == 0) && - (asoc->primary_destination != net) && - (net->ref_count < 2)) { - /* - * Ref-count of 1 so we cannot have data or control - * queued to this address. Skip it (non-CMT). - */ - continue; - } if (TAILQ_EMPTY(&asoc->control_send_queue) && TAILQ_EMPTY(&asoc->asconf_send_queue) && (net->flight_size >= net->cwnd)) { @@ -8266,15 +8264,8 @@ again_one_more_time: (chk->rec.chunk_id.id == SCTP_ECN_CWR) || (chk->rec.chunk_id.id == SCTP_PACKET_DROPPED) || (chk->rec.chunk_id.id == SCTP_ASCONF_ACK)) { - if (chk->rec.chunk_id.id == SCTP_HEARTBEAT_REQUEST) { hbflag = 1; - /* - * JRS 5/14/07 - Set the - * flag to say a heartbeat - * is being sent. - */ - pf_hbflag = 1; } /* remove these chunks at the end */ if ((chk->rec.chunk_id.id == SCTP_SELECTIVE_ACK) || @@ -8408,7 +8399,7 @@ again_one_more_time: } /* JRI: if dest is in PF state, do not send data to it */ if ((asoc->sctp_cmt_on_off > 0) && - (asoc->sctp_cmt_pf > 0) && + (net != stcb->asoc.alternate) && (net->dest_state & SCTP_ADDR_PF)) { goto no_data_fill; } @@ -8486,6 +8477,17 @@ again_one_more_time: /* Don't send the chunk on this net */ continue; } + if (asoc->sctp_cmt_on_off == 0) { + if ((asoc->alternate) && + (asoc->alternate != net) && + (chk->whoTo == NULL)) { + continue; + } else if ((net != asoc->primary_destination) && + (asoc->alternate == NULL) && + (chk->whoTo == NULL)) { + continue; + } + } if ((chk->send_size > omtu) && ((chk->flags & CHUNK_FLAGS_FRAGMENT_OK) == 0)) { /*- * strange, we have a chunk that is @@ -8646,18 +8648,6 @@ no_data_fill: * restart it. */ sctp_timer_start(SCTP_TIMER_TYPE_SEND, inp, stcb, net); - } else if ((asoc->sctp_cmt_on_off > 0) && - (asoc->sctp_cmt_pf > 0) && - pf_hbflag && - ((net->dest_state & SCTP_ADDR_PF) == SCTP_ADDR_PF) && - (!SCTP_OS_TIMER_PENDING(&net->rxt_timer.timer))) { - /* - * JRS 5/14/07 - If a HB has been sent to a - * PF destination and no T3 timer is - * currently running, start the T3 timer to - * track the HBs that were sent. - */ - sctp_timer_start(SCTP_TIMER_TYPE_SEND, inp, stcb, net); } /* Now send it, if there is anything to send :> */ if ((error = sctp_lowlevel_chunk_output(inp, @@ -8747,24 +8737,6 @@ no_data_fill: } SCTP_STAT_INCR_BY(sctps_senddata, bundle_at); sctp_clean_up_datalist(stcb, asoc, data_list, bundle_at, net); - if (SCTP_BASE_SYSCTL(sctp_early_fr)) { - if (net->flight_size < net->cwnd) { - /* start or restart it */ - if (SCTP_OS_TIMER_PENDING(&net->fr_timer.timer)) { - sctp_timer_stop(SCTP_TIMER_TYPE_EARLYFR, inp, stcb, net, - SCTP_FROM_SCTP_OUTPUT + SCTP_LOC_2); - } - SCTP_STAT_INCR(sctps_earlyfrstrout); - sctp_timer_start(SCTP_TIMER_TYPE_EARLYFR, inp, stcb, net); - } else { - /* stop it if its running */ - if (SCTP_OS_TIMER_PENDING(&net->fr_timer.timer)) { - SCTP_STAT_INCR(sctps_earlyfrstpout); - sctp_timer_stop(SCTP_TIMER_TYPE_EARLYFR, inp, stcb, net, - SCTP_FROM_SCTP_OUTPUT + SCTP_LOC_3); - } - } - } } if (one_chunk) { break; @@ -8833,8 +8805,7 @@ sctp_queue_op_err(struct sctp_tcb *stcb, struct mbuf *op_err) chk->flags = 0; chk->asoc = &stcb->asoc; chk->data = op_err; - chk->whoTo = chk->asoc->primary_destination; - atomic_add_int(&chk->whoTo->ref_count, 1); + chk->whoTo = NULL; hdr = mtod(op_err, struct sctp_chunkhdr *); hdr->chunk_type = SCTP_OPERATION_ERROR; hdr->chunk_flags = 0; @@ -8929,7 +8900,7 @@ sctp_send_cookie_echo(struct mbuf *m, chk->flags = CHUNK_FLAGS_FRAGMENT_OK; chk->asoc = &stcb->asoc; chk->data = cookie; - chk->whoTo = chk->asoc->primary_destination; + chk->whoTo = net; atomic_add_int(&chk->whoTo->ref_count, 1); TAILQ_INSERT_HEAD(&chk->asoc->control_send_queue, chk, sctp_next); chk->asoc->ctrl_queue_cnt++; @@ -9039,10 +9010,10 @@ sctp_send_cookie_ack(struct sctp_tcb *stcb) chk->data = cookie_ack; if (chk->asoc->last_control_chunk_from != NULL) { chk->whoTo = chk->asoc->last_control_chunk_from; + atomic_add_int(&chk->whoTo->ref_count, 1); } else { - chk->whoTo = chk->asoc->primary_destination; + chk->whoTo = NULL; } - atomic_add_int(&chk->whoTo->ref_count, 1); hdr = mtod(cookie_ack, struct sctp_chunkhdr *); hdr->chunk_type = SCTP_COOKIE_ACK; hdr->chunk_flags = 0; @@ -9084,8 +9055,9 @@ sctp_send_shutdown_ack(struct sctp_tcb *stcb, struct sctp_nets *net) chk->asoc = &stcb->asoc; chk->data = m_shutdown_ack; chk->whoTo = net; - atomic_add_int(&net->ref_count, 1); - + if (chk->whoTo) { + atomic_add_int(&chk->whoTo->ref_count, 1); + } ack_cp = mtod(m_shutdown_ack, struct sctp_shutdown_ack_chunk *); ack_cp->ch.chunk_type = SCTP_SHUTDOWN_ACK; ack_cp->ch.chunk_flags = 0; @@ -9126,8 +9098,9 @@ sctp_send_shutdown(struct sctp_tcb *stcb, struct sctp_nets *net) chk->asoc = &stcb->asoc; chk->data = m_shutdown; chk->whoTo = net; - atomic_add_int(&net->ref_count, 1); - + if (chk->whoTo) { + atomic_add_int(&chk->whoTo->ref_count, 1); + } shutdown_cp = mtod(m_shutdown, struct sctp_shutdown_chunk *); shutdown_cp->ch.chunk_type = SCTP_SHUTDOWN; shutdown_cp->ch.chunk_flags = 0; @@ -9178,7 +9151,9 @@ sctp_send_asconf(struct sctp_tcb *stcb, struct sctp_nets *net, int addr_locked) chk->flags = CHUNK_FLAGS_FRAGMENT_OK; chk->asoc = &stcb->asoc; chk->whoTo = net; - atomic_add_int(&chk->whoTo->ref_count, 1); + if (chk->whoTo) { + atomic_add_int(&chk->whoTo->ref_count, 1); + } TAILQ_INSERT_TAIL(&chk->asoc->asconf_send_queue, chk, sctp_next); chk->asoc->ctrl_queue_cnt++; return; @@ -9208,17 +9183,27 @@ sctp_send_asconf_ack(struct sctp_tcb *stcb) net = sctp_find_alternate_net(stcb, stcb->asoc.last_control_chunk_from, 0); if (net == NULL) { /* no alternate */ - if (stcb->asoc.last_control_chunk_from == NULL) - net = stcb->asoc.primary_destination; - else + if (stcb->asoc.last_control_chunk_from == NULL) { + if (stcb->asoc.alternate) { + net = stcb->asoc.alternate; + } else { + net = stcb->asoc.primary_destination; + } + } else { net = stcb->asoc.last_control_chunk_from; + } } } else { /* normal case */ - if (stcb->asoc.last_control_chunk_from == NULL) - net = stcb->asoc.primary_destination; - else + if (stcb->asoc.last_control_chunk_from == NULL) { + if (stcb->asoc.alternate) { + net = stcb->asoc.alternate; + } else { + net = stcb->asoc.primary_destination; + } + } else { net = stcb->asoc.last_control_chunk_from; + } } latest_ack->last_sent_to = net; @@ -9256,6 +9241,9 @@ sctp_send_asconf_ack(struct sctp_tcb *stcb) chk->copy_by_ref = 0; chk->whoTo = net; + if (chk->whoTo) { + atomic_add_int(&chk->whoTo->ref_count, 1); + } chk->data = m_ack; chk->send_size = 0; /* Get size */ @@ -9267,7 +9255,6 @@ sctp_send_asconf_ack(struct sctp_tcb *stcb) chk->snd_count = 0; chk->flags |= CHUNK_FLAGS_FRAGMENT_OK; /* XXX */ chk->asoc = &stcb->asoc; - atomic_add_int(&chk->whoTo->ref_count, 1); TAILQ_INSERT_TAIL(&chk->asoc->control_send_queue, chk, sctp_next); chk->asoc->ctrl_queue_cnt++; @@ -9797,7 +9784,11 @@ sctp_timer_validation(struct sctp_inpcb *inp, SCTP_TCB_LOCK_ASSERT(stcb); /* Gak, we did not have a timer somewhere */ SCTPDBG(SCTP_DEBUG_OUTPUT3, "Deadlock avoided starting timer on a dest at retran\n"); - sctp_timer_start(SCTP_TIMER_TYPE_SEND, inp, stcb, asoc->primary_destination); + if (asoc->alternate) { + sctp_timer_start(SCTP_TIMER_TYPE_SEND, inp, stcb, asoc->alternate); + } else { + sctp_timer_start(SCTP_TIMER_TYPE_SEND, inp, stcb, asoc->primary_destination); + } return (ret); } @@ -9945,8 +9936,7 @@ sctp_chunk_output(struct sctp_inpcb *inp, #endif /* Check for bad destinations, if they exist move chunks around. */ TAILQ_FOREACH(net, &asoc->nets, sctp_next) { - if ((net->dest_state & SCTP_ADDR_NOT_REACHABLE) == - SCTP_ADDR_NOT_REACHABLE) { + if (!(net->dest_state & SCTP_ADDR_REACHABLE)) { /*- * if possible move things off of this address we * still may send below due to the dormant state but @@ -9956,16 +9946,6 @@ sctp_chunk_output(struct sctp_inpcb *inp, */ if (net->ref_count > 1) sctp_move_chunks_from_net(stcb, net); - } else if ((asoc->sctp_cmt_on_off > 0) && - (asoc->sctp_cmt_pf > 0) && - ((net->dest_state & SCTP_ADDR_PF) == SCTP_ADDR_PF)) { - /* - * JRS 5/14/07 - If CMT PF is on and the current - * destination is in PF state, move all queued data - * to an alternate desination. - */ - if (net->ref_count > 1) - sctp_move_chunks_from_net(stcb, net); } else { /*- * if ((asoc->sat_network) || (net->addr_is_local)) @@ -10123,10 +10103,9 @@ send_forward_tsn(struct sctp_tcb *stcb, chk->sent = SCTP_DATAGRAM_UNSENT; chk->snd_count = 0; /* Do we correct its output location? */ - if (chk->whoTo != asoc->primary_destination) { + if (chk->whoTo) { sctp_free_remote_addr(chk->whoTo); - chk->whoTo = asoc->primary_destination; - atomic_add_int(&chk->whoTo->ref_count, 1); + chk->whoTo = NULL; } goto sctp_fill_in_rest; } @@ -10150,8 +10129,6 @@ send_forward_tsn(struct sctp_tcb *stcb, SCTP_BUF_RESV_UF(chk->data, SCTP_MIN_OVERHEAD); chk->sent = SCTP_DATAGRAM_UNSENT; chk->snd_count = 0; - chk->whoTo = asoc->primary_destination; - atomic_add_int(&chk->whoTo->ref_count, 1); TAILQ_INSERT_TAIL(&asoc->control_send_queue, chk, sctp_next); asoc->ctrl_queue_cnt++; sctp_fill_in_rest: @@ -10346,8 +10323,10 @@ sctp_send_sack(struct sctp_tcb *stcb, int so_locked sctp_m_freem(a_chk->data); a_chk->data = NULL; } - sctp_free_remote_addr(a_chk->whoTo); - a_chk->whoTo = NULL; + if (a_chk->whoTo) { + sctp_free_remote_addr(a_chk->whoTo); + a_chk->whoTo = NULL; + } break; } } @@ -10379,13 +10358,13 @@ sctp_send_sack(struct sctp_tcb *stcb, int so_locked a_chk->whoTo = NULL; if ((asoc->numduptsns) || - (asoc->last_data_chunk_from->dest_state & SCTP_ADDR_NOT_REACHABLE)) { + (!(asoc->last_data_chunk_from->dest_state & SCTP_ADDR_REACHABLE))) { /*- * Ok, we have some duplicates or the destination for the * sack is unreachable, lets see if we can select an * alternate than asoc->last_data_chunk_from */ - if ((!(asoc->last_data_chunk_from->dest_state & SCTP_ADDR_NOT_REACHABLE)) && + if ((asoc->last_data_chunk_from->dest_state & SCTP_ADDR_REACHABLE) && (asoc->used_alt_onsack > asoc->numnets)) { /* We used an alt last time, don't this time */ a_chk->whoTo = NULL; @@ -10710,6 +10689,7 @@ sctp_send_abort_tcb(struct sctp_tcb *stcb, struct mbuf *operr, int so_locked int sz; uint32_t auth_offset = 0; struct sctp_auth_chunk *auth = NULL; + struct sctp_nets *net; /*- * Add an AUTH chunk, if chunk requires it and save the offset into @@ -10750,16 +10730,19 @@ sctp_send_abort_tcb(struct sctp_tcb *stcb, struct mbuf *operr, int so_locked /* Put AUTH chunk at the front of the chain */ SCTP_BUF_NEXT(m_end) = m_abort; } - + if (stcb->asoc.alternate) { + net = stcb->asoc.alternate; + } else { + net = stcb->asoc.primary_destination; + } /* fill in the ABORT chunk */ abort = mtod(m_abort, struct sctp_abort_chunk *); abort->ch.chunk_type = SCTP_ABORT_ASSOCIATION; abort->ch.chunk_flags = 0; abort->ch.chunk_length = htons(sizeof(*abort) + sz); - (void)sctp_lowlevel_chunk_output(stcb->sctp_ep, stcb, - stcb->asoc.primary_destination, - (struct sockaddr *)&stcb->asoc.primary_destination->ro._l_addr, + (void)sctp_lowlevel_chunk_output(stcb->sctp_ep, stcb, net, + (struct sockaddr *)&net->ro._l_addr, m_out, auth_offset, auth, stcb->asoc.authinfo.active_keyid, 1, 0, NULL, 0, stcb->sctp_ep->sctp_lport, stcb->rport, htonl(stcb->asoc.peer_vtag), stcb->asoc.primary_destination->port, so_locked, NULL, NULL); @@ -11030,120 +11013,22 @@ sctp_send_shutdown_complete2(struct mbuf *m, int iphlen, struct sctphdr *sh, } -static struct sctp_nets * -sctp_select_hb_destination(struct sctp_tcb *stcb, struct timeval *now) -{ - struct sctp_nets *net, *hnet; - int ms_goneby, highest_ms, state_overide = 0; - - (void)SCTP_GETTIME_TIMEVAL(now); - highest_ms = 0; - hnet = NULL; - SCTP_TCB_LOCK_ASSERT(stcb); - TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { - if ( - ((net->dest_state & SCTP_ADDR_NOHB) && ((net->dest_state & SCTP_ADDR_UNCONFIRMED) == 0)) || - (net->dest_state & SCTP_ADDR_OUT_OF_SCOPE) - ) { - /* - * Skip this guy from consideration if HB is off AND - * its confirmed - */ - continue; - } - if (sctp_destination_is_reachable(stcb, (struct sockaddr *)&net->ro._l_addr) == 0) { - /* skip this dest net from consideration */ - continue; - } - if (net->last_sent_time.tv_sec) { - /* Sent to so we subtract */ - ms_goneby = (now->tv_sec - net->last_sent_time.tv_sec) * 1000; - } else - /* Never been sent to */ - ms_goneby = 0x7fffffff; - /*- - * When the address state is unconfirmed but still - * considered reachable, we HB at a higher rate. Once it - * goes confirmed OR reaches the "unreachable" state, thenw - * we cut it back to HB at a more normal pace. - */ - if ((net->dest_state & (SCTP_ADDR_UNCONFIRMED | SCTP_ADDR_NOT_REACHABLE)) == SCTP_ADDR_UNCONFIRMED) { - state_overide = 1; - } else { - state_overide = 0; - } - - if ((((unsigned int)ms_goneby >= net->RTO) || (state_overide)) && - (ms_goneby > highest_ms)) { - highest_ms = ms_goneby; - hnet = net; - } - } - if (hnet && - ((hnet->dest_state & (SCTP_ADDR_UNCONFIRMED | SCTP_ADDR_NOT_REACHABLE)) == SCTP_ADDR_UNCONFIRMED)) { - state_overide = 1; - } else { - state_overide = 0; - } - - if (hnet && highest_ms && (((unsigned int)highest_ms >= hnet->RTO) || state_overide)) { - /*- - * Found the one with longest delay bounds OR it is - * unconfirmed and still not marked unreachable. - */ - SCTPDBG(SCTP_DEBUG_OUTPUT4, "net:%p is the hb winner -", hnet); -#ifdef SCTP_DEBUG - if (hnet) { - SCTPDBG_ADDR(SCTP_DEBUG_OUTPUT4, - (struct sockaddr *)&hnet->ro._l_addr); - } else { - SCTPDBG(SCTP_DEBUG_OUTPUT4, " none\n"); - } -#endif - /* update the timer now */ - hnet->last_sent_time = *now; - return (hnet); - } - /* Nothing to HB */ - return (NULL); -} - -int -sctp_send_hb(struct sctp_tcb *stcb, int user_req, struct sctp_nets *u_net, int so_locked +void +sctp_send_hb(struct sctp_tcb *stcb, struct sctp_nets *net, int so_locked #if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING) SCTP_UNUSED #endif ) { struct sctp_tmit_chunk *chk; - struct sctp_nets *net; struct sctp_heartbeat_chunk *hb; struct timeval now; SCTP_TCB_LOCK_ASSERT(stcb); - if (user_req == 0) { - net = sctp_select_hb_destination(stcb, &now); - if (net == NULL) { - /*- - * All our busy none to send to, just start the - * timer again. - */ - if (stcb->asoc.state == 0) { - return (0); - } - sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, - stcb->sctp_ep, - stcb, - net); - return (0); - } - } else { - net = u_net; - if (net == NULL) { - return (0); - } - (void)SCTP_GETTIME_TIMEVAL(&now); + if (net == NULL) { + return; } + (void)SCTP_GETTIME_TIMEVAL(&now); switch (net->ro._l_addr.sa.sa_family) { #ifdef INET case AF_INET: @@ -11154,12 +11039,12 @@ sctp_send_hb(struct sctp_tcb *stcb, int user_req, struct sctp_nets *u_net, int s break; #endif default: - return (0); + return; } sctp_alloc_a_chunk(stcb, chk); if (chk == NULL) { SCTPDBG(SCTP_DEBUG_OUTPUT4, "Gak, can't get a chunk for hb\n"); - return (0); + return; } chk->copy_by_ref = 0; chk->rec.chunk_id.id = SCTP_HEARTBEAT_REQUEST; @@ -11170,7 +11055,7 @@ sctp_send_hb(struct sctp_tcb *stcb, int user_req, struct sctp_nets *u_net, int s chk->data = sctp_get_mbuf_for_msg(chk->send_size, 0, M_DONTWAIT, 1, MT_HEADER); if (chk->data == NULL) { sctp_free_a_chunk(stcb, chk, so_locked); - return (0); + return; } SCTP_BUF_RESV_UF(chk->data, SCTP_MIN_OVERHEAD); SCTP_BUF_LEN(chk->data) = chk->send_size; @@ -11191,7 +11076,6 @@ sctp_send_hb(struct sctp_tcb *stcb, int user_req, struct sctp_nets *u_net, int s hb->heartbeat.hb_info.time_value_1 = now.tv_sec; hb->heartbeat.hb_info.time_value_2 = now.tv_usec; /* Did our user request this one, put it in */ - hb->heartbeat.hb_info.user_req = user_req; hb->heartbeat.hb_info.addr_family = net->ro._l_addr.sa.sa_family; hb->heartbeat.hb_info.addr_len = net->ro._l_addr.sa.sa_len; if (net->dest_state & SCTP_ADDR_UNCONFIRMED) { @@ -11221,57 +11105,14 @@ sctp_send_hb(struct sctp_tcb *stcb, int user_req, struct sctp_nets *u_net, int s break; #endif default: - return (0); + return; break; } - - /* - * JRS 5/14/07 - In CMT PF, the T3 timer is used to track - * PF-heartbeats. Because of this, threshold management is done by - * the t3 timer handler, and does not need to be done upon the send - * of a PF-heartbeat. If CMT PF is on and the destination to which a - * heartbeat is being sent is in PF state, do NOT do threshold - * management. - */ - if ((stcb->asoc.sctp_cmt_pf == 0) || - ((net->dest_state & SCTP_ADDR_PF) != SCTP_ADDR_PF)) { - /* ok we have a destination that needs a beat */ - /* lets do the theshold management Qiaobing style */ - if (sctp_threshold_management(stcb->sctp_ep, stcb, net, - stcb->asoc.max_send_times)) { - /*- - * we have lost the association, in a way this is - * quite bad since we really are one less time since - * we really did not send yet. This is the down side - * to the Q's style as defined in the RFC and not my - * alternate style defined in the RFC. - */ - if (chk->data != NULL) { - sctp_m_freem(chk->data); - chk->data = NULL; - } - /* - * Here we do NOT use the macro since the - * association is now gone. - */ - if (chk->whoTo) { - sctp_free_remote_addr(chk->whoTo); - chk->whoTo = NULL; - } - sctp_free_a_chunk((struct sctp_tcb *)NULL, chk, so_locked); - return (-1); - } - } net->hb_responded = 0; TAILQ_INSERT_TAIL(&stcb->asoc.control_send_queue, chk, sctp_next); stcb->asoc.ctrl_queue_cnt++; SCTP_STAT_INCR(sctps_sendheartbeat); - /*- - * Call directly med level routine to put out the chunk. It will - * always tumble out control chunks aka HB but it may even tumble - * out data too. - */ - return (1); + return; } void @@ -11282,6 +11123,9 @@ sctp_send_ecn_echo(struct sctp_tcb *stcb, struct sctp_nets *net, struct sctp_ecne_chunk *ecne; struct sctp_tmit_chunk *chk; + if (net == NULL) { + return; + } asoc = &stcb->asoc; SCTP_TCB_LOCK_ASSERT(stcb); TAILQ_FOREACH(chk, &asoc->control_send_queue, sctp_next) { @@ -11323,6 +11167,7 @@ sctp_send_ecn_echo(struct sctp_tcb *stcb, struct sctp_nets *net, chk->snd_count = 0; chk->whoTo = net; atomic_add_int(&chk->whoTo->ref_count, 1); + stcb->asoc.ecn_echo_cnt_onq++; ecne = mtod(chk->data, struct sctp_ecne_chunk *); ecne->ch.chunk_type = SCTP_ECN_ECHO; @@ -11477,10 +11322,10 @@ jump_out: if (net) { /* we should hit here */ chk->whoTo = net; + atomic_add_int(&chk->whoTo->ref_count, 1); } else { - chk->whoTo = asoc->primary_destination; + chk->whoTo = NULL; } - atomic_add_int(&chk->whoTo->ref_count, 1); chk->rec.chunk_id.id = SCTP_PACKET_DROPPED; chk->rec.chunk_id.can_take_data = 1; drp->ch.chunk_type = SCTP_PACKET_DROPPED; @@ -11518,8 +11363,9 @@ sctp_send_cwr(struct sctp_tcb *stcb, struct sctp_nets *net, uint32_t high_tsn, u asoc = &stcb->asoc; SCTP_TCB_LOCK_ASSERT(stcb); - - + if (net == NULL) { + return; + } TAILQ_FOREACH(chk, &asoc->control_send_queue, sctp_next) { if ((chk->rec.chunk_id.id == SCTP_ECN_CWR) && (net == chk->whoTo)) { /* @@ -11849,9 +11695,12 @@ sctp_send_str_reset_req(struct sctp_tcb *stcb, /* setup chunk parameters */ chk->sent = SCTP_DATAGRAM_UNSENT; chk->snd_count = 0; - chk->whoTo = asoc->primary_destination; + if (stcb->asoc.alternate) { + chk->whoTo = stcb->asoc.alternate; + } else { + chk->whoTo = stcb->asoc.primary_destination; + } atomic_add_int(&chk->whoTo->ref_count, 1); - ch = mtod(chk->data, struct sctp_chunkhdr *); ch->chunk_type = SCTP_STREAM_RESET; ch->chunk_flags = 0; @@ -12910,7 +12759,11 @@ sctp_lower_sosend(struct socket *so, goto out_unlocked; } } else { - net = stcb->asoc.primary_destination; + if (stcb->asoc.alternate) { + net = stcb->asoc.alternate; + } else { + net = stcb->asoc.primary_destination; + } } atomic_add_int(&stcb->total_sends, 1); /* Keep the stcb from being freed under our feet */ @@ -13579,15 +13432,22 @@ dataless_eof: if ((SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_SENT) && (SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_RECEIVED) && (SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_ACK_SENT)) { + struct sctp_nets *netp; + + if (stcb->asoc.alternate) { + netp = stcb->asoc.alternate; + } else { + netp = stcb->asoc.primary_destination; + } /* only send SHUTDOWN the first time through */ - sctp_send_shutdown(stcb, stcb->asoc.primary_destination); + sctp_send_shutdown(stcb, netp); if (SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) { SCTP_STAT_DECR_GAUGE32(sctps_currestab); } SCTP_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_SENT); SCTP_CLEAR_SUBSTATE(asoc, SCTP_STATE_SHUTDOWN_PENDING); sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN, stcb->sctp_ep, stcb, - asoc->primary_destination); + netp); sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, stcb->sctp_ep, stcb, asoc->primary_destination); } |