summaryrefslogtreecommitdiffstats
path: root/sys/netinet/sctp_indata.c
diff options
context:
space:
mode:
authortuexen <tuexen@FreeBSD.org>2016-07-24 14:50:16 +0000
committertuexen <tuexen@FreeBSD.org>2016-07-24 14:50:16 +0000
commit39957276ecb5c9ba6ee716252ccd42d87bf38b80 (patch)
treea148d4cafbdcb3395be30594f3c982a3ecdfc79d /sys/netinet/sctp_indata.c
parentd962282f9d8ffeb4d2ee88155ecb9477283f76d2 (diff)
downloadFreeBSD-src-39957276ecb5c9ba6ee716252ccd42d87bf38b80.zip
FreeBSD-src-39957276ecb5c9ba6ee716252ccd42d87bf38b80.tar.gz
MFC r302904:
Fix a bug which results in a core dump when running netstat with the -W option and having a listening SCTP socket. The bug was introduced in r279122 when adding support for libxo. MFC r302907: When calling netstat -Laptcp the local address values are not aligned with the corresponding entry in the table header. r295136 increased the value width from 14 to 32 without the corresponding change to the table header. This commit adds the change to the table header width. MFC r302917: Ensure that the -a, -W, -L options for SCTP behave similar as for TCP. MFC r302928: Address a potential memory leak found a the clang static code analyzer running on the userland stack. MFC r302930: Don't free a data chunk twice. Found by the clang static code analyzer running for the userland stack. MFC r302935: Deal with a portential memory allocation failure, which was reported by the clang static code analyzer. Joint work with rrs@. MFC r302942: Add missing sctps_reasmusrmsgs counter. Joint work with rrs@. MFC r302945: Don't duplicate code for SCTP, just use the ones used for UDP and TCP. This fixes a bug with link local addresses. This will require and upcoming change in the kernel to bring SCTP to the same behaviour as UDP and TCP. MFC r302949: Fix the PR-SCTP behaviour. This is done by rrs@. MFC r302950: Add a constant required by RFC 7496. MFC r303024: netstat and sockstat expect the IPv6 link local addresses to have an embedded scope. So don't recover. MFC r303025: Use correct order of conditions to avoid NULL deref. MFC r303073: Fix a bug in deferred stream reset processing which results in using a length field before it is set. Thanks to Taylor Brandstetter for reporting the issue and providing a fix. Approved by: re (kib)
Diffstat (limited to 'sys/netinet/sctp_indata.c')
-rw-r--r--sys/netinet/sctp_indata.c39
1 files changed, 27 insertions, 12 deletions
diff --git a/sys/netinet/sctp_indata.c b/sys/netinet/sctp_indata.c
index 7a2f42c..357a047 100644
--- a/sys/netinet/sctp_indata.c
+++ b/sys/netinet/sctp_indata.c
@@ -753,7 +753,7 @@ sctp_handle_old_data(struct sctp_tcb *stcb, struct sctp_association *asoc, struc
*/
struct sctp_tmit_chunk *chk, *lchk, *tchk;
uint32_t fsn;
- struct sctp_queued_to_read *nc = NULL;
+ struct sctp_queued_to_read *nc;
int cnt_added;
if (control->first_frag_seen == 0) {
@@ -768,6 +768,11 @@ restart:
TAILQ_FOREACH_SAFE(chk, &control->reasm, sctp_next, lchk) {
if (chk->rec.data.fsn_num == fsn) {
/* Ok lets add it */
+ sctp_alloc_a_readq(stcb, nc);
+ if (nc == NULL) {
+ break;
+ }
+ memset(nc, 0, sizeof(struct sctp_queued_to_read));
TAILQ_REMOVE(&control->reasm, chk, sctp_next);
sctp_add_chk_to_control(control, strm, stcb, asoc, chk);
fsn++;
@@ -781,7 +786,6 @@ restart:
* on the control queue to a new
* control.
*/
- sctp_alloc_a_readq(stcb, nc);
sctp_build_readq_entry_from_ctl(nc, control);
tchk = TAILQ_FIRST(&control->reasm);
if (tchk->rec.data.rcv_flags & SCTP_DATA_FIRST_FRAG) {
@@ -819,6 +823,7 @@ restart:
if (control->on_strm_q) {
TAILQ_REMOVE(&strm->uno_inqueue, control, next_instrm);
control->on_strm_q = 0;
+ SCTP_STAT_INCR_COUNTER64(sctps_reasmusrmsgs);
}
if (control->on_read_q == 0) {
sctp_add_to_readq(stcb->sctp_ep, stcb, control,
@@ -826,16 +831,19 @@ restart:
SCTP_READ_LOCK_NOT_HELD, SCTP_SO_NOT_LOCKED);
}
sctp_wakeup_the_read_socket(stcb->sctp_ep, stcb, SCTP_SO_NOT_LOCKED);
- if ((nc) && (nc->first_frag_seen)) {
+ if ((nc->first_frag_seen) && !TAILQ_EMPTY(&nc->reasm)) {
/*
* Switch to the new guy and
* continue
*/
control = nc;
- nc = NULL;
goto restart;
+ } else {
+ sctp_free_a_readq(stcb, nc);
}
return (1);
+ } else {
+ sctp_free_a_readq(stcb, nc);
}
} else {
/* Can't add more */
@@ -961,11 +969,6 @@ place_chunk:
* should not happen since the FSN is a TSN and it
* should have been dropped earlier.
*/
- if (chk->data) {
- sctp_m_freem(chk->data);
- chk->data = NULL;
- }
- sctp_free_a_chunk(stcb, chk, SCTP_SO_NOT_LOCKED);
sctp_abort_in_reasm(stcb, control, chk,
abort_flag,
SCTP_FROM_SCTP_INDATA + SCTP_LOC_5);
@@ -1026,6 +1029,7 @@ sctp_deliver_reasm_check(struct sctp_tcb *stcb, struct sctp_association *asoc, s
control, control->on_strm_q);
}
#endif
+ SCTP_STAT_INCR_COUNTER64(sctps_reasmusrmsgs);
TAILQ_REMOVE(&strm->uno_inqueue, control, next_instrm);
control->on_strm_q = 0;
}
@@ -1080,6 +1084,7 @@ done_un:
control, control->on_strm_q);
}
#endif
+ SCTP_STAT_INCR_COUNTER64(sctps_reasmusrmsgs);
TAILQ_REMOVE(&strm->inqueue, control, next_instrm);
control->on_strm_q = 0;
}
@@ -1125,6 +1130,7 @@ deliver_more:
control, control->on_strm_q);
}
#endif
+ SCTP_STAT_INCR_COUNTER64(sctps_reasmusrmsgs);
TAILQ_REMOVE(&strm->inqueue, control, next_instrm);
control->on_strm_q = 0;
}
@@ -5277,10 +5283,11 @@ sctp_kick_prsctp_reorder_queue(struct sctp_tcb *stcb,
}
}
+
static void
sctp_flush_reassm_for_str_seq(struct sctp_tcb *stcb,
struct sctp_association *asoc,
- uint16_t stream, uint32_t seq)
+ uint16_t stream, uint32_t seq, int ordered, int old)
{
struct sctp_queued_to_read *control;
struct sctp_stream_in *strm;
@@ -5295,7 +5302,7 @@ sctp_flush_reassm_for_str_seq(struct sctp_tcb *stcb,
* queue.
*/
strm = &asoc->strmin[stream];
- control = find_reasm_entry(strm, (uint32_t) seq, 0, 0);
+ control = find_reasm_entry(strm, (uint32_t) seq, ordered, old);
if (control == NULL) {
/* Not found */
return;
@@ -5427,6 +5434,7 @@ sctp_handle_forward_tsn(struct sctp_tcb *stcb,
unsigned int num_str;
uint32_t sequence;
uint16_t stream;
+ uint16_t ordered, flags;
int old;
struct sctp_strseq *stseq, strseqbuf;
struct sctp_strseq_mid *stseq_m, strseqbuf_m;
@@ -5452,6 +5460,12 @@ sctp_handle_forward_tsn(struct sctp_tcb *stcb,
}
stream = ntohs(stseq_m->stream);
sequence = ntohl(stseq_m->msg_id);
+ flags = ntohs(stseq_m->flags);
+ if (flags & PR_SCTP_UNORDERED_FLAG) {
+ ordered = 0;
+ } else {
+ ordered = 1;
+ }
} else {
stseq = (struct sctp_strseq *)sctp_m_getptr(m, offset,
sizeof(struct sctp_strseq),
@@ -5462,6 +5476,7 @@ sctp_handle_forward_tsn(struct sctp_tcb *stcb,
}
stream = ntohs(stseq->stream);
sequence = (uint32_t) ntohs(stseq->sequence);
+ ordered = 1;
}
/* Convert */
@@ -5487,7 +5502,7 @@ sctp_handle_forward_tsn(struct sctp_tcb *stcb,
asoc->fragmented_delivery_inprogress = 0;
}
strm = &asoc->strmin[stream];
- sctp_flush_reassm_for_str_seq(stcb, asoc, stream, sequence);
+ sctp_flush_reassm_for_str_seq(stcb, asoc, stream, sequence, ordered, old);
TAILQ_FOREACH(ctl, &stcb->sctp_ep->read_queue, next) {
if ((ctl->sinfo_stream == stream) &&
(ctl->sinfo_ssn == sequence)) {
OpenPOWER on IntegriCloud