summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
Diffstat (limited to 'sys')
-rw-r--r--sys/netinet/sctp_asconf.c12
-rw-r--r--sys/netinet/sctp_auth.c2
-rw-r--r--sys/netinet/sctp_bsd_addr.c1
-rw-r--r--sys/netinet/sctp_cc_functions.c10
-rw-r--r--sys/netinet/sctp_constants.h7
-rw-r--r--sys/netinet/sctp_indata.c173
-rw-r--r--sys/netinet/sctp_input.c369
-rw-r--r--sys/netinet/sctp_lock_bsd.h6
-rw-r--r--sys/netinet/sctp_os_bsd.h1
-rw-r--r--sys/netinet/sctp_output.c110
-rw-r--r--sys/netinet/sctp_output.h21
-rw-r--r--sys/netinet/sctp_pcb.c25
-rw-r--r--sys/netinet/sctp_peeloff.c16
-rw-r--r--sys/netinet/sctp_timer.c22
-rw-r--r--sys/netinet/sctp_usrreq.c47
-rw-r--r--sys/netinet/sctputil.c314
-rw-r--r--sys/netinet/sctputil.h40
-rw-r--r--sys/netinet6/sctp6_usrreq.c4
18 files changed, 925 insertions, 255 deletions
diff --git a/sys/netinet/sctp_asconf.c b/sys/netinet/sctp_asconf.c
index e33408e..fb51dd4 100644
--- a/sys/netinet/sctp_asconf.c
+++ b/sys/netinet/sctp_asconf.c
@@ -280,7 +280,7 @@ sctp_process_asconf_add_ip(struct mbuf *m, struct sctp_asconf_paramhdr *aph,
aparam_length);
} else {
/* notify upper layer */
- sctp_ulp_notify(SCTP_NOTIFY_ASCONF_ADD_IP, stcb, 0, sa);
+ sctp_ulp_notify(SCTP_NOTIFY_ASCONF_ADD_IP, stcb, 0, sa, SCTP_SO_NOT_LOCKED);
if (response_required) {
m_reply =
sctp_asconf_success_response(aph->correlation_id);
@@ -316,7 +316,7 @@ sctp_asconf_del_remote_addrs_except(struct sctp_tcb *stcb, struct sockaddr *src)
(struct sockaddr *)&net->ro._l_addr);
/* notify upper layer */
sctp_ulp_notify(SCTP_NOTIFY_ASCONF_DELETE_IP, stcb, 0,
- (struct sockaddr *)&net->ro._l_addr);
+ (struct sockaddr *)&net->ro._l_addr, SCTP_SO_NOT_LOCKED);
}
}
return 0;
@@ -451,7 +451,7 @@ sctp_process_asconf_delete_ip(struct mbuf *m, struct sctp_asconf_paramhdr *aph,
m_reply = sctp_asconf_success_response(aph->correlation_id);
}
/* notify upper layer */
- sctp_ulp_notify(SCTP_NOTIFY_ASCONF_DELETE_IP, stcb, 0, sa);
+ sctp_ulp_notify(SCTP_NOTIFY_ASCONF_DELETE_IP, stcb, 0, sa, SCTP_SO_NOT_LOCKED);
}
return m_reply;
}
@@ -545,7 +545,7 @@ sctp_process_asconf_set_primary(struct mbuf *m,
SCTPDBG(SCTP_DEBUG_ASCONF1,
"process_asconf_set_primary: primary address set\n");
/* notify upper layer */
- sctp_ulp_notify(SCTP_NOTIFY_ASCONF_SET_PRIMARY, stcb, 0, sa);
+ sctp_ulp_notify(SCTP_NOTIFY_ASCONF_SET_PRIMARY, stcb, 0, sa, SCTP_SO_NOT_LOCKED);
if (response_required) {
m_reply = sctp_asconf_success_response(aph->correlation_id);
@@ -1592,7 +1592,7 @@ sctp_handle_asconf_ack(struct mbuf *m, int offset,
if (serial_num == (asoc->asconf_seq_out + 1)) {
SCTPDBG(SCTP_DEBUG_ASCONF1, "handle_asconf_ack: got unexpected next serial number! Aborting asoc!\n");
sctp_abort_an_association(stcb->sctp_ep, stcb,
- SCTP_CAUSE_ILLEGAL_ASCONF_ACK, NULL);
+ SCTP_CAUSE_ILLEGAL_ASCONF_ACK, NULL, SCTP_SO_NOT_LOCKED);
return;
}
if (serial_num != asoc->asconf_seq_out) {
@@ -2199,7 +2199,7 @@ sctp_set_primary_ip_address(struct sctp_ifa *ifa)
if (!sctp_asconf_queue_add(stcb, ifa,
SCTP_SET_PRIM_ADDR)) {
/* set primary queuing succeeded */
- SCTPDBG(SCTP_DEBUG_ASCONF1, ": queued on stcb=%p, ",
+ SCTPDBG(SCTP_DEBUG_ASCONF1, "set_primary_ip_address: queued on stcb=%p, ",
stcb);
SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, &ifa->address.sa);
if (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_OPEN) {
diff --git a/sys/netinet/sctp_auth.c b/sys/netinet/sctp_auth.c
index bfab3fd..5f45540 100644
--- a/sys/netinet/sctp_auth.c
+++ b/sys/netinet/sctp_auth.c
@@ -1843,7 +1843,7 @@ sctp_notify_authentication(struct sctp_tcb *stcb, uint32_t indication,
/* not that we need this */
control->tail_mbuf = m_notify;
sctp_add_to_readq(stcb->sctp_ep, stcb, control,
- &stcb->sctp_socket->so_rcv, 1);
+ &stcb->sctp_socket->so_rcv, 1, SCTP_SO_NOT_LOCKED);
}
diff --git a/sys/netinet/sctp_bsd_addr.c b/sys/netinet/sctp_bsd_addr.c
index 6d92b7b..8b5aaf9 100644
--- a/sys/netinet/sctp_bsd_addr.c
+++ b/sys/netinet/sctp_bsd_addr.c
@@ -321,7 +321,6 @@ sctp_addr_change(struct ifaddr *ifa, int cmd)
ifa->ifa_ifp->if_index, ifa->ifa_ifp->if_type,
ifa->ifa_ifp->if_xname,
(void *)ifa, ifa->ifa_addr, ifa_flags, 1);
-
} else if (cmd == RTM_DELETE) {
sctp_del_addr_from_vrf(SCTP_DEFAULT_VRFID, ifa->ifa_addr, ifa->ifa_ifp->if_index);
diff --git a/sys/netinet/sctp_cc_functions.c b/sys/netinet/sctp_cc_functions.c
index b934fd9..90a809c 100644
--- a/sys/netinet/sctp_cc_functions.c
+++ b/sys/netinet/sctp_cc_functions.c
@@ -221,7 +221,7 @@ sctp_cwnd_update_after_sack(struct sctp_tcb *stcb,
net->dest_state &= ~SCTP_ADDR_NOT_REACHABLE;
net->dest_state |= SCTP_ADDR_REACHABLE;
sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb,
- SCTP_RECEIVED_SACK, (void *)net);
+ SCTP_RECEIVED_SACK, (void *)net, SCTP_SO_NOT_LOCKED);
/* now was it the primary? if so restore */
if (net->dest_state & SCTP_ADDR_WAS_PRIMARY) {
(void)sctp_set_primary_addr(stcb, (struct sockaddr *)NULL, net);
@@ -710,7 +710,7 @@ sctp_hs_cwnd_update_after_sack(struct sctp_tcb *stcb,
net->dest_state &= ~SCTP_ADDR_NOT_REACHABLE;
net->dest_state |= SCTP_ADDR_REACHABLE;
sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb,
- SCTP_RECEIVED_SACK, (void *)net);
+ SCTP_RECEIVED_SACK, (void *)net, SCTP_SO_NOT_LOCKED);
/* now was it the primary? if so restore */
if (net->dest_state & SCTP_ADDR_WAS_PRIMARY) {
(void)sctp_set_primary_addr(stcb, (struct sockaddr *)NULL, net);
@@ -1011,7 +1011,7 @@ sctp_cwnd_update_after_fr_timer(struct sctp_inpcb *inp,
old_cwnd = net->cwnd;
- sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_EARLY_FR_TMR);
+ sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_EARLY_FR_TMR, SCTP_SO_NOT_LOCKED);
/*
* make a small adjustment to cwnd and force to CA.
*/
@@ -1405,7 +1405,7 @@ sctp_htcp_cwnd_update_after_sack(struct sctp_tcb *stcb,
net->dest_state &= ~SCTP_ADDR_NOT_REACHABLE;
net->dest_state |= SCTP_ADDR_REACHABLE;
sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb,
- SCTP_RECEIVED_SACK, (void *)net);
+ SCTP_RECEIVED_SACK, (void *)net, SCTP_SO_NOT_LOCKED);
/* now was it the primary? if so restore */
if (net->dest_state & SCTP_ADDR_WAS_PRIMARY) {
(void)sctp_set_primary_addr(stcb, (struct sockaddr *)NULL, net);
@@ -1591,7 +1591,7 @@ sctp_htcp_cwnd_update_after_fr_timer(struct sctp_inpcb *inp,
old_cwnd = net->cwnd;
- sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_EARLY_FR_TMR);
+ sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_EARLY_FR_TMR, SCTP_SO_NOT_LOCKED);
net->htcp_ca.last_cong = sctp_get_tick_count();
/*
* make a small adjustment to cwnd and force to CA.
diff --git a/sys/netinet/sctp_constants.h b/sys/netinet/sctp_constants.h
index faff3b4..5d65b78 100644
--- a/sys/netinet/sctp_constants.h
+++ b/sys/netinet/sctp_constants.h
@@ -1028,6 +1028,13 @@ __FBSDID("$FreeBSD$");
#define SCTP_DEF_ASOC_RESC_LIMIT 10
#define SCTP_DEF_SYSTEM_RESC_LIMIT 1000
+/*-
+ * defines for socket lock states.
+ * Used by __APPLE__ and SCTP_SO_LOCK_TESTING
+ */
+#define SCTP_SO_LOCKED 1
+#define SCTP_SO_NOT_LOCKED 0
+
#define IN4_ISPRIVATE_ADDRESS(a) \
((((uint8_t *)&(a)->s_addr)[0] == 10) || \
diff --git a/sys/netinet/sctp_indata.c b/sys/netinet/sctp_indata.c
index 03b67e0..52881d2 100644
--- a/sys/netinet/sctp_indata.c
+++ b/sys/netinet/sctp_indata.c
@@ -432,7 +432,7 @@ sctp_service_reassembly(struct sctp_tcb *stcb, struct sctp_association *asoc)
else
end = 0;
sctp_add_to_readq(stcb->sctp_ep,
- stcb, control, &stcb->sctp_socket->so_rcv, end);
+ stcb, control, &stcb->sctp_socket->so_rcv, end, SCTP_SO_NOT_LOCKED);
cntDel++;
} else {
if (chk->rec.data.rcv_flags & SCTP_DATA_LAST_FRAG)
@@ -508,7 +508,7 @@ sctp_service_reassembly(struct sctp_tcb *stcb, struct sctp_association *asoc)
strm->last_sequence_delivered++;
sctp_add_to_readq(stcb->sctp_ep, stcb,
ctl,
- &stcb->sctp_socket->so_rcv, 1);
+ &stcb->sctp_socket->so_rcv, 1, SCTP_SO_NOT_LOCKED);
ctl = ctlat;
} else {
break;
@@ -601,7 +601,7 @@ sctp_queue_data_to_stream(struct sctp_tcb *stcb, struct sctp_association *asoc,
}
stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_1;
sctp_abort_an_association(stcb->sctp_ep, stcb,
- SCTP_PEER_FAULTY, oper);
+ SCTP_PEER_FAULTY, oper, SCTP_SO_NOT_LOCKED);
*abort_flag = 1;
return;
@@ -618,7 +618,7 @@ sctp_queue_data_to_stream(struct sctp_tcb *stcb, struct sctp_association *asoc,
strm->last_sequence_delivered++;
sctp_add_to_readq(stcb->sctp_ep, stcb,
control,
- &stcb->sctp_socket->so_rcv, 1);
+ &stcb->sctp_socket->so_rcv, 1, SCTP_SO_NOT_LOCKED);
control = TAILQ_FIRST(&strm->inqueue);
while (control != NULL) {
/* all delivered */
@@ -641,7 +641,7 @@ sctp_queue_data_to_stream(struct sctp_tcb *stcb, struct sctp_association *asoc,
}
sctp_add_to_readq(stcb->sctp_ep, stcb,
control,
- &stcb->sctp_socket->so_rcv, 1);
+ &stcb->sctp_socket->so_rcv, 1, SCTP_SO_NOT_LOCKED);
control = at;
continue;
}
@@ -876,7 +876,7 @@ sctp_queue_data_for_reasm(struct sctp_tcb *stcb, struct sctp_association *asoc,
}
stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_2;
sctp_abort_an_association(stcb->sctp_ep, stcb,
- SCTP_PEER_FAULTY, oper);
+ SCTP_PEER_FAULTY, oper, SCTP_SO_NOT_LOCKED);
*abort_flag = 1;
} else if (asoc->fragmented_delivery_inprogress &&
(chk->rec.data.rcv_flags & SCTP_DATA_FIRST_FRAG) == SCTP_DATA_FIRST_FRAG) {
@@ -908,7 +908,7 @@ sctp_queue_data_for_reasm(struct sctp_tcb *stcb, struct sctp_association *asoc,
}
stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_3;
sctp_abort_an_association(stcb->sctp_ep, stcb,
- SCTP_PEER_FAULTY, oper);
+ SCTP_PEER_FAULTY, oper, SCTP_SO_NOT_LOCKED);
*abort_flag = 1;
} else if (asoc->fragmented_delivery_inprogress) {
/*
@@ -945,7 +945,7 @@ sctp_queue_data_for_reasm(struct sctp_tcb *stcb, struct sctp_association *asoc,
}
stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_4;
sctp_abort_an_association(stcb->sctp_ep,
- stcb, SCTP_PEER_FAULTY, oper);
+ stcb, SCTP_PEER_FAULTY, oper, SCTP_SO_NOT_LOCKED);
*abort_flag = 1;
} else if ((asoc->fragment_flags & SCTP_DATA_UNORDERED) !=
SCTP_DATA_UNORDERED &&
@@ -980,7 +980,7 @@ sctp_queue_data_for_reasm(struct sctp_tcb *stcb, struct sctp_association *asoc,
}
stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_5;
sctp_abort_an_association(stcb->sctp_ep,
- stcb, SCTP_PEER_FAULTY, oper);
+ stcb, SCTP_PEER_FAULTY, oper, SCTP_SO_NOT_LOCKED);
*abort_flag = 1;
}
}
@@ -1078,7 +1078,7 @@ sctp_queue_data_for_reasm(struct sctp_tcb *stcb, struct sctp_association *asoc,
}
stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_6;
sctp_abort_an_association(stcb->sctp_ep,
- stcb, SCTP_PEER_FAULTY, oper);
+ stcb, SCTP_PEER_FAULTY, oper, SCTP_SO_NOT_LOCKED);
*abort_flag = 1;
return;
}
@@ -1115,7 +1115,7 @@ sctp_queue_data_for_reasm(struct sctp_tcb *stcb, struct sctp_association *asoc,
}
stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_7;
sctp_abort_an_association(stcb->sctp_ep,
- stcb, SCTP_PEER_FAULTY, oper);
+ stcb, SCTP_PEER_FAULTY, oper, SCTP_SO_NOT_LOCKED);
*abort_flag = 1;
return;
@@ -1154,7 +1154,7 @@ sctp_queue_data_for_reasm(struct sctp_tcb *stcb, struct sctp_association *asoc,
}
stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_8;
sctp_abort_an_association(stcb->sctp_ep,
- stcb, SCTP_PEER_FAULTY, oper);
+ stcb, SCTP_PEER_FAULTY, oper, SCTP_SO_NOT_LOCKED);
*abort_flag = 1;
return;
@@ -1190,7 +1190,7 @@ sctp_queue_data_for_reasm(struct sctp_tcb *stcb, struct sctp_association *asoc,
}
stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_9;
sctp_abort_an_association(stcb->sctp_ep,
- stcb, SCTP_PEER_FAULTY, oper);
+ stcb, SCTP_PEER_FAULTY, oper, SCTP_SO_NOT_LOCKED);
*abort_flag = 1;
return;
@@ -1235,7 +1235,7 @@ sctp_queue_data_for_reasm(struct sctp_tcb *stcb, struct sctp_association *asoc,
}
stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_10;
sctp_abort_an_association(stcb->sctp_ep,
- stcb, SCTP_PEER_FAULTY, oper);
+ stcb, SCTP_PEER_FAULTY, oper, SCTP_SO_NOT_LOCKED);
*abort_flag = 1;
return;
@@ -1277,7 +1277,7 @@ sctp_queue_data_for_reasm(struct sctp_tcb *stcb, struct sctp_association *asoc,
}
stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_11;
sctp_abort_an_association(stcb->sctp_ep,
- stcb, SCTP_PEER_FAULTY, oper);
+ stcb, SCTP_PEER_FAULTY, oper, SCTP_SO_NOT_LOCKED);
*abort_flag = 1;
return;
@@ -1316,7 +1316,7 @@ sctp_queue_data_for_reasm(struct sctp_tcb *stcb, struct sctp_association *asoc,
}
stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_12;
sctp_abort_an_association(stcb->sctp_ep,
- stcb, SCTP_PEER_FAULTY, oper);
+ stcb, SCTP_PEER_FAULTY, oper, SCTP_SO_NOT_LOCKED);
*abort_flag = 1;
return;
@@ -1355,11 +1355,10 @@ sctp_queue_data_for_reasm(struct sctp_tcb *stcb, struct sctp_association *asoc,
}
stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_13;
sctp_abort_an_association(stcb->sctp_ep,
- stcb, SCTP_PEER_FAULTY, oper);
+ stcb, SCTP_PEER_FAULTY, oper, SCTP_SO_NOT_LOCKED);
*abort_flag = 1;
return;
-
}
}
}
@@ -1520,7 +1519,7 @@ sctp_process_a_data_chunk(struct sctp_tcb *stcb, struct sctp_association *asoc,
struct mbuf *op_err;
op_err = sctp_generate_invmanparam(SCTP_CAUSE_OUT_OF_RESC);
- sctp_abort_an_association(stcb->sctp_ep, stcb, 0, op_err);
+ sctp_abort_an_association(stcb->sctp_ep, stcb, 0, op_err, SCTP_SO_NOT_LOCKED);
*abort_flag = 1;
return (0);
}
@@ -1541,7 +1540,25 @@ sctp_process_a_data_chunk(struct sctp_tcb *stcb, struct sctp_association *asoc,
*/
if (stcb->sctp_socket->so_rcv.sb_cc) {
/* some to read, wake-up */
+#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ struct socket *so;
+
+ so = SCTP_INP_SO(stcb->sctp_ep);
+ 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);
+ if (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET) {
+ /* assoc was freed while we were unlocked */
+ SCTP_SOCKET_UNLOCK(so, 1);
+ return (0);
+ }
+#endif
sctp_sorwakeup(stcb->sctp_ep, stcb->sctp_socket);
+#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ SCTP_SOCKET_UNLOCK(so, 1);
+#endif
}
/* now is it in the mapping array of what we have accepted? */
if (compare_with_wrap(tsn,
@@ -1661,7 +1678,7 @@ sctp_process_a_data_chunk(struct sctp_tcb *stcb, struct sctp_association *asoc,
}
stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_14;
sctp_abort_an_association(stcb->sctp_ep, stcb,
- SCTP_PEER_FAULTY, oper);
+ SCTP_PEER_FAULTY, oper, SCTP_SO_NOT_LOCKED);
*abort_flag = 1;
return (0);
}
@@ -1746,7 +1763,7 @@ sctp_process_a_data_chunk(struct sctp_tcb *stcb, struct sctp_association *asoc,
if (control == NULL) {
goto failed_express_del;
}
- sctp_add_to_readq(stcb->sctp_ep, stcb, control, &stcb->sctp_socket->so_rcv, 1);
+ sctp_add_to_readq(stcb->sctp_ep, stcb, control, &stcb->sctp_socket->so_rcv, 1, SCTP_SO_NOT_LOCKED);
if ((chunk_flags & SCTP_DATA_UNORDERED) == 0) {
/* for ordered, bump what we delivered */
asoc->strmin[strmno].last_sequence_delivered++;
@@ -1911,7 +1928,7 @@ failed_pdapi_express_del:
}
stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_15;
sctp_abort_an_association(stcb->sctp_ep, stcb,
- SCTP_PEER_FAULTY, oper);
+ SCTP_PEER_FAULTY, oper, SCTP_SO_NOT_LOCKED);
*abort_flag = 1;
return (0);
@@ -1949,7 +1966,7 @@ failed_pdapi_express_del:
}
stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_16;
sctp_abort_an_association(stcb->sctp_ep,
- stcb, SCTP_PEER_FAULTY, oper);
+ stcb, SCTP_PEER_FAULTY, oper, SCTP_SO_NOT_LOCKED);
*abort_flag = 1;
return (0);
@@ -1996,7 +2013,7 @@ failed_pdapi_express_del:
}
stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_17;
sctp_abort_an_association(stcb->sctp_ep,
- stcb, SCTP_PEER_FAULTY, oper);
+ stcb, SCTP_PEER_FAULTY, oper, SCTP_SO_NOT_LOCKED);
*abort_flag = 1;
return (0);
@@ -2008,7 +2025,7 @@ failed_pdapi_express_del:
/* queue directly into socket buffer */
sctp_add_to_readq(stcb->sctp_ep, stcb,
control,
- &stcb->sctp_socket->so_rcv, 1);
+ &stcb->sctp_socket->so_rcv, 1, SCTP_SO_NOT_LOCKED);
} else {
/*
* Special check for when streams are resetting. We
@@ -2257,9 +2274,11 @@ sctp_sack_check(struct sctp_tcb *stcb, int ok_to_sack, int was_a_gap, int *abort
asoc->highest_tsn_inside_map,
MAX_TSN)) {
#ifdef INVARIANTS
- panic("huh, cumack greater than high-tsn in map");
+ panic("huh, cumack 0x%x greater than high-tsn 0x%x in map",
+ asoc->cumulative_tsn, asoc->highest_tsn_inside_map);
#else
- SCTP_PRINTF("huh, cumack greater than high-tsn in map - should panic?\n");
+ SCTP_PRINTF("huh, cumack 0x%x greater than high-tsn 0x%x in map - should panic?\n",
+ asoc->cumulative_tsn, asoc->highest_tsn_inside_map);
asoc->highest_tsn_inside_map = asoc->cumulative_tsn;
#endif
}
@@ -2717,7 +2736,7 @@ sctp_process_data(struct mbuf **mm, int iphlen, int *offset, int length,
}
if (num_chunks) {
/*
- * Did we get data, if sa update the time for auto-close and
+ * Did we get data, if so update the time for auto-close and
* give peer credit for being alive.
*/
SCTP_STAT_INCR(sctps_recvpktwithdata);
@@ -3209,7 +3228,7 @@ sctp_strike_gap_ack_chunks(struct sctp_tcb *stcb, struct sctp_association *asoc,
if (tp1->data != NULL) {
(void)sctp_release_pr_sctp_chunk(stcb, tp1,
(SCTP_RESPONSE_TO_USER_REQ | SCTP_NOTIFY_DATAGRAM_SENT),
- &asoc->sent_queue);
+ &asoc->sent_queue, SCTP_SO_NOT_LOCKED);
}
tp1 = TAILQ_NEXT(tp1, sctp_next);
continue;
@@ -3222,7 +3241,7 @@ sctp_strike_gap_ack_chunks(struct sctp_tcb *stcb, struct sctp_association *asoc,
if (tp1->data != NULL) {
(void)sctp_release_pr_sctp_chunk(stcb, tp1,
(SCTP_RESPONSE_TO_USER_REQ | SCTP_NOTIFY_DATAGRAM_SENT),
- &asoc->sent_queue);
+ &asoc->sent_queue, SCTP_SO_NOT_LOCKED);
}
tp1 = TAILQ_NEXT(tp1, sctp_next);
continue;
@@ -3386,7 +3405,6 @@ sctp_strike_gap_ack_chunks(struct sctp_tcb *stcb, struct sctp_association *asoc,
}
if (tp1->sent < SCTP_DATAGRAM_RESEND) {
tp1->sent++;
-
}
}
}
@@ -3637,7 +3655,7 @@ sctp_try_advance_peer_ack_point(struct sctp_tcb *stcb,
if (tp1->data) {
(void)sctp_release_pr_sctp_chunk(stcb, tp1,
(SCTP_RESPONSE_TO_USER_REQ | SCTP_NOTIFY_DATAGRAM_SENT),
- &asoc->sent_queue);
+ &asoc->sent_queue, SCTP_SO_NOT_LOCKED);
}
} else {
/*
@@ -3670,12 +3688,32 @@ sctp_try_advance_peer_ack_point(struct sctp_tcb *stcb,
*/
sctp_ulp_notify(SCTP_NOTIFY_DG_FAIL, stcb,
(SCTP_RESPONSE_TO_USER_REQ | SCTP_NOTIFY_DATAGRAM_SENT),
- tp1);
+ tp1, SCTP_SO_NOT_LOCKED);
sctp_m_freem(tp1->data);
tp1->data = NULL;
if (stcb->sctp_socket) {
- sctp_sowwakeup(stcb->sctp_ep,
- stcb->sctp_socket);
+#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ struct socket *so;
+
+ so = SCTP_INP_SO(stcb->sctp_ep);
+ 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);
+ if (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET) {
+ /*
+ * assoc was freed while we
+ * were unlocked
+ */
+ SCTP_SOCKET_UNLOCK(so, 1);
+ return (NULL);
+ }
+#endif
+ sctp_sowwakeup(stcb->sctp_ep, stcb->sctp_socket);
+#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ SCTP_SOCKET_UNLOCK(so, 1);
+#endif
if (sctp_logging_level & SCTP_WAKE_LOGGING_ENABLE) {
sctp_wakeup_log(stcb, tp1->rec.data.TSN_seq, 1, SCTP_WAKESND_FROM_FWDTSN);
}
@@ -3781,7 +3819,6 @@ sctp_express_handle_sack(struct sctp_tcb *stcb, uint32_t cumack,
int win_probe_recovered = 0;
int j, done_once = 0;
-
if (sctp_logging_level & SCTP_LOG_SACK_ARRIVALS_ENABLE) {
sctp_misc_ints(SCTP_SACK_LOG_EXPRESS, cumack,
rwnd, stcb->asoc.last_acked_seq, stcb->asoc.peers_rwnd);
@@ -3811,7 +3848,6 @@ sctp_express_handle_sack(struct sctp_tcb *stcb, uint32_t cumack,
goto again;
}
return;
-
}
/* First setup for CC stuff */
TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
@@ -3862,7 +3898,7 @@ sctp_express_handle_sack(struct sctp_tcb *stcb, uint32_t cumack,
*ippp = htonl(SCTP_FROM_SCTP_INDATA + SCTP_LOC_25);
}
stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_25;
- sctp_abort_an_association(stcb->sctp_ep, stcb, SCTP_PEER_FAULTY, oper);
+ sctp_abort_an_association(stcb->sctp_ep, stcb, SCTP_PEER_FAULTY, oper, SCTP_SO_NOT_LOCKED);
return;
#endif
}
@@ -3981,11 +4017,32 @@ sctp_express_handle_sack(struct sctp_tcb *stcb, uint32_t cumack,
}
if (stcb->sctp_socket) {
+#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ struct socket *so;
+
+#endif
+
SOCKBUF_LOCK(&stcb->sctp_socket->so_snd);
if (sctp_logging_level & SCTP_WAKE_LOGGING_ENABLE) {
sctp_wakeup_log(stcb, cumack, 1, SCTP_WAKESND_FROM_SACK);
}
+#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ so = SCTP_INP_SO(stcb->sctp_ep);
+ 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);
+ if (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET) {
+ /* assoc was freed while we were unlocked */
+ SCTP_SOCKET_UNLOCK(so, 1);
+ return;
+ }
+#endif
sctp_sowwakeup_locked(stcb->sctp_ep, stcb->sctp_socket);
+#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ SCTP_SOCKET_UNLOCK(so, 1);
+#endif
} else {
if (sctp_logging_level & SCTP_WAKE_LOGGING_ENABLE) {
sctp_wakeup_log(stcb, cumack, 1, SCTP_NOWAKE_FROM_SACK);
@@ -4195,7 +4252,7 @@ again:
*ippp = htonl(SCTP_FROM_SCTP_INDATA + SCTP_LOC_24);
}
stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_24;
- sctp_abort_an_association(stcb->sctp_ep, stcb, SCTP_RESPONSE_TO_USER_REQ, oper);
+ sctp_abort_an_association(stcb->sctp_ep, stcb, SCTP_RESPONSE_TO_USER_REQ, oper, SCTP_SO_NOT_LOCKED);
} else {
if ((SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) ||
(SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
@@ -4344,8 +4401,6 @@ sctp_handle_sack(struct mbuf *m, int offset,
if (dupdata == NULL)
break;
off_to_dup += sizeof(uint32_t);
-
-
}
}
} else {
@@ -4396,7 +4451,7 @@ sctp_handle_sack(struct mbuf *m, int offset,
*ippp = htonl(SCTP_FROM_SCTP_INDATA + SCTP_LOC_25);
}
stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_25;
- sctp_abort_an_association(stcb->sctp_ep, stcb, SCTP_PEER_FAULTY, oper);
+ sctp_abort_an_association(stcb->sctp_ep, stcb, SCTP_PEER_FAULTY, oper, SCTP_SO_NOT_LOCKED);
return;
#endif
}
@@ -4707,11 +4762,31 @@ skip_segments:
done_with_it:
if ((wake_him) && (stcb->sctp_socket)) {
+#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ struct socket *so;
+
+#endif
SOCKBUF_LOCK(&stcb->sctp_socket->so_snd);
if (sctp_logging_level & SCTP_WAKE_LOGGING_ENABLE) {
sctp_wakeup_log(stcb, cum_ack, wake_him, SCTP_WAKESND_FROM_SACK);
}
+#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ so = SCTP_INP_SO(stcb->sctp_ep);
+ 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);
+ if (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET) {
+ /* assoc was freed while we were unlocked */
+ SCTP_SOCKET_UNLOCK(so, 1);
+ return;
+ }
+#endif
sctp_sowwakeup_locked(stcb->sctp_ep, stcb->sctp_socket);
+#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ SCTP_SOCKET_UNLOCK(so, 1);
+#endif
} else {
if (sctp_logging_level & SCTP_WAKE_LOGGING_ENABLE) {
sctp_wakeup_log(stcb, cum_ack, wake_him, SCTP_NOWAKE_FROM_SACK);
@@ -4865,7 +4940,7 @@ done_with_it:
*ippp = htonl(SCTP_FROM_SCTP_INDATA + SCTP_LOC_31);
}
stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_31;
- sctp_abort_an_association(stcb->sctp_ep, stcb, SCTP_RESPONSE_TO_USER_REQ, oper);
+ sctp_abort_an_association(stcb->sctp_ep, stcb, SCTP_RESPONSE_TO_USER_REQ, oper, SCTP_SO_NOT_LOCKED);
return;
} else {
if ((SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) ||
@@ -4926,7 +5001,6 @@ done_with_it:
asoc->advanced_peer_ack_point = cum_ack;
}
/* C2. try to further move advancedPeerAckPoint ahead */
-
if ((asoc->peer_supports_prsctp) && (asoc->pr_sctp_cnt > 0)) {
struct sctp_tmit_chunk *lchk;
@@ -5167,7 +5241,7 @@ sctp_kick_prsctp_reorder_queue(struct sctp_tcb *stcb,
if (stcb->sctp_socket) {
sctp_add_to_readq(stcb->sctp_ep, stcb,
ctl,
- &stcb->sctp_socket->so_rcv, 1);
+ &stcb->sctp_socket->so_rcv, 1, SCTP_SO_NOT_LOCKED);
}
} else {
/* no more delivery now. */
@@ -5194,7 +5268,7 @@ sctp_kick_prsctp_reorder_queue(struct sctp_tcb *stcb,
if (stcb->sctp_socket) {
sctp_add_to_readq(stcb->sctp_ep, stcb,
ctl,
- &stcb->sctp_socket->so_rcv, 1);
+ &stcb->sctp_socket->so_rcv, 1, SCTP_SO_NOT_LOCKED);
}
tt = strmin->last_sequence_delivered + 1;
} else {
@@ -5308,7 +5382,7 @@ sctp_handle_forward_tsn(struct sctp_tcb *stcb,
}
stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_INDATA + SCTP_LOC_33;
sctp_abort_an_association(stcb->sctp_ep, stcb,
- SCTP_PEER_FAULTY, oper);
+ SCTP_PEER_FAULTY, oper, SCTP_SO_NOT_LOCKED);
return;
}
SCTP_STAT_INCR(sctps_fwdtsn_map_over);
@@ -5322,7 +5396,6 @@ slide_out:
sctp_log_map(0, 3, asoc->highest_tsn_inside_map, SCTP_MAP_SLIDE_RESULT);
}
asoc->last_echo_tsn = asoc->highest_tsn_inside_map;
-
} else {
SCTP_TCB_LOCK_ASSERT(stcb);
if ((compare_with_wrap(((uint32_t) asoc->cumulative_tsn + gap), asoc->highest_tsn_inside_map, MAX_TSN)) ||
@@ -5435,7 +5508,7 @@ slide_out:
str_seq = (asoc->str_of_pdapi << 16) | asoc->ssn_of_pdapi;
sctp_ulp_notify(SCTP_NOTIFY_PARTIAL_DELVIERY_INDICATION,
- stcb, SCTP_PARTIAL_DELIVERY_ABORTED, (void *)&str_seq);
+ stcb, SCTP_PARTIAL_DELIVERY_ABORTED, (void *)&str_seq, SCTP_SO_NOT_LOCKED);
}
break;
@@ -5452,7 +5525,7 @@ slide_out:
str_seq = (asoc->str_of_pdapi << 16) | asoc->ssn_of_pdapi;
sctp_ulp_notify(SCTP_NOTIFY_PARTIAL_DELVIERY_INDICATION,
- stcb, SCTP_PARTIAL_DELIVERY_ABORTED, (void *)&str_seq);
+ stcb, SCTP_PARTIAL_DELIVERY_ABORTED, (void *)&str_seq, SCTP_SO_NOT_LOCKED);
asoc->fragmented_delivery_inprogress = 0;
}
/*************************************************************/
diff --git a/sys/netinet/sctp_input.c b/sys/netinet/sctp_input.c
index be3602a..904f79c 100644
--- a/sys/netinet/sctp_input.c
+++ b/sys/netinet/sctp_input.c
@@ -271,7 +271,7 @@ sctp_process_init(struct sctp_init_chunk *cp, struct sctp_tcb *stcb,
asoc->stream_queue_cnt--;
sctp_ulp_notify(SCTP_NOTIFY_SPECIAL_SP_FAIL,
stcb, SCTP_NOTIFY_DATAGRAM_UNSENT,
- sp);
+ sp, SCTP_SO_NOT_LOCKED);
if (sp->data) {
sctp_m_freem(sp->data);
sp->data = NULL;
@@ -382,7 +382,7 @@ sctp_process_init_ack(struct mbuf *m, int iphlen, int offset,
&abort_flag, (struct sctp_chunkhdr *)cp);
if (abort_flag) {
/* Send an abort and notify peer */
- sctp_abort_an_association(stcb->sctp_ep, stcb, SCTP_CAUSE_PROTOCOL_VIOLATION, op_err);
+ sctp_abort_an_association(stcb->sctp_ep, stcb, SCTP_CAUSE_PROTOCOL_VIOLATION, op_err, SCTP_SO_NOT_LOCKED);
*abort_no_unlock = 1;
return (-1);
}
@@ -550,7 +550,7 @@ sctp_handle_heartbeat_ack(struct sctp_heartbeat_chunk *cp,
}
}
sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_CONFIRMED,
- stcb, 0, (void *)r_net);
+ stcb, 0, (void *)r_net, SCTP_SO_NOT_LOCKED);
}
r_net->error_count = 0;
r_net->hb_responded = 1;
@@ -560,7 +560,7 @@ sctp_handle_heartbeat_ack(struct sctp_heartbeat_chunk *cp,
r_net->dest_state &= ~SCTP_ADDR_NOT_REACHABLE;
r_net->dest_state |= SCTP_ADDR_REACHABLE;
sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb,
- SCTP_HEARTBEAT_SUCCESS, (void *)r_net);
+ SCTP_HEARTBEAT_SUCCESS, (void *)r_net, SCTP_SO_NOT_LOCKED);
/* now was it the primary? if so restore */
if (r_net->dest_state & SCTP_ADDR_WAS_PRIMARY) {
(void)sctp_set_primary_addr(stcb, (struct sockaddr *)NULL, r_net);
@@ -593,6 +593,11 @@ static void
sctp_handle_abort(struct sctp_abort_chunk *cp,
struct sctp_tcb *stcb, struct sctp_nets *net)
{
+#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ struct socket *so;
+
+#endif
+
SCTPDBG(SCTP_DEBUG_INPUT2, "sctp_handle_abort: handling ABORT\n");
if (stcb == NULL)
return;
@@ -600,7 +605,7 @@ sctp_handle_abort(struct sctp_abort_chunk *cp,
/* stop any receive timers */
sctp_timer_stop(SCTP_TIMER_TYPE_RECV, stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_INPUT + SCTP_LOC_6);
/* notify user of the abort and clean up... */
- sctp_abort_notification(stcb, 0);
+ sctp_abort_notification(stcb, 0, SCTP_SO_NOT_LOCKED);
/* free the tcb */
SCTP_STAT_INCR_COUNTER32(sctps_aborted);
if ((SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_OPEN) ||
@@ -610,9 +615,20 @@ sctp_handle_abort(struct sctp_abort_chunk *cp,
#ifdef SCTP_ASOCLOG_OF_TSNS
sctp_print_out_track_log(stcb);
#endif
+#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ so = SCTP_INP_SO(stcb->sctp_ep);
+ 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
stcb->asoc.state |= SCTP_STATE_WAS_ABORTED;
(void)sctp_free_assoc(stcb->sctp_ep, stcb, SCTP_NORMAL_PROC,
SCTP_FROM_SCTP_INPUT + SCTP_LOC_6);
+#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ SCTP_SOCKET_UNLOCK(so, 1);
+#endif
SCTPDBG(SCTP_DEBUG_INPUT2, "sctp_handle_abort: finished\n");
}
@@ -623,6 +639,11 @@ sctp_handle_shutdown(struct sctp_shutdown_chunk *cp,
struct sctp_association *asoc;
int some_on_streamwheel;
+#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ struct socket *so;
+
+#endif
+
SCTPDBG(SCTP_DEBUG_INPUT2,
"sctp_handle_shutdown: handling SHUTDOWN\n");
if (stcb == NULL)
@@ -647,7 +668,23 @@ sctp_handle_shutdown(struct sctp_shutdown_chunk *cp,
asoc->control_pdapi->pdapi_aborted = 1;
asoc->control_pdapi = NULL;
SCTP_INP_READ_UNLOCK(stcb->sctp_ep);
+#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ so = SCTP_INP_SO(stcb->sctp_ep);
+ 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);
+ if (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET) {
+ /* assoc was freed while we were unlocked */
+ SCTP_SOCKET_UNLOCK(so, 1);
+ return;
+ }
+#endif
sctp_sorwakeup(stcb->sctp_ep, stcb->sctp_socket);
+#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ SCTP_SOCKET_UNLOCK(so, 1);
+#endif
}
/* goto SHUTDOWN_RECEIVED state to block new requests */
if (stcb->sctp_socket) {
@@ -659,7 +696,7 @@ sctp_handle_shutdown(struct sctp_shutdown_chunk *cp,
* notify upper layer that peer has initiated a
* shutdown
*/
- sctp_ulp_notify(SCTP_NOTIFY_PEER_SHUTDOWN, stcb, 0, NULL);
+ sctp_ulp_notify(SCTP_NOTIFY_PEER_SHUTDOWN, stcb, 0, NULL, SCTP_SO_NOT_LOCKED);
/* reset time */
(void)SCTP_GETTIME_TIMEVAL(&asoc->time_entered);
@@ -705,6 +742,11 @@ sctp_handle_shutdown_ack(struct sctp_shutdown_ack_chunk *cp,
{
struct sctp_association *asoc;
+#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ struct socket *so;
+
+ so = SCTP_INP_SO(stcb->sctp_ep);
+#endif
SCTPDBG(SCTP_DEBUG_INPUT2,
"sctp_handle_shutdown_ack: handling SHUTDOWN ACK\n");
if (stcb == NULL)
@@ -727,13 +769,28 @@ sctp_handle_shutdown_ack(struct sctp_shutdown_ack_chunk *cp,
asoc->control_pdapi->pdapi_aborted = 1;
asoc->control_pdapi = NULL;
SCTP_INP_READ_UNLOCK(stcb->sctp_ep);
+#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ 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);
+ if (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET) {
+ /* assoc was freed while we were unlocked */
+ SCTP_SOCKET_UNLOCK(so, 1);
+ return;
+ }
+#endif
sctp_sorwakeup(stcb->sctp_ep, stcb->sctp_socket);
+#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ SCTP_SOCKET_UNLOCK(so, 1);
+#endif
}
/* are the queues empty? */
if (!TAILQ_EMPTY(&asoc->send_queue) ||
!TAILQ_EMPTY(&asoc->sent_queue) ||
!TAILQ_EMPTY(&asoc->out_wheel)) {
- sctp_report_all_outbound(stcb, 0);
+ sctp_report_all_outbound(stcb, 0, SCTP_SO_NOT_LOCKED);
}
/* stop the timer */
sctp_timer_stop(SCTP_TIMER_TYPE_SHUTDOWN, stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_INPUT + SCTP_LOC_9);
@@ -741,7 +798,7 @@ sctp_handle_shutdown_ack(struct sctp_shutdown_ack_chunk *cp,
sctp_send_shutdown_complete(stcb, net);
/* notify upper layer protocol */
if (stcb->sctp_socket) {
- sctp_ulp_notify(SCTP_NOTIFY_ASSOC_DOWN, stcb, 0, NULL);
+ sctp_ulp_notify(SCTP_NOTIFY_ASSOC_DOWN, stcb, 0, NULL, SCTP_SO_NOT_LOCKED);
if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
(stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) {
/* Set the connected flag to disconnected */
@@ -750,8 +807,18 @@ sctp_handle_shutdown_ack(struct sctp_shutdown_ack_chunk *cp,
}
SCTP_STAT_INCR_COUNTER32(sctps_shutdown);
/* free the TCB but first save off the ep */
+#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ 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(stcb->sctp_ep, stcb, SCTP_NORMAL_PROC,
SCTP_FROM_SCTP_INPUT + SCTP_LOC_10);
+#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ SCTP_SOCKET_UNLOCK(so, 1);
+#endif
}
/*
@@ -835,9 +902,13 @@ sctp_handle_error(struct sctp_chunkhdr *ch,
uint16_t error_type;
uint16_t error_len;
struct sctp_association *asoc;
-
int adjust;
+#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ struct socket *so;
+
+#endif
+
/* parse through all of the errors and process */
asoc = &stcb->asoc;
phdr = (struct sctp_paramhdr *)((caddr_t)ch +
@@ -875,10 +946,21 @@ sctp_handle_error(struct sctp_chunkhdr *ch,
asoc->stale_cookie_count++;
if (asoc->stale_cookie_count >
asoc->max_init_times) {
- sctp_abort_notification(stcb, 0);
+ sctp_abort_notification(stcb, 0, SCTP_SO_NOT_LOCKED);
/* now free the asoc */
+#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ so = SCTP_INP_SO(stcb->sctp_ep);
+ 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(stcb->sctp_ep, stcb, SCTP_NORMAL_PROC,
SCTP_FROM_SCTP_INPUT + SCTP_LOC_11);
+#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ SCTP_SOCKET_UNLOCK(so, 1);
+#endif
return (-1);
}
/* blast back to INIT state */
@@ -886,7 +968,7 @@ sctp_handle_error(struct sctp_chunkhdr *ch,
asoc->state |= SCTP_STATE_COOKIE_WAIT;
sctp_stop_all_cookie_timers(stcb);
- sctp_send_initiate(stcb->sctp_ep, stcb);
+ sctp_send_initiate(stcb->sctp_ep, stcb, SCTP_SO_NOT_LOCKED);
}
break;
case SCTP_CAUSE_UNRESOLVABLE_ADDR:
@@ -1021,7 +1103,7 @@ sctp_handle_init_ack(struct mbuf *m, int iphlen, int offset,
stcb->asoc.primary_destination->dest_state &=
~SCTP_ADDR_UNCONFIRMED;
sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_CONFIRMED,
- stcb, 0, (void *)stcb->asoc.primary_destination);
+ stcb, 0, (void *)stcb->asoc.primary_destination, SCTP_SO_NOT_LOCKED);
}
if (sctp_process_init_ack(m, iphlen, offset, sh, cp, stcb,
net, abort_no_unlock, vrf_id) < 0) {
@@ -1219,6 +1301,10 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset,
(stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) &&
(inp->sctp_socket->so_qlimit == 0)
) {
+#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ struct socket *so;
+
+#endif
/*
* Here is where collision would go if we
* did a connect() and instead got a
@@ -1227,7 +1313,22 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset,
*/
stcb->sctp_ep->sctp_flags |=
SCTP_PCB_FLAGS_CONNECTED;
- soisconnected(stcb->sctp_ep->sctp_socket);
+#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ so = SCTP_INP_SO(stcb->sctp_ep);
+ atomic_add_int(&stcb->asoc.refcnt, 1);
+ SCTP_TCB_UNLOCK(stcb);
+ SCTP_SOCKET_LOCK(so, 1);
+ SCTP_TCB_LOCK(stcb);
+ atomic_add_int(&stcb->asoc.refcnt, -1);
+ if (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET) {
+ SCTP_SOCKET_UNLOCK(so, 1);
+ return (NULL);
+ }
+#endif
+ soisconnected(stcb->sctp_socket);
+#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ SCTP_SOCKET_UNLOCK(so, 1);
+#endif
}
/* notify upper layer */
*notification = SCTP_NOTIFY_ASSOC_UP;
@@ -1375,9 +1476,28 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset,
if (((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
(stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) &&
(inp->sctp_socket->so_qlimit == 0)) {
+#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ struct socket *so;
+
+#endif
stcb->sctp_ep->sctp_flags |=
SCTP_PCB_FLAGS_CONNECTED;
- soisconnected(stcb->sctp_ep->sctp_socket);
+#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ so = SCTP_INP_SO(stcb->sctp_ep);
+ atomic_add_int(&stcb->asoc.refcnt, 1);
+ SCTP_TCB_UNLOCK(stcb);
+ SCTP_SOCKET_LOCK(so, 1);
+ SCTP_TCB_LOCK(stcb);
+ atomic_add_int(&stcb->asoc.refcnt, -1);
+ if (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET) {
+ SCTP_SOCKET_UNLOCK(so, 1);
+ return (NULL);
+ }
+#endif
+ soisconnected(stcb->sctp_socket);
+#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ SCTP_SOCKET_UNLOCK(so, 1);
+#endif
}
if (SCTP_GET_STATE(asoc) == SCTP_STATE_COOKIE_ECHOED)
SCTP_STAT_INCR_COUNTER32(sctps_activeestab);
@@ -1407,7 +1527,7 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset,
* sctp_chunk_output will get the retrans out behind
* this.
*/
- sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_COOKIE_ACK);
+ sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_COOKIE_ACK, SCTP_SO_NOT_LOCKED);
}
if (how_indx < sizeof(asoc->cookie_how))
asoc->cookie_how[how_indx] = 11;
@@ -1476,7 +1596,7 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset,
/* send up all the data */
SCTP_TCB_SEND_LOCK(stcb);
- sctp_report_all_outbound(stcb, 1);
+ sctp_report_all_outbound(stcb, 1, SCTP_SO_NOT_LOCKED);
for (i = 0; i < stcb->asoc.streamoutcnt; i++) {
stcb->asoc.strmout[i].stream_no = i;
stcb->asoc.strmout[i].next_sequence_sent = 0;
@@ -1577,6 +1697,12 @@ sctp_process_cookie_new(struct mbuf *m, int iphlen, int offset,
uint32_t old_tag;
uint8_t auth_chunk_buf[SCTP_PARAM_BUFFER_SIZE];
+#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ struct socket *so;
+
+ so = SCTP_INP_SO(inp);
+#endif
+
/*
* find and validate the INIT chunk in the cookie (peer's info) the
* INIT should start after the cookie-echo header struct (chunk
@@ -1673,9 +1799,17 @@ sctp_process_cookie_new(struct mbuf *m, int iphlen, int offset,
op_err = sctp_generate_invmanparam(SCTP_CAUSE_OUT_OF_RESC);
sctp_abort_association(inp, (struct sctp_tcb *)NULL, m, iphlen,
sh, op_err, vrf_id);
+#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ SCTP_TCB_UNLOCK(stcb);
+ SCTP_SOCKET_LOCK(so, 1);
+ SCTP_TCB_LOCK(stcb);
+#endif
(void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC,
SCTP_FROM_SCTP_INPUT + SCTP_LOC_16);
- atomic_add_int(&stcb->asoc.refcnt, -1);
+#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ SCTP_SOCKET_UNLOCK(so, 1);
+#endif
+ atomic_subtract_int(&stcb->asoc.refcnt, 1);
return (NULL);
}
/* process the INIT-ACK info (my info) */
@@ -1698,8 +1832,16 @@ sctp_process_cookie_new(struct mbuf *m, int iphlen, int offset,
retval = 0;
if (retval < 0) {
atomic_add_int(&stcb->asoc.refcnt, 1);
+#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ SCTP_TCB_UNLOCK(stcb);
+ SCTP_SOCKET_LOCK(so, 1);
+ SCTP_TCB_LOCK(stcb);
+#endif
(void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_INPUT + SCTP_LOC_16);
- atomic_add_int(&stcb->asoc.refcnt, -1);
+#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ SCTP_SOCKET_UNLOCK(so, 1);
+#endif
+ atomic_subtract_int(&stcb->asoc.refcnt, 1);
return (NULL);
}
/* load all addresses */
@@ -1707,8 +1849,16 @@ sctp_process_cookie_new(struct mbuf *m, int iphlen, int offset,
init_offset + sizeof(struct sctp_init_chunk), initack_offset, sh,
init_src)) {
atomic_add_int(&stcb->asoc.refcnt, 1);
+#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ SCTP_TCB_UNLOCK(stcb);
+ SCTP_SOCKET_LOCK(so, 1);
+ SCTP_TCB_LOCK(stcb);
+#endif
(void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_INPUT + SCTP_LOC_17);
- atomic_add_int(&stcb->asoc.refcnt, -1);
+#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ SCTP_SOCKET_UNLOCK(so, 1);
+#endif
+ atomic_subtract_int(&stcb->asoc.refcnt, 1);
return (NULL);
}
/*
@@ -1728,8 +1878,16 @@ sctp_process_cookie_new(struct mbuf *m, int iphlen, int offset,
SCTPDBG(SCTP_DEBUG_AUTH1,
"COOKIE-ECHO: AUTH failed\n");
atomic_add_int(&stcb->asoc.refcnt, 1);
+#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ SCTP_TCB_UNLOCK(stcb);
+ SCTP_SOCKET_LOCK(so, 1);
+ SCTP_TCB_LOCK(stcb);
+#endif
(void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_INPUT + SCTP_LOC_18);
- atomic_add_int(&stcb->asoc.refcnt, -1);
+#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ SCTP_SOCKET_UNLOCK(so, 1);
+#endif
+ atomic_subtract_int(&stcb->asoc.refcnt, 1);
return (NULL);
} else {
/* remaining chunks checked... good to go */
@@ -1776,8 +1934,16 @@ sctp_process_cookie_new(struct mbuf *m, int iphlen, int offset,
sizeof(sin6->sin6_addr));
} else {
atomic_add_int(&stcb->asoc.refcnt, 1);
+#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ SCTP_TCB_UNLOCK(stcb);
+ SCTP_SOCKET_LOCK(so, 1);
+ SCTP_TCB_LOCK(stcb);
+#endif
(void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_INPUT + SCTP_LOC_19);
- atomic_add_int(&stcb->asoc.refcnt, -1);
+#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ SCTP_SOCKET_UNLOCK(so, 1);
+#endif
+ atomic_subtract_int(&stcb->asoc.refcnt, 1);
return (NULL);
}
@@ -1802,7 +1968,21 @@ sctp_process_cookie_new(struct mbuf *m, int iphlen, int offset,
* a bit of protection is worth having..
*/
stcb->sctp_ep->sctp_flags |= SCTP_PCB_FLAGS_CONNECTED;
- soisconnected(stcb->sctp_ep->sctp_socket);
+#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ 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);
+ if (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET) {
+ SCTP_SOCKET_UNLOCK(so, 1);
+ return (NULL);
+ }
+#endif
+ soisconnected(stcb->sctp_socket);
+#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ SCTP_SOCKET_UNLOCK(so, 1);
+#endif
} else if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) &&
(inp->sctp_socket->so_qlimit)) {
/*
@@ -2163,7 +2343,7 @@ sctp_handle_cookie_echo(struct mbuf *m, int iphlen, int offset,
(void)sctp_set_primary_addr((*stcb), (struct sockaddr *)NULL,
netl);
sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_CONFIRMED,
- (*stcb), 0, (void *)netl);
+ (*stcb), 0, (void *)netl, SCTP_SO_NOT_LOCKED);
}
}
if (*stcb) {
@@ -2186,7 +2366,7 @@ sctp_handle_cookie_echo(struct mbuf *m, int iphlen, int offset,
* For a restart we will keep the same
* socket, no need to do anything. I THINK!!
*/
- sctp_ulp_notify(notification, *stcb, 0, (void *)&sac_restart_id);
+ sctp_ulp_notify(notification, *stcb, 0, (void *)&sac_restart_id, SCTP_SO_NOT_LOCKED);
return (m);
}
oso = (*inp_p)->sctp_socket;
@@ -2200,12 +2380,27 @@ sctp_handle_cookie_echo(struct mbuf *m, int iphlen, int offset,
if (so == NULL) {
struct mbuf *op_err;
+#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ struct socket *pcb_so;
+
+#endif
/* Too many sockets */
SCTPDBG(SCTP_DEBUG_INPUT1, "process_cookie_new: no room for another socket!\n");
op_err = sctp_generate_invmanparam(SCTP_CAUSE_OUT_OF_RESC);
sctp_abort_association(*inp_p, NULL, m, iphlen,
sh, op_err, vrf_id);
+#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ pcb_so = SCTP_INP_SO(*inp_p);
+ atomic_add_int(&(*stcb)->asoc.refcnt, 1);
+ SCTP_TCB_UNLOCK((*stcb));
+ SCTP_SOCKET_LOCK(pcb_so, 1);
+ SCTP_TCB_LOCK((*stcb));
+ atomic_subtract_int(&(*stcb)->asoc.refcnt, 1);
+#endif
(void)sctp_free_assoc(*inp_p, *stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_INPUT + SCTP_LOC_20);
+#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ SCTP_SOCKET_UNLOCK(pcb_so, 1);
+#endif
return (NULL);
}
inp = (struct sctp_inpcb *)so->so_pcb;
@@ -2222,7 +2417,6 @@ sctp_handle_cookie_echo(struct mbuf *m, int iphlen, int offset,
(SCTP_PCB_COPY_FLAGS & (*inp_p)->sctp_flags) |
SCTP_PCB_FLAGS_DONT_WAKE);
inp->sctp_features = (*inp_p)->sctp_features;
-
inp->sctp_socket = so;
inp->sctp_frag_point = (*inp_p)->sctp_frag_point;
inp->partial_delivery_point = (*inp_p)->partial_delivery_point;
@@ -2274,18 +2468,28 @@ sctp_handle_cookie_echo(struct mbuf *m, int iphlen, int offset,
SCTP_INP_DECR_REF(inp);
/* Switch over to the new guy */
*inp_p = inp;
- sctp_ulp_notify(notification, *stcb, 0, NULL);
+ sctp_ulp_notify(notification, *stcb, 0, NULL, SCTP_SO_NOT_LOCKED);
/*
* Pull it from the incomplete queue and wake the
* guy
*/
+#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ 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
soisconnected(so);
+#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ SCTP_SOCKET_UNLOCK(so, 1);
+#endif
return (m);
}
}
if ((notification) && ((*inp_p)->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE)) {
- sctp_ulp_notify(notification, *stcb, 0, NULL);
+ sctp_ulp_notify(notification, *stcb, 0, NULL, SCTP_SO_NOT_LOCKED);
}
return (m);
}
@@ -2323,11 +2527,30 @@ sctp_handle_cookie_ack(struct sctp_cookie_ack_chunk *cp,
&asoc->time_entered, sctp_align_safe_nocopy);
}
(void)SCTP_GETTIME_TIMEVAL(&asoc->time_entered);
- sctp_ulp_notify(SCTP_NOTIFY_ASSOC_UP, stcb, 0, NULL);
+ sctp_ulp_notify(SCTP_NOTIFY_ASSOC_UP, stcb, 0, NULL, SCTP_SO_NOT_LOCKED);
if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
(stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) {
+#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ struct socket *so;
+
+#endif
stcb->sctp_ep->sctp_flags |= SCTP_PCB_FLAGS_CONNECTED;
- soisconnected(stcb->sctp_ep->sctp_socket);
+#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ so = SCTP_INP_SO(stcb->sctp_ep);
+ 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);
+ if (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET) {
+ SCTP_SOCKET_UNLOCK(so, 1);
+ return;
+ }
+#endif
+ soisconnected(stcb->sctp_socket);
+#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ SCTP_SOCKET_UNLOCK(so, 1);
+#endif
}
sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep,
stcb, net);
@@ -2477,6 +2700,11 @@ sctp_handle_shutdown_complete(struct sctp_shutdown_complete_chunk *cp,
{
struct sctp_association *asoc;
+#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ struct socket *so;
+
+#endif
+
SCTPDBG(SCTP_DEBUG_INPUT2,
"sctp_handle_shutdown_complete: handling SHUTDOWN-COMPLETE\n");
if (stcb == NULL)
@@ -2493,12 +2721,12 @@ sctp_handle_shutdown_complete(struct sctp_shutdown_complete_chunk *cp,
}
/* notify upper layer protocol */
if (stcb->sctp_socket) {
- sctp_ulp_notify(SCTP_NOTIFY_ASSOC_DOWN, stcb, 0, NULL);
+ sctp_ulp_notify(SCTP_NOTIFY_ASSOC_DOWN, stcb, 0, NULL, SCTP_SO_NOT_LOCKED);
/* are the queues empty? they should be */
if (!TAILQ_EMPTY(&asoc->send_queue) ||
!TAILQ_EMPTY(&asoc->sent_queue) ||
!TAILQ_EMPTY(&asoc->out_wheel)) {
- sctp_report_all_outbound(stcb, 0);
+ sctp_report_all_outbound(stcb, 0, SCTP_SO_NOT_LOCKED);
}
}
/* stop the timer */
@@ -2507,8 +2735,18 @@ sctp_handle_shutdown_complete(struct sctp_shutdown_complete_chunk *cp,
/* free the TCB */
SCTPDBG(SCTP_DEBUG_INPUT2,
"sctp_handle_shutdown_complete: calls free-asoc\n");
-
+#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ so = SCTP_INP_SO(stcb->sctp_ep);
+ 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(stcb->sctp_ep, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_INPUT + SCTP_LOC_23);
+#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ SCTP_SOCKET_UNLOCK(so, 1);
+#endif
return;
}
@@ -2683,7 +2921,7 @@ process_chunk_drop(struct sctp_tcb *stcb, struct sctp_chunk_desc *desc,
*/
sctp_timer_stop(SCTP_TIMER_TYPE_INIT, stcb->sctp_ep,
stcb, net, SCTP_FROM_SCTP_INPUT + SCTP_LOC_25);
- sctp_send_initiate(stcb->sctp_ep, stcb);
+ sctp_send_initiate(stcb->sctp_ep, stcb, SCTP_SO_NOT_LOCKED);
}
break;
case SCTP_SELECTIVE_ACK:
@@ -2775,7 +3013,7 @@ sctp_reset_in_stream(struct sctp_tcb *stcb, int number_entries, uint16_t * list)
stcb->asoc.strmin[i].last_sequence_delivered = 0xffff;
}
}
- sctp_ulp_notify(SCTP_NOTIFY_STR_RESET_RECV, stcb, number_entries, (void *)list);
+ sctp_ulp_notify(SCTP_NOTIFY_STR_RESET_RECV, stcb, number_entries, (void *)list, SCTP_SO_NOT_LOCKED);
}
static void
@@ -2799,7 +3037,7 @@ sctp_reset_out_streams(struct sctp_tcb *stcb, int number_entries, uint16_t * lis
stcb->asoc.strmout[temp].next_sequence_sent = 0;
}
}
- sctp_ulp_notify(SCTP_NOTIFY_STR_RESET_SEND, stcb, number_entries, (void *)list);
+ sctp_ulp_notify(SCTP_NOTIFY_STR_RESET_SEND, stcb, number_entries, (void *)list, SCTP_SO_NOT_LOCKED);
}
@@ -2904,7 +3142,7 @@ sctp_handle_stream_reset_response(struct sctp_tcb *stcb,
/* do it */
sctp_reset_out_streams(stcb, number_entries, srparam->list_of_streams);
} else {
- sctp_ulp_notify(SCTP_NOTIFY_STR_RESET_FAILED_OUT, stcb, number_entries, srparam->list_of_streams);
+ sctp_ulp_notify(SCTP_NOTIFY_STR_RESET_FAILED_OUT, stcb, number_entries, srparam->list_of_streams, SCTP_SO_NOT_LOCKED);
}
} else if (type == SCTP_STR_RESET_IN_REQUEST) {
/* Answered my request */
@@ -2912,7 +3150,7 @@ sctp_handle_stream_reset_response(struct sctp_tcb *stcb,
if (asoc->stream_reset_outstanding)
asoc->stream_reset_outstanding--;
if (action != SCTP_STREAM_RESET_PERFORMED) {
- sctp_ulp_notify(SCTP_NOTIFY_STR_RESET_FAILED_IN, stcb, number_entries, srparam->list_of_streams);
+ sctp_ulp_notify(SCTP_NOTIFY_STR_RESET_FAILED_IN, stcb, number_entries, srparam->list_of_streams, SCTP_SO_NOT_LOCKED);
}
} else if (type == SCTP_STR_RESET_TSN_REQUEST) {
/**
@@ -3492,6 +3730,11 @@ __attribute__((noinline))
int auth_skipped = 0;
int asconf_cnt = 0;
+#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ struct socket *so;
+
+#endif
+
SCTPDBG(SCTP_DEBUG_INPUT1, "sctp_process_control: iphlen=%u, offset=%u, length=%u stcb:%p\n",
iphlen, *offset, length, stcb);
@@ -3825,7 +4068,7 @@ process_control_chunks:
sctp_send_shutdown_ack(stcb,
stcb->asoc.primary_destination);
*offset = length;
- sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_CONTROL_PROC);
+ sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_CONTROL_PROC, SCTP_SO_NOT_LOCKED);
if (locked_tcb) {
SCTP_TCB_UNLOCK(locked_tcb);
}
@@ -3860,7 +4103,18 @@ process_control_chunks:
}
*offset = length;
if (stcb) {
+#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ 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_27);
+#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ SCTP_SOCKET_UNLOCK(so, 1);
+#endif
}
return (NULL);
}
@@ -3887,7 +4141,7 @@ process_control_chunks:
return (NULL);
if ((stcb) && ret == 0)
- sctp_chunk_output(stcb->sctp_ep, stcb, SCTP_OUTPUT_FROM_CONTROL_PROC);
+ sctp_chunk_output(stcb->sctp_ep, stcb, SCTP_OUTPUT_FROM_CONTROL_PROC, SCTP_SO_NOT_LOCKED);
*offset = length;
if (locked_tcb) {
SCTP_TCB_UNLOCK(locked_tcb);
@@ -4187,7 +4441,18 @@ process_control_chunks:
if ((stcb) && (stcb->asoc.total_output_queue_size)) {
;
} else if (stcb) {
+#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ 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_27);
+#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ SCTP_SOCKET_UNLOCK(so, 1);
+#endif
*offset = length;
return (NULL);
}
@@ -4336,7 +4601,18 @@ process_control_chunks:
*fwd_tsn_seen = 1;
if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) {
/* We are not interested anymore */
+#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ 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_29);
+#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ SCTP_SOCKET_UNLOCK(so, 1);
+#endif
*offset = length;
return (NULL);
}
@@ -4370,7 +4646,18 @@ process_control_chunks:
}
if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) {
/* We are not interested anymore */
+#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ 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_30);
+#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ SCTP_SOCKET_UNLOCK(so, 1);
+#endif
*offset = length;
return (NULL);
}
@@ -4821,7 +5108,7 @@ trigger_send:
(stcb->asoc.peers_rwnd <= 0 && stcb->asoc.total_flight == 0)))) {
sctp_mobility_feature_off(inp, SCTP_MOBILITY_DO_FASTHANDOFF);
SCTPDBG(SCTP_DEBUG_INPUT3, "Calling chunk OUTPUT\n");
- sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_CONTROL_PROC);
+ sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_CONTROL_PROC, SCTP_SO_NOT_LOCKED);
SCTPDBG(SCTP_DEBUG_INPUT3, "chunk OUTPUT returns\n");
}
#ifdef SCTP_AUDITING_ENABLED
@@ -4947,7 +5234,7 @@ sctp_input(i_pak, off)
vrf_id);
if ((inp) && (stcb)) {
sctp_send_packet_dropped(stcb, net, m, iphlen, 1);
- sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_INPUT_ERROR);
+ sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_INPUT_ERROR, SCTP_SO_NOT_LOCKED);
} else if ((inp != NULL) && (stcb == NULL)) {
refcount_up = 1;
}
diff --git a/sys/netinet/sctp_lock_bsd.h b/sys/netinet/sctp_lock_bsd.h
index b1afc90..5aa3791 100644
--- a/sys/netinet/sctp_lock_bsd.h
+++ b/sys/netinet/sctp_lock_bsd.h
@@ -375,4 +375,10 @@ extern int sctp_logoff_stuff;
} while (0)
+#if defined(SCTP_SO_LOCK_TESTING)
+#define SCTP_INP_SO(sctpinp) (sctpinp)->ip_inp.inp.inp_socket
+#define SCTP_SOCKET_LOCK(so, refcnt)
+#define SCTP_SOCKET_UNLOCK(so, refcnt)
+#endif
+
#endif
diff --git a/sys/netinet/sctp_os_bsd.h b/sys/netinet/sctp_os_bsd.h
index 9a1dc43..b30e249 100644
--- a/sys/netinet/sctp_os_bsd.h
+++ b/sys/netinet/sctp_os_bsd.h
@@ -272,6 +272,7 @@ typedef struct callout sctp_os_timer_t;
/* The packed define for 64 bit platforms */
#define SCTP_PACKED __attribute__((packed))
+#define SCTP_UNUSED __attribute__((unused))
/*
* Functions
diff --git a/sys/netinet/sctp_output.c b/sys/netinet/sctp_output.c
index 28b39d1..3b60f85 100644
--- a/sys/netinet/sctp_output.c
+++ b/sys/netinet/sctp_output.c
@@ -3270,7 +3270,12 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp,
int nofragment_flag,
int ecn_ok,
struct sctp_tmit_chunk *chk,
- int out_of_asoc_ok)
+ int out_of_asoc_ok,
+ int so_locked
+#if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
+ SCTP_UNUSED
+#endif
+)
/* nofragment_flag to tell if IP_DF should be set (IPv4 only) */
{
/*
@@ -3456,7 +3461,8 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp,
sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN,
stcb,
SCTP_FAILED_THRESHOLD,
- (void *)net);
+ (void *)net,
+ so_locked);
net->dest_state &= ~SCTP_ADDR_REACHABLE;
net->dest_state |= SCTP_ADDR_NOT_REACHABLE;
/*
@@ -3840,7 +3846,11 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp,
void
-sctp_send_initiate(struct sctp_inpcb *inp, struct sctp_tcb *stcb)
+sctp_send_initiate(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int so_locked
+#if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
+ SCTP_UNUSED
+#endif
+)
{
struct mbuf *m, *m_at, *mp_last;
struct sctp_nets *net;
@@ -4108,7 +4118,7 @@ sctp_send_initiate(struct sctp_inpcb *inp, struct sctp_tcb *stcb)
SCTPDBG(SCTP_DEBUG_OUTPUT4, "Sending INIT - calls lowlevel_output\n");
ret = sctp_lowlevel_chunk_output(inp, stcb, net,
(struct sockaddr *)&net->ro._l_addr,
- m, 0, NULL, 0, 0, NULL, 0);
+ m, 0, NULL, 0, 0, NULL, 0, so_locked);
SCTPDBG(SCTP_DEBUG_OUTPUT4, "lowlevel_output - %d\n", ret);
SCTP_STAT_INCR_COUNTER64(sctps_outcontrolchunks);
sctp_timer_start(SCTP_TIMER_TYPE_INIT, inp, stcb, net);
@@ -5169,7 +5179,7 @@ sctp_send_initiate_ack(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
p_len += padval;
}
(void)sctp_lowlevel_chunk_output(inp, NULL, NULL, to, m, 0, NULL, 0, 0,
- NULL, 0);
+ NULL, 0, SCTP_SO_NOT_LOCKED);
SCTP_STAT_INCR_COUNTER64(sctps_outcontrolchunks);
}
@@ -5279,7 +5289,7 @@ sctp_prune_prsctp(struct sctp_tcb *stcb,
cause = SCTP_RESPONSE_TO_USER_REQ | SCTP_NOTIFY_DATAGRAM_UNSENT;
ret_spc = sctp_release_pr_sctp_chunk(stcb, chk,
cause,
- &asoc->sent_queue);
+ &asoc->sent_queue, SCTP_SO_LOCKED);
freed_spc += ret_spc;
if (freed_spc >= dataout) {
return;
@@ -5304,7 +5314,7 @@ sctp_prune_prsctp(struct sctp_tcb *stcb,
ret_spc = sctp_release_pr_sctp_chunk(stcb, chk,
SCTP_RESPONSE_TO_USER_REQ | SCTP_NOTIFY_DATAGRAM_UNSENT,
- &asoc->send_queue);
+ &asoc->send_queue, SCTP_SO_LOCKED);
freed_spc += ret_spc;
if (freed_spc >= dataout) {
@@ -5670,7 +5680,11 @@ sctp_med_chunk_output(struct sctp_inpcb *inp,
int *num_out,
int *reason_code,
int control_only, int *cwnd_full, int from_where,
- struct timeval *now, int *now_filled, int frag_point);
+ struct timeval *now, int *now_filled, int frag_point, int so_locked
+#if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
+ SCTP_UNUSED
+#endif
+);
static void
sctp_sendall_iterator(struct sctp_inpcb *inp, struct sctp_tcb *stcb, void *ptr,
@@ -5720,7 +5734,7 @@ sctp_sendall_iterator(struct sctp_inpcb *inp, struct sctp_tcb *stcb, void *ptr,
atomic_add_int(&stcb->asoc.refcnt, 1);
sctp_abort_an_association(inp, stcb,
SCTP_RESPONSE_TO_USER_REQ,
- m);
+ m, SCTP_SO_NOT_LOCKED);
/*
* sctp_abort_an_association calls sctp_free_asoc()
* free association will NOT free it since we
@@ -5814,7 +5828,7 @@ sctp_sendall_iterator(struct sctp_inpcb *inp, struct sctp_tcb *stcb, void *ptr,
atomic_add_int(&stcb->asoc.refcnt, 1);
sctp_abort_an_association(stcb->sctp_ep, stcb,
SCTP_RESPONSE_TO_USER_REQ,
- NULL);
+ NULL, SCTP_SO_NOT_LOCKED);
atomic_add_int(&stcb->asoc.refcnt, -1);
goto no_chunk_output;
}
@@ -5835,7 +5849,7 @@ sctp_sendall_iterator(struct sctp_inpcb *inp, struct sctp_tcb *stcb, void *ptr,
do_chunk_output = 0;
}
if (do_chunk_output)
- sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_USR_SEND);
+ sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_USR_SEND, SCTP_SO_NOT_LOCKED);
else if (added_control) {
int num_out = 0, reason = 0, cwnd_full = 0, now_filled = 0;
struct timeval now;
@@ -5843,7 +5857,7 @@ sctp_sendall_iterator(struct sctp_inpcb *inp, struct sctp_tcb *stcb, void *ptr,
frag_point = sctp_get_frag_point(stcb, &stcb->asoc);
(void)sctp_med_chunk_output(inp, stcb, &stcb->asoc, &num_out,
- &reason, 1, &cwnd_full, 1, &now, &now_filled, frag_point);
+ &reason, 1, &cwnd_full, 1, &now, &now_filled, frag_point, SCTP_SO_NOT_LOCKED);
}
no_chunk_output:
if (ret) {
@@ -6858,7 +6872,11 @@ sctp_med_chunk_output(struct sctp_inpcb *inp,
int *num_out,
int *reason_code,
int control_only, int *cwnd_full, int from_where,
- struct timeval *now, int *now_filled, int frag_point)
+ struct timeval *now, int *now_filled, int frag_point, int so_locked
+#if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
+ SCTP_UNUSED
+#endif
+)
{
/*
* Ok this is the generic chunk service queue. we must do the
@@ -7268,7 +7286,7 @@ again_one_more_time:
if ((error = sctp_lowlevel_chunk_output(inp, stcb, net,
(struct sockaddr *)&net->ro._l_addr,
outchain, auth_offset, auth,
- no_fragmentflg, 0, NULL, asconf))) {
+ no_fragmentflg, 0, NULL, asconf, so_locked))) {
if (error == ENOBUFS) {
asoc->ifp_had_enobuf = 1;
SCTP_STAT_INCR(sctps_lowlevelerr);
@@ -7548,7 +7566,7 @@ again_one_more_time:
no_fragmentflg,
bundle_at,
data_list[0],
- asconf))) {
+ asconf, so_locked))) {
/* error, we could not output */
if (error == ENOBUFS) {
SCTP_STAT_INCR(sctps_lowlevelerr);
@@ -8110,7 +8128,11 @@ static int
sctp_chunk_retransmission(struct sctp_inpcb *inp,
struct sctp_tcb *stcb,
struct sctp_association *asoc,
- int *cnt_out, struct timeval *now, int *now_filled, int *fr_done)
+ int *cnt_out, struct timeval *now, int *now_filled, int *fr_done, int so_locked
+#if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
+ SCTP_UNUSED
+#endif
+)
{
/*-
* send out one MTU of retransmission. If fast_retransmit is
@@ -8223,7 +8245,7 @@ sctp_chunk_retransmission(struct sctp_inpcb *inp,
if ((error = sctp_lowlevel_chunk_output(inp, stcb, chk->whoTo,
(struct sockaddr *)&chk->whoTo->ro._l_addr, m, auth_offset,
- auth, no_fragmentflg, 0, NULL, asconf))) {
+ auth, no_fragmentflg, 0, NULL, asconf, so_locked))) {
SCTP_STAT_INCR(sctps_lowlevelerr);
return (error);
}
@@ -8272,7 +8294,7 @@ sctp_chunk_retransmission(struct sctp_inpcb *inp,
chk->snd_count,
sctp_max_retran_chunk);
atomic_add_int(&stcb->asoc.refcnt, 1);
- sctp_abort_an_association(stcb->sctp_ep, stcb, 0, NULL);
+ sctp_abort_an_association(stcb->sctp_ep, stcb, 0, NULL, so_locked);
SCTP_TCB_LOCK(stcb);
atomic_subtract_int(&stcb->asoc.refcnt, 1);
return (SCTP_RETRAN_EXIT);
@@ -8461,7 +8483,7 @@ one_chunk_around:
/* Now lets send it, if there is anything to send :> */
if ((error = sctp_lowlevel_chunk_output(inp, stcb, net,
(struct sockaddr *)&net->ro._l_addr, m, auth_offset,
- auth, no_fragmentflg, 0, NULL, asconf))) {
+ auth, no_fragmentflg, 0, NULL, asconf, so_locked))) {
/* error, we could not output */
SCTP_STAT_INCR(sctps_lowlevelerr);
return (error);
@@ -8620,7 +8642,12 @@ sctp_timer_validation(struct sctp_inpcb *inp,
void
sctp_chunk_output(struct sctp_inpcb *inp,
struct sctp_tcb *stcb,
- int from_where)
+ int from_where,
+ int so_locked
+#if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
+ SCTP_UNUSED
+#endif
+)
{
/*-
* Ok this is the generic chunk service queue. we must do the
@@ -8686,12 +8713,12 @@ sctp_chunk_output(struct sctp_inpcb *inp,
*/
(void)sctp_med_chunk_output(inp, stcb, asoc, &num_out, &reason_code, 1,
&cwnd_full, from_where,
- &now, &now_filled, frag_point);
+ &now, &now_filled, frag_point, so_locked);
return;
} else if (from_where != SCTP_OUTPUT_FROM_HB_TMR) {
/* if its not from a HB then do it */
fr_done = 0;
- ret = sctp_chunk_retransmission(inp, stcb, asoc, &num_out, &now, &now_filled, &fr_done);
+ ret = sctp_chunk_retransmission(inp, stcb, asoc, &num_out, &now, &now_filled, &fr_done, so_locked);
if (fr_done) {
tot_frs++;
}
@@ -8711,7 +8738,7 @@ sctp_chunk_output(struct sctp_inpcb *inp,
*/
(void)sctp_med_chunk_output(inp, stcb, asoc, &num_out, &reason_code, 1,
&cwnd_full, from_where,
- &now, &now_filled, frag_point);
+ &now, &now_filled, frag_point, so_locked);
#ifdef SCTP_AUDITING_ENABLED
sctp_auditing(8, inp, stcb, NULL);
#endif
@@ -8738,7 +8765,7 @@ sctp_chunk_output(struct sctp_inpcb *inp,
#endif
/* Push out any control */
(void)sctp_med_chunk_output(inp, stcb, asoc, &num_out, &reason_code, 1, &cwnd_full, from_where,
- &now, &now_filled, frag_point);
+ &now, &now_filled, frag_point, so_locked);
return;
}
if (tot_frs > asoc->max_burst) {
@@ -8811,7 +8838,7 @@ sctp_chunk_output(struct sctp_inpcb *inp,
do {
error = sctp_med_chunk_output(inp, stcb, asoc, &num_out,
&reason_code, 0, &cwnd_full, from_where,
- &now, &now_filled, frag_point);
+ &now, &now_filled, frag_point, so_locked);
if (error) {
SCTPDBG(SCTP_DEBUG_OUTPUT1, "Error %d was returned from med-c-op\n", error);
if (sctp_logging_level & SCTP_LOG_MAXBURST_ENABLE) {
@@ -9092,7 +9119,6 @@ sctp_send_sack(struct sctp_tcb *stcb)
int num_dups = 0;
int space_req;
-
a_chk = NULL;
asoc = &stcb->asoc;
SCTP_TCB_LOCK_ASSERT(stcb);
@@ -9354,7 +9380,11 @@ sctp_send_sack(struct sctp_tcb *stcb)
void
-sctp_send_abort_tcb(struct sctp_tcb *stcb, struct mbuf *operr)
+sctp_send_abort_tcb(struct sctp_tcb *stcb, struct mbuf *operr, int so_locked
+#if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
+ SCTP_UNUSED
+#endif
+)
{
struct mbuf *m_abort;
struct mbuf *m_out = NULL, *m_end = NULL;
@@ -9409,7 +9439,6 @@ sctp_send_abort_tcb(struct sctp_tcb *stcb, struct mbuf *operr)
abort->ch.chunk_flags = 0;
abort->ch.chunk_length = htons(sizeof(*abort) + sz);
-
/* prepend and fill in the SCTP header */
SCTP_BUF_PREPEND(m_out, sizeof(struct sctphdr), M_DONTWAIT);
if (m_out == NULL) {
@@ -9426,7 +9455,7 @@ sctp_send_abort_tcb(struct sctp_tcb *stcb, struct mbuf *operr)
(void)sctp_lowlevel_chunk_output(stcb->sctp_ep, stcb,
stcb->asoc.primary_destination,
(struct sockaddr *)&stcb->asoc.primary_destination->ro._l_addr,
- m_out, auth_offset, auth, 1, 0, NULL, 0);
+ m_out, auth_offset, auth, 1, 0, NULL, 0, so_locked);
SCTP_STAT_INCR_COUNTER64(sctps_outcontrolchunks);
}
@@ -9455,7 +9484,7 @@ sctp_send_shutdown_complete(struct sctp_tcb *stcb,
SCTP_BUF_LEN(m_shutdown_comp) = sizeof(struct sctp_shutdown_complete_msg);
(void)sctp_lowlevel_chunk_output(stcb->sctp_ep, stcb, net,
(struct sockaddr *)&net->ro._l_addr,
- m_shutdown_comp, 0, NULL, 1, 0, NULL, 0);
+ m_shutdown_comp, 0, NULL, 1, 0, NULL, 0, SCTP_SO_NOT_LOCKED);
SCTP_STAT_INCR_COUNTER64(sctps_outcontrolchunks);
return;
}
@@ -10877,6 +10906,7 @@ sctp_lower_sosend(struct socket *so,
net = NULL;
stcb = NULL;
asoc = NULL;
+
t_inp = inp = (struct sctp_inpcb *)so->so_pcb;
if (inp == NULL) {
SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP_OUTPUT, EFAULT);
@@ -11422,7 +11452,7 @@ sctp_lower_sosend(struct socket *so,
/* release this lock, otherwise we hang on ourselves */
sctp_abort_an_association(stcb->sctp_ep, stcb,
SCTP_RESPONSE_TO_USER_REQ,
- mm);
+ mm, SCTP_SO_LOCKED);
/* now relock the stcb so everything is sane */
hold_tcblock = 0;
stcb = NULL;
@@ -11777,7 +11807,7 @@ sctp_lower_sosend(struct socket *so,
queue_only_for_init = 0;
queue_only = 0;
} else {
- sctp_send_initiate(inp, stcb);
+ sctp_send_initiate(inp, stcb, SCTP_SO_LOCKED);
SCTP_SET_STATE(asoc, SCTP_STATE_COOKIE_WAIT);
queue_only_for_init = 0;
queue_only = 1;
@@ -11797,12 +11827,12 @@ sctp_lower_sosend(struct socket *so,
hold_tcblock = 1;
sctp_chunk_output(inp,
stcb,
- SCTP_OUTPUT_FROM_USR_SEND);
+ SCTP_OUTPUT_FROM_USR_SEND, SCTP_SO_LOCKED);
}
} else {
sctp_chunk_output(inp,
stcb,
- SCTP_OUTPUT_FROM_USR_SEND);
+ SCTP_OUTPUT_FROM_USR_SEND, SCTP_SO_LOCKED);
}
if (hold_tcblock == 1) {
SCTP_TCB_UNLOCK(stcb);
@@ -11960,7 +11990,7 @@ dataless_eof:
}
sctp_abort_an_association(stcb->sctp_ep, stcb,
SCTP_RESPONSE_TO_USER_REQ,
- NULL);
+ NULL, SCTP_SO_LOCKED);
/*
* now relock the stcb so everything
* is sane
@@ -12039,7 +12069,7 @@ skip_out_eof:
queue_only_for_init = 0;
queue_only = 0;
} else {
- sctp_send_initiate(inp, stcb);
+ sctp_send_initiate(inp, stcb, SCTP_SO_LOCKED);
SCTP_SET_STATE(&stcb->asoc, SCTP_STATE_COOKIE_WAIT);
queue_only_for_init = 0;
queue_only = 1;
@@ -12053,11 +12083,11 @@ skip_out_eof:
* send
*/
if (SCTP_TCB_TRYLOCK(stcb)) {
- sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_USR_SEND);
+ sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_USR_SEND, SCTP_SO_LOCKED);
hold_tcblock = 1;
}
} else {
- sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_USR_SEND);
+ sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_USR_SEND, SCTP_SO_LOCKED);
}
} else if ((queue_only == 0) &&
(stcb->asoc.peers_rwnd == 0) &&
@@ -12067,7 +12097,7 @@ skip_out_eof:
hold_tcblock = 1;
SCTP_TCB_LOCK(stcb);
}
- sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_USR_SEND);
+ sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_USR_SEND, SCTP_SO_LOCKED);
} else if (some_on_control) {
int num_out, reason, cwnd_full, frag_point;
@@ -12078,7 +12108,7 @@ skip_out_eof:
}
frag_point = sctp_get_frag_point(stcb, &stcb->asoc);
(void)sctp_med_chunk_output(inp, stcb, &stcb->asoc, &num_out,
- &reason, 1, &cwnd_full, 1, &now, &now_filled, frag_point);
+ &reason, 1, &cwnd_full, 1, &now, &now_filled, frag_point, SCTP_SO_LOCKED);
}
SCTPDBG(SCTP_DEBUG_OUTPUT1, "USR Send complete qo:%d prw:%d unsent:%d tf:%d cooq:%d toqs:%d err:%d",
queue_only, stcb->asoc.peers_rwnd, un_sent,
diff --git a/sys/netinet/sctp_output.h b/sys/netinet/sctp_output.h
index 0643e94..bd35269 100644
--- a/sys/netinet/sctp_output.h
+++ b/sys/netinet/sctp_output.h
@@ -74,7 +74,12 @@ int
int
sctp_v4src_match_nexthop(struct sctp_ifa *sifa, sctp_route_t * ro);
-void sctp_send_initiate(struct sctp_inpcb *, struct sctp_tcb *);
+void
+sctp_send_initiate(struct sctp_inpcb *, struct sctp_tcb *, int
+#if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
+ SCTP_UNUSED
+#endif
+);
void
sctp_send_initiate_ack(struct sctp_inpcb *, struct sctp_tcb *,
@@ -128,8 +133,18 @@ sctp_insert_on_wheel(struct sctp_tcb *stcb,
struct sctp_association *asoc,
struct sctp_stream_out *strq, int holdslock);
-void sctp_chunk_output(struct sctp_inpcb *, struct sctp_tcb *, int);
-void sctp_send_abort_tcb(struct sctp_tcb *, struct mbuf *);
+void
+sctp_chunk_output(struct sctp_inpcb *, struct sctp_tcb *, int, int
+#if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
+ SCTP_UNUSED
+#endif
+);
+void
+sctp_send_abort_tcb(struct sctp_tcb *, struct mbuf *, int
+#if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
+ SCTP_UNUSED
+#endif
+);
void send_forward_tsn(struct sctp_tcb *, struct sctp_association *);
diff --git a/sys/netinet/sctp_pcb.c b/sys/netinet/sctp_pcb.c
index fdec3e5..30fc1cb 100644
--- a/sys/netinet/sctp_pcb.c
+++ b/sys/netinet/sctp_pcb.c
@@ -611,7 +611,6 @@ out_now:
}
-
static struct sctp_tcb *
sctp_tcb_special_locate(struct sctp_inpcb **inp_p, struct sockaddr *from,
struct sockaddr *to, struct sctp_nets **netp, uint32_t vrf_id)
@@ -1243,7 +1242,6 @@ sctp_endpoint_probe(struct sockaddr *nam, struct sctppcbhead *head,
return (NULL);
}
-
struct sctp_inpcb *
sctp_pcb_findep(struct sockaddr *nam, int find_tcp_pool, int have_lock,
uint32_t vrf_id)
@@ -2604,7 +2602,6 @@ sctp_inpcb_free(struct sctp_inpcb *inp, int immediate, int from)
#ifdef SCTP_LOG_CLOSING
sctp_log_closing(inp, NULL, 0);
#endif
-
SCTP_ITERATOR_LOCK();
so = inp->sctp_socket;
if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) {
@@ -2650,11 +2647,11 @@ sctp_inpcb_free(struct sctp_inpcb *inp, int immediate, int from)
cnt_in_sd = 0;
for ((asoc = LIST_FIRST(&inp->sctp_asoc_list)); asoc != NULL;
asoc = nasoc) {
- nasoc = LIST_NEXT(asoc, sctp_tcblist);
SCTP_TCB_LOCK(asoc);
+ nasoc = LIST_NEXT(asoc, sctp_tcblist);
if (asoc->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) {
/* Skip guys being freed */
- asoc->sctp_socket = NULL;
+ /* asoc->sctp_socket = NULL; FIXME MT */
cnt_in_sd++;
SCTP_TCB_UNLOCK(asoc);
continue;
@@ -2668,7 +2665,6 @@ sctp_inpcb_free(struct sctp_inpcb *inp, int immediate, int from)
* it wants the data to get across first.
*/
/* Just abandon things in the front states */
-
if (sctp_free_assoc(inp, asoc, SCTP_PCBFREE_NOFORCE,
SCTP_FROM_SCTP_PCB + SCTP_LOC_2) == 0) {
cnt_in_sd++;
@@ -2704,7 +2700,7 @@ sctp_inpcb_free(struct sctp_inpcb *inp, int immediate, int from)
*ippp = htonl(SCTP_FROM_SCTP_PCB + SCTP_LOC_3);
}
asoc->sctp_ep->last_abort_code = SCTP_FROM_SCTP_PCB + SCTP_LOC_3;
- sctp_send_abort_tcb(asoc, op_err);
+ sctp_send_abort_tcb(asoc, op_err, SCTP_SO_LOCKED);
SCTP_STAT_INCR_COUNTER32(sctps_aborted);
if ((SCTP_GET_STATE(&asoc->asoc) == SCTP_STATE_OPEN) ||
(SCTP_GET_STATE(&asoc->asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
@@ -2738,7 +2734,7 @@ sctp_inpcb_free(struct sctp_inpcb *inp, int immediate, int from)
asoc->asoc.primary_destination);
sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, asoc->sctp_ep, asoc,
asoc->asoc.primary_destination);
- sctp_chunk_output(inp, asoc, SCTP_OUTPUT_FROM_CLOSING);
+ sctp_chunk_output(inp, asoc, SCTP_OUTPUT_FROM_SHUT_TMR, SCTP_SO_LOCKED);
}
} else {
/* mark into shutdown pending */
@@ -2787,7 +2783,7 @@ sctp_inpcb_free(struct sctp_inpcb *inp, int immediate, int from)
*ippp = htonl(SCTP_FROM_SCTP_PCB + SCTP_LOC_5);
}
asoc->sctp_ep->last_abort_code = SCTP_FROM_SCTP_PCB + SCTP_LOC_5;
- sctp_send_abort_tcb(asoc, op_err);
+ sctp_send_abort_tcb(asoc, op_err, SCTP_SO_LOCKED);
SCTP_STAT_INCR_COUNTER32(sctps_aborted);
if ((SCTP_GET_STATE(&asoc->asoc) == SCTP_STATE_OPEN) ||
(SCTP_GET_STATE(&asoc->asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
@@ -2800,7 +2796,7 @@ sctp_inpcb_free(struct sctp_inpcb *inp, int immediate, int from)
}
continue;
} else {
- sctp_chunk_output(inp, asoc, SCTP_OUTPUT_FROM_CLOSING);
+ sctp_chunk_output(inp, asoc, SCTP_OUTPUT_FROM_CLOSING, SCTP_SO_LOCKED);
}
}
cnt_in_sd++;
@@ -2864,7 +2860,7 @@ sctp_inpcb_free(struct sctp_inpcb *inp, int immediate, int from)
}
asoc->sctp_ep->last_abort_code = SCTP_FROM_SCTP_PCB + SCTP_LOC_7;
- sctp_send_abort_tcb(asoc, op_err);
+ sctp_send_abort_tcb(asoc, op_err, SCTP_SO_LOCKED);
SCTP_STAT_INCR_COUNTER32(sctps_aborted);
} else if (asoc->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) {
cnt++;
@@ -3018,12 +3014,9 @@ sctp_inpcb_free(struct sctp_inpcb *inp, int immediate, int from)
SCTP_INP_READ_DESTROY(inp);
SCTP_ASOC_CREATE_LOCK_DESTROY(inp);
SCTP_INP_INFO_WUNLOCK();
-
SCTP_ITERATOR_UNLOCK();
-
SCTP_ZONE_FREE(sctppcbinfo.ipi_zone_ep, inp);
SCTP_DECR_EP_COUNT();
-
}
@@ -3780,7 +3773,6 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre
int cnt = 0;
/* first, lets purge the entry from the hash table. */
- SCTP_TCB_LOCK_ASSERT(stcb);
#ifdef SCTP_LOG_CLOSING
sctp_log_closing(inp, stcb, 6);
@@ -5468,7 +5460,6 @@ sctp_set_primary_addr(struct sctp_tcb *stcb, struct sockaddr *sa,
}
}
-
int
sctp_is_vtag_good(struct sctp_inpcb *inp, uint32_t tag, struct timeval *now)
{
@@ -5712,7 +5703,7 @@ sctp_drain_mbufs(struct sctp_inpcb *inp, struct sctp_tcb *stcb)
asoc->last_revoke_count = cnt;
(void)SCTP_OS_TIMER_STOP(&stcb->asoc.dack_timer.timer);
sctp_send_sack(stcb);
- sctp_chunk_output(stcb->sctp_ep, stcb, SCTP_OUTPUT_FROM_DRAIN);
+ sctp_chunk_output(stcb->sctp_ep, stcb, SCTP_OUTPUT_FROM_DRAIN, SCTP_SO_NOT_LOCKED);
reneged_asoc_ids[reneged_at] = sctp_get_associd(stcb);
reneged_at++;
}
diff --git a/sys/netinet/sctp_peeloff.c b/sys/netinet/sctp_peeloff.c
index b286c96..424de2c 100644
--- a/sys/netinet/sctp_peeloff.c
+++ b/sys/netinet/sctp_peeloff.c
@@ -60,8 +60,8 @@ sctp_can_peel_off(struct socket *head, sctp_assoc_t assoc_id)
}
stcb = sctp_findassociation_ep_asocid(inp, assoc_id, 1);
if (stcb == NULL) {
- SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_PEELOFF, ENOTCONN);
- return (ENOTCONN);
+ SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_PEELOFF, ENOENT);
+ return (ENOENT);
}
state = SCTP_GET_STATE((&stcb->asoc));
if ((state == SCTP_STATE_EMPTY) ||
@@ -161,26 +161,27 @@ sctp_get_peeloff(struct socket *head, sctp_assoc_t assoc_id, int *error)
*error = ENOTCONN;
return (NULL);
}
+ atomic_add_int(&stcb->asoc.refcnt, 1);
+ SCTP_TCB_UNLOCK(stcb);
newso = sonewconn(head, SS_ISCONNECTED
);
if (newso == NULL) {
SCTPDBG(SCTP_DEBUG_PEEL1, "sctp_peeloff:sonewconn failed\n");
SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTP_PEELOFF, ENOMEM);
*error = ENOMEM;
- SCTP_TCB_UNLOCK(stcb);
+ atomic_subtract_int(&stcb->asoc.refcnt, 1);
return (NULL);
}
+ SCTP_TCB_LOCK(stcb);
+ atomic_subtract_int(&stcb->asoc.refcnt, 1);
n_inp = (struct sctp_inpcb *)newso->so_pcb;
SOCK_LOCK(head);
- SCTP_INP_WLOCK(inp);
- SCTP_INP_WLOCK(n_inp);
n_inp->sctp_flags = (SCTP_PCB_FLAGS_UDPTYPE |
SCTP_PCB_FLAGS_CONNECTED |
SCTP_PCB_FLAGS_IN_TCPPOOL | /* Turn on Blocking IO */
(SCTP_PCB_COPY_FLAGS & inp->sctp_flags));
n_inp->sctp_features = inp->sctp_features;
- n_inp->sctp_mobility_features = inp->sctp_mobility_features;
n_inp->sctp_frag_point = inp->sctp_frag_point;
n_inp->partial_delivery_point = inp->partial_delivery_point;
n_inp->sctp_context = inp->sctp_context;
@@ -222,8 +223,6 @@ sctp_get_peeloff(struct socket *head, sctp_assoc_t assoc_id, int *error)
* Now we must move it from one hash table to another and get the
* stcb in the right place.
*/
- SCTP_INP_WUNLOCK(n_inp);
- SCTP_INP_WUNLOCK(inp);
sctp_move_pcb_and_assoc(inp, n_inp, stcb);
atomic_add_int(&stcb->asoc.refcnt, 1);
SCTP_TCB_UNLOCK(stcb);
@@ -233,6 +232,5 @@ sctp_get_peeloff(struct socket *head, sctp_assoc_t assoc_id, int *error)
*/
sctp_pull_off_control_to_new_inp(inp, n_inp, stcb, M_WAITOK);
atomic_subtract_int(&stcb->asoc.refcnt, 1);
-
return (newso);
}
diff --git a/sys/netinet/sctp_timer.c b/sys/netinet/sctp_timer.c
index a5322e5..50550f8 100644
--- a/sys/netinet/sctp_timer.c
+++ b/sys/netinet/sctp_timer.c
@@ -143,7 +143,7 @@ sctp_early_fr_timer(struct sctp_inpcb *inp,
*/
stcb->asoc.cc_functions.sctp_cwnd_update_after_fr_timer(inp, stcb, net);
} else if (cnt_resend) {
- sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_EARLY_FR_TMR);
+ sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_EARLY_FR_TMR, SCTP_SO_NOT_LOCKED);
}
/* Restart it? */
if (net->flight_size < net->cwnd) {
@@ -219,7 +219,7 @@ sctp_threshold_management(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN,
stcb,
SCTP_FAILED_THRESHOLD,
- (void *)net);
+ (void *)net, SCTP_SO_NOT_LOCKED);
}
}
/*********HOLD THIS COMMENT FOR PATCH OF ALTERNATE
@@ -280,7 +280,7 @@ sctp_threshold_management(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
*ippp = htonl(SCTP_FROM_SCTP_TIMER + SCTP_LOC_1);
}
inp->last_abort_code = SCTP_FROM_SCTP_TIMER + SCTP_LOC_1;
- sctp_abort_an_association(inp, stcb, SCTP_FAILED_THRESHOLD, oper);
+ sctp_abort_an_association(inp, stcb, SCTP_FAILED_THRESHOLD, oper, SCTP_SO_NOT_LOCKED);
return (1);
}
return (0);
@@ -702,7 +702,7 @@ sctp_mark_all_for_resend(struct sctp_tcb *stcb,
(void)sctp_release_pr_sctp_chunk(stcb,
chk,
(SCTP_RESPONSE_TO_USER_REQ | SCTP_NOTIFY_DATAGRAM_SENT),
- &stcb->asoc.sent_queue);
+ &stcb->asoc.sent_queue, SCTP_SO_NOT_LOCKED);
}
}
continue;
@@ -714,7 +714,7 @@ sctp_mark_all_for_resend(struct sctp_tcb *stcb,
(void)sctp_release_pr_sctp_chunk(stcb,
chk,
(SCTP_RESPONSE_TO_USER_REQ | SCTP_NOTIFY_DATAGRAM_SENT),
- &stcb->asoc.sent_queue);
+ &stcb->asoc.sent_queue, SCTP_SO_NOT_LOCKED);
}
}
continue;
@@ -1132,7 +1132,7 @@ sctp_t1init_timer(struct sctp_inpcb *inp,
* complete the rest of its sends.
*/
stcb->asoc.delayed_connection = 0;
- sctp_send_initiate(inp, stcb);
+ sctp_send_initiate(inp, stcb, SCTP_SO_NOT_LOCKED);
return (0);
}
if (SCTP_GET_STATE((&stcb->asoc)) != SCTP_STATE_COOKIE_WAIT) {
@@ -1159,7 +1159,7 @@ sctp_t1init_timer(struct sctp_inpcb *inp,
}
}
/* Send out a new init */
- sctp_send_initiate(inp, stcb);
+ sctp_send_initiate(inp, stcb, SCTP_SO_NOT_LOCKED);
return (0);
}
@@ -1203,7 +1203,7 @@ sctp_cookie_timer(struct sctp_inpcb *inp,
}
inp->last_abort_code = SCTP_FROM_SCTP_TIMER + SCTP_LOC_4;
sctp_abort_an_association(inp, stcb, SCTP_INTERNAL_ERROR,
- oper);
+ oper, SCTP_SO_NOT_LOCKED);
} else {
#ifdef INVARIANTS
panic("Cookie timer expires in wrong state?");
@@ -1501,7 +1501,7 @@ sctp_audit_stream_queues_for_size(struct sctp_inpcb *inp,
}
if (chks_in_queue) {
/* call the output queue function */
- sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_T3);
+ sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_T3, SCTP_SO_NOT_LOCKED);
if ((TAILQ_EMPTY(&stcb->asoc.send_queue)) &&
(TAILQ_EMPTY(&stcb->asoc.sent_queue))) {
/*
@@ -1725,7 +1725,7 @@ sctp_autoclose_timer(struct sctp_inpcb *inp,
* queues and know that we are clear to send
* shutdown
*/
- sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_AUTOCLOSE_TMR);
+ sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_AUTOCLOSE_TMR, SCTP_SO_NOT_LOCKED);
/* Are we clean? */
if (TAILQ_EMPTY(&asoc->send_queue) &&
TAILQ_EMPTY(&asoc->sent_queue)) {
@@ -1875,7 +1875,7 @@ select_a_new_ep:
* first I must verify that this won't effect things :-0
*/
if (it->no_chunk_output == 0)
- sctp_chunk_output(it->inp, it->stcb, SCTP_OUTPUT_FROM_T3);
+ sctp_chunk_output(it->inp, it->stcb, SCTP_OUTPUT_FROM_T3, SCTP_SO_NOT_LOCKED);
SCTP_TCB_UNLOCK(it->stcb);
next_assoc:
diff --git a/sys/netinet/sctp_usrreq.c b/sys/netinet/sctp_usrreq.c
index ccfb5d2..bf11663 100644
--- a/sys/netinet/sctp_usrreq.c
+++ b/sys/netinet/sctp_usrreq.c
@@ -229,6 +229,10 @@ sctp_notify(struct sctp_inpcb *inp,
struct sctp_tcb *stcb,
struct sctp_nets *net)
{
+#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ struct socket *so;
+
+#endif
/* protection */
if ((inp == NULL) || (stcb == NULL) || (net == NULL) ||
(sh == NULL) || (to == NULL)) {
@@ -285,7 +289,7 @@ sctp_notify(struct sctp_inpcb *inp,
net->error_count = net->failure_threshold + 1;
sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN,
stcb, SCTP_FAILED_THRESHOLD,
- (void *)net);
+ (void *)net, SCTP_SO_NOT_LOCKED);
}
if (stcb) {
SCTP_TCB_UNLOCK(stcb);
@@ -299,8 +303,23 @@ sctp_notify(struct sctp_inpcb *inp,
* either case treat it like a OOTB abort with no
* TCB
*/
- sctp_abort_notification(stcb, SCTP_PEER_FAULTY);
+ sctp_abort_notification(stcb, SCTP_PEER_FAULTY, SCTP_SO_NOT_LOCKED);
+#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ 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_USRREQ + SCTP_LOC_2);
+#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ SCTP_SOCKET_UNLOCK(so, 1);
+ /*
+ * SCTP_TCB_UNLOCK(stcb); MT: I think this is not
+ * needed.
+ */
+#endif
/* no need to unlock here, since the TCB is gone */
}
} else {
@@ -526,12 +545,10 @@ sctp_attach(struct socket *so, int proto, struct thread *p)
}
inp = (struct sctp_inpcb *)so->so_pcb;
SCTP_INP_WLOCK(inp);
-
inp->sctp_flags &= ~SCTP_PCB_FLAGS_BOUND_V6; /* I'm not v6! */
ip_inp = &inp->ip_inp.inp;
ip_inp->inp_vflag |= INP_IPV4;
ip_inp->inp_ip_ttl = ip_defttl;
-
#ifdef IPSEC
error = ipsec_init_policy(so, &ip_inp->inp_sp);
#ifdef SCTP_LOG_CLOSING
@@ -789,7 +806,7 @@ sctp_disconnect(struct socket *so)
ph->param_type = htons(SCTP_CAUSE_USER_INITIATED_ABT);
ph->param_length = htons(SCTP_BUF_LEN(err));
}
- sctp_send_abort_tcb(stcb, err);
+ sctp_send_abort_tcb(stcb, err, SCTP_SO_LOCKED);
SCTP_STAT_INCR_COUNTER32(sctps_aborted);
}
SCTP_INP_RUNLOCK(inp);
@@ -814,7 +831,7 @@ sctp_disconnect(struct socket *so)
sctp_stop_timers_for_shutdown(stcb);
sctp_send_shutdown(stcb,
stcb->asoc.primary_destination);
- sctp_chunk_output(stcb->sctp_ep, stcb, SCTP_OUTPUT_FROM_T3);
+ sctp_chunk_output(stcb->sctp_ep, stcb, SCTP_OUTPUT_FROM_T3, SCTP_SO_LOCKED);
if ((SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) ||
(SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
SCTP_STAT_DECR_GAUGE32(sctps_currestab);
@@ -881,7 +898,7 @@ sctp_disconnect(struct socket *so)
*ippp = htonl(SCTP_FROM_SCTP_USRREQ + SCTP_LOC_4);
}
stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_USRREQ + SCTP_LOC_4;
- sctp_send_abort_tcb(stcb, op_err);
+ sctp_send_abort_tcb(stcb, op_err, SCTP_SO_LOCKED);
SCTP_STAT_INCR_COUNTER32(sctps_aborted);
if ((SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_OPEN) ||
(SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
@@ -891,7 +908,7 @@ sctp_disconnect(struct socket *so)
(void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_5);
return (0);
} else {
- sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_CLOSING);
+ sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_CLOSING, SCTP_SO_LOCKED);
}
}
SCTP_TCB_UNLOCK(stcb);
@@ -961,7 +978,7 @@ sctp_shutdown(struct socket *so)
sctp_stop_timers_for_shutdown(stcb);
sctp_send_shutdown(stcb,
stcb->asoc.primary_destination);
- sctp_chunk_output(stcb->sctp_ep, stcb, SCTP_OUTPUT_FROM_T3);
+ sctp_chunk_output(stcb->sctp_ep, stcb, SCTP_OUTPUT_FROM_T3, SCTP_SO_NOT_LOCKED);
if ((SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) ||
(SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
SCTP_STAT_DECR_GAUGE32(sctps_currestab);
@@ -1023,10 +1040,10 @@ sctp_shutdown(struct socket *so)
stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_USRREQ + SCTP_LOC_6;
sctp_abort_an_association(stcb->sctp_ep, stcb,
SCTP_RESPONSE_TO_USER_REQ,
- op_err);
+ op_err, SCTP_SO_LOCKED);
goto skip_unlock;
} else {
- sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_CLOSING);
+ sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_CLOSING, SCTP_SO_LOCKED);
}
}
SCTP_TCB_UNLOCK(stcb);
@@ -1412,7 +1429,7 @@ sctp_do_connect_x(struct socket *so, struct sctp_inpcb *inp, void *optval,
sctp_timer_start(SCTP_TIMER_TYPE_INIT, inp, stcb, stcb->asoc.primary_destination);
} else {
(void)SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered);
- sctp_send_initiate(inp, stcb);
+ sctp_send_initiate(inp, stcb, SCTP_SO_LOCKED);
}
SCTP_TCB_UNLOCK(stcb);
if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) {
@@ -3095,7 +3112,7 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
send_out, (stcb->asoc.str_reset_seq_in - 3),
send_in, send_tsn);
- sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_STRRST_REQ);
+ sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_STRRST_REQ, SCTP_SO_LOCKED);
SCTP_TCB_UNLOCK(stcb);
}
break;
@@ -3161,7 +3178,7 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
sctp_timer_stop(SCTP_TIMER_TYPE_INIT, inp, stcb,
stcb->asoc.primary_destination,
SCTP_FROM_SCTP_USRREQ + SCTP_LOC_9);
- sctp_send_initiate(inp, stcb);
+ sctp_send_initiate(inp, stcb, SCTP_SO_LOCKED);
} else {
/*
* already expired or did not use delayed
@@ -4064,7 +4081,7 @@ sctp_connect(struct socket *so, struct sockaddr *addr, struct thread *p)
/* initialize authentication parameters for the assoc */
sctp_initialize_auth_params(inp, stcb);
- sctp_send_initiate(inp, stcb);
+ sctp_send_initiate(inp, stcb, SCTP_SO_LOCKED);
SCTP_TCB_UNLOCK(stcb);
out_now:
if (create_lock_on) {
diff --git a/sys/netinet/sctputil.c b/sys/netinet/sctputil.c
index 715cc4d..31b9c06 100644
--- a/sys/netinet/sctputil.c
+++ b/sys/netinet/sctputil.c
@@ -1277,7 +1277,7 @@ select_a_new_ep:
* first I must verify that this won't effect things :-0
*/
if (it->no_chunk_output == 0)
- sctp_chunk_output(it->inp, it->stcb, SCTP_OUTPUT_FROM_T3);
+ sctp_chunk_output(it->inp, it->stcb, SCTP_OUTPUT_FROM_T3, SCTP_SO_NOT_LOCKED);
SCTP_TCB_UNLOCK(it->stcb);
next_assoc:
@@ -1391,10 +1391,14 @@ sctp_timeout_handler(void *t)
struct sctp_tcb *stcb;
struct sctp_nets *net;
struct sctp_timer *tmr;
+
+#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ struct socket *so;
+
+#endif
int did_output;
struct sctp_iterator *it = NULL;
-
tmr = (struct sctp_timer *)t;
inp = (struct sctp_inpcb *)tmr->ep;
stcb = (struct sctp_tcb *)tmr->tcb;
@@ -1547,7 +1551,7 @@ sctp_timeout_handler(void *t)
#ifdef SCTP_AUDITING_ENABLED
sctp_auditing(4, inp, stcb, net);
#endif
- sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_T3);
+ sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_T3, SCTP_SO_NOT_LOCKED);
if ((stcb->asoc.num_send_timers_up == 0) &&
(stcb->asoc.sent_queue_cnt > 0)
) {
@@ -1592,7 +1596,7 @@ sctp_timeout_handler(void *t)
#ifdef SCTP_AUDITING_ENABLED
sctp_auditing(4, inp, stcb, net);
#endif
- sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_SACK_TMR);
+ sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_SACK_TMR, SCTP_SO_NOT_LOCKED);
break;
case SCTP_TIMER_TYPE_SHUTDOWN:
if ((stcb == NULL) || (inp == NULL)) {
@@ -1607,7 +1611,7 @@ sctp_timeout_handler(void *t)
#ifdef SCTP_AUDITING_ENABLED
sctp_auditing(4, inp, stcb, net);
#endif
- sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_SHUT_TMR);
+ sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_SHUT_TMR, SCTP_SO_NOT_LOCKED);
break;
case SCTP_TIMER_TYPE_HEARTBEAT:
{
@@ -1637,7 +1641,7 @@ sctp_timeout_handler(void *t)
#endif
sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT,
stcb->sctp_ep, stcb, lnet);
- sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_HB_TMR);
+ sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_HB_TMR, SCTP_SO_NOT_LOCKED);
}
break;
case SCTP_TIMER_TYPE_COOKIE:
@@ -1657,7 +1661,7 @@ sctp_timeout_handler(void *t)
* We consider T3 and Cookie timer pretty much the same with
* respect to where from in chunk_output.
*/
- sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_T3);
+ sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_T3, SCTP_SO_NOT_LOCKED);
break;
case SCTP_TIMER_TYPE_NEWCOOKIE:
{
@@ -1709,7 +1713,7 @@ sctp_timeout_handler(void *t)
#ifdef SCTP_AUDITING_ENABLED
sctp_auditing(4, inp, stcb, net);
#endif
- sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_SHUT_ACK_TMR);
+ sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_SHUT_ACK_TMR, SCTP_SO_NOT_LOCKED);
break;
case SCTP_TIMER_TYPE_SHUTDOWNGUARD:
if ((stcb == NULL) || (inp == NULL)) {
@@ -1717,7 +1721,7 @@ sctp_timeout_handler(void *t)
}
SCTP_STAT_INCR(sctps_timoshutdownguard);
sctp_abort_an_association(inp, stcb,
- SCTP_SHUTDOWN_GUARD_EXPIRES, NULL);
+ SCTP_SHUTDOWN_GUARD_EXPIRES, NULL, SCTP_SO_NOT_LOCKED);
/* no need to unlock on tcb its gone */
goto out_decr;
@@ -1730,7 +1734,7 @@ sctp_timeout_handler(void *t)
goto out_decr;
}
SCTP_STAT_INCR(sctps_timostrmrst);
- sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_STRRST_TMR);
+ sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_STRRST_TMR, SCTP_SO_NOT_LOCKED);
break;
case SCTP_TIMER_TYPE_EARLYFR:
/* Need to do FR of things for net */
@@ -1752,7 +1756,7 @@ sctp_timeout_handler(void *t)
#ifdef SCTP_AUDITING_ENABLED
sctp_auditing(4, inp, stcb, net);
#endif
- sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_ASCONF_TMR);
+ sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_ASCONF_TMR, SCTP_SO_NOT_LOCKED);
break;
case SCTP_TIMER_TYPE_AUTOCLOSE:
@@ -1761,7 +1765,7 @@ sctp_timeout_handler(void *t)
}
SCTP_STAT_INCR(sctps_timoautoclose);
sctp_autoclose_timer(inp, stcb, net);
- sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_AUTOCLOSE_TMR);
+ sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_AUTOCLOSE_TMR, SCTP_SO_NOT_LOCKED);
did_output = 0;
break;
case SCTP_TIMER_TYPE_ASOCKILL:
@@ -1772,7 +1776,18 @@ sctp_timeout_handler(void *t)
/* Can we free it yet? */
SCTP_INP_DECR_REF(inp);
sctp_timer_stop(SCTP_TIMER_TYPE_ASOCKILL, inp, stcb, NULL, SCTP_FROM_SCTPUTIL + SCTP_LOC_1);
+#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ 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_SCTPUTIL + SCTP_LOC_2);
+#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ SCTP_SOCKET_UNLOCK(so, 1);
+#endif
/*
* free asoc, always unlocks (or destroy's) so prevent
* duplicate unlock or unlock of a free mtx :-0
@@ -2829,12 +2844,21 @@ int sctp_asoc_change_wake = 0;
static void
sctp_notify_assoc_change(uint32_t event, struct sctp_tcb *stcb,
- uint32_t error, void *data)
+ uint32_t error, void *data, int so_locked
+#if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
+ SCTP_UNUSED
+#endif
+)
{
struct mbuf *m_notify;
struct sctp_assoc_change *sac;
struct sctp_queued_to_read *control;
+#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ struct socket *so;
+
+#endif
+
/*
* First if we are are going down dump everything we can to the
* socket rcv queue.
@@ -2863,8 +2887,27 @@ sctp_notify_assoc_change(uint32_t event, struct sctp_tcb *stcb,
stcb->sctp_socket->so_error = ECONNRESET;
}
/* Wake ANY sleepers */
+#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ so = SCTP_INP_SO(stcb->sctp_ep);
+ if (!so_locked) {
+ 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);
+ if (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET) {
+ SCTP_SOCKET_UNLOCK(so, 1);
+ return;
+ }
+ }
+#endif
sorwakeup(stcb->sctp_socket);
sowwakeup(stcb->sctp_socket);
+#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ if (!so_locked) {
+ SCTP_SOCKET_UNLOCK(so, 1);
+ }
+#endif
sctp_asoc_change_wake++;
}
if (sctp_is_feature_off(stcb->sctp_ep, SCTP_PCB_FLAGS_RECVASSOCEVNT)) {
@@ -2903,10 +2946,29 @@ sctp_notify_assoc_change(uint32_t event, struct sctp_tcb *stcb,
control->spec_flags = M_NOTIFICATION;
sctp_add_to_readq(stcb->sctp_ep, stcb,
control,
- &stcb->sctp_socket->so_rcv, 1);
+ &stcb->sctp_socket->so_rcv, 1, so_locked);
if (event == SCTP_COMM_LOST) {
/* Wake up any sleeper */
+#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ so = SCTP_INP_SO(stcb->sctp_ep);
+ if (!so_locked) {
+ 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);
+ if (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET) {
+ SCTP_SOCKET_UNLOCK(so, 1);
+ return;
+ }
+ }
+#endif
sctp_sowwakeup(stcb->sctp_ep, stcb->sctp_socket);
+#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ if (!so_locked) {
+ SCTP_SOCKET_UNLOCK(so, 1);
+ }
+#endif
}
}
@@ -2970,13 +3032,17 @@ sctp_notify_peer_addr_change(struct sctp_tcb *stcb, uint32_t state,
control->tail_mbuf = m_notify;
sctp_add_to_readq(stcb->sctp_ep, stcb,
control,
- &stcb->sctp_socket->so_rcv, 1);
+ &stcb->sctp_socket->so_rcv, 1, SCTP_SO_NOT_LOCKED);
}
static void
sctp_notify_send_failed(struct sctp_tcb *stcb, uint32_t error,
- struct sctp_tmit_chunk *chk)
+ struct sctp_tmit_chunk *chk, int so_locked
+#if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
+ SCTP_UNUSED
+#endif
+)
{
struct mbuf *m_notify;
struct sctp_send_failed *ssf;
@@ -3036,13 +3102,17 @@ sctp_notify_send_failed(struct sctp_tcb *stcb, uint32_t error,
control->spec_flags = M_NOTIFICATION;
sctp_add_to_readq(stcb->sctp_ep, stcb,
control,
- &stcb->sctp_socket->so_rcv, 1);
+ &stcb->sctp_socket->so_rcv, 1, so_locked);
}
static void
sctp_notify_send_failed2(struct sctp_tcb *stcb, uint32_t error,
- struct sctp_stream_queue_pending *sp)
+ struct sctp_stream_queue_pending *sp, int so_locked
+#if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
+ SCTP_UNUSED
+#endif
+)
{
struct mbuf *m_notify;
struct sctp_send_failed *ssf;
@@ -3102,7 +3172,7 @@ sctp_notify_send_failed2(struct sctp_tcb *stcb, uint32_t error,
control->spec_flags = M_NOTIFICATION;
sctp_add_to_readq(stcb->sctp_ep, stcb,
control,
- &stcb->sctp_socket->so_rcv, 1);
+ &stcb->sctp_socket->so_rcv, 1, so_locked);
}
@@ -3149,7 +3219,7 @@ sctp_notify_adaptation_layer(struct sctp_tcb *stcb,
control->tail_mbuf = m_notify;
sctp_add_to_readq(stcb->sctp_ep, stcb,
control,
- &stcb->sctp_socket->so_rcv, 1);
+ &stcb->sctp_socket->so_rcv, 1, SCTP_SO_NOT_LOCKED);
}
/* This always must be called with the read-queue LOCKED in the INP */
@@ -3242,7 +3312,24 @@ sctp_notify_shutdown_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)) {
/* mark socket closed for read/write and wakeup! */
+#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ struct socket *so;
+
+ so = SCTP_INP_SO(stcb->sctp_ep);
+ 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);
+ if (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET) {
+ SCTP_SOCKET_UNLOCK(so, 1);
+ return;
+ }
+#endif
socantsendmore(stcb->sctp_socket);
+#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ SCTP_SOCKET_UNLOCK(so, 1);
+#endif
}
if (sctp_is_feature_off(stcb->sctp_ep, SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT))
/* event not enabled */
@@ -3276,7 +3363,7 @@ sctp_notify_shutdown_event(struct sctp_tcb *stcb)
control->tail_mbuf = m_notify;
sctp_add_to_readq(stcb->sctp_ep, stcb,
control,
- &stcb->sctp_socket->so_rcv, 1);
+ &stcb->sctp_socket->so_rcv, 1, SCTP_SO_NOT_LOCKED);
}
static void
@@ -3344,13 +3431,17 @@ sctp_notify_stream_reset(struct sctp_tcb *stcb,
control->tail_mbuf = m_notify;
sctp_add_to_readq(stcb->sctp_ep, stcb,
control,
- &stcb->sctp_socket->so_rcv, 1);
+ &stcb->sctp_socket->so_rcv, 1, SCTP_SO_NOT_LOCKED);
}
void
sctp_ulp_notify(uint32_t notification, struct sctp_tcb *stcb,
- uint32_t error, void *data)
+ uint32_t error, void *data, int so_locked
+#if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
+ SCTP_UNUSED
+#endif
+)
{
if (stcb == NULL) {
/* unlikely but */
@@ -3379,7 +3470,7 @@ sctp_ulp_notify(uint32_t notification, struct sctp_tcb *stcb,
switch (notification) {
case SCTP_NOTIFY_ASSOC_UP:
if (stcb->asoc.assoc_up_sent == 0) {
- sctp_notify_assoc_change(SCTP_COMM_UP, stcb, error, NULL);
+ sctp_notify_assoc_change(SCTP_COMM_UP, stcb, error, NULL, so_locked);
stcb->asoc.assoc_up_sent = 1;
}
if (stcb->asoc.adaptation_needed && (stcb->asoc.adaptation_sent == 0)) {
@@ -3387,7 +3478,7 @@ sctp_ulp_notify(uint32_t notification, struct sctp_tcb *stcb,
}
break;
case SCTP_NOTIFY_ASSOC_DOWN:
- sctp_notify_assoc_change(SCTP_SHUTDOWN_COMP, stcb, error, NULL);
+ sctp_notify_assoc_change(SCTP_SHUTDOWN_COMP, stcb, error, NULL, so_locked);
break;
case SCTP_NOTIFY_INTERFACE_DOWN:
{
@@ -3418,11 +3509,11 @@ sctp_ulp_notify(uint32_t notification, struct sctp_tcb *stcb,
}
case SCTP_NOTIFY_SPECIAL_SP_FAIL:
sctp_notify_send_failed2(stcb, error,
- (struct sctp_stream_queue_pending *)data);
+ (struct sctp_stream_queue_pending *)data, so_locked);
break;
case SCTP_NOTIFY_DG_FAIL:
sctp_notify_send_failed(stcb, error,
- (struct sctp_tmit_chunk *)data);
+ (struct sctp_tmit_chunk *)data, so_locked);
break;
case SCTP_NOTIFY_PARTIAL_DELVIERY_INDICATION:
{
@@ -3438,9 +3529,9 @@ sctp_ulp_notify(uint32_t notification, struct sctp_tcb *stcb,
case SCTP_NOTIFY_ASSOC_ABORTED:
if ((stcb) && (((stcb->asoc.state & SCTP_STATE_MASK) == SCTP_STATE_COOKIE_WAIT) ||
((stcb->asoc.state & SCTP_STATE_MASK) == SCTP_STATE_COOKIE_ECHOED))) {
- sctp_notify_assoc_change(SCTP_CANT_STR_ASSOC, stcb, error, NULL);
+ sctp_notify_assoc_change(SCTP_CANT_STR_ASSOC, stcb, error, NULL, so_locked);
} else {
- sctp_notify_assoc_change(SCTP_COMM_LOST, stcb, error, NULL);
+ sctp_notify_assoc_change(SCTP_COMM_LOST, stcb, error, NULL, so_locked);
}
break;
case SCTP_NOTIFY_PEER_OPENED_STREAM:
@@ -3448,7 +3539,7 @@ sctp_ulp_notify(uint32_t notification, struct sctp_tcb *stcb,
case SCTP_NOTIFY_STREAM_OPENED_OK:
break;
case SCTP_NOTIFY_ASSOC_RESTART:
- sctp_notify_assoc_change(SCTP_RESTART, stcb, error, data);
+ sctp_notify_assoc_change(SCTP_RESTART, stcb, error, data, so_locked);
break;
case SCTP_NOTIFY_HB_RESP:
break;
@@ -3505,7 +3596,11 @@ sctp_ulp_notify(uint32_t notification, struct sctp_tcb *stcb,
}
void
-sctp_report_all_outbound(struct sctp_tcb *stcb, int holds_lock)
+sctp_report_all_outbound(struct sctp_tcb *stcb, int holds_lock, int so_locked
+#if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
+ SCTP_UNUSED
+#endif
+)
{
struct sctp_association *asoc;
struct sctp_stream_out *outs;
@@ -3546,7 +3641,7 @@ sctp_report_all_outbound(struct sctp_tcb *stcb, int holds_lock)
}
sctp_free_bufspace(stcb, asoc, chk, 1);
sctp_ulp_notify(SCTP_NOTIFY_DG_FAIL, stcb,
- SCTP_NOTIFY_DATAGRAM_SENT, chk);
+ SCTP_NOTIFY_DATAGRAM_SENT, chk, so_locked);
if (chk->data) {
sctp_m_freem(chk->data);
chk->data = NULL;
@@ -3574,7 +3669,7 @@ sctp_report_all_outbound(struct sctp_tcb *stcb, int holds_lock)
}
}
sctp_free_bufspace(stcb, asoc, chk, 1);
- sctp_ulp_notify(SCTP_NOTIFY_DG_FAIL, stcb, SCTP_NOTIFY_DATAGRAM_UNSENT, chk);
+ sctp_ulp_notify(SCTP_NOTIFY_DG_FAIL, stcb, SCTP_NOTIFY_DATAGRAM_UNSENT, chk, so_locked);
if (chk->data) {
sctp_m_freem(chk->data);
chk->data = NULL;
@@ -3595,7 +3690,7 @@ sctp_report_all_outbound(struct sctp_tcb *stcb, int holds_lock)
TAILQ_REMOVE(&outs->outqueue, sp, next);
sctp_free_spbufspace(stcb, asoc, sp);
sctp_ulp_notify(SCTP_NOTIFY_SPECIAL_SP_FAIL, stcb,
- SCTP_NOTIFY_DATAGRAM_UNSENT, (void *)sp);
+ SCTP_NOTIFY_DATAGRAM_UNSENT, (void *)sp, so_locked);
if (sp->data) {
sctp_m_freem(sp->data);
sp->data = NULL;
@@ -3616,7 +3711,11 @@ sctp_report_all_outbound(struct sctp_tcb *stcb, int holds_lock)
}
void
-sctp_abort_notification(struct sctp_tcb *stcb, int error)
+sctp_abort_notification(struct sctp_tcb *stcb, int error, int so_locked
+#if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
+ SCTP_UNUSED
+#endif
+)
{
if (stcb == NULL) {
@@ -3628,13 +3727,13 @@ sctp_abort_notification(struct sctp_tcb *stcb, int error)
return;
}
/* Tell them we lost the asoc */
- sctp_report_all_outbound(stcb, 1);
+ sctp_report_all_outbound(stcb, 1, so_locked);
if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) &&
(stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_CONNECTED))) {
stcb->sctp_ep->sctp_flags |= SCTP_PCB_FLAGS_WAS_ABORTED;
}
- sctp_ulp_notify(SCTP_NOTIFY_ASSOC_ABORTED, stcb, error, NULL);
+ sctp_ulp_notify(SCTP_NOTIFY_ASSOC_ABORTED, stcb, error, NULL, so_locked);
}
void
@@ -3644,11 +3743,16 @@ sctp_abort_association(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
{
uint32_t vtag;
+#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ struct socket *so;
+
+#endif
+
vtag = 0;
if (stcb != NULL) {
/* We have a TCB to abort, send notification too */
vtag = stcb->asoc.peer_vtag;
- sctp_abort_notification(stcb, 0);
+ sctp_abort_notification(stcb, 0, SCTP_SO_NOT_LOCKED);
/* get the assoc vrf id and table id */
vrf_id = stcb->asoc.vrf_id;
stcb->asoc.state |= SCTP_STATE_WAS_ABORTED;
@@ -3656,7 +3760,18 @@ sctp_abort_association(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
sctp_send_abort(m, iphlen, sh, vtag, op_err, vrf_id);
if (stcb != NULL) {
/* Ok, now lets free it */
+#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ 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_SCTPUTIL + SCTP_LOC_4);
+#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ SCTP_SOCKET_UNLOCK(so, 1);
+#endif
} else {
if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) {
if (LIST_FIRST(&inp->sctp_asoc_list) == NULL) {
@@ -3733,10 +3848,23 @@ none_in:
void
sctp_abort_an_association(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
- int error, struct mbuf *op_err)
+ int error, struct mbuf *op_err,
+ int so_locked
+#if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
+ SCTP_UNUSED
+#endif
+)
{
uint32_t vtag;
+#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ struct socket *so;
+
+#endif
+
+#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ so = SCTP_INP_SO(inp);
+#endif
if (stcb == NULL) {
/* Got to have a TCB */
if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) {
@@ -3752,9 +3880,9 @@ sctp_abort_an_association(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
vtag = stcb->asoc.peer_vtag;
/* notify the ulp */
if ((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0)
- sctp_abort_notification(stcb, error);
+ sctp_abort_notification(stcb, error, so_locked);
/* notify the peer */
- sctp_send_abort_tcb(stcb, op_err);
+ sctp_send_abort_tcb(stcb, op_err, so_locked);
SCTP_STAT_INCR_COUNTER32(sctps_aborted);
if ((SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_OPEN) ||
(SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
@@ -3764,7 +3892,21 @@ sctp_abort_an_association(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
#ifdef SCTP_ASOCLOG_OF_TSNS
sctp_print_out_track_log(stcb);
#endif
+#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ if (!so_locked) {
+ 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_SCTPUTIL + SCTP_LOC_5);
+#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ if (!so_locked) {
+ SCTP_SOCKET_UNLOCK(so, 1);
+ }
+#endif
}
void
@@ -4105,7 +4247,12 @@ sctp_add_to_readq(struct sctp_inpcb *inp,
struct sctp_tcb *stcb,
struct sctp_queued_to_read *control,
struct sockbuf *sb,
- int end)
+ int end,
+ int so_locked
+#if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
+ SCTP_UNUSED
+#endif
+)
{
/*
* Here we must place the control on the end of the socket read
@@ -4172,8 +4319,30 @@ sctp_add_to_readq(struct sctp_inpcb *inp,
if (inp && inp->sctp_socket) {
if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_ZERO_COPY_ACTIVE)) {
SCTP_ZERO_COPY_EVENT(inp, inp->sctp_socket);
- } else
+ } else {
+#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ struct socket *so;
+
+ so = SCTP_INP_SO(inp);
+ if (!so_locked) {
+ 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);
+ if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) {
+ SCTP_SOCKET_UNLOCK(so, 1);
+ return;
+ }
+ }
+#endif
sctp_sorwakeup(inp, inp->sctp_socket);
+#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ if (!so_locked) {
+ SCTP_SOCKET_UNLOCK(so, 1);
+ }
+#endif
+ }
}
}
@@ -4296,8 +4465,26 @@ get_out:
if (inp && inp->sctp_socket) {
if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_ZERO_COPY_ACTIVE)) {
SCTP_ZERO_COPY_EVENT(inp, inp->sctp_socket);
- } else
+ } else {
+#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ struct socket *so;
+
+ 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);
+ if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) {
+ SCTP_SOCKET_UNLOCK(so, 1);
+ return (0);
+ }
+#endif
sctp_sorwakeup(inp, inp->sctp_socket);
+#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ SCTP_SOCKET_UNLOCK(so, 1);
+#endif
+ }
}
return (0);
}
@@ -4367,7 +4554,11 @@ sctp_free_bufspace(struct sctp_tcb *stcb, struct sctp_association *asoc,
int
sctp_release_pr_sctp_chunk(struct sctp_tcb *stcb, struct sctp_tmit_chunk *tp1,
- int reason, struct sctpchunk_listhead *queue)
+ int reason, struct sctpchunk_listhead *queue, int so_locked
+#if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
+ SCTP_UNUSED
+#endif
+)
{
int ret_sz = 0;
int notdone;
@@ -4377,11 +4568,38 @@ sctp_release_pr_sctp_chunk(struct sctp_tcb *stcb, struct sctp_tmit_chunk *tp1,
ret_sz += tp1->book_size;
tp1->sent = SCTP_FORWARD_TSN_SKIP;
if (tp1->data) {
+#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ struct socket *so;
+
+#endif
sctp_free_bufspace(stcb, &stcb->asoc, tp1, 1);
- sctp_ulp_notify(SCTP_NOTIFY_DG_FAIL, stcb, reason, tp1);
+ sctp_ulp_notify(SCTP_NOTIFY_DG_FAIL, stcb, reason, tp1, SCTP_SO_NOT_LOCKED);
sctp_m_freem(tp1->data);
tp1->data = NULL;
+#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ so = SCTP_INP_SO(stcb->sctp_ep);
+ if (!so_locked) {
+ 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);
+ if (stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET) {
+ /*
+ * assoc was freed while we were
+ * unlocked
+ */
+ SCTP_SOCKET_UNLOCK(so, 1);
+ return (ret_sz);
+ }
+ }
+#endif
sctp_sowwakeup(stcb->sctp_ep, stcb->sctp_socket);
+#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ if (!so_locked) {
+ SCTP_SOCKET_UNLOCK(so, 1);
+ }
+#endif
}
if (PR_SCTP_BUF_ENABLED(tp1->flags)) {
stcb->asoc.sent_queue_cnt_removeable--;
@@ -4423,7 +4641,7 @@ sctp_release_pr_sctp_chunk(struct sctp_tcb *stcb, struct sctp_tmit_chunk *tp1,
*/
if (tp1) {
ret_sz += sctp_release_pr_sctp_chunk(stcb, tp1, reason,
- &stcb->asoc.send_queue);
+ &stcb->asoc.send_queue, so_locked);
} else {
SCTP_PRINTF("hmm, nothing on the send queue and no EOM?\n");
}
@@ -4627,7 +4845,7 @@ sctp_user_rcvd(struct sctp_tcb *stcb, uint32_t * freed_so_far, int hold_rlock,
SCTP_STAT_INCR(sctps_wu_sacks_sent);
sctp_send_sack(stcb);
sctp_chunk_output(stcb->sctp_ep, stcb,
- SCTP_OUTPUT_FROM_USR_RCVD);
+ SCTP_OUTPUT_FROM_USR_RCVD, SCTP_SO_LOCKED);
/* make sure no timer is running */
sctp_timer_stop(SCTP_TIMER_TYPE_RECV, stcb->sctp_ep, stcb, NULL, SCTP_FROM_SCTPUTIL + SCTP_LOC_6);
SCTP_TCB_UNLOCK(stcb);
diff --git a/sys/netinet/sctputil.h b/sys/netinet/sctputil.h
index b1f5542..8d02967 100644
--- a/sys/netinet/sctputil.h
+++ b/sys/netinet/sctputil.h
@@ -104,7 +104,12 @@ sctp_add_to_readq(struct sctp_inpcb *inp,
struct sctp_tcb *stcb,
struct sctp_queued_to_read *control,
struct sockbuf *sb,
- int end);
+ int end,
+ int so_locked
+#if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
+ SCTP_UNUSED
+#endif
+);
int
sctp_append_to_readq(struct sctp_inpcb *inp,
@@ -139,7 +144,12 @@ int sctp_add_pad_tombuf(struct mbuf *, int);
int sctp_pad_lastmbuf(struct mbuf *, int, struct mbuf *);
-void sctp_ulp_notify(uint32_t, struct sctp_tcb *, uint32_t, void *);
+void
+sctp_ulp_notify(uint32_t, struct sctp_tcb *, uint32_t, void *, int
+#if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
+ SCTP_UNUSED
+#endif
+);
void
sctp_pull_off_control_to_new_inp(struct sctp_inpcb *old_inp,
@@ -149,11 +159,21 @@ sctp_pull_off_control_to_new_inp(struct sctp_inpcb *old_inp,
void sctp_stop_timers_for_shutdown(struct sctp_tcb *);
-void sctp_report_all_outbound(struct sctp_tcb *, int);
+void
+sctp_report_all_outbound(struct sctp_tcb *, int, int
+#if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
+ SCTP_UNUSED
+#endif
+);
int sctp_expand_mapping_array(struct sctp_association *, uint32_t);
-void sctp_abort_notification(struct sctp_tcb *, int);
+void
+sctp_abort_notification(struct sctp_tcb *, int, int
+#if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
+ SCTP_UNUSED
+#endif
+);
/* We abort responding to an IP packet for some reason */
void
@@ -164,7 +184,11 @@ sctp_abort_association(struct sctp_inpcb *, struct sctp_tcb *,
/* We choose to abort via user input */
void
sctp_abort_an_association(struct sctp_inpcb *, struct sctp_tcb *, int,
- struct mbuf *);
+ struct mbuf *, int
+#if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
+ SCTP_UNUSED
+#endif
+);
void
sctp_handle_ootb(struct mbuf *, int, int, struct sctphdr *,
@@ -211,7 +235,11 @@ sctp_notify_partial_delivery_indication(struct sctp_tcb *stcb,
int
sctp_release_pr_sctp_chunk(struct sctp_tcb *, struct sctp_tmit_chunk *,
- int, struct sctpchunk_listhead *);
+ int, struct sctpchunk_listhead *, int
+#if !defined(__APPLE__) && !defined(SCTP_SO_LOCK_TESTING)
+ SCTP_UNUSED
+#endif
+);
struct mbuf *sctp_generate_invmanparam(int);
diff --git a/sys/netinet6/sctp6_usrreq.c b/sys/netinet6/sctp6_usrreq.c
index ac74d64..2d4c82c 100644
--- a/sys/netinet6/sctp6_usrreq.c
+++ b/sys/netinet6/sctp6_usrreq.c
@@ -139,7 +139,7 @@ sctp6_input(struct mbuf **i_pak, int *offp, int proto)
/* in6p's ref-count increased && stcb locked */
if ((in6p) && (stcb)) {
sctp_send_packet_dropped(stcb, net, m, iphlen, 1);
- sctp_chunk_output((struct sctp_inpcb *)in6p, stcb, 2);
+ sctp_chunk_output((struct sctp_inpcb *)in6p, stcb, SCTP_OUTPUT_FROM_INPUT_ERROR, SCTP_SO_NOT_LOCKED);
} else if ((in6p != NULL) && (stcb == NULL)) {
refcount_up = 1;
}
@@ -911,7 +911,7 @@ sctp6_connect(struct socket *so, struct sockaddr *addr, struct thread *p)
/* initialize authentication parameters for the assoc */
sctp_initialize_auth_params(inp, stcb);
- sctp_send_initiate(inp, stcb);
+ sctp_send_initiate(inp, stcb, SCTP_SO_LOCKED);
SCTP_TCB_UNLOCK(stcb);
return error;
}
OpenPOWER on IntegriCloud