diff options
author | rrs <rrs@FreeBSD.org> | 2007-05-17 12:16:24 +0000 |
---|---|---|
committer | rrs <rrs@FreeBSD.org> | 2007-05-17 12:16:24 +0000 |
commit | f03ff79b8eb759f4448ea239b33f54a4de64e72b (patch) | |
tree | 9c331efc7294abb10b0a637e060b8adcbb36b8be /sys | |
parent | 471f392f70d74931953e70708e2b2883ec00fcdd (diff) | |
download | FreeBSD-src-f03ff79b8eb759f4448ea239b33f54a4de64e72b.zip FreeBSD-src-f03ff79b8eb759f4448ea239b33f54a4de64e72b.tar.gz |
- Fixed 1-2-1 model to not worry about associd in sockopts
- Fixed RTOinfo for bounding.
- Fixed connect() to return ECONNREFUSED when an ABORT is received.
- Added comments to direct Static Analysis not to look at some things
it does not understand (comments are /* sa_ignore XXXXX */)
- Bind when colliding was broken, missing not_found = 1 before
checking to see if the port was in use caused endless bind loop.
- Cookie life needs to be in milliseconds to conform to socket api.
- Cookie life is not supposed to change if its 0, On the assoc
level set we changed it to 0 opps.
- Two more static analysis issues identified by the cisco
tool. Null checks needed.
- An issue for sendfile(). Need to validate the correct
input argument.
- When sending failed due to a no route to host, we leaked
the mbuf chain failing to call m_freem().
- Fix #ifdef issue for getting hash block len when HAVE_SHA2 is NOT defined
Reviewed by: gnn
Diffstat (limited to 'sys')
-rw-r--r-- | sys/netinet/sctp.h | 8 | ||||
-rw-r--r-- | sys/netinet/sctp_asconf.c | 38 | ||||
-rw-r--r-- | sys/netinet/sctp_auth.c | 2 | ||||
-rw-r--r-- | sys/netinet/sctp_constants.h | 4 | ||||
-rw-r--r-- | sys/netinet/sctp_indata.c | 6 | ||||
-rw-r--r-- | sys/netinet/sctp_input.c | 6 | ||||
-rw-r--r-- | sys/netinet/sctp_output.c | 14 | ||||
-rw-r--r-- | sys/netinet/sctp_pcb.c | 45 | ||||
-rw-r--r-- | sys/netinet/sctp_sysctl.c | 8 | ||||
-rw-r--r-- | sys/netinet/sctp_timer.c | 2 | ||||
-rw-r--r-- | sys/netinet/sctp_uio.h | 8 | ||||
-rw-r--r-- | sys/netinet/sctp_usrreq.c | 127 | ||||
-rw-r--r-- | sys/netinet/sctputil.c | 9 | ||||
-rw-r--r-- | sys/netinet6/sctp6_usrreq.c | 1 |
14 files changed, 175 insertions, 103 deletions
diff --git a/sys/netinet/sctp.h b/sys/netinet/sctp.h index e15b3dd..a8bcec6 100644 --- a/sys/netinet/sctp.h +++ b/sys/netinet/sctp.h @@ -116,7 +116,8 @@ struct sctp_paramhdr { /* authentication support */ #define SCTP_PEER_AUTH_CHUNKS 0x00000102 #define SCTP_LOCAL_AUTH_CHUNKS 0x00000103 - +#define SCTP_GET_ASSOC_NUMBER 0x00000104 /* ro */ +#define SCTP_GET_ASSOC_ID_LIST 0x00000105 /* ro */ /* * user socket options: BSD implementation specific @@ -153,9 +154,8 @@ struct sctp_paramhdr { /* read only */ #define SCTP_GET_SNDBUF_USE 0x00001101 #define SCTP_GET_STAT_LOG 0x00001103 -#define SCTP_GET_ASOC_ID_LIST 0x00001104 /* ro */ -#define SCTP_PCB_STATUS 0x00001105 -#define SCTP_GET_NONCE_VALUES 0x00001106 +#define SCTP_PCB_STATUS 0x00001104 +#define SCTP_GET_NONCE_VALUES 0x00001105 /* Special hook for dynamically setting primary for all assoc's, * this is a write only option that requires root privledge. diff --git a/sys/netinet/sctp_asconf.c b/sys/netinet/sctp_asconf.c index 92ab278..4151524 100644 --- a/sys/netinet/sctp_asconf.c +++ b/sys/netinet/sctp_asconf.c @@ -286,8 +286,10 @@ sctp_process_asconf_add_ip(struct mbuf *m, struct sctp_asconf_paramhdr *aph, m_reply = sctp_asconf_success_response(aph->correlation_id); } - sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, NULL, SCTP_FROM_SCTP_ASCONF + SCTP_LOC_1); - sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, NULL); + sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, + NULL, SCTP_FROM_SCTP_ASCONF + SCTP_LOC_1); + sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, + stcb, NULL); } return m_reply; @@ -864,7 +866,8 @@ sctp_asconf_cleanup(struct sctp_tcb *stcb, struct sctp_nets *net) /* * clear out any existing asconfs going out */ - sctp_timer_stop(SCTP_TIMER_TYPE_ASCONF, stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_ASCONF + SCTP_LOC_2); + sctp_timer_stop(SCTP_TIMER_TYPE_ASCONF, stcb->sctp_ep, stcb, net, + SCTP_FROM_SCTP_ASCONF + SCTP_LOC_2); stcb->asoc.asconf_seq_out++; /* remove the old ASCONF on our outbound queue */ sctp_toss_old_asconf(stcb); @@ -1328,7 +1331,8 @@ sctp_handle_asconf_ack(struct mbuf *m, int offset, return; } /* stop our timer */ - sctp_timer_stop(SCTP_TIMER_TYPE_ASCONF, stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_ASCONF + SCTP_LOC_3); + sctp_timer_stop(SCTP_TIMER_TYPE_ASCONF, stcb->sctp_ep, stcb, net, + SCTP_FROM_SCTP_ASCONF + SCTP_LOC_3); /* process the ASCONF-ACK contents */ ack_length = ntohs(cp->ch.chunk_length) - @@ -1664,7 +1668,8 @@ sctp_iterator_ep_end(struct sctp_inpcb *inp, void *ptr, uint32_t val) LIST_FOREACH(l, &asc->list_of_work, sctp_nxt_addr) { ifa = l->ifa; if (l->action == SCTP_ADD_IP_ADDRESS) { - LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) { + LIST_FOREACH(laddr, &inp->sctp_addr_list, + sctp_nxt_addr) { if (laddr->ifa == ifa) { laddr->action = 0; break; @@ -1821,7 +1826,6 @@ sctp_iterator_stcb(struct sctp_inpcb *inp, struct sctp_tcb *stcb, void *ptr, /* does the peer do asconf? */ if (stcb->asoc.peer_supports_asconf) { /* queue an asconf for this addr */ - status = sctp_asconf_queue_add(stcb, ifa, type); /* * if queued ok, and in correct state, set @@ -2175,7 +2179,8 @@ sctp_compose_asconf(struct sctp_tcb *stcb, int *retlen) } /* chain it all together */ SCTP_BUF_NEXT(m_asconf_chk) = m_asconf; - *retlen = acp->ch.chunk_length = ntohs(SCTP_BUF_LEN(m_asconf_chk) + SCTP_BUF_LEN(m_asconf)); + *retlen = SCTP_BUF_LEN(m_asconf_chk) + SCTP_BUF_LEN(m_asconf); + acp->ch.chunk_length = ntohs(*retlen); /* update "sent" flag */ stcb->asoc.asconf_sent++; @@ -2537,7 +2542,8 @@ sctp_check_address_list(struct sctp_tcb *stcb, struct mbuf *m, int offset, * sctp_bindx() support */ uint32_t -sctp_addr_mgmt_ep_sa(struct sctp_inpcb *inp, struct sockaddr *sa, uint32_t type, uint32_t vrf_id) +sctp_addr_mgmt_ep_sa(struct sctp_inpcb *inp, struct sockaddr *sa, + uint32_t type, uint32_t vrf_id) { struct sctp_ifa *ifa; @@ -2559,11 +2565,13 @@ sctp_addr_mgmt_ep_sa(struct sctp_inpcb *inp, struct sockaddr *sa, uint32_t type, struct sctp_laddr *wi; SCTP_MALLOC(asc, struct sctp_asconf_iterator *, - sizeof(struct sctp_asconf_iterator), "SCTP_ASCONF_ITERATOR"); + sizeof(struct sctp_asconf_iterator), + "SCTP_ASCONF_ITERATOR"); if (asc == NULL) { return (ENOMEM); } - wi = SCTP_ZONE_GET(sctppcbinfo.ipi_zone_laddr, struct sctp_laddr); + wi = SCTP_ZONE_GET(sctppcbinfo.ipi_zone_laddr, + struct sctp_laddr); if (wi == NULL) { SCTP_FREE(asc); return (ENOMEM); @@ -2573,7 +2581,12 @@ sctp_addr_mgmt_ep_sa(struct sctp_inpcb *inp, struct sockaddr *sa, uint32_t type, } else if (type == SCTP_DEL_IP_ADDRESS) { struct sctp_laddr *laddr; - LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) { + if (inp->laddr_count < 2) { + /* can't delete the last local address */ + return (EINVAL); + } + LIST_FOREACH(laddr, &inp->sctp_addr_list, + sctp_nxt_addr) { if (ifa == laddr->ifa) { /* Mark in the delete */ laddr->action = type; @@ -2591,7 +2604,8 @@ sctp_addr_mgmt_ep_sa(struct sctp_inpcb *inp, struct sockaddr *sa, uint32_t type, sctp_iterator_stcb, sctp_iterator_ep_end, SCTP_PCB_ANY_FLAGS, - SCTP_PCB_ANY_FEATURES, SCTP_ASOC_ANY_STATE, (void *)asc, 0, + SCTP_PCB_ANY_FEATURES, + SCTP_ASOC_ANY_STATE, (void *)asc, 0, sctp_iterator_end, inp, 0); } else { /* invalid address! */ diff --git a/sys/netinet/sctp_auth.c b/sys/netinet/sctp_auth.c index 5ea9ca9..42ba003 100644 --- a/sys/netinet/sctp_auth.c +++ b/sys/netinet/sctp_auth.c @@ -837,8 +837,8 @@ sctp_get_hmac_block_len(uint16_t hmac_algo) case SCTP_AUTH_HMAC_ID_MD5: #ifdef HAVE_SHA224 case SCTP_AUTH_HMAC_ID_SHA224: - return (64); #endif + return (64); #ifdef HAVE_SHA2 case SCTP_AUTH_HMAC_ID_SHA256: return (64); diff --git a/sys/netinet/sctp_constants.h b/sys/netinet/sctp_constants.h index 8c623aa..b695d81 100644 --- a/sys/netinet/sctp_constants.h +++ b/sys/netinet/sctp_constants.h @@ -490,8 +490,8 @@ __FBSDID("$FreeBSD$"); */ #define SCTP_DEFAULT_MBUFS_IN_CHAIN 5 -/* How long a cookie lives in seconds */ -#define SCTP_DEFAULT_COOKIE_LIFE 60 +/* How long a cookie lives in milli-seconds */ +#define SCTP_DEFAULT_COOKIE_LIFE 60000 /* resource limit of streams */ #define MAX_SCTP_STREAMS 2048 diff --git a/sys/netinet/sctp_indata.c b/sys/netinet/sctp_indata.c index ba8a9a0..a021fed 100644 --- a/sys/netinet/sctp_indata.c +++ b/sys/netinet/sctp_indata.c @@ -389,6 +389,7 @@ sctp_service_reassembly(struct sctp_tcb *stcb, struct sctp_association *asoc) /* Now free the address and data */ sctp_free_remote_addr(chk->whoTo); sctp_free_a_chunk(stcb, chk); + /* sa_ignore FREED_MEMORY */ chk = TAILQ_FIRST(&asoc->reasmqueue); } return; @@ -515,6 +516,7 @@ sctp_service_reassembly(struct sctp_tcb *stcb, struct sctp_association *asoc) } break; } + /* sa_ignore FREED_MEMORY */ chk = TAILQ_FIRST(&asoc->reasmqueue); } while (chk); } @@ -2107,6 +2109,7 @@ finish_express_del: sctp_reset_in_stream(stcb, liste->number_entries, liste->req.list_of_streams); TAILQ_REMOVE(&asoc->resetHead, liste, next_resp); SCTP_FREE(liste); + /* sa_ignore FREED_MEMORY */ liste = TAILQ_FIRST(&asoc->resetHead); ctl = TAILQ_FIRST(&asoc->pending_reply_queue); if (ctl && (liste == NULL)) { @@ -3458,6 +3461,7 @@ sctp_strike_gap_ack_chunks(struct sctp_tcb *stcb, struct sctp_association *asoc, */ tp1->no_fr_allowed = 1; alt = tp1->whoTo; + /* sa_ignore NO_NULL_CHK */ alt = sctp_find_alternate_net(stcb, alt, 1); if (alt == NULL) { alt = tp1->whoTo; @@ -3550,6 +3554,7 @@ sctp_strike_gap_ack_chunks(struct sctp_tcb *stcb, struct sctp_association *asoc, if (alt != tp1->whoTo) { /* yes, there is an alternate. */ sctp_free_remote_addr(tp1->whoTo); + /* sa_ignore FREED_MEMORY */ tp1->whoTo = alt; atomic_add_int(&alt->ref_count, 1); } @@ -4443,6 +4448,7 @@ again: * Find first chunk that was used with window probe * and clear the sent */ + /* sa_ignore FREED_MEMORY */ TAILQ_FOREACH(tp1, &asoc->sent_queue, sctp_next) { if (tp1->window_probe) { /* move back to data send queue */ diff --git a/sys/netinet/sctp_input.c b/sys/netinet/sctp_input.c index 6ac5f6d..bacdfe3 100644 --- a/sys/netinet/sctp_input.c +++ b/sys/netinet/sctp_input.c @@ -224,6 +224,7 @@ sctp_process_init(struct sctp_init_chunk *cp, struct sctp_tcb *stcb, sp, stcb); sctp_free_a_strmoq(stcb, sp); + /* sa_ignore FREED_MEMORY */ sp = TAILQ_FIRST(&outs->outqueue); } } @@ -294,6 +295,7 @@ sctp_process_init(struct sctp_init_chunk *cp, struct sctp_tcb *stcb, * removed). Up front when the INIT arrives we will discard it if it * is a restart and new addresses have been added. */ + /* sa_ignore MEMLEAK */ return (0); } @@ -1921,7 +1923,7 @@ sctp_handle_cookie_echo(struct mbuf *m, int iphlen, int offset, */ (void)SCTP_GETTIME_TIMEVAL(&now); /* Expire time is in Ticks, so we convert to seconds */ - time_expires.tv_sec = cookie->time_entered.tv_sec + cookie->cookie_life; + time_expires.tv_sec = cookie->time_entered.tv_sec + TICKS_TO_SEC(cookie->cookie_life); time_expires.tv_usec = cookie->time_entered.tv_usec; if (timevalcmp(&now, &time_expires, >)) { /* cookie is stale! */ @@ -4485,6 +4487,7 @@ sctp_common_input_processing(struct mbuf **mm, int iphlen, int offset, } if (IS_SCTP_CONTROL(ch)) { /* process the control portion of the SCTP packet */ + /* sa_ignore NO_NULL_CHK */ stcb = sctp_process_control(m, iphlen, &offset, length, sh, ch, inp, stcb, &net, &fwd_tsn_seen, vrf_id, table_id); if (stcb) { @@ -4864,6 +4867,7 @@ sctp_skip_csum_4: ecn_bits = ip->ip_tos; + /* sa_ignore NO_NULL_CHK */ sctp_common_input_processing(&m, iphlen, offset, length, sh, ch, inp, stcb, net, ecn_bits, vrf_id, table_id); diff --git a/sys/netinet/sctp_output.c b/sys/netinet/sctp_output.c index 3ec5245..39de2af 100644 --- a/sys/netinet/sctp_output.c +++ b/sys/netinet/sctp_output.c @@ -3445,6 +3445,7 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp, } } } + sctp_m_freem(m); return (EHOSTUNREACH); } if (ro != &iproute) { @@ -4282,10 +4283,12 @@ invalid_size: 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) { + 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; @@ -6112,6 +6115,7 @@ sctp_move_to_outqueue(struct sctp_tcb *stcb, struct sctp_nets *net, SCTP_TCB_LOCK_ASSERT(stcb); asoc = &stcb->asoc; one_more_time: + /* sa_ignore FREED_MEMORY */ sp = TAILQ_FIRST(&strq->outqueue); if (sp == NULL) { *locked = 0; @@ -10574,7 +10578,7 @@ sctp_lower_sosend(struct socket *so, error = EFAULT; goto out_unlocked; } - if ((uio == NULL) && (top == NULL)) { + if ((uio == NULL) && (i_pak == NULL)) { return (EINVAL); } atomic_add_int(&inp->total_sends, 1); diff --git a/sys/netinet/sctp_pcb.c b/sys/netinet/sctp_pcb.c index 09bdd2e..536ab72 100644 --- a/sys/netinet/sctp_pcb.c +++ b/sys/netinet/sctp_pcb.c @@ -1860,7 +1860,7 @@ sctp_inpcb_alloc(struct socket *so) sctp_timer_start(SCTP_TIMER_TYPE_NEWCOOKIE, inp, NULL, NULL); /* How long is a cookie good for ? */ - m->def_cookie_life = sctp_valid_cookie_life_default; + m->def_cookie_life = MSEC_TO_TICKS(sctp_valid_cookie_life_default); /* * Initialize authentication parameters */ @@ -1996,7 +1996,6 @@ sctp_isport_inuse(struct sctp_inpcb *inp, uint16_t lport, uint32_t vrf_id) head = &sctppcbinfo.sctp_ephash[SCTP_PCBHASH_ALLADDR(lport, sctppcbinfo.hashmark)]; - LIST_FOREACH(t_inp, head, sctp_hash) { if (t_inp->sctp_lport != lport) { continue; @@ -2106,9 +2105,7 @@ sctp_inpcb_bind(struct socket *so, struct sockaddr *addr, struct thread *p) return (EAFNOSUPPORT); } } - /* - * Setup a vrf_id to be the default for the non-bind-all case. - */ + /* Setup a vrf_id to be the default for the non-bind-all case. */ vrf_id = inp->def_vrf_id; SCTP_INP_INFO_WLOCK(); @@ -2210,11 +2207,12 @@ sctp_inpcb_bind(struct socket *so, struct sockaddr *addr, struct thread *p) if (port_attempt < IPPORT_RESERVED) { port_attempt += IPPORT_RESERVED; } + not_found = 1; vrf_id = inp->def_vrf_id; - if (sctp_isport_inuse(inp, htons(port_attempt), vrf_id) == 1) { + if (sctp_isport_inuse(inp, htons(port_attempt), + vrf_id) == 1) { /* got a port we can use */ not_found = 0; - break; } if (not_found == 1) { /* We can use this port */ @@ -2224,17 +2222,19 @@ sctp_inpcb_bind(struct socket *so, struct sockaddr *addr, struct thread *p) /* try upper half */ next_half: port_attempt = ((port_guess >> 16) & 0x0000ffff); + if (port_attempt == 0) { goto last_try; } if (port_attempt < IPPORT_RESERVED) { port_attempt += IPPORT_RESERVED; } + not_found = 1; vrf_id = inp->def_vrf_id; - if (sctp_isport_inuse(inp, htons(port_attempt), vrf_id) == 1) { + if (sctp_isport_inuse(inp, htons(port_attempt), + vrf_id) == 1) { /* got a port we can use */ not_found = 0; - break; } if (not_found == 1) { /* We can use this port */ @@ -2252,11 +2252,11 @@ sctp_inpcb_bind(struct socket *so, struct sockaddr *addr, struct thread *p) if (port_attempt < IPPORT_RESERVED) { port_attempt += IPPORT_RESERVED; } + not_found = 1; vrf_id = inp->def_vrf_id; if (sctp_isport_inuse(inp, htons(port_attempt), vrf_id) == 1) { /* got a port we can use */ not_found = 0; - break; } if (not_found == 1) { /* We can use this port */ @@ -2322,7 +2322,8 @@ sctp_inpcb_bind(struct socket *so, struct sockaddr *addr, struct thread *p) * zero out the port to find the address! yuck! can't do * this earlier since need port for sctp_pcb_findep() */ - ifa = sctp_find_ifa_by_addr((struct sockaddr *)&store_sa, vrf_id, 0); + ifa = sctp_find_ifa_by_addr((struct sockaddr *)&store_sa, + vrf_id, 0); if (ifa == NULL) { /* Can't find an interface with that address */ SCTP_INP_WUNLOCK(inp); @@ -2340,15 +2341,12 @@ sctp_inpcb_bind(struct socket *so, struct sockaddr *addr, struct thread *p) } /* we're not bound all */ inp->sctp_flags &= ~SCTP_PCB_FLAGS_BOUNDALL; - /* set the automatic addr changes from kernel flag */ + /* allow bindx() to send ASCONF's for binding changes */ sctp_feature_on(inp, SCTP_PCB_FLAGS_DO_ASCONF); + /* set the automatic addr changes from kernel flag */ if (sctp_auto_asconf == 0) { sctp_feature_off(inp, SCTP_PCB_FLAGS_AUTO_ASCONF); } else { - /* - * allow bindx() to send ASCONF's for binding - * changes - */ sctp_feature_on(inp, SCTP_PCB_FLAGS_AUTO_ASCONF); } @@ -2752,6 +2750,7 @@ sctp_inpcb_free(struct sctp_inpcb *inp, int immediate, int from) (void)SCTP_OS_TIMER_STOP(&inp->sctp_ep.signature_change.timer); inp->sctp_ep.signature_change.type = SCTP_TIMER_TYPE_NONE; /* Clear the read queue */ + /* sa_ignore FREED_MEMORY */ while ((sq = TAILQ_FIRST(&inp->read_queue)) != NULL) { /* Its only abandoned if it had data left */ if (sq->length) @@ -2813,6 +2812,7 @@ sctp_inpcb_free(struct sctp_inpcb *inp, int immediate, int from) while (shared_key) { LIST_REMOVE(shared_key, next); sctp_free_sharedkey(shared_key); + /* sa_ignore FREED_MEMORY */ shared_key = LIST_FIRST(&inp->sctp_ep.shared_keys); } @@ -3885,10 +3885,12 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre /* Free the zone stuff */ SCTP_ZONE_FREE(sctppcbinfo.ipi_zone_strmoq, sp); SCTP_DECR_STRMOQ_COUNT(); + /* sa_ignore FREED_MEMORY */ sp = TAILQ_FIRST(&outs->outqueue); } } + /* sa_ignore FREED_MEMORY */ while ((liste = TAILQ_FIRST(&asoc->resetHead)) != NULL) { TAILQ_REMOVE(&asoc->resetHead, liste, next_resp); SCTP_FREE(liste); @@ -3907,6 +3909,7 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre /* Free the ctl entry */ SCTP_ZONE_FREE(sctppcbinfo.ipi_zone_readq, sq); SCTP_DECR_READQ_COUNT(); + /* sa_ignore FREED_MEMORY */ sq = TAILQ_FIRST(&asoc->pending_reply_queue); } @@ -3922,6 +3925,7 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre SCTP_DECR_CHK_COUNT(); atomic_subtract_int(&sctppcbinfo.ipi_free_chunks, 1); asoc->free_chunk_cnt--; + /* sa_ignore FREED_MEMORY */ chk = TAILQ_FIRST(&asoc->free_chunks); } /* pending send queue SHOULD be empty */ @@ -3937,6 +3941,7 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre sctp_free_remote_addr(chk->whoTo); SCTP_ZONE_FREE(sctppcbinfo.ipi_zone_chunk, chk); SCTP_DECR_CHK_COUNT(); + /* sa_ignore FREED_MEMORY */ chk = TAILQ_FIRST(&asoc->send_queue); } } @@ -3959,6 +3964,7 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre sctp_free_remote_addr(chk->whoTo); SCTP_ZONE_FREE(sctppcbinfo.ipi_zone_chunk, chk); SCTP_DECR_CHK_COUNT(); + /* sa_ignore FREED_MEMORY */ chk = TAILQ_FIRST(&asoc->sent_queue); } } @@ -3981,6 +3987,7 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre sctp_free_remote_addr(chk->whoTo); SCTP_ZONE_FREE(sctppcbinfo.ipi_zone_chunk, chk); SCTP_DECR_CHK_COUNT(); + /* sa_ignore FREED_MEMORY */ chk = TAILQ_FIRST(&asoc->control_send_queue); } } @@ -4002,6 +4009,7 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre ccnt++; SCTP_ZONE_FREE(sctppcbinfo.ipi_zone_chunk, chk); SCTP_DECR_CHK_COUNT(); + /* sa_ignore FREED_MEMORY */ chk = TAILQ_FIRST(&asoc->reasmqueue); } } @@ -4052,6 +4060,7 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre } asoc->streamincnt = 0; while (!TAILQ_EMPTY(&asoc->nets)) { + /* sa_ignore FREED_MEMORY */ net = TAILQ_FIRST(&asoc->nets); /* pull from list */ if ((sctppcbinfo.ipi_count_raddr == 0) || (prev == net)) { @@ -4066,12 +4075,14 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre } while (!SCTP_LIST_EMPTY(&asoc->sctp_restricted_addrs)) { + /* sa_ignore FREED_MEMORY */ laddr = LIST_FIRST(&asoc->sctp_restricted_addrs); sctp_remove_laddr(laddr); } /* pending asconf (address) parameters */ while (!TAILQ_EMPTY(&asoc->asconf_queue)) { + /* sa_ignore FREED_MEMORY */ aparam = TAILQ_FIRST(&asoc->asconf_queue); TAILQ_REMOVE(&asoc->asconf_queue, aparam, next); SCTP_FREE(aparam); @@ -4097,6 +4108,7 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre while (shared_key) { LIST_REMOVE(shared_key, next); sctp_free_sharedkey(shared_key); + /* sa_ignore FREED_MEMORY */ shared_key = LIST_FIRST(&asoc->shared_keys); } @@ -5612,5 +5624,6 @@ sctp_initiate_iterator(inp_func inpf, sctp_timer_start(SCTP_TIMER_TYPE_ITERATOR, (struct sctp_inpcb *)it, NULL, NULL); #endif + /* sa_ignore MEMLEAK {memory is put on the tailq for the iterator} */ return (0); } diff --git a/sys/netinet/sctp_sysctl.c b/sys/netinet/sctp_sysctl.c index 13e0ab0..ce1ab45 100644 --- a/sys/netinet/sctp_sysctl.c +++ b/sys/netinet/sctp_sysctl.c @@ -195,6 +195,12 @@ sctp_assoclist(SYSCTL_HANDLER_ARGS) xinpcb.total_recvs = inp->total_recvs; xinpcb.total_nospaces = inp->total_nospaces; xinpcb.fragmentation_point = inp->sctp_frag_point; + if (inp->sctp_socket != NULL) { + sotoxsocket(inp->sctp_socket, &xinpcb.xsocket); + } else { + bzero(&xinpcb.xsocket, sizeof xinpcb.xsocket); + xinpcb.xsocket.xso_protocol = IPPROTO_SCTP; + } SCTP_INP_INCR_REF(inp); SCTP_INP_RUNLOCK(inp); SCTP_INP_INFO_RUNLOCK(); @@ -407,7 +413,7 @@ SYSCTL_UINT(_net_inet_sctp, OID_AUTO, init_rto_max, CTLFLAG_RW, SYSCTL_UINT(_net_inet_sctp, OID_AUTO, valid_cookie_life, CTLFLAG_RW, &sctp_valid_cookie_life_default, 0, - "Default cookie lifetime in sec"); + "Default cookie lifetime in ticks"); SYSCTL_UINT(_net_inet_sctp, OID_AUTO, init_rtx_max, CTLFLAG_RW, &sctp_init_rtx_max_default, 0, diff --git a/sys/netinet/sctp_timer.c b/sys/netinet/sctp_timer.c index b027f0b..d00ff79 100644 --- a/sys/netinet/sctp_timer.c +++ b/sys/netinet/sctp_timer.c @@ -346,6 +346,7 @@ sctp_find_alternate_net(struct sctp_tcb *stcb, if ( ((alt->dest_state & SCTP_ADDR_REACHABLE) == SCTP_ADDR_REACHABLE) && (alt->ro.ro_rt != NULL) && + /* sa_ignore NO_NULL_CHK */ (!(alt->dest_state & SCTP_ADDR_UNCONFIRMED)) ) { /* Found a reachable address */ @@ -368,6 +369,7 @@ sctp_find_alternate_net(struct sctp_tcb *stcb, } alt = TAILQ_FIRST(&stcb->asoc.nets); } + /* sa_ignore NO_NULL_CHK */ if ((!(alt->dest_state & SCTP_ADDR_UNCONFIRMED)) && (alt != net)) { /* Found an alternate address */ diff --git a/sys/netinet/sctp_uio.h b/sys/netinet/sctp_uio.h index 8a67a0e..f3e0836 100644 --- a/sys/netinet/sctp_uio.h +++ b/sys/netinet/sctp_uio.h @@ -42,6 +42,7 @@ __FBSDID("$FreeBSD$"); #include <sys/types.h> #include <sys/socket.h> #include <sys/time.h> +#include <sys/socketvar.h> #include <netinet/in.h> typedef uint32_t sctp_assoc_t; @@ -528,12 +529,8 @@ struct sctp_assoc_value { uint32_t assoc_value; }; -#define MAX_ASOC_IDS_RET 255 struct sctp_assoc_ids { - uint16_t asls_assoc_start; /* array of index's start at 0 */ - uint8_t asls_numb_present; - uint8_t asls_more_to_get; - sctp_assoc_t asls_assoc_id[MAX_ASOC_IDS_RET]; + sctp_assoc_t gaids_assoc_id[0]; }; struct sctp_cwnd_args { @@ -934,6 +931,7 @@ struct xsctp_inpcb { uint32_t total_recvs; uint32_t total_nospaces; uint32_t fragmentation_point; + struct xsocket xsocket; /* add more endpoint specific data here */ }; diff --git a/sys/netinet/sctp_usrreq.c b/sys/netinet/sctp_usrreq.c index f5bbbfc..b38a28b 100644 --- a/sys/netinet/sctp_usrreq.c +++ b/sys/netinet/sctp_usrreq.c @@ -1364,18 +1364,21 @@ sctp_do_connect_x(struct socket *so, struct sctp_inpcb *inp, void *optval, soisconnecting(so); } out_now: - if (creat_lock_on) + if (creat_lock_on) { SCTP_ASOC_CREATE_UNLOCK(inp); + } SCTP_INP_DECR_REF(inp); return error; } #define SCTP_FIND_STCB(inp, stcb, assoc_id) { \ - if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) { \ + if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||\ + (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) { \ SCTP_INP_RLOCK(inp); \ stcb = LIST_FIRST(&inp->sctp_asoc_list); \ - if (stcb) \ + if (stcb) { \ SCTP_TCB_LOCK(stcb); \ + } \ SCTP_INP_RUNLOCK(inp); \ } else if (assoc_id != 0) { \ stcb = sctp_findassociation_ep_asocid(inp, assoc_id, 1); \ @@ -1534,49 +1537,41 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize, *optsize = sizeof(*av); } break; - case SCTP_GET_ASOC_ID_LIST: + case SCTP_GET_ASSOC_NUMBER: { - struct sctp_assoc_ids *ids; - int cnt, at; - uint16_t orig; + uint32_t *value, cnt; - SCTP_CHECK_AND_CAST(ids, optval, struct sctp_assoc_ids, *optsize); + SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize); cnt = 0; SCTP_INP_RLOCK(inp); - stcb = LIST_FIRST(&inp->sctp_asoc_list); - if (stcb == NULL) { - none_out_now: - ids->asls_numb_present = 0; - ids->asls_more_to_get = 0; - SCTP_INP_RUNLOCK(inp); - break; - } - orig = ids->asls_assoc_start; - stcb = LIST_FIRST(&inp->sctp_asoc_list); - while (orig) { - stcb = LIST_NEXT(stcb, sctp_tcblist); - orig--; - cnt--; - if (stcb == NULL) - goto none_out_now; + LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { + cnt++; } - if (stcb == NULL) - goto none_out_now; + SCTP_INP_RUNLOCK(inp); + *value = cnt; + *optsize = sizeof(uint32_t); + } + break; + case SCTP_GET_ASSOC_ID_LIST: + { + struct sctp_assoc_ids *ids; + unsigned int at, limit; + + SCTP_CHECK_AND_CAST(ids, optval, struct sctp_assoc_ids, *optsize); at = 0; - ids->asls_numb_present = 0; - ids->asls_more_to_get = 1; - while (at < MAX_ASOC_IDS_RET) { - ids->asls_assoc_id[at] = sctp_get_associd(stcb); - at++; - ids->asls_numb_present++; - stcb = LIST_NEXT(stcb, sctp_tcblist); - if (stcb == NULL) { - ids->asls_more_to_get = 0; + limit = *optsize / sizeof(sctp_assoc_t); + SCTP_INP_RLOCK(inp); + LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { + if (at < limit) { + ids->gaids_assoc_id[at++] = sctp_get_associd(stcb); + } else { + error = EINVAL; break; } } SCTP_INP_RUNLOCK(inp); + *optsize = at * sizeof(sctp_assoc_t); } break; case SCTP_CONTEXT: @@ -1896,8 +1891,9 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize, sas = (struct sockaddr_storage *)&saddr->addr[0]; limit = *optsize - sizeof(sctp_assoc_t); actual = sctp_fill_up_addresses(inp, stcb, limit, sas); - if (stcb) + if (stcb) { SCTP_TCB_UNLOCK(stcb); + } *optsize = sizeof(struct sockaddr_storage) + actual; } break; @@ -2143,7 +2139,7 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize, sasoc->sasoc_number_peer_destinations = stcb->asoc.numnets; sasoc->sasoc_peer_rwnd = stcb->asoc.peers_rwnd; sasoc->sasoc_local_rwnd = stcb->asoc.my_rwnd; - sasoc->sasoc_cookie_life = stcb->asoc.cookie_life; + sasoc->sasoc_cookie_life = TICKS_TO_MSEC(stcb->asoc.cookie_life); sasoc->sasoc_sack_delay = stcb->asoc.delayed_ack; sasoc->sasoc_sack_freq = stcb->asoc.sack_freq; SCTP_TCB_UNLOCK(stcb); @@ -2153,7 +2149,7 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize, sasoc->sasoc_number_peer_destinations = 0; sasoc->sasoc_peer_rwnd = 0; sasoc->sasoc_local_rwnd = sbspace(&inp->sctp_socket->so_rcv); - sasoc->sasoc_cookie_life = inp->sctp_ep.def_cookie_life; + sasoc->sasoc_cookie_life = TICKS_TO_MSEC(inp->sctp_ep.def_cookie_life); sasoc->sasoc_sack_delay = TICKS_TO_MSEC(inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_RECV]); sasoc->sasoc_sack_freq = inp->sctp_ep.sctp_sack_freq; SCTP_INP_RUNLOCK(inp); @@ -3146,31 +3142,53 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, case SCTP_RTOINFO: { struct sctp_rtoinfo *srto; + uint32_t new_init, new_min, new_max; SCTP_CHECK_AND_CAST(srto, optval, struct sctp_rtoinfo, optsize); SCTP_FIND_STCB(inp, stcb, srto->srto_assoc_id); if (stcb) { - /* Set in ms we hope :-) */ if (srto->srto_initial) - stcb->asoc.initial_rto = srto->srto_initial; + new_init = srto->srto_initial; + else + new_init = stcb->asoc.initial_rto; if (srto->srto_max) - stcb->asoc.maxrto = srto->srto_max; + new_max = srto->srto_max; + else + new_max = stcb->asoc.maxrto; if (srto->srto_min) - stcb->asoc.minrto = srto->srto_min; + new_min = srto->srto_min; + else + new_min = stcb->asoc.minrto; + if ((new_min <= new_init) && (new_init <= new_max)) { + stcb->asoc.initial_rto = new_init; + stcb->asoc.maxrto = new_max; + stcb->asoc.minrto = new_min; + } else { + error = EDOM; + } SCTP_TCB_UNLOCK(stcb); } else { SCTP_INP_WLOCK(inp); - /* - * If we have a null asoc, its default for - * the endpoint - */ if (srto->srto_initial) - inp->sctp_ep.initial_rto = srto->srto_initial; + new_init = srto->srto_initial; + else + new_init = inp->sctp_ep.initial_rto; if (srto->srto_max) - inp->sctp_ep.sctp_maxrto = srto->srto_max; + new_max = srto->srto_max; + else + new_max = inp->sctp_ep.sctp_maxrto; if (srto->srto_min) - inp->sctp_ep.sctp_minrto = srto->srto_min; + new_min = srto->srto_min; + else + new_min = inp->sctp_ep.sctp_minrto; + if ((new_min <= new_init) && (new_init <= new_max)) { + inp->sctp_ep.initial_rto = new_init; + inp->sctp_ep.sctp_maxrto = new_max; + inp->sctp_ep.sctp_minrto = new_min; + } else { + error = EDOM; + } SCTP_INP_WUNLOCK(inp); } } @@ -3188,8 +3206,8 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, sasoc->sasoc_number_peer_destinations = stcb->asoc.numnets; sasoc->sasoc_peer_rwnd = 0; sasoc->sasoc_local_rwnd = 0; - if (stcb->asoc.cookie_life) - stcb->asoc.cookie_life = sasoc->sasoc_cookie_life; + if (sasoc->sasoc_cookie_life) + stcb->asoc.cookie_life = MSEC_TO_TICKS(sasoc->sasoc_cookie_life); stcb->asoc.delayed_ack = sasoc->sasoc_sack_delay; if (sasoc->sasoc_sack_freq) { stcb->asoc.sack_freq = sasoc->sasoc_sack_freq; @@ -3203,7 +3221,7 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, sasoc->sasoc_peer_rwnd = 0; sasoc->sasoc_local_rwnd = 0; if (sasoc->sasoc_cookie_life) - inp->sctp_ep.def_cookie_life = sasoc->sasoc_cookie_life; + inp->sctp_ep.def_cookie_life = MSEC_TO_TICKS(sasoc->sasoc_cookie_life); inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_RECV] = MSEC_TO_TICKS(sasoc->sasoc_sack_delay); if (sasoc->sasoc_sack_freq) { inp->sctp_ep.sctp_sack_freq = sasoc->sasoc_sack_freq; @@ -3419,8 +3437,9 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, */ if (addrs->sget_assoc_id == 0) { /* delete the address */ - (void)sctp_addr_mgmt_ep_sa(inp, addr_touse, - SCTP_DEL_IP_ADDRESS, vrf_id); + error = sctp_addr_mgmt_ep_sa(inp, addr_touse, + SCTP_DEL_IP_ADDRESS, + vrf_id); } else { /* * FIX: decide whether we allow assoc based diff --git a/sys/netinet/sctputil.c b/sys/netinet/sctputil.c index 0a2d4f4..f3c685a 100644 --- a/sys/netinet/sctputil.c +++ b/sys/netinet/sctputil.c @@ -1292,6 +1292,7 @@ again: SCTP_IPI_ITERATOR_WQ_UNLOCK(); sctp_iterator_work(it); SCTP_IPI_ITERATOR_WQ_LOCK(); + /* sa_ignore FREED_MEMORY */ it = TAILQ_FIRST(&sctppcbinfo.iteratorhead); } if (TAILQ_FIRST(&sctppcbinfo.iteratorhead)) { @@ -1859,7 +1860,7 @@ sctp_timer_start(int t_type, struct sctp_inpcb *inp, struct sctp_tcb *stcb, } } if (cnt_of_unconf) { - lnet = NULL; + net = lnet = NULL; (void)sctp_heartbeat_timer(inp, stcb, lnet, cnt_of_unconf); } if (stcb->asoc.hb_random_idx > 3) { @@ -2745,7 +2746,7 @@ sctp_notify_assoc_change(uint32_t event, struct sctp_tcb *stcb, */ if (((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) && - ((event == SCTP_COMM_LOST) || (event == SCTP_SHUTDOWN_COMP))) { + ((event == SCTP_COMM_LOST) || (event == SCTP_CANT_STR_ASSOC))) { if (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_COOKIE_WAIT) stcb->sctp_socket->so_error = ECONNREFUSED; else @@ -3444,6 +3445,7 @@ sctp_report_all_outbound(struct sctp_tcb *stcb, int holds_lock) sp->net = NULL; /* Free the chunk */ sctp_free_a_strmoq(stcb, sp); + /* sa_ignore FREED_MEMORY */ sp = TAILQ_FIRST(&outs->outqueue); } } @@ -3474,6 +3476,7 @@ sctp_report_all_outbound(struct sctp_tcb *stcb, int holds_lock) sctp_free_remote_addr(chk->whoTo); chk->whoTo = NULL; sctp_free_a_chunk(stcb, chk); + /* sa_ignore FREED_MEMORY */ chk = TAILQ_FIRST(&asoc->send_queue); } } @@ -3504,6 +3507,7 @@ sctp_report_all_outbound(struct sctp_tcb *stcb, int holds_lock) sctp_free_remote_addr(chk->whoTo); chk->whoTo = NULL; sctp_free_a_chunk(stcb, chk); + /* sa_ignore FREED_MEMORY */ chk = TAILQ_FIRST(&asoc->sent_queue); } } @@ -4782,6 +4786,7 @@ restart_nosblocks: hold_sblock = 0; } /* we possibly have data we can read */ + /* sa_ignore FREED_MEMORY */ control = TAILQ_FIRST(&inp->read_queue); if (control == NULL) { /* diff --git a/sys/netinet6/sctp6_usrreq.c b/sys/netinet6/sctp6_usrreq.c index 58fb8a5..1a5e411 100644 --- a/sys/netinet6/sctp6_usrreq.c +++ b/sys/netinet6/sctp6_usrreq.c @@ -217,6 +217,7 @@ sctp_skip_csum: /* Length now holds the total packet length payload + iphlen */ length = ntohs(ip6->ip6_plen) + iphlen; + /* sa_ignore NO_NULL_CHK */ sctp_common_input_processing(&m, iphlen, offset, length, sh, ch, in6p, stcb, net, ecn_bits, vrf_id, table_id); /* inp's ref-count reduced && stcb unlocked */ |