summaryrefslogtreecommitdiffstats
path: root/sys/netinet/sctp_input.c
diff options
context:
space:
mode:
authorrrs <rrs@FreeBSD.org>2007-06-22 13:50:56 +0000
committerrrs <rrs@FreeBSD.org>2007-06-22 13:50:56 +0000
commitcdfbc0147192329ec8c28c33e01dc1ba04756b5a (patch)
tree2b354542a2dde75a52870cd61eab47d12ffb8788 /sys/netinet/sctp_input.c
parent2f486f25b672cff71428e86c7369dbc7ed9d21a5 (diff)
downloadFreeBSD-src-cdfbc0147192329ec8c28c33e01dc1ba04756b5a.zip
FreeBSD-src-cdfbc0147192329ec8c28c33e01dc1ba04756b5a.tar.gz
- Fix stream reset so it limits the number of streams that can be listed
- Fix fwd-tsn to use proper accessor so it does not overrun mbufs - Fix stream reset error reporting to actually work (it has always been broken if the peer rejects a stream reset) - Some 64 bit friendly changes Approved by: re(bmah@freebsd.org)
Diffstat (limited to 'sys/netinet/sctp_input.c')
-rw-r--r--sys/netinet/sctp_input.c60
1 files changed, 45 insertions, 15 deletions
diff --git a/sys/netinet/sctp_input.c b/sys/netinet/sctp_input.c
index 0dc56f7..e3d49bd 100644
--- a/sys/netinet/sctp_input.c
+++ b/sys/netinet/sctp_input.c
@@ -2832,7 +2832,7 @@ sctp_handle_stream_reset_response(struct sctp_tcb *stcb,
fwdtsn.ch.chunk_length = htons(sizeof(struct sctp_forward_tsn_chunk));
fwdtsn.ch.chunk_type = SCTP_FORWARD_CUM_TSN;
fwdtsn.new_cumulative_tsn = htonl(ntohl(resp->senders_next_tsn) - 1);
- sctp_handle_forward_tsn(stcb, &fwdtsn, &abort_flag);
+ sctp_handle_forward_tsn(stcb, &fwdtsn, &abort_flag, NULL, 0);
if (abort_flag) {
return (1);
}
@@ -2860,7 +2860,7 @@ sctp_handle_stream_reset_response(struct sctp_tcb *stcb,
static void
sctp_handle_str_reset_request_in(struct sctp_tcb *stcb,
struct sctp_tmit_chunk *chk,
- struct sctp_stream_reset_in_request *req)
+ struct sctp_stream_reset_in_request *req, int trunc)
{
uint32_t seq;
int len, i;
@@ -2875,7 +2875,12 @@ sctp_handle_str_reset_request_in(struct sctp_tcb *stcb,
seq = ntohl(req->request_seq);
if (asoc->str_reset_seq_in == seq) {
- if (stcb->asoc.stream_reset_out_is_outstanding == 0) {
+ if (trunc) {
+ /* Can't do it, since they exceeded our buffer size */
+ asoc->last_reset_action[1] = asoc->last_reset_action[0];
+ asoc->last_reset_action[0] = SCTP_STREAM_RESET_DENIED;
+ sctp_add_stream_reset_result(chk, seq, asoc->last_reset_action[0]);
+ } else if (stcb->asoc.stream_reset_out_is_outstanding == 0) {
len = ntohs(req->ph.param_length);
number_entries = ((len - sizeof(struct sctp_stream_reset_in_request)) / sizeof(uint16_t));
for (i = 0; i < number_entries; i++) {
@@ -2930,7 +2935,7 @@ sctp_handle_str_reset_request_tsn(struct sctp_tcb *stcb,
fwdtsn.ch.chunk_type = SCTP_FORWARD_CUM_TSN;
fwdtsn.ch.chunk_flags = 0;
fwdtsn.new_cumulative_tsn = htonl(stcb->asoc.highest_tsn_inside_map + 1);
- sctp_handle_forward_tsn(stcb, &fwdtsn, &abort_flag);
+ sctp_handle_forward_tsn(stcb, &fwdtsn, &abort_flag, NULL, 0);
if (abort_flag) {
return (1);
}
@@ -2975,7 +2980,7 @@ sctp_handle_str_reset_request_tsn(struct sctp_tcb *stcb,
static void
sctp_handle_str_reset_request_out(struct sctp_tcb *stcb,
struct sctp_tmit_chunk *chk,
- struct sctp_stream_reset_out_request *req)
+ struct sctp_stream_reset_out_request *req, int trunc)
{
uint32_t seq, tsn;
int number_entries, len;
@@ -2998,7 +3003,10 @@ sctp_handle_str_reset_request_out(struct sctp_tcb *stcb,
/* move the reset action back one */
asoc->last_reset_action[1] = asoc->last_reset_action[0];
- if ((tsn == asoc->cumulative_tsn) ||
+ if (trunc) {
+ sctp_add_stream_reset_result(chk, seq, SCTP_STREAM_RESET_DENIED);
+ asoc->last_reset_action[0] = SCTP_STREAM_RESET_DENIED;
+ } else if ((tsn == asoc->cumulative_tsn) ||
(compare_with_wrap(asoc->cumulative_tsn, tsn, MAX_TSN))) {
/* we can do it now */
sctp_reset_in_stream(stcb, number_entries, req->list_of_streams);
@@ -3047,12 +3055,20 @@ sctp_handle_str_reset_request_out(struct sctp_tcb *stcb,
}
}
-static int
-sctp_handle_stream_reset(struct sctp_tcb *stcb, struct sctp_stream_reset_out_req *sr_req)
+#ifdef __GNUC__
+__attribute__((noinline))
+#endif
+ static int
+ sctp_handle_stream_reset(struct sctp_tcb *stcb, struct mbuf *m, int offset,
+ struct sctp_stream_reset_out_req *sr_req)
{
int chk_length, param_len, ptype;
+ struct sctp_paramhdr pstore;
+ uint8_t cstore[SCTP_CHUNK_BUFFER_SIZE];
+
uint32_t seq;
int num_req = 0;
+ int trunc = 0;
struct sctp_tmit_chunk *chk;
struct sctp_chunkhdr *ch;
struct sctp_paramhdr *ph;
@@ -3096,15 +3112,26 @@ strres_nochunk:
ch->chunk_flags = 0;
ch->chunk_length = htons(chk->send_size);
SCTP_BUF_LEN(chk->data) = SCTP_SIZE32(chk->send_size);
- ph = (struct sctp_paramhdr *)&sr_req->sr_req;
+ offset += sizeof(struct sctp_chunkhdr);
while ((size_t)chk_length >= sizeof(struct sctp_stream_reset_tsn_request)) {
+ ph = (struct sctp_paramhdr *)sctp_m_getptr(m, offset, sizeof(pstore), (uint8_t *) & pstore);
+ if (ph == NULL)
+ break;
param_len = ntohs(ph->param_length);
if (param_len < (int)sizeof(struct sctp_stream_reset_tsn_request)) {
/* bad param */
break;
}
+ ph = (struct sctp_paramhdr *)sctp_m_getptr(m, offset, min(param_len, sizeof(cstore)),
+ (uint8_t *) & cstore);
ptype = ntohs(ph->param_type);
num_param++;
+ if (param_len > sizeof(cstore)) {
+ trunc = 1;
+ } else {
+ trunc = 0;
+ }
+
if (num_param > SCTP_MAX_RESET_PARAMS) {
/* hit the max of parameters already sorry.. */
break;
@@ -3121,18 +3148,22 @@ strres_nochunk:
(void)sctp_handle_stream_reset_response(stcb, seq, SCTP_STREAM_RESET_PERFORMED, NULL);
}
}
- sctp_handle_str_reset_request_out(stcb, chk, req_out);
+ sctp_handle_str_reset_request_out(stcb, chk, req_out, trunc);
} else if (ptype == SCTP_STR_RESET_IN_REQUEST) {
struct sctp_stream_reset_in_request *req_in;
num_req++;
+
+
req_in = (struct sctp_stream_reset_in_request *)ph;
- sctp_handle_str_reset_request_in(stcb, chk, req_in);
+
+ sctp_handle_str_reset_request_in(stcb, chk, req_in, trunc);
} else if (ptype == SCTP_STR_RESET_TSN_REQUEST) {
struct sctp_stream_reset_tsn_request *req_tsn;
num_req++;
req_tsn = (struct sctp_stream_reset_tsn_request *)ph;
+
if (sctp_handle_str_reset_request_tsn(stcb, chk, req_tsn)) {
ret_code = 1;
goto strres_nochunk;
@@ -3153,8 +3184,7 @@ strres_nochunk:
} else {
break;
}
-
- ph = (struct sctp_paramhdr *)((caddr_t)ph + SCTP_SIZE32(param_len));
+ offset += SCTP_SIZE32(param_len);
chk_length -= SCTP_SIZE32(param_len);
}
if (num_req == 0) {
@@ -4223,7 +4253,7 @@ process_control_chunks:
return (NULL);
}
sctp_handle_forward_tsn(stcb,
- (struct sctp_forward_tsn_chunk *)ch, &abort_flag);
+ (struct sctp_forward_tsn_chunk *)ch, &abort_flag, m, *offset);
if (abort_flag) {
*offset = length;
return (NULL);
@@ -4257,7 +4287,7 @@ process_control_chunks:
*/
stcb->asoc.peer_supports_strreset = 1;
}
- if (sctp_handle_stream_reset(stcb, (struct sctp_stream_reset_out_req *)ch)) {
+ if (sctp_handle_stream_reset(stcb, m, *offset, (struct sctp_stream_reset_out_req *)ch)) {
/* stop processing */
*offset = length;
return (NULL);
OpenPOWER on IntegriCloud