aboutsummaryrefslogtreecommitdiff
path: root/third_party/usrsctp/usrsctplib/usrsctplib/netinet/sctp_input.c
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/usrsctp/usrsctplib/usrsctplib/netinet/sctp_input.c')
-rwxr-xr-xthird_party/usrsctp/usrsctplib/usrsctplib/netinet/sctp_input.c545
1 files changed, 253 insertions, 292 deletions
diff --git a/third_party/usrsctp/usrsctplib/usrsctplib/netinet/sctp_input.c b/third_party/usrsctp/usrsctplib/usrsctplib/netinet/sctp_input.c
index f3c3644855..fb6e4c23eb 100755
--- a/third_party/usrsctp/usrsctplib/usrsctplib/netinet/sctp_input.c
+++ b/third_party/usrsctp/usrsctplib/usrsctplib/netinet/sctp_input.c
@@ -108,57 +108,12 @@ sctp_handle_init(struct mbuf *m, int iphlen, int offset,
if (stcb == NULL) {
SCTP_INP_RLOCK(inp);
}
- /* validate length */
- if (ntohs(cp->ch.chunk_length) < sizeof(struct sctp_init_chunk)) {
- op_err = sctp_generate_cause(SCTP_CAUSE_INVALID_PARAM, "");
- sctp_abort_association(inp, stcb, m, iphlen, src, dst, sh, op_err,
-#if defined(__FreeBSD__) && !defined(__Userspace__)
- mflowtype, mflowid,
-#endif
- vrf_id, port);
- if (stcb)
- *abort_no_unlock = 1;
- goto outnow;
- }
- /* validate parameters */
+ /* Validate parameters */
init = &cp->init;
- if (init->initiate_tag == 0) {
- /* protocol error... send abort */
- op_err = sctp_generate_cause(SCTP_CAUSE_INVALID_PARAM, "");
- sctp_abort_association(inp, stcb, m, iphlen, src, dst, sh, op_err,
-#if defined(__FreeBSD__) && !defined(__Userspace__)
- mflowtype, mflowid,
-#endif
- vrf_id, port);
- if (stcb)
- *abort_no_unlock = 1;
- goto outnow;
- }
- if (ntohl(init->a_rwnd) < SCTP_MIN_RWND) {
- /* invalid parameter... send abort */
- op_err = sctp_generate_cause(SCTP_CAUSE_INVALID_PARAM, "");
- sctp_abort_association(inp, stcb, m, iphlen, src, dst, sh, op_err,
-#if defined(__FreeBSD__) && !defined(__Userspace__)
- mflowtype, mflowid,
-#endif
- vrf_id, port);
- if (stcb)
- *abort_no_unlock = 1;
- goto outnow;
- }
- if (init->num_inbound_streams == 0) {
- /* protocol error... send abort */
- op_err = sctp_generate_cause(SCTP_CAUSE_INVALID_PARAM, "");
- sctp_abort_association(inp, stcb, m, iphlen, src, dst, sh, op_err,
-#if defined(__FreeBSD__) && !defined(__Userspace__)
- mflowtype, mflowid,
-#endif
- vrf_id, port);
- if (stcb)
- *abort_no_unlock = 1;
- goto outnow;
- }
- if (init->num_outbound_streams == 0) {
+ if ((ntohl(init->initiate_tag) == 0) ||
+ (ntohl(init->a_rwnd) < SCTP_MIN_RWND) ||
+ (ntohs(init->num_inbound_streams) == 0) ||
+ (ntohs(init->num_outbound_streams) == 0)) {
/* protocol error... send abort */
op_err = sctp_generate_cause(SCTP_CAUSE_INVALID_PARAM, "");
sctp_abort_association(inp, stcb, m, iphlen, src, dst, sh, op_err,
@@ -514,26 +469,34 @@ sctp_process_init_ack(struct mbuf *m, int iphlen, int offset,
asoc = &stcb->asoc;
asoc->peer_supports_nat = (uint8_t)nat_friendly;
/* process the peer's parameters in the INIT-ACK */
- retval = sctp_process_init((struct sctp_init_chunk *)cp, stcb);
- if (retval < 0) {
+ if (sctp_process_init((struct sctp_init_chunk *)cp, stcb) < 0) {
if (op_err != NULL) {
sctp_m_freem(op_err);
}
- return (retval);
+ op_err = sctp_generate_cause(SCTP_CAUSE_OUT_OF_RESC, "");
+ SCTPDBG(SCTP_DEBUG_INPUT1, "sctp_process_init() failed\n");
+ sctp_abort_association(stcb->sctp_ep, stcb, m, iphlen,
+ src, dst, sh, op_err,
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ mflowtype, mflowid,
+#endif
+ vrf_id, net->port);
+ *abort_no_unlock = 1;
+ return (-1);
}
initack_limit = offset + ntohs(cp->ch.chunk_length);
/* load all addresses */
if ((retval = sctp_load_addresses_from_init(stcb, m,
- (offset + sizeof(struct sctp_init_chunk)), initack_limit,
- src, dst, NULL, stcb->asoc.port))) {
+ offset + sizeof(struct sctp_init_chunk),
+ initack_limit, src, dst, NULL, stcb->asoc.port)) < 0) {
if (op_err != NULL) {
sctp_m_freem(op_err);
}
op_err = sctp_generate_cause(SCTP_BASE_SYSCTL(sctp_diag_info_code),
"Problem with address parameters");
SCTPDBG(SCTP_DEBUG_INPUT1,
- "Load addresses from INIT causes an abort %d\n",
- retval);
+ "Load addresses from INIT causes an abort %d\n",
+ retval);
sctp_abort_association(stcb->sctp_ep, stcb, m, iphlen,
src, dst, sh, op_err,
#if defined(__FreeBSD__) && !defined(__Userspace__)
@@ -1420,57 +1383,12 @@ sctp_handle_init_ack(struct mbuf *m, int iphlen, int offset,
"sctp_handle_init_ack: TCB is null\n");
return (-1);
}
- if (ntohs(cp->ch.chunk_length) < sizeof(struct sctp_init_ack_chunk)) {
- /* Invalid length */
- op_err = sctp_generate_cause(SCTP_CAUSE_INVALID_PARAM, "");
- sctp_abort_association(stcb->sctp_ep, stcb, m, iphlen,
- src, dst, sh, op_err,
-#if defined(__FreeBSD__) && !defined(__Userspace__)
- mflowtype, mflowid,
-#endif
- vrf_id, net->port);
- *abort_no_unlock = 1;
- return (-1);
- }
init_ack = &cp->init;
- /* validate parameters */
- if (init_ack->initiate_tag == 0) {
- /* protocol error... send an abort */
- op_err = sctp_generate_cause(SCTP_CAUSE_INVALID_PARAM, "");
- sctp_abort_association(stcb->sctp_ep, stcb, m, iphlen,
- src, dst, sh, op_err,
-#if defined(__FreeBSD__) && !defined(__Userspace__)
- mflowtype, mflowid,
-#endif
- vrf_id, net->port);
- *abort_no_unlock = 1;
- return (-1);
- }
- if (ntohl(init_ack->a_rwnd) < SCTP_MIN_RWND) {
- /* protocol error... send an abort */
- op_err = sctp_generate_cause(SCTP_CAUSE_INVALID_PARAM, "");
- sctp_abort_association(stcb->sctp_ep, stcb, m, iphlen,
- src, dst, sh, op_err,
-#if defined(__FreeBSD__) && !defined(__Userspace__)
- mflowtype, mflowid,
-#endif
- vrf_id, net->port);
- *abort_no_unlock = 1;
- return (-1);
- }
- if (init_ack->num_inbound_streams == 0) {
- /* protocol error... send an abort */
- op_err = sctp_generate_cause(SCTP_CAUSE_INVALID_PARAM, "");
- sctp_abort_association(stcb->sctp_ep, stcb, m, iphlen,
- src, dst, sh, op_err,
-#if defined(__FreeBSD__) && !defined(__Userspace__)
- mflowtype, mflowid,
-#endif
- vrf_id, net->port);
- *abort_no_unlock = 1;
- return (-1);
- }
- if (init_ack->num_outbound_streams == 0) {
+ /* Validate parameters. */
+ if ((ntohl(init_ack->initiate_tag) == 0) ||
+ (ntohl(init_ack->a_rwnd) < SCTP_MIN_RWND) ||
+ (ntohs(init_ack->num_inbound_streams) == 0) ||
+ (ntohs(init_ack->num_outbound_streams) == 0)) {
/* protocol error... send an abort */
op_err = sctp_generate_cause(SCTP_CAUSE_INVALID_PARAM, "");
sctp_abort_association(stcb->sctp_ep, stcb, m, iphlen,
@@ -1624,6 +1542,7 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset,
vrf_id, net->port);
if (how_indx < sizeof(asoc->cookie_how))
asoc->cookie_how[how_indx] = 2;
+ SCTP_TCB_UNLOCK(stcb);
return (NULL);
}
/*
@@ -1638,9 +1557,11 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset,
(uint8_t *) & init_buf);
if (init_cp == NULL) {
/* could not pull a INIT chunk in cookie */
+ SCTP_TCB_UNLOCK(stcb);
return (NULL);
}
if (init_cp->ch.chunk_type != SCTP_INITIATION) {
+ SCTP_TCB_UNLOCK(stcb);
return (NULL);
}
/*
@@ -1653,9 +1574,11 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset,
(uint8_t *) & initack_buf);
if (initack_cp == NULL) {
/* could not pull INIT-ACK chunk in cookie */
+ SCTP_TCB_UNLOCK(stcb);
return (NULL);
}
if (initack_cp->ch.chunk_type != SCTP_INITIATION_ACK) {
+ SCTP_TCB_UNLOCK(stcb);
return (NULL);
}
if ((ntohl(initack_cp->init.initiate_tag) == asoc->my_vtag) &&
@@ -1681,6 +1604,7 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset,
*/
if (how_indx < sizeof(asoc->cookie_how))
asoc->cookie_how[how_indx] = 17;
+ SCTP_TCB_UNLOCK(stcb);
return (NULL);
}
switch (SCTP_GET_STATE(stcb)) {
@@ -1693,10 +1617,17 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset,
* have the right seq no's.
*/
/* First we must process the INIT !! */
- retval = sctp_process_init(init_cp, stcb);
- if (retval < 0) {
+ if (sctp_process_init(init_cp, stcb) < 0) {
if (how_indx < sizeof(asoc->cookie_how))
asoc->cookie_how[how_indx] = 3;
+ op_err = sctp_generate_cause(SCTP_CAUSE_OUT_OF_RESC, "");
+ SCTPDBG(SCTP_DEBUG_INPUT1, "sctp_process_init() failed\n");
+ sctp_abort_association(stcb->sctp_ep, stcb, m, iphlen,
+ src, dst, sh, op_err,
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ mflowtype, mflowid,
+#endif
+ vrf_id, net->port);
return (NULL);
}
/* we have already processed the INIT so no problem */
@@ -1741,6 +1672,7 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset,
SCTP_TCB_LOCK(stcb);
atomic_add_int(&stcb->asoc.refcnt, -1);
if (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET) {
+ SCTP_TCB_UNLOCK(stcb);
SCTP_SOCKET_UNLOCK(so, 1);
return (NULL);
}
@@ -1776,16 +1708,22 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset,
break;
} /* end switch */
sctp_stop_all_cookie_timers(stcb);
- /*
- * We ignore the return code here.. not sure if we should
- * somehow abort.. but we do have an existing asoc. This
- * really should not fail.
- */
- if (sctp_load_addresses_from_init(stcb, m,
- init_offset + sizeof(struct sctp_init_chunk),
- initack_offset, src, dst, init_src, stcb->asoc.port)) {
+ if ((retval = sctp_load_addresses_from_init(stcb, m,
+ init_offset + sizeof(struct sctp_init_chunk),
+ initack_offset, src, dst, init_src, stcb->asoc.port)) < 0) {
if (how_indx < sizeof(asoc->cookie_how))
asoc->cookie_how[how_indx] = 4;
+ op_err = sctp_generate_cause(SCTP_BASE_SYSCTL(sctp_diag_info_code),
+ "Problem with address parameters");
+ SCTPDBG(SCTP_DEBUG_INPUT1,
+ "Load addresses from INIT causes an abort %d\n",
+ retval);
+ sctp_abort_association(stcb->sctp_ep, stcb, m, iphlen,
+ src, dst, sh, op_err,
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ mflowtype, mflowid,
+#endif
+ vrf_id, net->port);
return (NULL);
}
/* respond with a COOKIE-ACK */
@@ -1805,6 +1743,7 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset,
*/
if (how_indx < sizeof(asoc->cookie_how))
asoc->cookie_how[how_indx] = 6;
+ SCTP_TCB_UNLOCK(stcb);
return (NULL);
}
/* If nat support, and the below and stcb is established,
@@ -1830,6 +1769,7 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset,
mflowtype, mflowid, inp->fibnum,
#endif
vrf_id, port);
+ SCTP_TCB_UNLOCK(stcb);
return (NULL);
}
if ((ntohl(initack_cp->init.initiate_tag) == asoc->my_vtag) &&
@@ -1859,6 +1799,7 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset,
if (how_indx < sizeof(asoc->cookie_how))
asoc->cookie_how[how_indx] = 7;
+ SCTP_TCB_UNLOCK(stcb);
return (NULL);
}
if (how_indx < sizeof(asoc->cookie_how))
@@ -1901,17 +1842,35 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset,
}
}
/* process the INIT info (peer's info) */
- retval = sctp_process_init(init_cp, stcb);
- if (retval < 0) {
+ if (sctp_process_init(init_cp, stcb) < 0) {
if (how_indx < sizeof(asoc->cookie_how))
asoc->cookie_how[how_indx] = 9;
+ op_err = sctp_generate_cause(SCTP_CAUSE_OUT_OF_RESC, "");
+ SCTPDBG(SCTP_DEBUG_INPUT1, "sctp_process_init() failed\n");
+ sctp_abort_association(stcb->sctp_ep, stcb, m, iphlen,
+ src, dst, sh, op_err,
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ mflowtype, mflowid,
+#endif
+ vrf_id, net->port);
return (NULL);
}
- if (sctp_load_addresses_from_init(stcb, m,
- init_offset + sizeof(struct sctp_init_chunk),
- initack_offset, src, dst, init_src, stcb->asoc.port)) {
+ if ((retval = sctp_load_addresses_from_init(stcb, m,
+ init_offset + sizeof(struct sctp_init_chunk),
+ initack_offset, src, dst, init_src, stcb->asoc.port)) < 0) {
if (how_indx < sizeof(asoc->cookie_how))
asoc->cookie_how[how_indx] = 10;
+ op_err = sctp_generate_cause(SCTP_BASE_SYSCTL(sctp_diag_info_code),
+ "Problem with address parameters");
+ SCTPDBG(SCTP_DEBUG_INPUT1,
+ "Load addresses from INIT causes an abort %d\n",
+ retval);
+ sctp_abort_association(stcb->sctp_ep, stcb, m, iphlen,
+ src, dst, sh, op_err,
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ mflowtype, mflowid,
+#endif
+ vrf_id, net->port);
return (NULL);
}
if ((SCTP_GET_STATE(stcb) == SCTP_STATE_COOKIE_WAIT) ||
@@ -1933,6 +1892,7 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset,
SCTP_TCB_LOCK(stcb);
atomic_add_int(&stcb->asoc.refcnt, -1);
if (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET) {
+ SCTP_TCB_UNLOCK(stcb);
SCTP_SOCKET_UNLOCK(so, 1);
return (NULL);
}
@@ -1985,19 +1945,25 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset,
#endif
if (asoc->peer_supports_nat) {
+ struct sctp_tcb *local_stcb;
+
/* This is a gross gross hack.
* Just call the cookie_new code since we
* are allowing a duplicate association.
* I hope this works...
*/
- return (sctp_process_cookie_new(m, iphlen, offset, src, dst,
- sh, cookie, cookie_len,
- inp, netp, init_src,notification,
- auth_skipped, auth_offset, auth_len,
+ local_stcb = sctp_process_cookie_new(m, iphlen, offset, src, dst,
+ sh, cookie, cookie_len,
+ inp, netp, init_src,notification,
+ auth_skipped, auth_offset, auth_len,
#if defined(__FreeBSD__) && !defined(__Userspace__)
- mflowtype, mflowid,
+ mflowtype, mflowid,
#endif
- vrf_id, port));
+ vrf_id, port);
+ if (local_stcb == NULL) {
+ SCTP_TCB_UNLOCK(stcb);
+ }
+ return (local_stcb);
}
/*
* case A in Section 5.2.4 Table 2: XXMM (peer restarted)
@@ -2005,11 +1971,7 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset,
/* temp code */
if (how_indx < sizeof(asoc->cookie_how))
asoc->cookie_how[how_indx] = 12;
- sctp_timer_stop(SCTP_TIMER_TYPE_INIT, inp, stcb, net,
- SCTP_FROM_SCTP_INPUT + SCTP_LOC_16);
- sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net,
- SCTP_FROM_SCTP_INPUT + SCTP_LOC_17);
-
+ sctp_stop_association_timers(stcb, false);
/* notify upper layer */
*notification = SCTP_NOTIFY_ASSOC_RESTART;
atomic_add_int(&stcb->asoc.refcnt, 1);
@@ -2042,6 +2004,10 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset,
asoc->str_reset_seq_in = asoc->init_seq_number;
asoc->advanced_peer_ack_point = asoc->last_acked_seq;
asoc->send_sack = 1;
+ asoc->data_pkts_seen = 0;
+ asoc->last_data_chunk_from = NULL;
+ asoc->last_control_chunk_from = NULL;
+ asoc->last_net_cmt_send_started = NULL;
if (asoc->mapping_array) {
memset(asoc->mapping_array, 0,
asoc->mapping_array_size);
@@ -2106,6 +2072,9 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset,
SCTP_ZONE_FREE(SCTP_BASE_INFO(ipi_zone_chunk), chk);
SCTP_DECR_CHK_COUNT();
}
+ asoc->ctrl_queue_cnt = 0;
+ asoc->str_reset = NULL;
+ asoc->stream_reset_outstanding = 0;
TAILQ_FOREACH_SAFE(chk, &asoc->asconf_send_queue, sctp_next, nchk) {
TAILQ_REMOVE(&asoc->asconf_send_queue, chk, sctp_next);
if (chk->data) {
@@ -2154,11 +2123,17 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset,
asoc->total_flight = 0;
asoc->total_flight_count = 0;
/* process the INIT info (peer's info) */
- retval = sctp_process_init(init_cp, stcb);
- if (retval < 0) {
+ if (sctp_process_init(init_cp, stcb) < 0) {
if (how_indx < sizeof(asoc->cookie_how))
asoc->cookie_how[how_indx] = 13;
-
+ op_err = sctp_generate_cause(SCTP_CAUSE_OUT_OF_RESC, "");
+ SCTPDBG(SCTP_DEBUG_INPUT1, "sctp_process_init() failed\n");
+ sctp_abort_association(stcb->sctp_ep, stcb, m, iphlen,
+ src, dst, sh, op_err,
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ mflowtype, mflowid,
+#endif
+ vrf_id, net->port);
return (NULL);
}
/*
@@ -2167,26 +2142,38 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset,
*/
net->hb_responded = 1;
- if (sctp_load_addresses_from_init(stcb, m,
- init_offset + sizeof(struct sctp_init_chunk),
- initack_offset, src, dst, init_src, stcb->asoc.port)) {
+ if ((retval = sctp_load_addresses_from_init(stcb, m,
+ init_offset + sizeof(struct sctp_init_chunk),
+ initack_offset, src, dst, init_src, stcb->asoc.port)) < 0) {
if (how_indx < sizeof(asoc->cookie_how))
asoc->cookie_how[how_indx] = 14;
-
+ op_err = sctp_generate_cause(SCTP_BASE_SYSCTL(sctp_diag_info_code),
+ "Problem with address parameters");
+ SCTPDBG(SCTP_DEBUG_INPUT1,
+ "Load addresses from INIT causes an abort %d\n",
+ retval);
+ sctp_abort_association(stcb->sctp_ep, stcb, m, iphlen,
+ src, dst, sh, op_err,
+#if defined(__FreeBSD__) && !defined(__Userspace__)
+ mflowtype, mflowid,
+#endif
+ vrf_id, net->port);
return (NULL);
}
/* respond with a COOKIE-ACK */
- sctp_stop_all_cookie_timers(stcb);
- sctp_toss_old_cookies(stcb, asoc);
sctp_send_cookie_ack(stcb);
if (how_indx < sizeof(asoc->cookie_how))
asoc->cookie_how[how_indx] = 15;
-
+ if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_AUTOCLOSE) &&
+ (asoc->sctp_autoclose_ticks > 0)) {
+ sctp_timer_start(SCTP_TIMER_TYPE_AUTOCLOSE, inp, stcb, NULL);
+ }
return (stcb);
}
if (how_indx < sizeof(asoc->cookie_how))
asoc->cookie_how[how_indx] = 16;
/* all other cases... */
+ SCTP_TCB_UNLOCK(stcb);
return (NULL);
}
@@ -2360,8 +2347,7 @@ sctp_process_cookie_new(struct mbuf *m, int iphlen, int offset,
asoc->advanced_peer_ack_point = asoc->last_acked_seq;
/* process the INIT info (peer's info) */
- retval = sctp_process_init(init_cp, stcb);
- if (retval < 0) {
+ if (sctp_process_init(init_cp, stcb) < 0) {
#if defined(__APPLE__) && !defined(__Userspace__)
atomic_add_int(&stcb->asoc.refcnt, 1);
SCTP_TCB_UNLOCK(stcb);
@@ -2377,9 +2363,9 @@ sctp_process_cookie_new(struct mbuf *m, int iphlen, int offset,
return (NULL);
}
/* load all addresses */
- if (sctp_load_addresses_from_init(stcb, m,
- init_offset + sizeof(struct sctp_init_chunk), initack_offset,
- src, dst, init_src, port)) {
+ if ((retval = sctp_load_addresses_from_init(stcb, m,
+ init_offset + sizeof(struct sctp_init_chunk),
+ initack_offset, src, dst, init_src, port)) < 0) {
#if defined(__APPLE__) && !defined(__Userspace__)
atomic_add_int(&stcb->asoc.refcnt, 1);
SCTP_TCB_UNLOCK(stcb);
@@ -2956,12 +2942,15 @@ sctp_handle_cookie_echo(struct mbuf *m, int iphlen, int offset,
had_a_existing_tcb = 1;
*stcb = sctp_process_cookie_existing(m, iphlen, offset,
src, dst, sh,
- cookie, cookie_len, *inp_p, *stcb, netp, to,
- &notification, auth_skipped, auth_offset, auth_len,
+ cookie, cookie_len, *inp_p, *stcb, netp, to,
+ &notification, auth_skipped, auth_offset, auth_len,
#if defined(__FreeBSD__) && !defined(__Userspace__)
mflowtype, mflowid,
#endif
vrf_id, port);
+ if (*stcb == NULL) {
+ *locked_tcb = NULL;
+ }
}
if (*stcb == NULL) {
@@ -3847,19 +3836,16 @@ sctp_find_stream_reset(struct sctp_tcb *stcb, uint32_t seq, struct sctp_tmit_chu
int len, clen;
asoc = &stcb->asoc;
- if (TAILQ_EMPTY(&stcb->asoc.control_send_queue)) {
- asoc->stream_reset_outstanding = 0;
- return (NULL);
- }
- if (stcb->asoc.str_reset == NULL) {
+ chk = asoc->str_reset;
+ if (TAILQ_EMPTY(&asoc->control_send_queue) ||
+ (chk == NULL)) {
asoc->stream_reset_outstanding = 0;
return (NULL);
}
- chk = stcb->asoc.str_reset;
if (chk->data == NULL) {
return (NULL);
}
- if (bchk) {
+ if (bchk != NULL) {
/* he wants a copy of the chk pointer */
*bchk = chk;
}
@@ -4798,6 +4784,7 @@ sctp_process_control(struct mbuf *m, int iphlen, int *offset, int length,
int ret;
int abort_no_unlock = 0;
int ecne_seen = 0;
+ int abort_flag;
/*
* How big should this be, and should it be alloc'd? Lets try the
* d-mtu-ceiling for now (2k) and that should hopefully work ...
@@ -4962,29 +4949,6 @@ sctp_process_control(struct mbuf *m, int iphlen, int *offset, int length,
}
return (NULL);
}
- } else if (ch->chunk_type == SCTP_SHUTDOWN_ACK) {
- if (vtag_in != asoc->my_vtag) {
- /*
- * this could be a stale SHUTDOWN-ACK or the
- * peer never got the SHUTDOWN-COMPLETE and
- * is still hung; we have started a new asoc
- * but it won't complete until the shutdown
- * is completed
- */
- if (stcb != NULL) {
- SCTP_TCB_UNLOCK(stcb);
- }
- SCTP_SNPRINTF(msg, sizeof(msg), "OOTB, %s:%d at %s", __FILE__, __LINE__, __func__);
- op_err = sctp_generate_cause(SCTP_BASE_SYSCTL(sctp_diag_info_code),
- msg);
- sctp_handle_ootb(m, iphlen, *offset, src, dst,
- sh, inp, op_err,
-#if defined(__FreeBSD__) && !defined(__Userspace__)
- mflowtype, mflowid, fibnum,
-#endif
- vrf_id, port);
- return (NULL);
- }
} else {
/* for all other chunks, vtag must match */
if (vtag_in != asoc->my_vtag) {
@@ -5047,10 +5011,7 @@ sctp_process_control(struct mbuf *m, int iphlen, int *offset, int length,
chunk_buf);
if (ch == NULL) {
*offset = length;
- if (stcb != NULL) {
- SCTP_TCB_UNLOCK(stcb);
- }
- return (NULL);
+ return (stcb);
}
num_chunks++;
@@ -5084,12 +5045,12 @@ sctp_process_control(struct mbuf *m, int iphlen, int *offset, int length,
/* The INIT chunk must be the only chunk. */
if ((num_chunks > 1) ||
(length - *offset > (int)SCTP_SIZE32(chk_length))) {
- /* RFC 4960 requires that no ABORT is sent */
+ /*
+ * RFC 4960bis requires stopping the
+ * processing of the packet.
+ */
*offset = length;
- if (stcb != NULL) {
- SCTP_TCB_UNLOCK(stcb);
- }
- return (NULL);
+ return (stcb);
}
/* Honor our resource limit. */
if (chk_length > SCTP_LARGEST_INIT_ACCEPTED) {
@@ -5296,20 +5257,19 @@ sctp_process_control(struct mbuf *m, int iphlen, int *offset, int length,
if ((stcb != NULL) && (netp != NULL) && (*netp != NULL)) {
SCTP_STAT_INCR(sctps_recvheartbeat);
sctp_send_heartbeat_ack(stcb, m, *offset,
- chk_length, *netp);
+ chk_length, *netp);
}
break;
case SCTP_HEARTBEAT_ACK:
SCTPDBG(SCTP_DEBUG_INPUT3, "SCTP_HEARTBEAT_ACK\n");
if ((stcb == NULL) || (chk_length != sizeof(struct sctp_heartbeat_chunk))) {
/* Its not ours */
- *offset = length;
- return (stcb);
+ break;
}
SCTP_STAT_INCR(sctps_recvheartbeatack);
if ((netp != NULL) && (*netp != NULL)) {
sctp_handle_heartbeat_ack((struct sctp_heartbeat_chunk *)ch,
- stcb, *netp);
+ stcb, *netp);
}
break;
case SCTP_ABORT_ASSOCIATION:
@@ -5330,14 +5290,12 @@ sctp_process_control(struct mbuf *m, int iphlen, int *offset, int length,
SCTPDBG(SCTP_DEBUG_INPUT3, "SCTP_SHUTDOWN, stcb %p\n",
(void *)stcb);
if ((stcb == NULL) || (chk_length != sizeof(struct sctp_shutdown_chunk))) {
- *offset = length;
- return (stcb);
+ break;
}
if ((netp != NULL) && (*netp != NULL)) {
- int abort_flag = 0;
-
+ abort_flag = 0;
sctp_handle_shutdown((struct sctp_shutdown_chunk *)ch,
- stcb, *netp, &abort_flag);
+ stcb, *netp, &abort_flag);
if (abort_flag) {
*offset = length;
return (NULL);
@@ -5346,11 +5304,12 @@ sctp_process_control(struct mbuf *m, int iphlen, int *offset, int length,
break;
case SCTP_SHUTDOWN_ACK:
SCTPDBG(SCTP_DEBUG_INPUT3, "SCTP_SHUTDOWN_ACK, stcb %p\n", (void *)stcb);
- if ((stcb != NULL) && (netp != NULL) && (*netp != NULL)) {
+ if ((chk_length == sizeof(struct sctp_shutdown_ack_chunk)) &&
+ (stcb != NULL) && (netp != NULL) && (*netp != NULL)) {
sctp_handle_shutdown_ack((struct sctp_shutdown_ack_chunk *)ch, stcb, *netp);
+ *offset = length;
+ return (NULL);
}
- *offset = length;
- return (NULL);
break;
case SCTP_OPERATION_ERROR:
SCTPDBG(SCTP_DEBUG_INPUT3, "SCTP_OP_ERR\n");
@@ -5494,7 +5453,7 @@ sctp_process_control(struct mbuf *m, int iphlen, int *offset, int length,
case SCTP_COOKIE_ACK:
SCTPDBG(SCTP_DEBUG_INPUT3, "SCTP_COOKIE_ACK, stcb %p\n", (void *)stcb);
if ((stcb == NULL) || chk_length != sizeof(struct sctp_cookie_ack_chunk)) {
- return (stcb);
+ break;
}
if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) {
/* We are not interested anymore */
@@ -5524,26 +5483,29 @@ sctp_process_control(struct mbuf *m, int iphlen, int *offset, int length,
break;
case SCTP_ECN_ECHO:
SCTPDBG(SCTP_DEBUG_INPUT3, "SCTP_ECN_ECHO\n");
- if ((stcb == NULL) || (chk_length != sizeof(struct sctp_ecne_chunk))) {
- /* Its not ours */
- *offset = length;
- return (stcb);
+ if (stcb == NULL) {
+ break;
}
if (stcb->asoc.ecn_supported == 0) {
goto unknown_chunk;
}
+ if (chk_length != sizeof(struct sctp_ecne_chunk)) {
+ break;
+ }
sctp_handle_ecn_echo((struct sctp_ecne_chunk *)ch, stcb);
ecne_seen = 1;
break;
case SCTP_ECN_CWR:
SCTPDBG(SCTP_DEBUG_INPUT3, "SCTP_ECN_CWR\n");
- if ((stcb == NULL) || (chk_length != sizeof(struct sctp_cwr_chunk))) {
- *offset = length;
- return (stcb);
+ if (stcb == NULL) {
+ break;
}
if (stcb->asoc.ecn_supported == 0) {
goto unknown_chunk;
}
+ if (chk_length != sizeof(struct sctp_cwr_chunk)) {
+ break;
+ }
sctp_handle_ecn_cwr((struct sctp_cwr_chunk *)ch, stcb, *netp);
break;
case SCTP_SHUTDOWN_COMPLETE:
@@ -5554,12 +5516,13 @@ sctp_process_control(struct mbuf *m, int iphlen, int *offset, int length,
*offset = length;
return (stcb);
}
- if ((stcb != NULL) && (netp != NULL) && (*netp != NULL)) {
+ if ((chk_length == sizeof(struct sctp_shutdown_complete_chunk)) &&
+ (stcb != NULL) && (netp != NULL) && (*netp != NULL)) {
sctp_handle_shutdown_complete((struct sctp_shutdown_complete_chunk *)ch,
- stcb, *netp);
+ stcb, *netp);
+ *offset = length;
+ return (NULL);
}
- *offset = length;
- return (NULL);
break;
case SCTP_ASCONF:
SCTPDBG(SCTP_DEBUG_INPUT3, "SCTP_ASCONF\n");
@@ -5568,32 +5531,33 @@ sctp_process_control(struct mbuf *m, int iphlen, int *offset, int length,
goto unknown_chunk;
}
sctp_handle_asconf(m, *offset, src,
- (struct sctp_asconf_chunk *)ch, stcb, asconf_cnt == 0);
+ (struct sctp_asconf_chunk *)ch, stcb, asconf_cnt == 0);
asconf_cnt++;
}
break;
case SCTP_ASCONF_ACK:
SCTPDBG(SCTP_DEBUG_INPUT3, "SCTP_ASCONF_ACK\n");
+ if (stcb == NULL) {
+ break;
+ }
+ if (stcb->asoc.asconf_supported == 0) {
+ goto unknown_chunk;
+ }
if (chk_length < sizeof(struct sctp_asconf_ack_chunk)) {
- /* Its not ours */
- *offset = length;
- return (stcb);
+ break;
}
- if ((stcb != NULL) && (netp != NULL) && (*netp != NULL)) {
- if (stcb->asoc.asconf_supported == 0) {
- goto unknown_chunk;
- }
+ if ((netp != NULL) && (*netp != NULL)) {
/* He's alive so give him credit */
if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_THRESHOLD_LOGGING) {
sctp_misc_ints(SCTP_THRESHOLD_CLEAR,
- stcb->asoc.overall_error_count,
- 0,
- SCTP_FROM_SCTP_INPUT,
- __LINE__);
+ stcb->asoc.overall_error_count,
+ 0,
+ SCTP_FROM_SCTP_INPUT,
+ __LINE__);
}
stcb->asoc.overall_error_count = 0;
sctp_handle_asconf_ack(m, *offset,
- (struct sctp_asconf_ack_chunk *)ch, stcb, *netp, &abort_no_unlock);
+ (struct sctp_asconf_ack_chunk *)ch, stcb, *netp, &abort_no_unlock);
if (abort_no_unlock)
return (NULL);
}
@@ -5602,72 +5566,70 @@ sctp_process_control(struct mbuf *m, int iphlen, int *offset, int length,
case SCTP_IFORWARD_CUM_TSN:
SCTPDBG(SCTP_DEBUG_INPUT3, "%s\n",
ch->chunk_type == SCTP_FORWARD_CUM_TSN ? "FORWARD_TSN" : "I_FORWARD_TSN");
+ if (stcb == NULL) {
+ break;
+ }
+ if (stcb->asoc.prsctp_supported == 0) {
+ goto unknown_chunk;
+ }
if (chk_length < sizeof(struct sctp_forward_tsn_chunk)) {
- /* Its not ours */
- *offset = length;
- return (stcb);
+ break;
}
-
- if (stcb != NULL) {
- int abort_flag = 0;
-
- if (stcb->asoc.prsctp_supported == 0) {
- goto unknown_chunk;
- }
- if (((stcb->asoc.idata_supported == 1) && (ch->chunk_type == SCTP_FORWARD_CUM_TSN)) ||
- ((stcb->asoc.idata_supported == 0) && (ch->chunk_type == SCTP_IFORWARD_CUM_TSN))) {
- if (ch->chunk_type == SCTP_FORWARD_CUM_TSN) {
- SCTP_SNPRINTF(msg, sizeof(msg), "%s", "FORWARD-TSN chunk received when I-FORWARD-TSN was negotiated");
- } else {
- SCTP_SNPRINTF(msg, sizeof(msg), "%s", "I-FORWARD-TSN chunk received when FORWARD-TSN was negotiated");
- }
- op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg);
- sctp_abort_an_association(inp, stcb, op_err, SCTP_SO_NOT_LOCKED);
- *offset = length;
- return (NULL);
+ if (((stcb->asoc.idata_supported == 1) && (ch->chunk_type == SCTP_FORWARD_CUM_TSN)) ||
+ ((stcb->asoc.idata_supported == 0) && (ch->chunk_type == SCTP_IFORWARD_CUM_TSN))) {
+ if (ch->chunk_type == SCTP_FORWARD_CUM_TSN) {
+ SCTP_SNPRINTF(msg, sizeof(msg), "%s", "FORWARD-TSN chunk received when I-FORWARD-TSN was negotiated");
+ } else {
+ SCTP_SNPRINTF(msg, sizeof(msg), "%s", "I-FORWARD-TSN chunk received when FORWARD-TSN was negotiated");
}
- *fwd_tsn_seen = 1;
- if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) {
- /* We are not interested anymore */
+ op_err = sctp_generate_cause(SCTP_CAUSE_PROTOCOL_VIOLATION, msg);
+ sctp_abort_an_association(inp, stcb, op_err, SCTP_SO_NOT_LOCKED);
+ *offset = length;
+ return (NULL);
+ }
+ *fwd_tsn_seen = 1;
+ if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) {
+ /* We are not interested anymore */
#if defined(__APPLE__) && !defined(__Userspace__)
- so = SCTP_INP_SO(inp);
- atomic_add_int(&stcb->asoc.refcnt, 1);
- SCTP_TCB_UNLOCK(stcb);
- SCTP_SOCKET_LOCK(so, 1);
- SCTP_TCB_LOCK(stcb);
- atomic_subtract_int(&stcb->asoc.refcnt, 1);
+ so = SCTP_INP_SO(inp);
+ atomic_add_int(&stcb->asoc.refcnt, 1);
+ SCTP_TCB_UNLOCK(stcb);
+ SCTP_SOCKET_LOCK(so, 1);
+ SCTP_TCB_LOCK(stcb);
+ atomic_subtract_int(&stcb->asoc.refcnt, 1);
#endif
- (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC,
- SCTP_FROM_SCTP_INPUT + SCTP_LOC_31);
+ (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC,
+ SCTP_FROM_SCTP_INPUT + SCTP_LOC_31);
#if defined(__APPLE__) && !defined(__Userspace__)
- SCTP_SOCKET_UNLOCK(so, 1);
+ SCTP_SOCKET_UNLOCK(so, 1);
#endif
- *offset = length;
- return (NULL);
- }
- /*
- * For sending a SACK this looks like DATA
- * chunks.
- */
- stcb->asoc.last_data_chunk_from = stcb->asoc.last_control_chunk_from;
- sctp_handle_forward_tsn(stcb,
- (struct sctp_forward_tsn_chunk *)ch, &abort_flag, m, *offset);
- if (abort_flag) {
- *offset = length;
- return (NULL);
- }
+ *offset = length;
+ return (NULL);
+ }
+ /*
+ * For sending a SACK this looks like DATA
+ * chunks.
+ */
+ stcb->asoc.last_data_chunk_from = stcb->asoc.last_control_chunk_from;
+ abort_flag = 0;
+ sctp_handle_forward_tsn(stcb,
+ (struct sctp_forward_tsn_chunk *)ch, &abort_flag, m, *offset);
+ if (abort_flag) {
+ *offset = length;
+ return (NULL);
}
break;
case SCTP_STREAM_RESET:
SCTPDBG(SCTP_DEBUG_INPUT3, "SCTP_STREAM_RESET\n");
- if ((stcb == NULL) || (chk_length < sizeof(struct sctp_stream_reset_tsn_req))) {
- /* Its not ours */
- *offset = length;
- return (stcb);
+ if (stcb == NULL) {
+ break;
}
if (stcb->asoc.reconfig_supported == 0) {
goto unknown_chunk;
}
+ if (chk_length < sizeof(struct sctp_stream_reset_tsn_req)) {
+ break;
+ }
if (sctp_handle_stream_reset(stcb, m, *offset, ch)) {
/* stop processing */
*offset = length;
@@ -5676,20 +5638,19 @@ sctp_process_control(struct mbuf *m, int iphlen, int *offset, int length,
break;
case SCTP_PACKET_DROPPED:
SCTPDBG(SCTP_DEBUG_INPUT3, "SCTP_PACKET_DROPPED\n");
- /* re-get it all please */
+ if (stcb == NULL) {
+ break;
+ }
+ if (stcb->asoc.pktdrop_supported == 0) {
+ goto unknown_chunk;
+ }
if (chk_length < sizeof(struct sctp_pktdrop_chunk)) {
- /* Its not ours */
- *offset = length;
- return (stcb);
+ break;
}
-
- if ((stcb != NULL) && (netp != NULL) && (*netp != NULL)) {
- if (stcb->asoc.pktdrop_supported == 0) {
- goto unknown_chunk;
- }
+ if ((netp != NULL) && (*netp != NULL)) {
sctp_handle_packet_dropped((struct sctp_pktdrop_chunk *)ch,
- stcb, *netp,
- min(chk_length, contiguous));
+ stcb, *netp,
+ min(chk_length, contiguous));
}
break;
case SCTP_AUTHENTICATION:
@@ -5702,21 +5663,21 @@ sctp_process_control(struct mbuf *m, int iphlen, int *offset, int length,
auth_skipped = 1;
}
/* skip this chunk (temporarily) */
- goto next_chunk;
+ break;
}
if (stcb->asoc.auth_supported == 0) {
goto unknown_chunk;
}
if ((chk_length < (sizeof(struct sctp_auth_chunk))) ||
(chk_length > (sizeof(struct sctp_auth_chunk) +
- SCTP_AUTH_DIGEST_LEN_MAX))) {
+ SCTP_AUTH_DIGEST_LEN_MAX))) {
/* Its not ours */
*offset = length;
return (stcb);
}
if (got_auth == 1) {
/* skip this chunk... it's already auth'd */
- goto next_chunk;
+ break;
}
got_auth = 1;
if (sctp_handle_auth(stcb, (struct sctp_auth_chunk *)ch, m, *offset)) {
@@ -5777,7 +5738,7 @@ sctp_process_control(struct mbuf *m, int iphlen, int *offset, int length,
break;
}
ch = (struct sctp_chunkhdr *)sctp_m_getptr(m, *offset,
- sizeof(struct sctp_chunkhdr), chunk_buf);
+ sizeof(struct sctp_chunkhdr), chunk_buf);
if (ch == NULL) {
*offset = length;
return (stcb);