diff options
Diffstat (limited to 'sys/netinet/sctp_output.c')
-rw-r--r-- | sys/netinet/sctp_output.c | 338 |
1 files changed, 203 insertions, 135 deletions
diff --git a/sys/netinet/sctp_output.c b/sys/netinet/sctp_output.c index 71ef568..96d9495 100644 --- a/sys/netinet/sctp_output.c +++ b/sys/netinet/sctp_output.c @@ -3160,43 +3160,6 @@ sctp_find_cmsg(int c_type, void *data, struct mbuf *control, int cpsize) return (0); } - -struct mbuf * -sctp_get_mbuf_for_msg(unsigned int space_needed, int want_header, - int how, int allonebuf, int type) -{ - struct mbuf *m = NULL; - - m = m_getm2(NULL, space_needed, how, type, want_header ? M_PKTHDR : 0); - if (allonebuf) { - int siz; - - if (SCTP_BUF_IS_EXTENDED(m)) { - siz = SCTP_BUF_EXTEND_SIZE(m); - } else { - if (want_header) - siz = MHLEN; - else - siz = MLEN; - } - if (siz < space_needed) { - m_freem(m); - return (NULL); - } - } - if (SCTP_BUF_NEXT(m)) { - sctp_m_freem(SCTP_BUF_NEXT(m)); - SCTP_BUF_NEXT(m) = NULL; - } -#ifdef SCTP_MBUF_LOGGING - if (SCTP_BUF_IS_EXTENDED(m)) { - sctp_log_mb(m, SCTP_MBUF_IALLOC); - } -#endif - return (m); -} - - static struct mbuf * sctp_add_cookie(struct sctp_inpcb *inp, struct mbuf *init, int init_offset, struct mbuf *initack, int initack_offset, struct sctp_state_cookie *stc_in) @@ -3569,10 +3532,11 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp, printf("RTP route is %p through\n", ro->ro_rt); } #endif - +#ifdef _WHY_THIS_CODE if ((have_mtu) && (net) && (have_mtu > net->mtu)) { ro->ro_rt->rt_ifp->if_mtu = net->mtu; } +#endif if (ro != &iproute) { memcpy(&iproute, ro, sizeof(*ro)); } @@ -3580,9 +3544,11 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp, ro, o_flgs, inp->ip_inp.inp.inp_moptions ,(struct inpcb *)NULL ); +#ifdef _WHY_THIS_CODE if ((ro->ro_rt) && (have_mtu) && (net) && (have_mtu > net->mtu)) { ro->ro_rt->rt_ifp->if_mtu = have_mtu; } +#endif SCTP_STAT_INCR(sctps_sendpackets); SCTP_STAT_INCR_COUNTER64(sctps_outpackets); if (ret) @@ -4150,9 +4116,9 @@ sctp_arethere_unrecognized_parameters(struct mbuf *in_initpkt, struct sctp_paramhdr *phdr, params; struct mbuf *mat, *op_err; - char tempbuf[SCTP_CHUNK_BUFFER_SIZE]; + char tempbuf[SCTP_PARAM_BUFFER_SIZE]; int at, limit, pad_needed; - uint16_t ptype, plen; + uint16_t ptype, plen, padded_size; int err_at; *abort_processing = 0; @@ -4166,105 +4132,164 @@ sctp_arethere_unrecognized_parameters(struct mbuf *in_initpkt, while ((phdr != NULL) && ((size_t)limit >= sizeof(struct sctp_paramhdr))) { ptype = ntohs(phdr->param_type); plen = ntohs(phdr->param_length); - limit -= SCTP_SIZE32(plen); - if (plen < sizeof(struct sctp_paramhdr)) { -#ifdef SCTP_DEBUG - if (sctp_debug_on & SCTP_DEBUG_OUTPUT4) { - printf("sctp_output.c:Impossible length in parameter < %d\n", plen); - } -#endif - *abort_processing = 1; - break; + if ((plen > limit) || (plen < sizeof(struct sctp_paramhdr))) { + /* wacked parameter */ + goto invalid_size; } - /* + limit -= SCTP_SIZE32(plen); + /*- * All parameters for all chunks that we know/understand are * listed here. We process them other places and make * appropriate stop actions per the upper bits. However this * is the generic routine processor's can call to get back * an operr.. to either incorporate (init-ack) or send. */ - if ((ptype == SCTP_HEARTBEAT_INFO) || - (ptype == SCTP_IPV4_ADDRESS) || - (ptype == SCTP_IPV6_ADDRESS) || - (ptype == SCTP_STATE_COOKIE) || - (ptype == SCTP_UNRECOG_PARAM) || - (ptype == SCTP_COOKIE_PRESERVE) || - (ptype == SCTP_SUPPORTED_ADDRTYPE) || - (ptype == SCTP_PRSCTP_SUPPORTED) || - (ptype == SCTP_ADD_IP_ADDRESS) || - (ptype == SCTP_DEL_IP_ADDRESS) || - (ptype == SCTP_ECN_CAPABLE) || - (ptype == SCTP_ULP_ADAPTATION) || - (ptype == SCTP_ERROR_CAUSE_IND) || - (ptype == SCTP_RANDOM) || - (ptype == SCTP_CHUNK_LIST) || - (ptype == SCTP_CHUNK_LIST) || - (ptype == SCTP_SET_PRIM_ADDR) || - (ptype == SCTP_SUCCESS_REPORT) || - (ptype == SCTP_ULP_ADAPTATION) || - (ptype == SCTP_SUPPORTED_CHUNK_EXT) || - (ptype == SCTP_ECN_NONCE_SUPPORTED) - ) { - /* no skip it */ - at += SCTP_SIZE32(plen); - } else if (ptype == SCTP_HOSTNAME_ADDRESS) { - /* We can NOT handle HOST NAME addresses!! */ - int l_len; + padded_size = SCTP_SIZE32(plen); + switch (ptype) { + /* Param's with variable size */ + case SCTP_HEARTBEAT_INFO: + case SCTP_STATE_COOKIE: + case SCTP_UNRECOG_PARAM: + case SCTP_ERROR_CAUSE_IND: + /* ok skip fwd */ + at += padded_size; + break; + /* Param's with variable size within a range */ + case SCTP_CHUNK_LIST: + case SCTP_SUPPORTED_CHUNK_EXT: + if (padded_size > (sizeof(struct sctp_supported_chunk_types_param) + (sizeof(uint8_t) * SCTP_MAX_SUPPORTED_EXT))) { + goto invalid_size; + } + at += padded_size; + break; + case SCTP_SUPPORTED_ADDRTYPE: + if (padded_size > SCTP_MAX_ADDR_PARAMS_SIZE) { + goto invalid_size; + } + at += padded_size; + break; + case SCTP_RANDOM: + if (padded_size > (sizeof(struct sctp_auth_random) + SCTP_RANDOM_MAX_SIZE)) { + goto invalid_size; + } + at += padded_size; + break; + case SCTP_SET_PRIM_ADDR: + case SCTP_DEL_IP_ADDRESS: + case SCTP_ADD_IP_ADDRESS: + if ((padded_size != sizeof(struct sctp_asconf_addrv4_param)) && + (padded_size != sizeof(struct sctp_asconf_addr_param))) { + goto invalid_size; + } + at += padded_size; + break; + /* Param's with a fixed size */ + case SCTP_IPV4_ADDRESS: + if (padded_size != sizeof(struct sctp_ipv4addr_param)) { + goto invalid_size; + } + at += padded_size; + break; + case SCTP_IPV6_ADDRESS: + if (padded_size != sizeof(struct sctp_ipv6addr_param)) { + goto invalid_size; + } + at += padded_size; + break; + case SCTP_COOKIE_PRESERVE: + if (padded_size != sizeof(struct sctp_cookie_perserve_param)) { + goto invalid_size; + } + at += padded_size; + break; + case SCTP_ECN_NONCE_SUPPORTED: + case SCTP_PRSCTP_SUPPORTED: + if (padded_size != sizeof(struct sctp_paramhdr)) { + goto invalid_size; + } + at += padded_size; + break; + case SCTP_ECN_CAPABLE: + if (padded_size != sizeof(struct sctp_ecn_supported_param)) { + goto invalid_size; + } + at += padded_size; + break; + case SCTP_ULP_ADAPTATION: + if (padded_size != sizeof(struct sctp_adaptation_layer_indication)) { + goto invalid_size; + } + at += padded_size; + break; + case SCTP_SUCCESS_REPORT: + if (padded_size != sizeof(struct sctp_asconf_paramhdr)) { + goto invalid_size; + } + at += padded_size; + break; + case SCTP_HOSTNAME_ADDRESS: + { + /* We can NOT handle HOST NAME addresses!! */ + int l_len; #ifdef SCTP_DEBUG - if (sctp_debug_on & SCTP_DEBUG_OUTPUT4) { - printf("Can't handle hostname addresses.. abort processing\n"); - } + if (sctp_debug_on & SCTP_DEBUG_OUTPUT4) { + printf("Can't handle hostname addresses.. abort processing\n"); + } #endif - *abort_processing = 1; - if (op_err == NULL) { - /* Ok need to try to get a mbuf */ - l_len = sizeof(struct ip6_hdr) + sizeof(struct sctphdr) + sizeof(struct sctp_chunkhdr); - l_len += plen; - l_len += sizeof(struct sctp_paramhdr); - op_err = sctp_get_mbuf_for_msg(l_len, 0, M_DONTWAIT, 1, MT_DATA); - if (op_err) { - SCTP_BUF_LEN(op_err) = 0; - /* - * pre-reserve space for ip and sctp - * header and chunk hdr - */ - SCTP_BUF_RESV_UF(op_err, sizeof(struct ip6_hdr)); - SCTP_BUF_RESV_UF(op_err, sizeof(struct sctphdr)); - SCTP_BUF_RESV_UF(op_err, sizeof(struct sctp_chunkhdr)); + *abort_processing = 1; + if (op_err == NULL) { + /* Ok need to try to get a mbuf */ + l_len = sizeof(struct ip6_hdr) + sizeof(struct sctphdr) + sizeof(struct sctp_chunkhdr); + l_len += plen; + l_len += sizeof(struct sctp_paramhdr); + op_err = sctp_get_mbuf_for_msg(l_len, 0, M_DONTWAIT, 1, MT_DATA); + if (op_err) { + SCTP_BUF_LEN(op_err) = 0; + /* + * pre-reserve space for ip + * and sctp header and + * chunk hdr + */ + SCTP_BUF_RESV_UF(op_err, sizeof(struct ip6_hdr)); + SCTP_BUF_RESV_UF(op_err, sizeof(struct sctphdr)); + SCTP_BUF_RESV_UF(op_err, sizeof(struct sctp_chunkhdr)); + } } - } - if (op_err) { - /* If we have space */ - struct sctp_paramhdr s; + if (op_err) { + /* If we have space */ + struct sctp_paramhdr s; - if (err_at % 4) { - uint32_t cpthis = 0; + if (err_at % 4) { + uint32_t cpthis = 0; - pad_needed = 4 - (err_at % 4); - m_copyback(op_err, err_at, pad_needed, (caddr_t)&cpthis); - err_at += pad_needed; - } - s.param_type = htons(SCTP_CAUSE_UNRESOLVABLE_ADDR); - s.param_length = htons(sizeof(s) + plen); - m_copyback(op_err, err_at, sizeof(s), (caddr_t)&s); - err_at += sizeof(s); - phdr = sctp_get_next_param(mat, at, (struct sctp_paramhdr *)tempbuf, plen); - if (phdr == NULL) { - sctp_m_freem(op_err); - /* - * we are out of memory but we still - * need to have a look at what to do - * (the system is in trouble - * though). - */ - return (NULL); + pad_needed = 4 - (err_at % 4); + m_copyback(op_err, err_at, pad_needed, (caddr_t)&cpthis); + err_at += pad_needed; + } + s.param_type = htons(SCTP_CAUSE_UNRESOLVABLE_ADDR); + s.param_length = htons(sizeof(s) + plen); + m_copyback(op_err, err_at, sizeof(s), (caddr_t)&s); + err_at += sizeof(s); + phdr = sctp_get_next_param(mat, at, (struct sctp_paramhdr *)tempbuf, min(sizeof(tempbuf), plen)); + if (phdr == NULL) { + sctp_m_freem(op_err); + /* + * we are out of memory but + * we still need to have a + * look at what to do (the + * system is in trouble + * though). + */ + return (NULL); + } + m_copyback(op_err, err_at, plen, (caddr_t)phdr); + err_at += plen; } - m_copyback(op_err, err_at, plen, (caddr_t)phdr); - err_at += plen; + return (op_err); + break; } - return (op_err); - } else { + default: /* * we do not recognize the parameter figure out what * we do. @@ -4304,7 +4329,7 @@ sctp_arethere_unrecognized_parameters(struct mbuf *in_initpkt, if (plen > sizeof(tempbuf)) { plen = sizeof(tempbuf); } - phdr = sctp_get_next_param(mat, at, (struct sctp_paramhdr *)tempbuf, plen); + phdr = sctp_get_next_param(mat, at, (struct sctp_paramhdr *)tempbuf, min(sizeof(tempbuf), plen)); if (phdr == NULL) { sctp_m_freem(op_err); /* @@ -4314,6 +4339,7 @@ sctp_arethere_unrecognized_parameters(struct mbuf *in_initpkt, * system is in trouble * though). */ + op_err = NULL; goto more_processing; } m_copyback(op_err, err_at, plen, (caddr_t)phdr); @@ -4327,11 +4353,43 @@ sctp_arethere_unrecognized_parameters(struct mbuf *in_initpkt, /* skip this chunk and continue processing */ at += SCTP_SIZE32(plen); } + break; } phdr = sctp_get_next_param(mat, at, ¶ms, sizeof(params)); } return (op_err); +invalid_size: + *abort_processing = 1; + if ((op_err == NULL) && phdr) { + int l_len; + + l_len = sizeof(struct ip6_hdr) + sizeof(struct sctphdr) + sizeof(struct sctp_chunkhdr); + l_len += (2 * sizeof(struct sctp_paramhdr)); + op_err = sctp_get_mbuf_for_msg(l_len, 0, M_DONTWAIT, 1, MT_DATA); + SCTP_BUF_LEN(op_err) = 0; + SCTP_BUF_RESV_UF(op_err, sizeof(struct ip6_hdr)); + SCTP_BUF_RESV_UF(op_err, sizeof(struct sctphdr)); + SCTP_BUF_RESV_UF(op_err, sizeof(struct sctp_chunkhdr)); + } + if ((op_err) && phdr) { + struct sctp_paramhdr s; + + if (err_at % 4) { + uint32_t cpthis = 0; + + pad_needed = 4 - (err_at % 4); + m_copyback(op_err, err_at, pad_needed, (caddr_t)&cpthis); + err_at += pad_needed; + } + s.param_type = htons(SCTP_CAUSE_PROTOCOL_VIOLATION); + s.param_length = htons(sizeof(s) + sizeof(struct sctp_paramhdr)); + m_copyback(op_err, err_at, sizeof(s), (caddr_t)&s); + err_at += sizeof(s); + /* Only copy back the p-hdr that caused the issue */ + m_copyback(op_err, err_at, sizeof(struct sctp_paramhdr), (caddr_t)phdr); + } + return (op_err); } static int @@ -7976,6 +8034,9 @@ sctp_chunk_retransmission(struct sctp_inpcb *inp, #endif asoc->sent_queue_cnt = 0; asoc->sent_queue_cnt_removeable = 0; + /* send back 0/0 so we enter normal transmission */ + *cnt_out = 0; + return (0); } TAILQ_FOREACH(chk, &asoc->control_send_queue, sctp_next) { if ((chk->rec.chunk_id.id == SCTP_COOKIE_ECHO) || @@ -8444,13 +8505,16 @@ sctp_chunk_output(struct sctp_inpcb *inp, { /*- * Ok this is the generic chunk service queue. we must do the - * following: - See if there are retransmits pending, if so we must - * do these first and return. - Service the stream queue that is - * next, moving any message (note I must get a complete message i.e. - * FIRST/MIDDLE and LAST to the out queue in one pass) and assigning - * TSN's - Check to see if the cwnd/rwnd allows any output, if so we - * go ahead and fomulate and send the low level chunks. Making sure - * to combine any control in the control chunk queue also. + * following: + * - See if there are retransmits pending, if so we must + * do these first. + * - Service the stream queue that is next, moving any + * message (note I must get a complete message i.e. + * FIRST/MIDDLE and LAST to the out queue in one pass) and assigning + * TSN's + * - Check to see if the cwnd/rwnd allows any output, if so we + * go ahead and fomulate and send the low level chunks. Making sure + * to combine any control in the control chunk queue also. */ struct sctp_association *asoc; struct sctp_nets *net; @@ -8497,7 +8561,7 @@ sctp_chunk_output(struct sctp_inpcb *inp, */ if (from_where == SCTP_OUTPUT_FROM_COOKIE_ACK) { /*- - *Special hook for handling cookiess discarded + * Special hook for handling cookiess discarded * by peer that carried data. Send cookie-ack only * and then the next call with get the retran's. */ @@ -9064,7 +9128,7 @@ sctp_send_sack(struct sctp_tcb *stcb) gap_descriptor = (struct sctp_gap_ack_block *)((caddr_t)sack + sizeof(struct sctp_sack_chunk)); siz = (((asoc->highest_tsn_inside_map - asoc->mapping_array_base_tsn) + 1) + 7) / 8; - if (asoc->cumulative_tsn < asoc->mapping_array_base_tsn) { + if (compare_with_wrap(asoc->mapping_array_base_tsn, asoc->cumulative_tsn, MAX_TSN)) { offset = 1; /*- * cum-ack behind the mapping array, so we start and use all @@ -9075,7 +9139,7 @@ sctp_send_sack(struct sctp_tcb *stcb) offset = asoc->mapping_array_base_tsn - asoc->cumulative_tsn; /*- * we skip the first one when the cum-ack is at or above the - * mapping array base. + * mapping array base. Note this only works if */ jstart = 1; } @@ -11142,11 +11206,15 @@ sctp_lower_sosend(struct socket *so, } initial_out = uio->uio_resid; + SCTP_TCB_SEND_LOCK(stcb); if ((asoc->stream_locked) && (asoc->stream_locked_on != srcv->sinfo_stream)) { + SCTP_TCB_SEND_UNLOCK(stcb); error = EAGAIN; goto out; } + SCTP_TCB_SEND_UNLOCK(stcb); + strm = &stcb->asoc.strmout[srcv->sinfo_stream]; user_marks_eor = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXPLICIT_EOR); if (strm->last_msg_incomplete == 0) { |