diff options
Diffstat (limited to 'sys/netinet/sctp_output.c')
-rw-r--r-- | sys/netinet/sctp_output.c | 106 |
1 files changed, 86 insertions, 20 deletions
diff --git a/sys/netinet/sctp_output.c b/sys/netinet/sctp_output.c index 3b60f85..64eb825 100644 --- a/sys/netinet/sctp_output.c +++ b/sys/netinet/sctp_output.c @@ -2412,6 +2412,10 @@ once_again: /* address has been removed */ continue; } + if (laddr->action == SCTP_DEL_IP_ADDRESS) { + /* address is being deleted */ + continue; + } sifa = sctp_is_ifa_addr_preferred(laddr->ifa, dest_is_loop, dest_is_priv, fam); if (sifa == NULL) @@ -2437,6 +2441,10 @@ once_again_too: /* address has been removed */ continue; } + if (laddr->action == SCTP_DEL_IP_ADDRESS) { + /* address is being deleted */ + continue; + } sifa = sctp_is_ifa_addr_acceptable(laddr->ifa, dest_is_loop, dest_is_priv, fam); if (sifa == NULL) @@ -2547,6 +2555,10 @@ sctp_from_the_top: /* address has been removed */ continue; } + if (laddr->action == SCTP_DEL_IP_ADDRESS) { + /* address is being deleted */ + continue; + } sifa = sctp_is_ifa_addr_preferred(laddr->ifa, dest_is_loop, dest_is_priv, fam); if (sifa == NULL) continue; @@ -2558,7 +2570,6 @@ sctp_from_the_top: stcb->asoc.last_used_address = laddr; atomic_add_int(&sifa->refcount, 1); return (sifa); - } if (start_at_beginning == 0) { stcb->asoc.last_used_address = NULL; @@ -2579,6 +2590,10 @@ sctp_from_the_top2: /* address has been removed */ continue; } + if (laddr->action == SCTP_DEL_IP_ADDRESS) { + /* address is being deleted */ + continue; + } sifa = sctp_is_ifa_addr_acceptable(laddr->ifa, dest_is_loop, dest_is_priv, fam); if (sifa == NULL) @@ -3396,10 +3411,14 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp, /* call the routine to select the src address */ if (net) { - if (net->ro._s_addr && (net->ro._s_addr->localifa_flags & SCTP_BEING_DELETED)) { + if (net->ro._s_addr && (net->ro._s_addr->localifa_flags & (SCTP_BEING_DELETED | SCTP_ADDR_IFA_UNUSEABLE))) { sctp_free_ifa(net->ro._s_addr); net->ro._s_addr = NULL; net->src_addr_selected = 0; + if (ro->ro_rt) { + RTFREE(ro->ro_rt); + ro->ro_rt = NULL; + } } if (net->src_addr_selected == 0) { if (out_of_asoc_ok) { @@ -3671,10 +3690,14 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp, lsa6_tmp.sin6_len = sizeof(lsa6_tmp); lsa6 = &lsa6_tmp; if (net) { - if (net->ro._s_addr && net->ro._s_addr->localifa_flags & SCTP_BEING_DELETED) { + if (net->ro._s_addr && (net->ro._s_addr->localifa_flags & (SCTP_BEING_DELETED | SCTP_ADDR_IFA_UNUSEABLE))) { sctp_free_ifa(net->ro._s_addr); net->ro._s_addr = NULL; net->src_addr_selected = 0; + if (ro->ro_rt) { + RTFREE(ro->ro_rt); + ro->ro_rt = NULL; + } } if (net->src_addr_selected == 0) { if (out_of_asoc_ok) { @@ -4922,7 +4945,7 @@ sctp_send_initiate_ack(struct sctp_inpcb *inp, struct sctp_tcb *stcb, initackm_out->msg.init.initiate_tag = htonl(asoc->my_vtag); initackm_out->msg.init.initial_tsn = htonl(asoc->init_seq_number); } else { - uint32_t vtag; + uint32_t vtag, itsn; if (asoc) { atomic_add_int(&asoc->refcnt, 1); @@ -4930,7 +4953,8 @@ sctp_send_initiate_ack(struct sctp_inpcb *inp, struct sctp_tcb *stcb, vtag = sctp_select_a_tag(inp); initackm_out->msg.init.initiate_tag = htonl(vtag); /* get a TSN to use too */ - initackm_out->msg.init.initial_tsn = htonl(sctp_select_initial_TSN(&inp->sctp_ep)); + itsn = sctp_select_initial_TSN(&inp->sctp_ep); + initackm_out->msg.init.initial_tsn = htonl(itsn); SCTP_TCB_LOCK(stcb); atomic_add_int(&asoc->refcnt, -1); } else { @@ -5978,7 +6002,7 @@ sctp_sendall(struct sctp_inpcb *inp, struct uio *uio, struct mbuf *m, ca->sndlen += SCTP_BUF_LEN(m); m = SCTP_BUF_NEXT(m); } - ca->m = m; + ca->m = mat; } ret = sctp_initiate_iterator(NULL, sctp_sendall_iterator, NULL, SCTP_PCB_ANY_FLAGS, SCTP_PCB_ANY_FEATURES, @@ -6401,6 +6425,7 @@ re_look: /* No chunk memory */ out_gu: if (send_lock_up) { + /* sa_ignore NO_NULL_CHK */ SCTP_TCB_SEND_UNLOCK(stcb); send_lock_up = 0; } @@ -6972,6 +6997,14 @@ sctp_med_chunk_output(struct sctp_inpcb *inp, net = TAILQ_FIRST(&asoc->nets); } + /* + * JRI-TODO: CMT-MPI. Simply set the first + * destination (net) to be optimized for the next + * message to be pulled out of the outwheel. 1. peek + * at outwheel 2. If large message, set net = + * highest_cwnd 3. If small message, set net = + * lowest rtt + */ } else { net = asoc->primary_destination; if (net == NULL) { @@ -6980,12 +7013,27 @@ sctp_med_chunk_output(struct sctp_inpcb *inp, } } start_at = net; + one_more_time: for (; net != NULL; net = TAILQ_NEXT(net, sctp_next)) { net->window_probe = 0; if (old_startat && (old_startat == net)) { break; } + /* + * JRI: if dest is unreachable or unconfirmed, do + * not send data to it + */ + if ((net->dest_state & SCTP_ADDR_NOT_REACHABLE) || (net->dest_state & SCTP_ADDR_UNCONFIRMED)) { + continue; + } + /* + * JRI: if dest is in PF state, do not send data to + * it + */ + if (sctp_cmt_on_off && sctp_cmt_pf && (net->dest_state & SCTP_ADDR_PF)) { + continue; + } if ((sctp_cmt_on_off == 0) && (net->ref_count < 2)) { /* nothing can be in queue for this guy */ continue; @@ -6996,9 +7044,9 @@ one_more_time: continue; } /* - * @@@ JRI : this for loop we are in takes in each - * net, if its's got space in cwnd and has data sent - * to it (when CMT is off) then it calls + * JRI : this for loop we are in takes in each net, + * if its's got space in cwnd and has data sent to + * it (when CMT is off) then it calls * sctp_fill_outqueue for the net. This gets data on * the send queue for that network. * @@ -7026,6 +7074,7 @@ one_more_time: } skip_the_fill_from_streams: *cwnd_full = cwnd_full_ind; + /* now service each destination and send out what we can for it */ /* Nothing to send? */ if ((TAILQ_FIRST(&asoc->control_send_queue) == NULL) && @@ -8082,8 +8131,6 @@ sctp_send_asconf_ack(struct sctp_tcb *stcb) } latest_ack->last_sent_to = net; - atomic_add_int(&latest_ack->last_sent_to->ref_count, 1); - TAILQ_FOREACH(ack, &stcb->asoc.asconf_ack_sent, next) { if (ack->data == NULL) { continue; @@ -9221,6 +9268,7 @@ sctp_send_sack(struct sctp_tcb *stcb) a_chk->data = NULL; } sctp_free_a_chunk(stcb, a_chk); + /* sa_ignore NO_NULL_CHK */ if (stcb->asoc.delayed_ack) { sctp_timer_stop(SCTP_TIMER_TYPE_RECV, stcb->sctp_ep, stcb, NULL, SCTP_FROM_SCTP_OUTPUT + SCTP_LOC_6); @@ -9916,6 +9964,7 @@ sctp_send_packet_dropped(struct sctp_tcb *stcb, struct sctp_nets *net, struct sctp_chunkhdr *ch, chunk_buf; unsigned int chk_length; + /* sa_ignore NO_NULL_CHK */ asoc = &stcb->asoc; SCTP_TCB_LOCK_ASSERT(stcb); if (asoc->peer_supports_pktdrop == 0) { @@ -11131,8 +11180,7 @@ sctp_lower_sosend(struct socket *so, if ((use_rcvinfo) && (srcv) && ((srcv->sinfo_flags & SCTP_ABORT) || ((srcv->sinfo_flags & SCTP_EOF) && - (uio) && - (uio->uio_resid == 0)))) { + (sndlen == 0)))) { /*- * User asks to abort a non-existant assoc, * or EOF a non-existant assoc with no data @@ -11282,7 +11330,11 @@ sctp_lower_sosend(struct socket *so, (stcb->asoc.chunks_on_out_queue > sctp_max_chunks_on_queue)) { SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EWOULDBLOCK); - error = EWOULDBLOCK; + if (sndlen > SCTP_SB_LIMIT_SND(so)) + error = EMSGSIZE; + else + error = EWOULDBLOCK; + atomic_add_int(&stcb->sctp_ep->total_nospaces, 1); goto out_unlocked; } @@ -11402,9 +11454,14 @@ sctp_lower_sosend(struct socket *so, tot_demand = (tot_out + sizeof(struct sctp_paramhdr)); } else { /* Must fit in a MTU */ - if (uio) - tot_out = uio->uio_resid; + tot_out = sndlen; tot_demand = (tot_out + sizeof(struct sctp_paramhdr)); + if (tot_demand > SCTP_DEFAULT_ADD_MORE) { + /* To big */ + SCTP_LTRACE_ERR_RET(NULL, stcb, net, SCTP_FROM_SCTP_OUTPUT, EMSGSIZE); + error = EMSGSIZE; + goto out; + } mm = sctp_get_mbuf_for_msg(tot_demand, 0, M_WAIT, 1, MT_DATA); } if (mm == NULL) { @@ -11491,12 +11548,21 @@ sctp_lower_sosend(struct socket *so, } /* Unless E_EOR mode is on, we must make a send FIT in one call. */ if ((user_marks_eor == 0) && - (uio->uio_resid > (int)SCTP_SB_LIMIT_SND(stcb->sctp_socket))) { + (sndlen > SCTP_SB_LIMIT_SND(stcb->sctp_socket))) { /* It will NEVER fit */ SCTP_LTRACE_ERR_RET(NULL, stcb, net, SCTP_FROM_SCTP_OUTPUT, EMSGSIZE); error = EMSGSIZE; goto out_unlocked; } + if ((uio == NULL) && user_marks_eor) { + /*- + * We do not support eeor mode for + * sending with mbuf chains (like sendfile). + */ + SCTP_LTRACE_ERR_RET(NULL, stcb, net, SCTP_FROM_SCTP_OUTPUT, EINVAL); + error = EINVAL; + goto out_unlocked; + } if (user_marks_eor) { local_add_more = sctp_add_more_threshold; } else { @@ -11504,7 +11570,7 @@ sctp_lower_sosend(struct socket *so, * For non-eeor the whole message must fit in * the socket send buffer. */ - local_add_more = uio->uio_resid; + local_add_more = sndlen; } len = 0; if (((max_len < local_add_more) && @@ -11517,7 +11583,7 @@ sctp_lower_sosend(struct socket *so, if (sctp_logging_level & SCTP_BLK_LOGGING_ENABLE) { sctp_log_block(SCTP_BLOCK_LOG_INTO_BLKA, - so, asoc, uio->uio_resid); + so, asoc, sndlen); } be.error = 0; stcb->block_entry = &be; @@ -11557,7 +11623,7 @@ sctp_lower_sosend(struct socket *so, * sndlen covers for mbuf case uio_resid covers for the non-mbuf * case NOTE: uio will be null when top/mbuf is passed */ - if ((sndlen == 0) || ((uio) && (uio->uio_resid == 0))) { + if (sndlen == 0) { if (srcv->sinfo_flags & SCTP_EOF) { got_all_of_the_send = 1; goto dataless_eof; |