diff options
author | rrs <rrs@FreeBSD.org> | 2006-12-14 17:02:55 +0000 |
---|---|---|
committer | rrs <rrs@FreeBSD.org> | 2006-12-14 17:02:55 +0000 |
commit | 3de80805ffbf0e87c0ff547698814193edb8bd14 (patch) | |
tree | 940611c208a2462c47614c0688becd97244ad6fe /sys/netinet/sctp_usrreq.c | |
parent | d398e83b8a941f854ec49ad93c3694c17b0f8e88 (diff) | |
download | FreeBSD-src-3de80805ffbf0e87c0ff547698814193edb8bd14.zip FreeBSD-src-3de80805ffbf0e87c0ff547698814193edb8bd14.tar.gz |
1) Fixes on a number of different collision case LOR's.
2) Fix all "magic numbers" to be constants.
3) A collision case that would generate two associations to
the same peer due to a missing lock is fixed.
4) Added tracking of where timers are stopped.
Approved by: gnn
Diffstat (limited to 'sys/netinet/sctp_usrreq.c')
-rw-r--r-- | sys/netinet/sctp_usrreq.c | 218 |
1 files changed, 202 insertions, 16 deletions
diff --git a/sys/netinet/sctp_usrreq.c b/sys/netinet/sctp_usrreq.c index 58e7616..c650e35 100644 --- a/sys/netinet/sctp_usrreq.c +++ b/sys/netinet/sctp_usrreq.c @@ -316,7 +316,8 @@ sctp_notify_mbuf(struct sctp_inpcb *inp, /* Stop any PMTU timer */ if (callout_pending(&net->pmtu_timer.timer)) { tmr_stopped = 1; - sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net); + sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net, + SCTP_FROM_SCTP_USRREQ + SCTP_LOC_1); } /* Adjust destination size limit */ if (net->mtu > nxtsz) { @@ -386,7 +387,7 @@ sctp_notify(struct sctp_inpcb *inp, * TCB */ sctp_abort_notification(stcb, SCTP_PEER_FAULTY); - sctp_free_assoc(inp, stcb, 0); + sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_2); /* no need to unlock here, since the TCB is gone */ } } else { @@ -541,6 +542,184 @@ out: SYSCTL_PROC(_net_inet_sctp, OID_AUTO, getcred, CTLTYPE_OPAQUE | CTLFLAG_RW, 0, 0, sctp_getcred, "S,ucred", "Get the ucred of a SCTP connection"); +static int +sctp_assoclist(SYSCTL_HANDLER_ARGS) +{ + unsigned int number_of_endpoints; + unsigned int number_of_local_addresses; + unsigned int number_of_associations; + unsigned int number_of_remote_addresses; + unsigned int n; + int error; + struct sctp_inpcb *inp; + struct sctp_tcb *stcb; + struct sctp_nets *net; + struct sctp_laddr *laddr; + struct xsctp_inpcb xinpcb; + struct xsctp_tcb xstcb; + +/* struct xsctp_laddr xladdr; */ + struct xsctp_raddr xraddr; + + number_of_endpoints = 0; + number_of_local_addresses = 0; + number_of_associations = 0; + number_of_remote_addresses = 0; + + SCTP_INP_INFO_RLOCK(); + if (req->oldptr == USER_ADDR_NULL) { + LIST_FOREACH(inp, &sctppcbinfo.listhead, sctp_list) { + SCTP_INP_RLOCK(inp); + number_of_endpoints++; + /* FIXME MT */ + LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) { + number_of_local_addresses++; + } + LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { + number_of_associations++; + /* FIXME MT */ + LIST_FOREACH(laddr, &stcb->asoc.sctp_local_addr_list, sctp_nxt_addr) { + number_of_local_addresses++; + } + TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { + number_of_remote_addresses++; + } + } + SCTP_INP_RUNLOCK(inp); + } + SCTP_INP_INFO_RUNLOCK(); + n = (number_of_endpoints + 1) * sizeof(struct xsctp_inpcb) + + number_of_local_addresses * sizeof(struct xsctp_laddr) + + number_of_associations * sizeof(struct xsctp_tcb) + + number_of_remote_addresses * sizeof(struct xsctp_raddr); +#ifdef SCTP_DEBUG + printf("inps = %u, stcbs = %u, laddrs = %u, raddrs = %u\n", + number_of_endpoints, number_of_associations, + number_of_local_addresses, number_of_remote_addresses); +#endif + /* request some more memory than needed */ + req->oldidx = (n + n / 8); + return 0; + } + if (req->newptr != USER_ADDR_NULL) { + SCTP_INP_INFO_RUNLOCK(); + return EPERM; + } + LIST_FOREACH(inp, &sctppcbinfo.listhead, sctp_list) { + SCTP_INP_RLOCK(inp); + number_of_local_addresses = 0; + number_of_associations = 0; + /* + * LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) + * { number_of_local_addresses++; } + */ + LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { + number_of_associations++; + } + xinpcb.last = 0; + xinpcb.local_port = ntohs(inp->sctp_lport); + xinpcb.number_local_addresses = number_of_local_addresses; + xinpcb.number_associations = number_of_associations; + xinpcb.flags = inp->sctp_flags; + xinpcb.features = inp->sctp_features; + xinpcb.total_sends = inp->total_sends; + xinpcb.total_recvs = inp->total_recvs; + xinpcb.total_nospaces = inp->total_nospaces; + SCTP_INP_INCR_REF(inp); + SCTP_INP_RUNLOCK(inp); + SCTP_INP_INFO_RUNLOCK(); + error = SYSCTL_OUT(req, &xinpcb, sizeof(struct xsctp_inpcb)); + if (error) { + return error; + } + SCTP_INP_INFO_RLOCK(); + SCTP_INP_RLOCK(inp); + /* FIXME MT */ + /* + * LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) + * { error = SYSCTL_OUT(req, &xladdr, sizeof(struct + * xsctp_laddr)); if (error) { #if + * defined(SCTP_APPLE_FINE_GRAINED_LOCKING) + * socket_unlock(inp->ip_inp.inp.inp_socket, 1); + * lck_rw_unlock_shared(sctppcbinfo.ipi_ep_mtx); #endif + * SCTP_INP_RUNLOCK(inp); SCTP_INP_INFO_RUNLOCK(); return + * error; } } + */ + LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { + SCTP_TCB_LOCK(stcb); + atomic_add_int(&stcb->asoc.refcnt, 1); + SCTP_TCB_UNLOCK(stcb); + number_of_local_addresses = 0; + number_of_remote_addresses = 0; + /* FIXME MT */ + /* + * LIST_FOREACH(laddr, + * &stcb->asoc.sctp_local_addr_list, sctp_nxt_addr) + * { number_of_local_addresses++; } + */ + TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { + number_of_remote_addresses++; + } + xstcb.remote_port = ntohs(stcb->rport); + xstcb.number_local_addresses = number_of_local_addresses; + xstcb.number_remote_addresses = number_of_remote_addresses; + xstcb.number_incomming_streams = 0; + xstcb.number_outgoing_streams = 0; + xstcb.state = stcb->asoc.state; + xstcb.total_sends = stcb->total_sends; + xstcb.total_recvs = stcb->total_recvs; + xstcb.local_tag = stcb->asoc.my_vtag; + xstcb.remote_tag = stcb->asoc.peer_vtag; + xstcb.initial_tsn = stcb->asoc.init_seq_number; + xstcb.highest_tsn = stcb->asoc.sending_seq - 1; + xstcb.cumulative_tsn = stcb->asoc.last_acked_seq; + xstcb.cumulative_tsn_ack = stcb->asoc.cumulative_tsn; + SCTP_INP_RUNLOCK(inp); + SCTP_INP_INFO_RUNLOCK(); + error = SYSCTL_OUT(req, &xstcb, sizeof(struct xsctp_tcb)); + if (error) { + atomic_add_int(&stcb->asoc.refcnt, -1); + return error; + } + /* FIXME MT */ + /* + * LIST_FOREACH(laddr, + * &stcb->asoc.sctp_local_addr_list, sctp_nxt_addr) + * { error = SYSCTL_OUT(req, &xladdr, sizeof(struct + * xsctp_laddr)); if (error) { #if + * defined(SCTP_APPLE_FINE_GRAINED_LOCKING) + * socket_unlock(inp->ip_inp.inp.inp_socket, 1); + * lck_rw_unlock_shared(sctppcbinfo.ipi_ep_mtx); + * #endif SCTP_INP_RUNLOCK(inp); + * SCTP_INP_INFO_RUNLOCK(); return error; } + * */ + TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { + xraddr.state = net->dest_state; + xraddr.address = net->ro._l_addr; + error = SYSCTL_OUT(req, &xraddr, sizeof(struct xsctp_raddr)); + if (error) { + atomic_add_int(&stcb->asoc.refcnt, -1); + return error; + } + } + atomic_add_int(&stcb->asoc.refcnt, -1); + SCTP_INP_INFO_RLOCK(); + SCTP_INP_RLOCK(inp); + } + SCTP_INP_DECR_REF(inp); + SCTP_INP_RUNLOCK(inp); + } + SCTP_INP_INFO_RUNLOCK(); + + xinpcb.last = 1; + xinpcb.local_port = 0; + xinpcb.number_local_addresses = 0; + xinpcb.number_associations = 0; + xinpcb.flags = 0; + xinpcb.features = 0; + error = SYSCTL_OUT(req, &xinpcb, sizeof(struct xsctp_inpcb)); + return error; +} /* * sysctl definitions @@ -604,12 +783,10 @@ SYSCTL_INT(_net_inet_sctp, OID_AUTO, asoc_resource, CTLFLAG_RW, &sctp_asoc_free_resc_limit, 0, "Max number of cached resources in an asoc"); - SYSCTL_INT(_net_inet_sctp, OID_AUTO, chunkscale, CTLFLAG_RW, &sctp_chunkscale, 0, "Tuneable for Scaling of number of chunks and messages"); - SYSCTL_UINT(_net_inet_sctp, OID_AUTO, delayed_sack_time, CTLFLAG_RW, &sctp_delayed_sack_time_default, 0, "Default delayed SACK timer in msec"); @@ -666,7 +843,6 @@ SYSCTL_UINT(_net_inet_sctp, OID_AUTO, add_more_on_output, CTLFLAG_RW, &sctp_add_more_threshold, 0, "When space wise is it worthwhile to try to add more to a socket send buffer"); - SYSCTL_UINT(_net_inet_sctp, OID_AUTO, nr_outgoing_streams, CTLFLAG_RW, &sctp_nr_outgoing_streams_default, 0, "Default number of outgoing streams"); @@ -742,6 +918,11 @@ SYSCTL_INT(_net_inet_sctp, OID_AUTO, strict_data_order, CTLFLAG_RW, SYSCTL_STRUCT(_net_inet_sctp, OID_AUTO, stats, CTLFLAG_RW, &sctpstat, sctpstat, "SCTP statistics (struct sctps_stat, netinet/sctp.h"); + +SYSCTL_PROC(_net_inet_sctp, OID_AUTO, assoclist, CTLFLAG_RD, + 0, 0, sctp_assoclist, + "S,xassoc", "List of active SCTP associations"); + #ifdef SCTP_DEBUG SYSCTL_INT(_net_inet_sctp, OID_AUTO, debug, CTLFLAG_RW, &sctp_debug_on, 0, "Configure debug output"); @@ -1106,7 +1287,7 @@ sctp_disconnect(struct socket *so) (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) { SCTP_STAT_DECR_GAUGE32(sctps_currestab); } - sctp_free_assoc(inp, stcb, 0); + sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_3); /* No unlock tcb assoc is gone */ splx(s); return (0); @@ -1187,8 +1368,9 @@ sctp_disconnect(struct socket *so) SCTP_CAUSE_USER_INITIATED_ABT); ph->param_length = htons(op_err->m_len); ippp = (uint32_t *) (ph + 1); - *ippp = htonl(0x30000007); + *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_STAT_INCR_COUNTER32(sctps_aborted); if ((SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_OPEN) || @@ -1196,7 +1378,7 @@ sctp_disconnect(struct socket *so) SCTP_STAT_DECR_GAUGE32(sctps_currestab); } SCTP_INP_RUNLOCK(inp); - sctp_free_assoc(inp, stcb, 0); + sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_5); splx(s); return (0); } @@ -1325,8 +1507,9 @@ sctp_shutdown(struct socket *so) SCTP_CAUSE_USER_INITIATED_ABT); ph->param_length = htons(op_err->m_len); ippp = (uint32_t *) (ph + 1); - *ippp = htonl(0x30000008); + *ippp = htonl(SCTP_FROM_SCTP_USRREQ + SCTP_LOC_6); } + 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); @@ -1744,17 +1927,17 @@ sctp_do_connect_x(struct socket *so, for (i = 1; i < totaddr; i++) { if (sa->sa_family == AF_INET) { incr = sizeof(struct sockaddr_in); - if (sctp_add_remote_addr(stcb, sa, 0, 8)) { + if (sctp_add_remote_addr(stcb, sa, SCTP_DONOT_SETSCOPE, SCTP_ADDR_IS_CONFIRMED)) { /* assoc gone no un-lock */ - sctp_free_assoc(inp, stcb, 0); + sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_7); error = ENOBUFS; goto out_now; } } else if (sa->sa_family == AF_INET6) { incr = sizeof(struct sockaddr_in6); - if (sctp_add_remote_addr(stcb, sa, 0, 8)) { + if (sctp_add_remote_addr(stcb, sa, SCTP_DONOT_SETSCOPE, SCTP_ADDR_IS_CONFIRMED)) { /* assoc gone no un-lock */ - sctp_free_assoc(inp, stcb, 0); + sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_8); error = ENOBUFS; goto out_now; } @@ -3626,7 +3809,9 @@ sctp_optsset(struct socket *so, if (stcb->asoc.delayed_connection == 1) { stcb->asoc.delayed_connection = 0; SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered); - sctp_timer_stop(SCTP_TIMER_TYPE_INIT, inp, stcb, stcb->asoc.primary_destination); + 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); } else { /* @@ -3928,7 +4113,8 @@ sctp_optsset(struct socket *so, } if (paddrp->spp_flags & SPP_PMTUD_DISABLE) { if (callout_pending(&net->pmtu_timer.timer)) { - sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net); + sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net, + SCTP_FROM_SCTP_USRREQ + SCTP_LOC_10); } if (paddrp->spp_pathmtu > SCTP_DEFAULT_MINSEGMENT) { net->mtu = paddrp->spp_pathmtu; @@ -3983,7 +4169,7 @@ sctp_optsset(struct socket *so, * addresses */ if (cnt_of_unconf == 0) { - sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net); + sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_11); } } if (paddrp->spp_flags & SPP_HB_ENABLE) { |