summaryrefslogtreecommitdiffstats
path: root/sys/netinet/sctp_sysctl.c
diff options
context:
space:
mode:
authorrrs <rrs@FreeBSD.org>2007-05-28 11:17:24 +0000
committerrrs <rrs@FreeBSD.org>2007-05-28 11:17:24 +0000
commit953518c197f1cb83f3542e5632414645fa326689 (patch)
treed5292e14a920c4cac31f0eb379628b79f9c77442 /sys/netinet/sctp_sysctl.c
parentb4b7eeb094a1d9171e9bc849d768dd1b422dc540 (diff)
downloadFreeBSD-src-953518c197f1cb83f3542e5632414645fa326689.zip
FreeBSD-src-953518c197f1cb83f3542e5632414645fa326689.tar.gz
- fixed autclose to not allow setting on 1-2-1 model.
- bounded cookie-life to 1 second minimum in socket option set. - Delayed_ack_time becomes delayed_ack per new socket api document. - Improve port number selection, we now use low/high bounds and no chance of a endless loop. Only one call to random per bind as well. - fixes so set_peer_primary pre-screens addresses to be valid to this host. - maxseg did not allow setting on an assoc basis. We needed to thus track and use an association value instead of a inp value. - Fixed ep get of HB status to report back properly. - use settings flag to tell if assoc level hb is on off not the timer.. since the timer may still run if unconf address are present. - check for crazy ENABLE/DISABLE conditions. - set and get of pmtud (fixed path mtu) not always taking into account ovh. - Getting PMTU info on stcb only needs to return PMTUD_ENABLED if any net is doing PMTU discovery. - Panic or warning fixed to not do so when a valid ip frag is taking place. - sndrcvinfo appearing in both inp and stcb was full size, instead of the non-pad version. This saves about 92 bytes from each struct by carefully converting to use the smaller version. - one-2-one model get(maxseg) would always get ep value, never the tcb's value. - The delayed ack time could be under a tick, this fixes so it bounds it to at least 1 tick for platforms whos tick is more than a ms. - Fragment interleave level set to wrong default value. - Fragment interleave could not set level 0. - Defered stream reset was broken due to a guard check and ntohl issue. - Found two lock order reversals and fixed. - Tighten up address checking, if the user gives an address the sa_len had better be set properly. - Get asoc by assoc-id would return a locked tcb when it was asked not to if the tcb was in the restart hash. - sysctl to dig down and get more association details Reviewed by: gnn
Diffstat (limited to 'sys/netinet/sctp_sysctl.c')
-rw-r--r--sys/netinet/sctp_sysctl.c330
1 files changed, 246 insertions, 84 deletions
diff --git a/sys/netinet/sctp_sysctl.c b/sys/netinet/sctp_sysctl.c
index ce1ab45..fda9477 100644
--- a/sys/netinet/sctp_sysctl.c
+++ b/sys/netinet/sctp_sysctl.c
@@ -36,7 +36,7 @@ __FBSDID("$FreeBSD$");
#include <netinet/sctp_sysctl.h>
#include <netinet/sctp_pcb.h>
#include <netinet/sctputil.h>
-
+#include <netinet/sctp_output.h>
/*
* sysctl tunable variables
*/
@@ -112,6 +112,174 @@ uint32_t sctp_debug_on = 0;
#endif
+
+/* It returns an upper limit. No filtering is done here */
+static unsigned int
+number_of_addresses(struct sctp_inpcb *inp)
+{
+ int cnt;
+ struct sctp_vrf *vrf;
+ struct sctp_ifn *sctp_ifn;
+ struct sctp_ifa *sctp_ifa;
+ struct sctp_laddr *laddr;
+
+ cnt = 0;
+ /* neither Mac OS X nor FreeBSD support mulitple routing functions */
+ if ((vrf = sctp_find_vrf(inp->def_vrf_id)) == NULL) {
+ return (0);
+ }
+ if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) {
+ LIST_FOREACH(sctp_ifn, &vrf->ifnlist, next_ifn) {
+ LIST_FOREACH(sctp_ifa, &sctp_ifn->ifalist, next_ifa) {
+ if ((sctp_ifa->address.sa.sa_family == AF_INET) ||
+ (sctp_ifa->address.sa.sa_family == AF_INET6)) {
+ cnt++;
+ }
+ }
+ }
+ } else {
+ LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) {
+ if ((laddr->ifa->address.sa.sa_family == AF_INET) ||
+ (laddr->ifa->address.sa.sa_family == AF_INET6)) {
+ cnt++;
+ }
+ }
+ }
+ return (cnt);
+}
+
+static int
+copy_out_local_addresses(struct sctp_inpcb *inp, struct sctp_tcb *stcb, struct sysctl_req *req)
+{
+ struct sctp_ifn *sctp_ifn;
+ struct sctp_ifa *sctp_ifa;
+ int loopback_scope, ipv4_local_scope, local_scope, site_scope;
+ int ipv4_addr_legal, ipv6_addr_legal;
+ struct sctp_vrf *vrf;
+ struct xsctp_laddr xladdr;
+ struct sctp_laddr *laddr;
+ int error;
+
+ /* Turn on all the appropriate scope */
+ if (stcb) {
+ /* use association specific values */
+ loopback_scope = stcb->asoc.loopback_scope;
+ ipv4_local_scope = stcb->asoc.ipv4_local_scope;
+ local_scope = stcb->asoc.local_scope;
+ site_scope = stcb->asoc.site_scope;
+ } else {
+ /* use generic values for endpoints */
+ loopback_scope = 1;
+ ipv4_local_scope = 1;
+ local_scope = 1;
+ site_scope = 1;
+ }
+
+ /* use only address families of interest */
+ if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
+ ipv6_addr_legal = 1;
+ if (SCTP_IPV6_V6ONLY(inp)) {
+ ipv4_addr_legal = 0;
+ } else {
+ ipv4_addr_legal = 1;
+ }
+ } else {
+ ipv4_addr_legal = 1;
+ ipv6_addr_legal = 0;
+ }
+
+ error = 0;
+
+ /* neither Mac OS X nor FreeBSD support mulitple routing functions */
+ if ((vrf = sctp_find_vrf(inp->def_vrf_id)) == NULL) {
+ return (-1);
+ }
+ if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) {
+ LIST_FOREACH(sctp_ifn, &vrf->ifnlist, next_ifn) {
+ if ((loopback_scope == 0) && SCTP_IFN_IS_IFT_LOOP(sctp_ifn))
+ /* Skip loopback if loopback_scope not set */
+ continue;
+ LIST_FOREACH(sctp_ifa, &sctp_ifn->ifalist, next_ifa) {
+ if (stcb) {
+ /*
+ * ignore if blacklisted at
+ * association level
+ */
+ if (sctp_is_addr_restricted(stcb, sctp_ifa))
+ continue;
+ }
+ if ((sctp_ifa->address.sa.sa_family == AF_INET) && (ipv4_addr_legal)) {
+ struct sockaddr_in *sin;
+
+ sin = (struct sockaddr_in *)&sctp_ifa->address.sa;
+ if (sin->sin_addr.s_addr == 0)
+ continue;
+ if ((ipv4_local_scope == 0) && (IN4_ISPRIVATE_ADDRESS(&sin->sin_addr)))
+ continue;
+ } else if ((sctp_ifa->address.sa.sa_family == AF_INET6) && (ipv6_addr_legal)) {
+ struct sockaddr_in6 *sin6;
+
+ sin6 = (struct sockaddr_in6 *)&sctp_ifa->address.sa;
+ if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr))
+ continue;
+ if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
+ if (local_scope == 0)
+ continue;
+ if (sin6->sin6_scope_id == 0) {
+ /*
+ * bad link local
+ * address
+ */
+ if (sa6_recoverscope(sin6) != 0)
+ continue;
+ }
+ }
+ if ((site_scope == 0) && (IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr)))
+ continue;
+ } else
+ continue;
+ memset((void *)&xladdr, 0, sizeof(union sctp_sockstore));
+ memcpy((void *)&xladdr.address, (const void *)&sctp_ifa->address, sizeof(union sctp_sockstore));
+ (void)SCTP_GETTIME_TIMEVAL(&xladdr.start_time);
+ SCTP_INP_RUNLOCK(inp);
+ SCTP_INP_INFO_RUNLOCK();
+ error = SYSCTL_OUT(req, &xladdr, sizeof(struct xsctp_laddr));
+ if (error)
+ return (error);
+ else {
+ SCTP_INP_INFO_RLOCK();
+ SCTP_INP_RLOCK(inp);
+ }
+ }
+ }
+ } else {
+ LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) {
+ /* ignore if blacklisted at association level */
+ if (stcb && sctp_is_addr_restricted(stcb, laddr->ifa))
+ continue;
+ memset((void *)&xladdr, 0, sizeof(union sctp_sockstore));
+ memcpy((void *)&xladdr.address, (const void *)&laddr->ifa->address, sizeof(union sctp_sockstore));
+ xladdr.start_time = laddr->start_time;
+ SCTP_INP_RUNLOCK(inp);
+ SCTP_INP_INFO_RUNLOCK();
+ error = SYSCTL_OUT(req, &xladdr, sizeof(struct xsctp_laddr));
+ if (error)
+ return (error);
+ else {
+ SCTP_INP_INFO_RLOCK();
+ SCTP_INP_RLOCK(inp);
+ }
+ }
+ }
+ memset((void *)&xladdr, 0, sizeof(union sctp_sockstore));
+ xladdr.last = 1;
+ error = SYSCTL_OUT(req, &xladdr, sizeof(struct xsctp_laddr));
+ if (error)
+ return (error);
+ else
+ return (0);
+}
+
/*
* sysctl functions
*/
@@ -127,11 +295,8 @@ sctp_assoclist(SYSCTL_HANDLER_ARGS)
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;
@@ -144,12 +309,10 @@ sctp_assoclist(SYSCTL_HANDLER_ARGS)
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++;
- }
+ number_of_local_addresses += number_of_addresses(inp);
LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
number_of_associations++;
+ number_of_local_addresses += number_of_addresses(inp);
TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
number_of_remote_addresses++;
}
@@ -158,14 +321,10 @@ sctp_assoclist(SYSCTL_HANDLER_ARGS)
}
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
+ (number_of_local_addresses + number_of_endpoints + number_of_associations) * sizeof(struct xsctp_laddr) +
+ (number_of_associations + number_of_endpoints) * sizeof(struct xsctp_tcb) +
+ (number_of_remote_addresses + number_of_associations) * sizeof(struct xsctp_raddr);
+
/* request some more memory than needed */
req->oldidx = (n + n / 8);
return 0;
@@ -176,78 +335,53 @@ sctp_assoclist(SYSCTL_HANDLER_ARGS)
}
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;
xinpcb.fragmentation_point = inp->sctp_frag_point;
- if (inp->sctp_socket != NULL) {
- sotoxsocket(inp->sctp_socket, &xinpcb.xsocket);
- } else {
- bzero(&xinpcb.xsocket, sizeof xinpcb.xsocket);
- xinpcb.xsocket.xso_protocol = IPPROTO_SCTP;
- }
+ xinpcb.qlen = inp->sctp_socket->so_qlen;
+ xinpcb.maxqlen = inp->sctp_socket->so_qlimit;
SCTP_INP_INCR_REF(inp);
SCTP_INP_RUNLOCK(inp);
SCTP_INP_INFO_RUNLOCK();
error = SYSCTL_OUT(req, &xinpcb, sizeof(struct xsctp_inpcb));
if (error) {
+ SCTP_INP_DECR_REF(inp);
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_PER_SOCKET_LOCKING)
- * SCTP_SOCKET_UNLOCK(SCTP_INP_SO(inp), 1);
- * SCTP_UNLOCK_SHARED(sctppcbinfo.ipi_ep_mtx); #endif
- * SCTP_INP_RUNLOCK(inp); SCTP_INP_INFO_RUNLOCK(); return
- * error; } }
- */
+ error = copy_out_local_addresses(inp, NULL, req);
+ if (error) {
+ SCTP_INP_DECR_REF(inp);
+ 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;
- TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
- number_of_remote_addresses++;
- }
- xstcb.LocalPort = ntohs(inp->sctp_lport);
- xstcb.RemPort = ntohs(stcb->rport);
+ xstcb.last = 0;
+ xstcb.local_port = ntohs(inp->sctp_lport);
+ xstcb.remote_port = ntohs(stcb->rport);
if (stcb->asoc.primary_destination != NULL)
- xstcb.RemPrimAddr = stcb->asoc.primary_destination->ro._l_addr;
- xstcb.HeartBeatInterval = stcb->asoc.heart_beat_delay;
- xstcb.State = SCTP_GET_STATE(&stcb->asoc); /* FIXME */
- xstcb.InStreams = stcb->asoc.streamincnt;
- xstcb.OutStreams = stcb->asoc.streamoutcnt;
- xstcb.MaxRetr = stcb->asoc.overall_error_count;
- xstcb.PrimProcess = 0; /* not really supported yet */
- xstcb.T1expireds = stcb->asoc.timoinit + stcb->asoc.timocookie;
- xstcb.T2expireds = stcb->asoc.timoshutdown + stcb->asoc.timoshutdownack;
- xstcb.RtxChunks = stcb->asoc.marked_retrans;
- xstcb.StartTime = stcb->asoc.start_time;
- xstcb.DiscontinuityTime = stcb->asoc.discontinuity_time;
-
- xstcb.number_local_addresses = number_of_local_addresses;
- xstcb.number_remote_addresses = number_of_remote_addresses;
+ xstcb.primary_addr = stcb->asoc.primary_destination->ro._l_addr;
+ xstcb.heartbeat_interval = stcb->asoc.heart_beat_delay;
+ xstcb.state = SCTP_GET_STATE(&stcb->asoc); /* FIXME */
+ xstcb.in_streams = stcb->asoc.streamincnt;
+ xstcb.out_streams = stcb->asoc.streamoutcnt;
+ xstcb.max_nr_retrans = stcb->asoc.overall_error_count;
+ xstcb.primary_process = 0; /* not really supported
+ * yet */
+ xstcb.T1_expireries = stcb->asoc.timoinit + stcb->asoc.timocookie;
+ xstcb.T2_expireries = stcb->asoc.timoshutdown + stcb->asoc.timoshutdownack;
+ xstcb.retransmitted_tsns = stcb->asoc.marked_retrans;
+ xstcb.start_time = stcb->asoc.start_time;
+ xstcb.discontinuity_time = stcb->asoc.discontinuity_time;
+
xstcb.total_sends = stcb->total_sends;
xstcb.total_recvs = stcb->total_recvs;
xstcb.local_tag = stcb->asoc.my_vtag;
@@ -261,43 +395,71 @@ sctp_assoclist(SYSCTL_HANDLER_ARGS)
SCTP_INP_INFO_RUNLOCK();
error = SYSCTL_OUT(req, &xstcb, sizeof(struct xsctp_tcb));
if (error) {
+ SCTP_INP_DECR_REF(inp);
+ atomic_add_int(&stcb->asoc.refcnt, -1);
+ return error;
+ }
+ SCTP_INP_INFO_RLOCK();
+ SCTP_INP_RLOCK(inp);
+ error = copy_out_local_addresses(inp, stcb, req);
+ if (error) {
+ SCTP_INP_DECR_REF(inp);
atomic_add_int(&stcb->asoc.refcnt, -1);
return error;
}
TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
- xraddr.RemAddr = net->ro._l_addr;
- xraddr.RemAddrActive = ((net->dest_state & SCTP_ADDR_REACHABLE) == SCTP_ADDR_REACHABLE);
- xraddr.RemAddrConfirmed = ((net->dest_state & SCTP_ADDR_UNCONFIRMED) == 0);
- xraddr.RemAddrHBActive = ((net->dest_state & SCTP_ADDR_NOHB) == 0);
- xraddr.RemAddrRTO = net->RTO;
- xraddr.RemAddrMaxPathRtx = net->failure_threshold;
- xraddr.RemAddrRtx = net->marked_retrans;
- xraddr.RemAddrErrorCounter = net->error_count;
- xraddr.RemAddrCwnd = net->cwnd;
- xraddr.RemAddrFlightSize = net->flight_size;
- xraddr.RemAddrStartTime = net->start_time;
- xraddr.RemAddrMTU = net->mtu;
+ xraddr.last = 0;
+ xraddr.address = net->ro._l_addr;
+ xraddr.active = ((net->dest_state & SCTP_ADDR_REACHABLE) == SCTP_ADDR_REACHABLE);
+ xraddr.confirmed = ((net->dest_state & SCTP_ADDR_UNCONFIRMED) == 0);
+ xraddr.heartbeat_enabled = ((net->dest_state & SCTP_ADDR_NOHB) == 0);
+ xraddr.rto = net->RTO;
+ xraddr.max_path_rtx = net->failure_threshold;
+ xraddr.rtx = net->marked_retrans;
+ xraddr.error_counter = net->error_count;
+ xraddr.cwnd = net->cwnd;
+ xraddr.flight_size = net->flight_size;
+ xraddr.mtu = net->mtu;
+ xraddr.start_time = net->start_time;
+ SCTP_INP_RUNLOCK(inp);
+ SCTP_INP_INFO_RUNLOCK();
error = SYSCTL_OUT(req, &xraddr, sizeof(struct xsctp_raddr));
if (error) {
+ SCTP_INP_DECR_REF(inp);
atomic_add_int(&stcb->asoc.refcnt, -1);
return error;
}
+ SCTP_INP_INFO_RLOCK();
+ SCTP_INP_RLOCK(inp);
}
atomic_add_int(&stcb->asoc.refcnt, -1);
+ memset((void *)&xraddr, 0, sizeof(struct xsctp_raddr));
+ xraddr.last = 1;
+ SCTP_INP_RUNLOCK(inp);
+ SCTP_INP_INFO_RUNLOCK();
+ error = SYSCTL_OUT(req, &xraddr, sizeof(struct xsctp_raddr));
+ if (error) {
+ SCTP_INP_DECR_REF(inp);
+ return error;
+ }
SCTP_INP_INFO_RLOCK();
SCTP_INP_RLOCK(inp);
}
- SCTP_INP_DECR_REF(inp);
SCTP_INP_RUNLOCK(inp);
+ SCTP_INP_INFO_RUNLOCK();
+ memset((void *)&xstcb, 0, sizeof(struct xsctp_tcb));
+ xstcb.last = 1;
+ error = SYSCTL_OUT(req, &xstcb, sizeof(struct xsctp_tcb));
+ if (error) {
+ return error;
+ }
+ SCTP_INP_INFO_RLOCK();
+ SCTP_INP_DECR_REF(inp);
}
SCTP_INP_INFO_RUNLOCK();
+ memset((void *)&xinpcb, 0, sizeof(struct xsctp_inpcb));
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;
}
OpenPOWER on IntegriCloud