diff options
Diffstat (limited to 'sys')
-rw-r--r-- | sys/netinet/sctp_asconf.c | 12 | ||||
-rw-r--r-- | sys/netinet/sctp_auth.c | 2 | ||||
-rw-r--r-- | sys/netinet/sctp_bsd_addr.c | 1 | ||||
-rw-r--r-- | sys/netinet/sctp_cc_functions.c | 10 | ||||
-rw-r--r-- | sys/netinet/sctp_constants.h | 7 | ||||
-rw-r--r-- | sys/netinet/sctp_indata.c | 173 | ||||
-rw-r--r-- | sys/netinet/sctp_input.c | 369 | ||||
-rw-r--r-- | sys/netinet/sctp_lock_bsd.h | 6 | ||||
-rw-r--r-- | sys/netinet/sctp_os_bsd.h | 1 | ||||
-rw-r--r-- | sys/netinet/sctp_output.c | 110 | ||||
-rw-r--r-- | sys/netinet/sctp_output.h | 21 | ||||
-rw-r--r-- | sys/netinet/sctp_pcb.c | 25 | ||||
-rw-r--r-- | sys/netinet/sctp_peeloff.c | 16 | ||||
-rw-r--r-- | sys/netinet/sctp_timer.c | 22 | ||||
-rw-r--r-- | sys/netinet/sctp_usrreq.c | 47 | ||||
-rw-r--r-- | sys/netinet/sctputil.c | 314 | ||||
-rw-r--r-- | sys/netinet/sctputil.h | 40 | ||||
-rw-r--r-- | sys/netinet6/sctp6_usrreq.c | 4 |
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; } |