summaryrefslogtreecommitdiffstats
path: root/sys
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
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')
-rw-r--r--sys/netinet/sctp_auth.c9
-rw-r--r--sys/netinet/sctp_constants.h1
-rw-r--r--sys/netinet/sctp_header.h2
-rw-r--r--sys/netinet/sctp_indata.c39
-rw-r--r--sys/netinet/sctp_output.c11
-rw-r--r--sys/netinet/sctp_sysctl.c9
-rw-r--r--sys/netinet/sctp_uio.h3
7 files changed, 44 insertions, 30 deletions
diff --git a/sys/netinet/sctp_auth.c b/sys/netinet/sctp_auth.c
index 07dbf8b..1c9d528 100644
--- a/sys/netinet/sctp_auth.c
+++ b/sys/netinet/sctp_auth.c
@@ -542,7 +542,7 @@ sctp_insert_sharedkey(struct sctp_keyhead *shared_keys,
}
}
/* shouldn't reach here */
- return (0);
+ return (EINVAL);
}
void
@@ -622,8 +622,11 @@ sctp_copy_skeylist(const struct sctp_keyhead *src, struct sctp_keyhead *dest)
LIST_FOREACH(skey, src, next) {
new_skey = sctp_copy_sharedkey(skey);
if (new_skey != NULL) {
- (void)sctp_insert_sharedkey(dest, new_skey);
- count++;
+ if (sctp_insert_sharedkey(dest, new_skey)) {
+ sctp_free_sharedkey(new_skey);
+ } else {
+ count++;
+ }
}
}
return (count);
diff --git a/sys/netinet/sctp_constants.h b/sys/netinet/sctp_constants.h
index a58c206..ecde4fe 100644
--- a/sys/netinet/sctp_constants.h
+++ b/sys/netinet/sctp_constants.h
@@ -345,6 +345,7 @@ __FBSDID("$FreeBSD$");
#define SCTP_RTT_FROM_NON_DATA 0
#define SCTP_RTT_FROM_DATA 1
+#define PR_SCTP_UNORDERED_FLAG 0x0001
/* IP hdr (20/40) + 12+2+2 (enet) + sctp common 12 */
#define SCTP_FIRST_MBUF_RESV 68
diff --git a/sys/netinet/sctp_header.h b/sys/netinet/sctp_header.h
index 850290d..3f4948d 100644
--- a/sys/netinet/sctp_header.h
+++ b/sys/netinet/sctp_header.h
@@ -397,7 +397,7 @@ struct sctp_strseq {
struct sctp_strseq_mid {
uint16_t stream;
- uint16_t reserved;
+ uint16_t flags;
uint32_t msg_id;
};
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)) {
diff --git a/sys/netinet/sctp_output.c b/sys/netinet/sctp_output.c
index d8c3cae..1ad3d0c 100644
--- a/sys/netinet/sctp_output.c
+++ b/sys/netinet/sctp_output.c
@@ -10383,7 +10383,7 @@ sctp_fill_in_rest:
/* no more to look at */
break;
}
- if (at->rec.data.rcv_flags & SCTP_DATA_UNORDERED) {
+ if ((at->rec.data.rcv_flags & SCTP_DATA_UNORDERED) && old) {
/* We don't report these */
continue;
}
@@ -10504,7 +10504,7 @@ sctp_fill_in_rest:
tp1 = TAILQ_NEXT(at, sctp_next);
if (tp1 == NULL)
break;
- if (at->rec.data.rcv_flags & SCTP_DATA_UNORDERED) {
+ if (old && (at->rec.data.rcv_flags & SCTP_DATA_UNORDERED)) {
/* We don't report these */
i--;
at = tp1;
@@ -10519,8 +10519,11 @@ sctp_fill_in_rest:
strseq++;
} else {
strseq_m->stream = ntohs(at->rec.data.stream_number);
- strseq_m->reserved = ntohs(0);
strseq_m->msg_id = ntohl(at->rec.data.stream_seq);
+ if (at->rec.data.rcv_flags & SCTP_DATA_UNORDERED)
+ strseq_m->flags = ntohs(PR_SCTP_UNORDERED_FLAG);
+ else
+ strseq_m->flags = 0;
strseq_m++;
}
at = tp1;
@@ -11937,7 +11940,6 @@ sctp_send_deferred_reset_response(struct sctp_tcb *stcb,
return;
}
SCTP_BUF_RESV_UF(chk->data, SCTP_MIN_OVERHEAD);
- sctp_add_stream_reset_result(chk, ent->seq, response);
/* setup chunk parameters */
chk->sent = SCTP_DATAGRAM_UNSENT;
chk->snd_count = 0;
@@ -11952,6 +11954,7 @@ sctp_send_deferred_reset_response(struct sctp_tcb *stcb,
ch->chunk_length = htons(chk->book_size);
atomic_add_int(&chk->whoTo->ref_count, 1);
SCTP_BUF_LEN(chk->data) = chk->send_size;
+ sctp_add_stream_reset_result(chk, ent->seq, response);
/* insert the chunk for sending */
TAILQ_INSERT_TAIL(&asoc->control_send_queue,
chk,
diff --git a/sys/netinet/sctp_sysctl.c b/sys/netinet/sctp_sysctl.c
index aeb2e10..de21941 100644
--- a/sys/netinet/sctp_sysctl.c
+++ b/sys/netinet/sctp_sysctl.c
@@ -279,15 +279,6 @@ sctp_sysctl_copy_out_local_addresses(struct sctp_inpcb *inp, struct sctp_tcb *st
if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
if (local_scope == 0)
continue;
- if (sin6->sin6_scope_id == 0) {
- /*
- * bad link
- * local
- * address
- */
- if (sa6_recoverscope(sin6) != 0)
- continue;
- }
}
if ((site_scope == 0) && (IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr)))
continue;
diff --git a/sys/netinet/sctp_uio.h b/sys/netinet/sctp_uio.h
index c7e441d..e65b7b5 100644
--- a/sys/netinet/sctp_uio.h
+++ b/sys/netinet/sctp_uio.h
@@ -259,7 +259,8 @@ struct sctp_snd_all_completes {
/* The lower four bits is an enumeration of PR-SCTP policies */
#define SCTP_PR_SCTP_NONE 0x0000/* Reliable transfer */
#define SCTP_PR_SCTP_TTL 0x0001/* Time based PR-SCTP */
-#define SCTP_PR_SCTP_BUF 0x0002/* Buffer based PR-SCTP */
+#define SCTP_PR_SCTP_PRIO 0x0002/* Buffer based PR-SCTP */
+#define SCTP_PR_SCTP_BUF SCTP_PR_SCTP_PRIO /* For backwards compatibility */
#define SCTP_PR_SCTP_RTX 0x0003/* Number of retransmissions based PR-SCTP */
#define SCTP_PR_SCTP_MAX SCTP_PR_SCTP_RTX
#define SCTP_PR_SCTP_ALL 0x000f/* Used for aggregated stats */
OpenPOWER on IntegriCloud