summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authorrrs <rrs@FreeBSD.org>2007-09-08 17:48:46 +0000
committerrrs <rrs@FreeBSD.org>2007-09-08 17:48:46 +0000
commite1de0a1edadaa9d67f677c0aa3a582c9bcc34b9c (patch)
treec5cd7d7c9d05970381c8f80e243b1da248135d4c /sys
parent4dd82bd675126ae3087b47d4425b57c8c44aa790 (diff)
downloadFreeBSD-src-e1de0a1edadaa9d67f677c0aa3a582c9bcc34b9c.zip
FreeBSD-src-e1de0a1edadaa9d67f677c0aa3a582c9bcc34b9c.tar.gz
- send call has a reference to uio->uio_resid in
the recent send code, but uio may be NULL on sendfile calls. Change to use sndlen variable. - EMSGSIZE is not being returned in non-blocking mode and needs a small tweak to look if the msg would ever fit when returning EWOULDBLOCK. - FWD-TSN has a bug in stream processing which could cause a panic. This is a follow on to the codenomicon fix. - PDAPI level 1 and 2 do not work unless the reader gets his returned buffer full. Fix so we can break out when at level 1 or 2. - Fix fast-handoff features to copy across properly on accepted sockets - Fix sctp_peeloff() system call when no true system call exists to screen arguments for errors. In cases where a real system call exists the system call itself does this. - Fix raddr leak in recent add-ip code change for bundled asconfs (even when non-bundled asconfs are received) - Make sure ipi_addr lock is held when walking global addr list. Need to change this lock type to a rwlock(). - Add don't wake flag on both input and output when the socket is closing. - When deleting an address verify the interface is correct before allowing the delete to process. This protects panda and unnumbered. - Clean up old sysctl stuff and get rid of the old Open/Net BSD structures. - Add a function to watch the ranges in the sysctl sets. - When appending in the reassembly queue, validate that the assoc has not gone to about to be freed. If so (in the middle) abort out. Note this especially effects MAC I think due to the lock/unlock they do (or with LOCK testing in place). - Netstat patch to get rid of warnings. - Make sure that no data gets queued to inactive/unconfirmed destinations. This especially effect CMT but also makes a impact on regular SCTP as well. - During init collision when we detect seq number out of sync we need to treat it like Case C and discard the cookie (no invarient needed here). - Atomic access to the random store. - When we declare a vtag good, we need to shove it into the time wait hash to prevent further use. When the tag is put into the assoc hash, we need to remove it from the twait hash (where it will surely be). This prevents duplicate tag assignments. - Move decr-ref count to better protect sysctl out of data. - ltrace error corrections in sctp6_usrreq.c - Add hook for interface up/down to be sent to us. - Make sysctl() exported structures independent of processor architecture. - Fix route and src addr cache clearing for delete address case. - Make sure address marked SCTP_DEL_IP_ADDRESS is never selected as src addr. - in icmp handling fixed so we actually look at the icmp codes to figure out what to do. - Modified mobility code. Reception of DELETE IP ADDRESS for a primary destination and SET PRIMARY for a new primary destination is used for retransmission trigger to the new primary destination. Also, in this case, destination of chunks in send_queue are changed to the new primary destination. - Fix so that we disallow sending by mbuf to ever have EEOR mode set upon it. Approved by: re@freebsd.org (B Mah)
Diffstat (limited to 'sys')
-rw-r--r--sys/netinet/sctp.h2
-rw-r--r--sys/netinet/sctp_asconf.c178
-rw-r--r--sys/netinet/sctp_asconf.h7
-rw-r--r--sys/netinet/sctp_bsd_addr.c6
-rw-r--r--sys/netinet/sctp_constants.h21
-rw-r--r--sys/netinet/sctp_indata.c36
-rw-r--r--sys/netinet/sctp_input.c52
-rw-r--r--sys/netinet/sctp_output.c106
-rw-r--r--sys/netinet/sctp_pcb.c257
-rw-r--r--sys/netinet/sctp_pcb.h21
-rw-r--r--sys/netinet/sctp_structs.h3
-rw-r--r--sys/netinet/sctp_sysctl.c602
-rw-r--r--sys/netinet/sctp_sysctl.h215
-rw-r--r--sys/netinet/sctp_timer.c18
-rw-r--r--sys/netinet/sctp_timer.h4
-rw-r--r--sys/netinet/sctp_uio.h19
-rw-r--r--sys/netinet/sctp_usrreq.c184
-rw-r--r--sys/netinet/sctp_var.h2
-rw-r--r--sys/netinet/sctputil.c61
-rw-r--r--sys/netinet6/sctp6_usrreq.c129
20 files changed, 1268 insertions, 655 deletions
diff --git a/sys/netinet/sctp.h b/sys/netinet/sctp.h
index 94d407f..a97b07d 100644
--- a/sys/netinet/sctp.h
+++ b/sys/netinet/sctp.h
@@ -479,7 +479,7 @@ __attribute__((packed));
*/
#define SCTP_MOBILITY_BASE 0x00000001
#define SCTP_MOBILITY_FASTHANDOFF 0x00000002
-#define SCTP_MOBILITY_DO_FASTHANDOFF 0x00000004
+#define SCTP_MOBILITY_PRIM_DELETED 0x00000004
#define SCTP_SMALLEST_PMTU 512 /* smallest pmtu allowed when disabling PMTU
diff --git a/sys/netinet/sctp_asconf.c b/sys/netinet/sctp_asconf.c
index fb51dd4..e75f5de 100644
--- a/sys/netinet/sctp_asconf.c
+++ b/sys/netinet/sctp_asconf.c
@@ -40,6 +40,7 @@ __FBSDID("$FreeBSD$");
#include <netinet/sctputil.h>
#include <netinet/sctp_output.h>
#include <netinet/sctp_asconf.h>
+#include <netinet/sctp_timer.h>
/*
* debug flags:
@@ -550,6 +551,42 @@ sctp_process_asconf_set_primary(struct mbuf *m,
if (response_required) {
m_reply = sctp_asconf_success_response(aph->correlation_id);
}
+ /*
+ * Mobility adaptation. Ideally, when the reception of SET
+ * PRIMARY with DELETE IP ADDRESS of the previous primary
+ * destination, unacknowledged DATA are retransmitted
+ * immediately to the new primary destination for seamless
+ * handover. If the destination is UNCONFIRMED and marked
+ * to REQ_PRIM, The retransmission occur when reception of
+ * the HEARTBEAT-ACK. (See sctp_handle_heartbeat_ack in
+ * sctp_input.c) Also, when change of the primary
+ * destination, it is better that all subsequent new DATA
+ * containing already queued DATA are transmitted to the new
+ * primary destination. (by micchie)
+ */
+ if ((sctp_is_mobility_feature_on(stcb->sctp_ep,
+ SCTP_MOBILITY_BASE) ||
+ sctp_is_mobility_feature_on(stcb->sctp_ep,
+ SCTP_MOBILITY_FASTHANDOFF)) &&
+ sctp_is_mobility_feature_on(stcb->sctp_ep,
+ SCTP_MOBILITY_PRIM_DELETED) &&
+ (stcb->asoc.primary_destination->dest_state &
+ SCTP_ADDR_UNCONFIRMED) == 0) {
+
+ sctp_timer_stop(SCTP_TIMER_TYPE_PRIM_DELETED, stcb->sctp_ep, stcb, NULL, SCTP_FROM_SCTP_TIMER + SCTP_LOC_7);
+ if (sctp_is_mobility_feature_on(stcb->sctp_ep,
+ SCTP_MOBILITY_FASTHANDOFF)) {
+ sctp_assoc_immediate_retrans(stcb,
+ stcb->asoc.primary_destination);
+ }
+ if (sctp_is_mobility_feature_on(stcb->sctp_ep,
+ SCTP_MOBILITY_BASE)) {
+ sctp_move_chunks_from_deleted_prim(stcb,
+ stcb->asoc.primary_destination);
+ }
+ sctp_delete_prim_timer(stcb->sctp_ep, stcb,
+ stcb->asoc.deleted_primary);
+ }
} else {
/* couldn't set the requested primary address! */
SCTPDBG(SCTP_DEBUG_ASCONF1,
@@ -940,26 +977,138 @@ sctp_asconf_nets_cleanup(struct sctp_tcb *stcb, struct sctp_ifn *ifn)
}
}
+void
+sctp_move_chunks_from_deleted_prim(struct sctp_tcb *stcb, struct sctp_nets *dst)
+{
+ struct sctp_association *asoc;
+ struct sctp_stream_out *outs;
+ struct sctp_tmit_chunk *chk;
+ struct sctp_stream_queue_pending *sp;
+
+ if (dst->dest_state & SCTP_ADDR_UNCONFIRMED) {
+ SCTPDBG(SCTP_DEBUG_ASCONF1, "move_chunks_from_deleted_prim: specified destination is UNCONFIRMED\n");
+ return;
+ }
+ if (stcb->asoc.deleted_primary == NULL) {
+ SCTPDBG(SCTP_DEBUG_ASCONF1, "move_chunks_from_deleted_prim: Funny, old primary is not stored\n");
+ return;
+ }
+ asoc = &stcb->asoc;
+
+ /*
+ * now through all the streams checking for chunks sent to our bad
+ * network.
+ */
+ TAILQ_FOREACH(outs, &asoc->out_wheel, next_spoke) {
+ /* now clean up any chunks here */
+ TAILQ_FOREACH(sp, &outs->outqueue, next) {
+ if (sp->net == asoc->deleted_primary) {
+ sctp_free_remote_addr(sp->net);
+ sp->net = dst;
+ atomic_add_int(&dst->ref_count, 1);
+ }
+ }
+ }
+ /* Now check the pending queue */
+ TAILQ_FOREACH(chk, &asoc->send_queue, sctp_next) {
+ if (chk->whoTo == asoc->deleted_primary) {
+ sctp_free_remote_addr(chk->whoTo);
+ chk->whoTo = dst;
+ atomic_add_int(&dst->ref_count, 1);
+ }
+ }
+
+}
+
+extern int cur_oerr;
+
+void
+sctp_assoc_immediate_retrans(struct sctp_tcb *stcb, struct sctp_nets *dstnet)
+{
+ int error;
+ struct sctp_tmit_chunk *chk;
+
+ //for debug
+ if (dstnet->dest_state & SCTP_ADDR_UNCONFIRMED) {
+ SCTPDBG(SCTP_DEBUG_ASCONF1, "assoc_immediate_retrans: specified destination is UNCONFIRMED\n");
+ return;
+ }
+ if (stcb->asoc.deleted_primary == NULL) {
+ SCTPDBG(SCTP_DEBUG_ASCONF1, "assoc_immediate_retrans: Funny, old primary is not stored\n");
+ return;
+ }
+ if (!TAILQ_EMPTY(&stcb->asoc.sent_queue)) {
+ SCTPDBG(SCTP_DEBUG_ASCONF1, "Deleted primary is ");
+ SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, &stcb->asoc.deleted_primary->ro._l_addr.sa);
+ SCTPDBG(SCTP_DEBUG_ASCONF1, "Current Primary is ");
+ SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, &stcb->asoc.primary_destination->ro._l_addr.sa);
+ SCTPDBG(SCTP_DEBUG_ASCONF1, "Stopping send timer and calling t3rxt_timer\n");
+ sctp_timer_stop(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, stcb,
+ stcb->asoc.deleted_primary,
+ SCTP_FROM_SCTP_TIMER + SCTP_LOC_8);
+ stcb->asoc.num_send_timers_up--;
+ if (stcb->asoc.num_send_timers_up < 0) {
+ stcb->asoc.num_send_timers_up = 0;
+ }
+ SCTP_TCB_LOCK_ASSERT(stcb);
+ cur_oerr = stcb->asoc.overall_error_count;
+ error = sctp_t3rxt_timer(stcb->sctp_ep, stcb,
+ stcb->asoc.deleted_primary);
+ if (error) {
+ SCTPDBG(SCTP_DEBUG_ASCONF1, "t3rxt_timer error\n");
+ SCTP_INP_DECR_REF(stcb->sctp_ep);
+ return;
+ }
+ SCTP_TCB_LOCK_ASSERT(stcb);
+#ifdef SCTP_AUDITING_ENABLED
+ sctp_auditing(4, stcb->sctp_ep, stcb->asoc.deleted_primary);
+#endif
+ /* Debug code */
+ SCTPDBG(SCTP_DEBUG_ASCONF1, "assoc_immediate_retrans: calling chunk_output, retran_cnt is %d\n", stcb->asoc.sent_queue_retran_cnt);
+ TAILQ_FOREACH(chk, &stcb->asoc.sent_queue, sctp_next) {
+ SCTPDBG(SCTP_DEBUG_ASCONF1, "assoc_immediate_retrans: chk->whoTo is ");
+ SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, &chk->whoTo->ro._l_addr.sa);
+ SCTPDBG(SCTP_DEBUG_ASCONF1, "state is %d\n", chk->sent);
+ }
+ /* end Debug code */
+ sctp_chunk_output(stcb->sctp_ep, stcb, SCTP_OUTPUT_FROM_T3, SCTP_SO_NOT_LOCKED);
+ if ((stcb->asoc.num_send_timers_up == 0) &&
+ (stcb->asoc.sent_queue_cnt > 0)) {
+ struct sctp_tmit_chunk *chk;
+
+ chk = TAILQ_FIRST(&stcb->asoc.sent_queue);
+ sctp_timer_start(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep,
+ stcb, chk->whoTo);
+ }
+ }
+ return;
+}
+
static int
sctp_asconf_queue_mgmt(struct sctp_tcb *, struct sctp_ifa *, uint16_t);
-static void
+void
sctp_net_immediate_retrans(struct sctp_tcb *stcb, struct sctp_nets *net)
{
struct sctp_tmit_chunk *chk;
+ int cnt = 0; /* debug */
- SCTPDBG(SCTP_DEBUG_ASCONF2, "net_immediate_retrans()\n");
- SCTPDBG(SCTP_DEBUG_ASCONF2, "RTO is %d\n", net->RTO);
+ SCTPDBG(SCTP_DEBUG_ASCONF1, "net_immediate_retrans:\n");
+ SCTPDBG(SCTP_DEBUG_ASCONF1, "RTO is %d\n", net->RTO);
sctp_timer_stop(SCTP_TIMER_TYPE_SEND, stcb->sctp_ep, stcb, net,
SCTP_FROM_SCTP_TIMER + SCTP_LOC_5);
stcb->asoc.cc_functions.sctp_set_initial_cc_param(stcb, net);
net->error_count = 0;
TAILQ_FOREACH(chk, &stcb->asoc.sent_queue, sctp_next) {
if (chk->whoTo == net) {
- chk->sent = SCTP_DATAGRAM_RESEND;
- sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt);
+ if (chk->sent < SCTP_DATAGRAM_RESEND) {
+ chk->sent = SCTP_DATAGRAM_RESEND;
+ sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt);
+ cnt++;
+ }
}
}
+ SCTPDBG(SCTP_DEBUG_ASCONF1, "%d chunks are marked to RESEND, retran_cnt is %d\n", cnt, stcb->asoc.sent_queue_retran_cnt);
}
static void
@@ -1365,7 +1514,7 @@ sctp_asconf_queue_add_sa(struct sctp_tcb *stcb, struct sockaddr *sa,
vrf_id = SCTP_DEFAULT_VRFID;
}
- ifa = sctp_find_ifa_by_addr(sa, vrf_id, 0);
+ ifa = sctp_find_ifa_by_addr(sa, vrf_id, SCTP_ADDR_NOT_LOCKED);
if (ifa == NULL) {
/* Invalid address */
return (-1);
@@ -2061,8 +2210,7 @@ sctp_asconf_iterator_stcb(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
sctp_rtentry_t *rt;
/* delete this address if cached */
- if (net->ro._s_addr &&
- (net->ro._s_addr->ifa == ifa)) {
+ if (net->ro._s_addr == ifa) {
sctp_free_ifa(net->ro._s_addr);
net->ro._s_addr = NULL;
net->src_addr_selected = 0;
@@ -2223,8 +2371,10 @@ sctp_find_valid_localaddr(struct sctp_tcb *stcb)
struct sctp_ifn *sctp_ifn;
struct sctp_ifa *sctp_ifa;
+ SCTP_IPI_ADDR_LOCK();
vrf = sctp_find_vrf(stcb->asoc.vrf_id);
if (vrf == NULL) {
+ SCTP_IPI_ADDR_UNLOCK();
return (NULL);
}
LIST_FOREACH(sctp_ifn, &vrf->ifnlist, next_ifn) {
@@ -2250,6 +2400,7 @@ sctp_find_valid_localaddr(struct sctp_tcb *stcb)
if (sctp_is_addr_restricted(stcb, sctp_ifa))
continue;
/* found a valid local v4 address to use */
+ SCTP_IPI_ADDR_UNLOCK();
return (&sctp_ifa->address.sa);
} else if (sctp_ifa->address.sa.sa_family == AF_INET6 &&
stcb->asoc.ipv6_addr_legal) {
@@ -2271,11 +2422,13 @@ sctp_find_valid_localaddr(struct sctp_tcb *stcb)
continue;
/* found a valid local v6 address to use */
+ SCTP_IPI_ADDR_UNLOCK();
return (&sctp_ifa->address.sa);
}
}
}
/* no valid addresses found */
+ SCTP_IPI_ADDR_UNLOCK();
return (NULL);
}
@@ -2566,7 +2719,7 @@ sctp_process_initack_addresses(struct sctp_tcb *stcb, struct mbuf *m,
vrf_id = SCTP_DEFAULT_VRFID;
}
- sctp_ifa = sctp_find_ifa_by_addr(sa, vrf_id, 0);
+ sctp_ifa = sctp_find_ifa_by_addr(sa, vrf_id, SCTP_ADDR_NOT_LOCKED);
if (sctp_ifa == NULL) {
/* address doesn't exist anymore */
int status;
@@ -2773,8 +2926,10 @@ sctp_check_address_list_all(struct sctp_tcb *stcb, struct mbuf *m, int offset,
} else {
return;
}
+ SCTP_IPI_ADDR_LOCK();
vrf = sctp_find_vrf(vrf_id);
if (vrf == NULL) {
+ SCTP_IPI_ADDR_UNLOCK();
return;
}
/* go through all our known interfaces */
@@ -2798,6 +2953,7 @@ sctp_check_address_list_all(struct sctp_tcb *stcb, struct mbuf *m, int offset,
}
} /* end foreach ifa */
} /* end foreach ifn */
+ SCTP_IPI_ADDR_UNLOCK();
}
/*
@@ -2850,10 +3006,10 @@ sctp_addr_mgmt_ep_sa(struct sctp_inpcb *inp, struct sockaddr *sa,
ifa = sctp_ifap;
} else if (type == SCTP_ADD_IP_ADDRESS) {
/* For an add the address MUST be on the system */
- ifa = sctp_find_ifa_by_addr(sa, vrf_id, 0);
+ ifa = sctp_find_ifa_by_addr(sa, vrf_id, SCTP_ADDR_NOT_LOCKED);
} else if (type == SCTP_DEL_IP_ADDRESS) {
/* For a delete we need to find it in the inp */
- ifa = sctp_find_ifa_in_ep(inp, sa, 0);
+ ifa = sctp_find_ifa_in_ep(inp, sa, SCTP_ADDR_NOT_LOCKED);
} else {
ifa = NULL;
}
diff --git a/sys/netinet/sctp_asconf.h b/sys/netinet/sctp_asconf.h
index 017f303..86006da 100644
--- a/sys/netinet/sctp_asconf.h
+++ b/sys/netinet/sctp_asconf.h
@@ -79,6 +79,13 @@ extern void
sctp_check_address_list(struct sctp_tcb *, struct mbuf *, int, int,
struct sockaddr *, uint16_t, uint16_t, uint16_t, uint16_t);
+extern void
+ sctp_move_chunks_from_deleted_prim(struct sctp_tcb *, struct sctp_nets *);
+extern void
+ sctp_assoc_immediate_retrans(struct sctp_tcb *, struct sctp_nets *);
+extern void
+ sctp_net_immediate_retrans(struct sctp_tcb *, struct sctp_nets *);
+
#endif /* _KERNEL */
#endif /* !_NETINET_SCTP_ASCONF_H_ */
diff --git a/sys/netinet/sctp_bsd_addr.c b/sys/netinet/sctp_bsd_addr.c
index 8b5aaf9..e0aa304 100644
--- a/sys/netinet/sctp_bsd_addr.c
+++ b/sys/netinet/sctp_bsd_addr.c
@@ -167,6 +167,7 @@ sctp_is_desired_interface_type(struct ifaddr *ifa)
case IFT_ISDNBASIC:
case IFT_ISDNPRIMARY:
case IFT_PTPSERIAL:
+ case IFT_OTHER:
case IFT_PPP:
case IFT_LOOP:
case IFT_SLIP:
@@ -323,7 +324,10 @@ sctp_addr_change(struct ifaddr *ifa, int cmd)
(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);
+ sctp_del_addr_from_vrf(SCTP_DEFAULT_VRFID, ifa->ifa_addr,
+ ifa->ifa_ifp->if_index,
+ ifa->ifa_ifp->if_xname
+ );
/*
* We don't bump refcount here so when it completes the
* final delete will happen.
diff --git a/sys/netinet/sctp_constants.h b/sys/netinet/sctp_constants.h
index 5d65b78..c059a4d 100644
--- a/sys/netinet/sctp_constants.h
+++ b/sys/netinet/sctp_constants.h
@@ -471,11 +471,12 @@ __FBSDID("$FreeBSD$");
#define SCTP_NOTIFY_DATAGRAM_SENT 0x0002
#define SCTP_FAILED_THRESHOLD 0x0004
#define SCTP_HEARTBEAT_SUCCESS 0x0008
-#define SCTP_RESPONSE_TO_USER_REQ 0x000f
-#define SCTP_INTERNAL_ERROR 0x0010
-#define SCTP_SHUTDOWN_GUARD_EXPIRES 0x0020
-#define SCTP_RECEIVED_SACK 0x0040
-#define SCTP_PEER_FAULTY 0x0080
+#define SCTP_RESPONSE_TO_USER_REQ 0x0010
+#define SCTP_INTERNAL_ERROR 0x0020
+#define SCTP_SHUTDOWN_GUARD_EXPIRES 0x0040
+#define SCTP_RECEIVED_SACK 0x0080
+#define SCTP_PEER_FAULTY 0x0100
+#define SCTP_ICMP_REFUSED 0x0200
/* bits for TOS field */
#define SCTP_ECT0_BIT 0x02
@@ -591,8 +592,9 @@ __FBSDID("$FreeBSD$");
#define SCTP_TIMER_TYPE_ADDR_WQ 19
#define SCTP_TIMER_TYPE_ZERO_COPY 20
#define SCTP_TIMER_TYPE_ZCOPY_SENDQ 21
+#define SCTP_TIMER_TYPE_PRIM_DELETED 22
/* add new timers here - and increment LAST */
-#define SCTP_TIMER_TYPE_LAST 22
+#define SCTP_TIMER_TYPE_LAST 23
#define SCTP_IS_TIMER_TYPE_VALID(t) (((t) > SCTP_TIMER_TYPE_NONE) && \
((t) < SCTP_TIMER_TYPE_LAST))
@@ -652,6 +654,7 @@ __FBSDID("$FreeBSD$");
*/
#define SCTP_ASOC_MAX_CHUNKS_ON_QUEUE 512
+
/* The conversion from time to ticks and vice versa is done by rounding
* upwards. This way we can test in the code the time to be positive and
* know that this corresponds to a positive number of ticks.
@@ -1036,6 +1039,12 @@ __FBSDID("$FreeBSD$");
#define SCTP_SO_NOT_LOCKED 0
+/*-
+ * For address locks, do we hold the lock?
+ */
+#define SCTP_ADDR_LOCKED 1
+#define SCTP_ADDR_NOT_LOCKED 0
+
#define IN4_ISPRIVATE_ADDRESS(a) \
((((uint8_t *)&(a)->s_addr)[0] == 10) || \
((((uint8_t *)&(a)->s_addr)[0] == 172) && \
diff --git a/sys/netinet/sctp_indata.c b/sys/netinet/sctp_indata.c
index 52881d2..5179e75 100644
--- a/sys/netinet/sctp_indata.c
+++ b/sys/netinet/sctp_indata.c
@@ -375,8 +375,10 @@ sctp_service_reassembly(struct sctp_tcb *stcb, struct sctp_association *asoc)
cntDel = stream_no = 0;
if ((stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) ||
+ (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) ||
(stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET)) {
- /* socket above is long gone */
+ /* socket above is long gone or going.. */
+abandon:
asoc->fragmented_delivery_inprogress = 0;
chk = TAILQ_FIRST(&asoc->reasmqueue);
while (chk) {
@@ -449,12 +451,16 @@ sctp_service_reassembly(struct sctp_tcb *stcb, struct sctp_association *asoc)
* is corrupt, or there is a EOM already on
* the mbuf chain.
*/
- if ((stcb->asoc.control_pdapi == NULL) || (stcb->asoc.control_pdapi->tail_mbuf == NULL)) {
- panic("This should not happen control_pdapi NULL?");
+ if (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) {
+ goto abandon;
+ } else {
+ if ((stcb->asoc.control_pdapi == NULL) || (stcb->asoc.control_pdapi->tail_mbuf == NULL)) {
+ panic("This should not happen control_pdapi NULL?");
+ }
+ /* if we did not panic, it was a EOM */
+ panic("Bad chunking ??");
+ return;
}
- /* if we did not panic, it was a EOM */
- panic("Bad chunking ??");
- return;
}
cntDel++;
}
@@ -5542,7 +5548,6 @@ slide_out:
num_str = fwd_sz / sizeof(struct sctp_strseq);
for (i = 0; i < num_str; i++) {
uint16_t st;
- unsigned char *xx;
stseq = (struct sctp_strseq *)sctp_m_getptr(m, offset,
sizeof(struct sctp_strseq),
@@ -5552,22 +5557,21 @@ slide_out:
break;
}
/* Convert */
- xx = (unsigned char *)&stseq[i];
- st = ntohs(stseq[i].stream);
- stseq[i].stream = st;
- st = ntohs(stseq[i].sequence);
- stseq[i].sequence = st;
+ st = ntohs(stseq->stream);
+ stseq->stream = st;
+ st = ntohs(stseq->sequence);
+ stseq->sequence = st;
/* now process */
- if (stseq[i].stream >= asoc->streamincnt) {
+ if (stseq->stream >= asoc->streamincnt) {
/* screwed up streams, stop! */
break;
}
- strm = &asoc->strmin[stseq[i].stream];
- if (compare_with_wrap(stseq[i].sequence,
+ strm = &asoc->strmin[stseq->stream];
+ if (compare_with_wrap(stseq->sequence,
strm->last_sequence_delivered, MAX_SEQ)) {
/* Update the sequence number */
strm->last_sequence_delivered =
- stseq[i].sequence;
+ stseq->sequence;
}
/* now kick the stream the new way */
sctp_kick_prsctp_reorder_queue(stcb, strm);
diff --git a/sys/netinet/sctp_input.c b/sys/netinet/sctp_input.c
index 904f79c..bcc5045 100644
--- a/sys/netinet/sctp_input.c
+++ b/sys/netinet/sctp_input.c
@@ -45,6 +45,7 @@ __FBSDID("$FreeBSD$");
#include <netinet/sctp_indata.h>
#include <netinet/sctp_asconf.h>
#include <netinet/sctp_bsd_addr.h>
+#include <netinet/sctp_timer.h>
@@ -548,6 +549,28 @@ sctp_handle_heartbeat_ack(struct sctp_heartbeat_chunk *cp,
TAILQ_REMOVE(&stcb->asoc.nets, stcb->asoc.primary_destination, sctp_next);
TAILQ_INSERT_HEAD(&stcb->asoc.nets, stcb->asoc.primary_destination, sctp_next);
}
+ /* Mobility adaptation */
+ if ((sctp_is_mobility_feature_on(stcb->sctp_ep,
+ SCTP_MOBILITY_BASE) ||
+ sctp_is_mobility_feature_on(stcb->sctp_ep,
+ SCTP_MOBILITY_FASTHANDOFF)) &&
+ sctp_is_mobility_feature_on(stcb->sctp_ep,
+ SCTP_MOBILITY_PRIM_DELETED)) {
+
+ sctp_timer_stop(SCTP_TIMER_TYPE_PRIM_DELETED, stcb->sctp_ep, stcb, NULL, SCTP_FROM_SCTP_TIMER + SCTP_LOC_7);
+ if (sctp_is_mobility_feature_on(stcb->sctp_ep,
+ SCTP_MOBILITY_FASTHANDOFF)) {
+ sctp_assoc_immediate_retrans(stcb,
+ stcb->asoc.primary_destination);
+ }
+ if (sctp_is_mobility_feature_on(stcb->sctp_ep,
+ SCTP_MOBILITY_BASE)) {
+ sctp_move_chunks_from_deleted_prim(stcb,
+ stcb->asoc.primary_destination);
+ }
+ sctp_delete_prim_timer(stcb->sctp_ep, stcb,
+ stcb->asoc.deleted_primary);
+ }
}
sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_CONFIRMED,
stcb, 0, (void *)r_net, SCTP_SO_NOT_LOCKED);
@@ -1255,13 +1278,24 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset,
* to get into the OPEN state
*/
if (ntohl(initack_cp->init.initial_tsn) != asoc->init_seq_number) {
-#ifdef INVARIANTS
- panic("Case D and non-match seq?");
-#else
- SCTP_PRINTF("Case D, seq non-match %x vs %x?\n",
- ntohl(initack_cp->init.initial_tsn),
- asoc->init_seq_number);
-#endif
+ /*-
+ * Opps, this means that we somehow generated two vtag's
+ * the same. I.e. we did:
+ * Us Peer
+ * <---INIT(tag=a)------
+ * ----INIT-ACK(tag=t)-->
+ * ----INIT(tag=t)------> *1
+ * <---INIT-ACK(tag=a)---
+ * <----CE(tag=t)------------- *2
+ *
+ * At point *1 we should be generating a different
+ * tag t'. Which means we would throw away the CE and send
+ * ours instead. Basically this is case C (throw away side).
+ */
+ if (how_indx < sizeof(asoc->cookie_how))
+ asoc->cookie_how[how_indx] = 17;
+ return (NULL);
+
}
switch SCTP_GET_STATE
(asoc) {
@@ -2417,6 +2451,7 @@ 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_mobility_features = (*inp_p)->sctp_mobility_features;
inp->sctp_socket = so;
inp->sctp_frag_point = (*inp_p)->sctp_frag_point;
inp->partial_delivery_point = (*inp_p)->partial_delivery_point;
@@ -5101,12 +5136,9 @@ trigger_send:
un_sent = (stcb->asoc.total_output_queue_size - stcb->asoc.total_flight);
if (!TAILQ_EMPTY(&stcb->asoc.control_send_queue) ||
- /* For retransmission to new primary destination (by micchie) */
- sctp_is_mobility_feature_on(inp, SCTP_MOBILITY_DO_FASTHANDOFF) ||
((un_sent) &&
(stcb->asoc.peers_rwnd > 0 ||
(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_SO_NOT_LOCKED);
SCTPDBG(SCTP_DEBUG_INPUT3, "chunk OUTPUT returns\n");
diff --git a/sys/netinet/sctp_output.c b/sys/netinet/sctp_output.c
index 3b60f85..64eb825 100644
--- a/sys/netinet/sctp_output.c
+++ b/sys/netinet/sctp_output.c
@@ -2412,6 +2412,10 @@ once_again:
/* address has been removed */
continue;
}
+ if (laddr->action == SCTP_DEL_IP_ADDRESS) {
+ /* address is being deleted */
+ continue;
+ }
sifa = sctp_is_ifa_addr_preferred(laddr->ifa, dest_is_loop,
dest_is_priv, fam);
if (sifa == NULL)
@@ -2437,6 +2441,10 @@ once_again_too:
/* address has been removed */
continue;
}
+ if (laddr->action == SCTP_DEL_IP_ADDRESS) {
+ /* address is being deleted */
+ continue;
+ }
sifa = sctp_is_ifa_addr_acceptable(laddr->ifa, dest_is_loop,
dest_is_priv, fam);
if (sifa == NULL)
@@ -2547,6 +2555,10 @@ sctp_from_the_top:
/* address has been removed */
continue;
}
+ if (laddr->action == SCTP_DEL_IP_ADDRESS) {
+ /* address is being deleted */
+ continue;
+ }
sifa = sctp_is_ifa_addr_preferred(laddr->ifa, dest_is_loop, dest_is_priv, fam);
if (sifa == NULL)
continue;
@@ -2558,7 +2570,6 @@ sctp_from_the_top:
stcb->asoc.last_used_address = laddr;
atomic_add_int(&sifa->refcount, 1);
return (sifa);
-
}
if (start_at_beginning == 0) {
stcb->asoc.last_used_address = NULL;
@@ -2579,6 +2590,10 @@ sctp_from_the_top2:
/* address has been removed */
continue;
}
+ if (laddr->action == SCTP_DEL_IP_ADDRESS) {
+ /* address is being deleted */
+ continue;
+ }
sifa = sctp_is_ifa_addr_acceptable(laddr->ifa, dest_is_loop,
dest_is_priv, fam);
if (sifa == NULL)
@@ -3396,10 +3411,14 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp,
/* call the routine to select the src address */
if (net) {
- if (net->ro._s_addr && (net->ro._s_addr->localifa_flags & SCTP_BEING_DELETED)) {
+ if (net->ro._s_addr && (net->ro._s_addr->localifa_flags & (SCTP_BEING_DELETED | SCTP_ADDR_IFA_UNUSEABLE))) {
sctp_free_ifa(net->ro._s_addr);
net->ro._s_addr = NULL;
net->src_addr_selected = 0;
+ if (ro->ro_rt) {
+ RTFREE(ro->ro_rt);
+ ro->ro_rt = NULL;
+ }
}
if (net->src_addr_selected == 0) {
if (out_of_asoc_ok) {
@@ -3671,10 +3690,14 @@ sctp_lowlevel_chunk_output(struct sctp_inpcb *inp,
lsa6_tmp.sin6_len = sizeof(lsa6_tmp);
lsa6 = &lsa6_tmp;
if (net) {
- if (net->ro._s_addr && net->ro._s_addr->localifa_flags & SCTP_BEING_DELETED) {
+ if (net->ro._s_addr && (net->ro._s_addr->localifa_flags & (SCTP_BEING_DELETED | SCTP_ADDR_IFA_UNUSEABLE))) {
sctp_free_ifa(net->ro._s_addr);
net->ro._s_addr = NULL;
net->src_addr_selected = 0;
+ if (ro->ro_rt) {
+ RTFREE(ro->ro_rt);
+ ro->ro_rt = NULL;
+ }
}
if (net->src_addr_selected == 0) {
if (out_of_asoc_ok) {
@@ -4922,7 +4945,7 @@ sctp_send_initiate_ack(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
initackm_out->msg.init.initiate_tag = htonl(asoc->my_vtag);
initackm_out->msg.init.initial_tsn = htonl(asoc->init_seq_number);
} else {
- uint32_t vtag;
+ uint32_t vtag, itsn;
if (asoc) {
atomic_add_int(&asoc->refcnt, 1);
@@ -4930,7 +4953,8 @@ sctp_send_initiate_ack(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
vtag = sctp_select_a_tag(inp);
initackm_out->msg.init.initiate_tag = htonl(vtag);
/* get a TSN to use too */
- initackm_out->msg.init.initial_tsn = htonl(sctp_select_initial_TSN(&inp->sctp_ep));
+ itsn = sctp_select_initial_TSN(&inp->sctp_ep);
+ initackm_out->msg.init.initial_tsn = htonl(itsn);
SCTP_TCB_LOCK(stcb);
atomic_add_int(&asoc->refcnt, -1);
} else {
@@ -5978,7 +6002,7 @@ sctp_sendall(struct sctp_inpcb *inp, struct uio *uio, struct mbuf *m,
ca->sndlen += SCTP_BUF_LEN(m);
m = SCTP_BUF_NEXT(m);
}
- ca->m = m;
+ ca->m = mat;
}
ret = sctp_initiate_iterator(NULL, sctp_sendall_iterator, NULL,
SCTP_PCB_ANY_FLAGS, SCTP_PCB_ANY_FEATURES,
@@ -6401,6 +6425,7 @@ re_look:
/* No chunk memory */
out_gu:
if (send_lock_up) {
+ /* sa_ignore NO_NULL_CHK */
SCTP_TCB_SEND_UNLOCK(stcb);
send_lock_up = 0;
}
@@ -6972,6 +6997,14 @@ sctp_med_chunk_output(struct sctp_inpcb *inp,
net = TAILQ_FIRST(&asoc->nets);
}
+ /*
+ * JRI-TODO: CMT-MPI. Simply set the first
+ * destination (net) to be optimized for the next
+ * message to be pulled out of the outwheel. 1. peek
+ * at outwheel 2. If large message, set net =
+ * highest_cwnd 3. If small message, set net =
+ * lowest rtt
+ */
} else {
net = asoc->primary_destination;
if (net == NULL) {
@@ -6980,12 +7013,27 @@ sctp_med_chunk_output(struct sctp_inpcb *inp,
}
}
start_at = net;
+
one_more_time:
for (; net != NULL; net = TAILQ_NEXT(net, sctp_next)) {
net->window_probe = 0;
if (old_startat && (old_startat == net)) {
break;
}
+ /*
+ * JRI: if dest is unreachable or unconfirmed, do
+ * not send data to it
+ */
+ if ((net->dest_state & SCTP_ADDR_NOT_REACHABLE) || (net->dest_state & SCTP_ADDR_UNCONFIRMED)) {
+ continue;
+ }
+ /*
+ * JRI: if dest is in PF state, do not send data to
+ * it
+ */
+ if (sctp_cmt_on_off && sctp_cmt_pf && (net->dest_state & SCTP_ADDR_PF)) {
+ continue;
+ }
if ((sctp_cmt_on_off == 0) && (net->ref_count < 2)) {
/* nothing can be in queue for this guy */
continue;
@@ -6996,9 +7044,9 @@ one_more_time:
continue;
}
/*
- * @@@ JRI : this for loop we are in takes in each
- * net, if its's got space in cwnd and has data sent
- * to it (when CMT is off) then it calls
+ * JRI : this for loop we are in takes in each net,
+ * if its's got space in cwnd and has data sent to
+ * it (when CMT is off) then it calls
* sctp_fill_outqueue for the net. This gets data on
* the send queue for that network.
*
@@ -7026,6 +7074,7 @@ one_more_time:
}
skip_the_fill_from_streams:
*cwnd_full = cwnd_full_ind;
+
/* now service each destination and send out what we can for it */
/* Nothing to send? */
if ((TAILQ_FIRST(&asoc->control_send_queue) == NULL) &&
@@ -8082,8 +8131,6 @@ sctp_send_asconf_ack(struct sctp_tcb *stcb)
}
latest_ack->last_sent_to = net;
- atomic_add_int(&latest_ack->last_sent_to->ref_count, 1);
-
TAILQ_FOREACH(ack, &stcb->asoc.asconf_ack_sent, next) {
if (ack->data == NULL) {
continue;
@@ -9221,6 +9268,7 @@ sctp_send_sack(struct sctp_tcb *stcb)
a_chk->data = NULL;
}
sctp_free_a_chunk(stcb, a_chk);
+ /* sa_ignore NO_NULL_CHK */
if (stcb->asoc.delayed_ack) {
sctp_timer_stop(SCTP_TIMER_TYPE_RECV,
stcb->sctp_ep, stcb, NULL, SCTP_FROM_SCTP_OUTPUT + SCTP_LOC_6);
@@ -9916,6 +9964,7 @@ sctp_send_packet_dropped(struct sctp_tcb *stcb, struct sctp_nets *net,
struct sctp_chunkhdr *ch, chunk_buf;
unsigned int chk_length;
+ /* sa_ignore NO_NULL_CHK */
asoc = &stcb->asoc;
SCTP_TCB_LOCK_ASSERT(stcb);
if (asoc->peer_supports_pktdrop == 0) {
@@ -11131,8 +11180,7 @@ sctp_lower_sosend(struct socket *so,
if ((use_rcvinfo) && (srcv) &&
((srcv->sinfo_flags & SCTP_ABORT) ||
((srcv->sinfo_flags & SCTP_EOF) &&
- (uio) &&
- (uio->uio_resid == 0)))) {
+ (sndlen == 0)))) {
/*-
* User asks to abort a non-existant assoc,
* or EOF a non-existant assoc with no data
@@ -11282,7 +11330,11 @@ sctp_lower_sosend(struct socket *so,
(stcb->asoc.chunks_on_out_queue >
sctp_max_chunks_on_queue)) {
SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EWOULDBLOCK);
- error = EWOULDBLOCK;
+ if (sndlen > SCTP_SB_LIMIT_SND(so))
+ error = EMSGSIZE;
+ else
+ error = EWOULDBLOCK;
+
atomic_add_int(&stcb->sctp_ep->total_nospaces, 1);
goto out_unlocked;
}
@@ -11402,9 +11454,14 @@ sctp_lower_sosend(struct socket *so,
tot_demand = (tot_out + sizeof(struct sctp_paramhdr));
} else {
/* Must fit in a MTU */
- if (uio)
- tot_out = uio->uio_resid;
+ tot_out = sndlen;
tot_demand = (tot_out + sizeof(struct sctp_paramhdr));
+ if (tot_demand > SCTP_DEFAULT_ADD_MORE) {
+ /* To big */
+ SCTP_LTRACE_ERR_RET(NULL, stcb, net, SCTP_FROM_SCTP_OUTPUT, EMSGSIZE);
+ error = EMSGSIZE;
+ goto out;
+ }
mm = sctp_get_mbuf_for_msg(tot_demand, 0, M_WAIT, 1, MT_DATA);
}
if (mm == NULL) {
@@ -11491,12 +11548,21 @@ sctp_lower_sosend(struct socket *so,
}
/* Unless E_EOR mode is on, we must make a send FIT in one call. */
if ((user_marks_eor == 0) &&
- (uio->uio_resid > (int)SCTP_SB_LIMIT_SND(stcb->sctp_socket))) {
+ (sndlen > SCTP_SB_LIMIT_SND(stcb->sctp_socket))) {
/* It will NEVER fit */
SCTP_LTRACE_ERR_RET(NULL, stcb, net, SCTP_FROM_SCTP_OUTPUT, EMSGSIZE);
error = EMSGSIZE;
goto out_unlocked;
}
+ if ((uio == NULL) && user_marks_eor) {
+ /*-
+ * We do not support eeor mode for
+ * sending with mbuf chains (like sendfile).
+ */
+ SCTP_LTRACE_ERR_RET(NULL, stcb, net, SCTP_FROM_SCTP_OUTPUT, EINVAL);
+ error = EINVAL;
+ goto out_unlocked;
+ }
if (user_marks_eor) {
local_add_more = sctp_add_more_threshold;
} else {
@@ -11504,7 +11570,7 @@ sctp_lower_sosend(struct socket *so,
* For non-eeor the whole message must fit in
* the socket send buffer.
*/
- local_add_more = uio->uio_resid;
+ local_add_more = sndlen;
}
len = 0;
if (((max_len < local_add_more) &&
@@ -11517,7 +11583,7 @@ sctp_lower_sosend(struct socket *so,
if (sctp_logging_level & SCTP_BLK_LOGGING_ENABLE) {
sctp_log_block(SCTP_BLOCK_LOG_INTO_BLKA,
- so, asoc, uio->uio_resid);
+ so, asoc, sndlen);
}
be.error = 0;
stcb->block_entry = &be;
@@ -11557,7 +11623,7 @@ sctp_lower_sosend(struct socket *so,
* sndlen covers for mbuf case uio_resid covers for the non-mbuf
* case NOTE: uio will be null when top/mbuf is passed
*/
- if ((sndlen == 0) || ((uio) && (uio->uio_resid == 0))) {
+ if (sndlen == 0) {
if (srcv->sinfo_flags & SCTP_EOF) {
got_all_of_the_send = 1;
goto dataless_eof;
diff --git a/sys/netinet/sctp_pcb.c b/sys/netinet/sctp_pcb.c
index 30fc1cb..e7830fc 100644
--- a/sys/netinet/sctp_pcb.c
+++ b/sys/netinet/sctp_pcb.c
@@ -296,6 +296,110 @@ sctp_delete_ifn(struct sctp_ifn *sctp_ifnp, int hold_addr_lock)
sctp_free_ifn(sctp_ifnp);
}
+void
+sctp_mark_ifa_addr_down(uint32_t vrf_id, struct sockaddr *addr, const char *if_name, uint32_t ifn_index)
+{
+ struct sctp_vrf *vrf;
+ struct sctp_ifa *sctp_ifap = NULL;
+
+ SCTP_IPI_ADDR_LOCK();
+ vrf = sctp_find_vrf(vrf_id);
+ if (vrf == NULL) {
+ SCTPDBG(SCTP_DEBUG_PCB1, "Can't find vrf_id:%d\n", vrf_id);
+ goto out;
+
+ }
+ sctp_ifap = sctp_find_ifa_by_addr(addr, vrf->vrf_id, SCTP_ADDR_LOCKED);
+ if (sctp_ifap == NULL) {
+ SCTPDBG(SCTP_DEBUG_PCB1, "Can't find sctp_ifap for address\n");
+ goto out;
+ }
+ if (sctp_ifap->ifn_p == NULL) {
+ SCTPDBG(SCTP_DEBUG_PCB1, "IFA has no IFN - can't mark unuseable\n");
+ goto out;
+ }
+ if (if_name) {
+ int len1, len2;
+
+ len1 = strlen(if_name);
+ len2 = strlen(sctp_ifap->ifn_p->ifn_name);
+ if (len1 != len2) {
+ SCTPDBG(SCTP_DEBUG_PCB1, "IFN of ifa names different lenght %d vs %d - ignored\n",
+ len1, len2);
+ goto out;
+ }
+ if (strncmp(if_name, sctp_ifap->ifn_p->ifn_name, len1) != 0) {
+ SCTPDBG(SCTP_DEBUG_PCB1, "IFN %s of IFA not the same as %s\n",
+ sctp_ifap->ifn_p->ifn_name,
+ if_name);
+ goto out;
+ }
+ } else {
+ if (sctp_ifap->ifn_p->ifn_index != ifn_index) {
+ SCTPDBG(SCTP_DEBUG_PCB1, "IFA owned by ifn_index:%d down command for ifn_index:%d - ignored\n",
+ sctp_ifap->ifn_p->ifn_index, ifn_index);
+ goto out;
+ }
+ }
+
+ sctp_ifap->localifa_flags &= (~SCTP_ADDR_VALID);
+ sctp_ifap->localifa_flags |= SCTP_ADDR_IFA_UNUSEABLE;
+out:
+ SCTP_IPI_ADDR_UNLOCK();
+}
+
+void
+sctp_mark_ifa_addr_up(uint32_t vrf_id, struct sockaddr *addr, const char *if_name, uint32_t ifn_index)
+{
+ struct sctp_vrf *vrf;
+ struct sctp_ifa *sctp_ifap = NULL;
+
+ SCTP_IPI_ADDR_LOCK();
+ vrf = sctp_find_vrf(vrf_id);
+ if (vrf == NULL) {
+ SCTPDBG(SCTP_DEBUG_PCB1, "Can't find vrf_id:%d\n", vrf_id);
+ goto out;
+
+ }
+ sctp_ifap = sctp_find_ifa_by_addr(addr, vrf->vrf_id, SCTP_ADDR_LOCKED);
+ if (sctp_ifap == NULL) {
+ SCTPDBG(SCTP_DEBUG_PCB1, "Can't find sctp_ifap for address\n");
+ goto out;
+ }
+ if (sctp_ifap->ifn_p == NULL) {
+ SCTPDBG(SCTP_DEBUG_PCB1, "IFA has no IFN - can't mark unuseable\n");
+ goto out;
+ }
+ if (if_name) {
+ int len1, len2;
+
+ len1 = strlen(if_name);
+ len2 = strlen(sctp_ifap->ifn_p->ifn_name);
+ if (len1 != len2) {
+ SCTPDBG(SCTP_DEBUG_PCB1, "IFN of ifa names different lenght %d vs %d - ignored\n",
+ len1, len2);
+ goto out;
+ }
+ if (strncmp(if_name, sctp_ifap->ifn_p->ifn_name, len1) != 0) {
+ SCTPDBG(SCTP_DEBUG_PCB1, "IFN %s of IFA not the same as %s\n",
+ sctp_ifap->ifn_p->ifn_name,
+ if_name);
+ goto out;
+ }
+ } else {
+ if (sctp_ifap->ifn_p->ifn_index != ifn_index) {
+ SCTPDBG(SCTP_DEBUG_PCB1, "IFA owned by ifn_index:%d down command for ifn_index:%d - ignored\n",
+ sctp_ifap->ifn_p->ifn_index, ifn_index);
+ goto out;
+ }
+ }
+
+ sctp_ifap->localifa_flags &= (~SCTP_ADDR_IFA_UNUSEABLE);
+ sctp_ifap->localifa_flags |= SCTP_ADDR_VALID;
+out:
+ SCTP_IPI_ADDR_UNLOCK();
+}
+
struct sctp_ifa *
sctp_add_addr_to_vrf(uint32_t vrf_id, void *ifn, uint32_t ifn_index,
@@ -361,7 +465,7 @@ sctp_add_addr_to_vrf(uint32_t vrf_id, void *ifn, uint32_t ifn_index,
atomic_add_int(&sctppcbinfo.ipi_count_ifns, 1);
new_ifn_af = 1;
}
- sctp_ifap = sctp_find_ifa_by_addr(addr, vrf->vrf_id, 1);
+ sctp_ifap = sctp_find_ifa_by_addr(addr, vrf->vrf_id, SCTP_ADDR_LOCKED);
if (sctp_ifap) {
/* Hmm, it already exists? */
if ((sctp_ifap->ifn_p) &&
@@ -384,15 +488,19 @@ sctp_add_addr_to_vrf(uint32_t vrf_id, void *ifn, uint32_t ifn_index,
} else {
if (sctp_ifap->ifn_p) {
/*
- * The first IFN gets the address,
- * duplicates are ignored.
+ * The last IFN gets the address, old ones
+ * are deleted.
*/
if (new_ifn_af) {
/*
* Remove the created one that we
* don't want
*/
- sctp_delete_ifn(sctp_ifnp, 1);
+ sctp_free_ifn(sctp_ifap->ifn_p);
+ if (sctp_ifap->ifn_p->refcount == 1)
+ sctp_delete_ifn(sctp_ifap->ifn_p, 1);
+ sctp_ifap->ifn_p = sctp_ifnp;
+ atomic_add_int(&sctp_ifap->ifn_p->refcount, 1);
}
goto exit_stage_left;
} else {
@@ -488,7 +596,7 @@ sctp_add_addr_to_vrf(uint32_t vrf_id, void *ifn, uint32_t ifn_index,
*/
SCTPDBG(SCTP_DEBUG_PCB1, "Lost and address change ???\n");
/* Opps, must decrement the count */
- sctp_del_addr_from_vrf(vrf_id, addr, ifn_index);
+ sctp_del_addr_from_vrf(vrf_id, addr, ifn_index, if_name);
return (NULL);
}
SCTP_INCR_LADDR_COUNT();
@@ -516,7 +624,7 @@ sctp_add_addr_to_vrf(uint32_t vrf_id, void *ifn, uint32_t ifn_index,
void
sctp_del_addr_from_vrf(uint32_t vrf_id, struct sockaddr *addr,
- uint32_t ifn_index)
+ uint32_t ifn_index, const char *if_name)
{
struct sctp_vrf *vrf;
struct sctp_ifa *sctp_ifap = NULL;
@@ -528,8 +636,51 @@ sctp_del_addr_from_vrf(uint32_t vrf_id, struct sockaddr *addr,
SCTP_PRINTF("Can't find vrf_id:%d\n", vrf_id);
goto out_now;
}
- sctp_ifap = sctp_find_ifa_by_addr(addr, vrf->vrf_id, 1);
+ sctp_ifap = sctp_find_ifa_by_addr(addr, vrf->vrf_id, SCTP_ADDR_LOCKED);
if (sctp_ifap) {
+ /* Validate the delete */
+ if (sctp_ifap->ifn_p) {
+ int valid = 0;
+
+ /*-
+ * The name has priority over the ifn_index
+ * if its given. We do this especially for
+ * panda who might recycle indexes fast.
+ */
+ if (if_name) {
+ int len1, len2;
+
+ len1 = min(SCTP_IFNAMSIZ, strlen(if_name));
+ len2 = min(SCTP_IFNAMSIZ, strlen(sctp_ifap->ifn_p->ifn_name));
+ if (len1 && len2 && (len1 == len2)) {
+ /* we can compare them */
+ if (strncmp(if_name, sctp_ifap->ifn_p->ifn_name, len1) == 0) {
+ /*
+ * They match its a correct
+ * delete
+ */
+ valid = 1;
+ }
+ }
+ }
+ if (!valid) {
+ /* last ditch check ifn_index */
+ if (ifn_index == sctp_ifap->ifn_p->ifn_index) {
+ valid = 1;
+ }
+ }
+ if (!valid) {
+#ifdef SCTP_DEBUG
+ SCTPDBG(SCTP_DEBUG_PCB1, "Deleting address:");
+ SCTPDBG_ADDR(SCTP_DEBUG_PCB1, addr);
+ SCTPDBG(SCTP_DEBUG_PCB1, "ifn:%d ifname:%s does not match addresses\n",
+ ifn_index, ((if_name == NULL) ? "NULL" : if_name));
+ SCTPDBG(SCTP_DEBUG_PCB1, "ifn:%d ifname:%s - ignoring delete\n",
+ sctp_ifap->ifn_p->ifn_index, sctp_ifap->ifn_p->ifn_name);
+#endif
+ return;
+ }
+ }
sctp_ifap->localifa_flags &= SCTP_ADDR_VALID;
sctp_ifap->localifa_flags |= SCTP_BEING_DELETED;
vrf->total_ifa_count--;
@@ -1857,8 +2008,8 @@ sctp_inpcb_alloc(struct socket *so, uint32_t vrf_id)
* unsupported socket type (RAW, etc)- in case we missed it
* in protosw
*/
- SCTP_ZONE_FREE(sctppcbinfo.ipi_zone_ep, inp);
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, EOPNOTSUPP);
+ SCTP_ZONE_FREE(sctppcbinfo.ipi_zone_ep, inp);
return (EOPNOTSUPP);
}
if (sctp_default_frag_interleave == SCTP_FRAG_LEVEL_1) {
@@ -1875,8 +2026,8 @@ sctp_inpcb_alloc(struct socket *so, uint32_t vrf_id)
&inp->sctp_hashmark);
if (inp->sctp_tcbhash == NULL) {
SCTP_PRINTF("Out of SCTP-INPCB->hashinit - no resources\n");
- SCTP_ZONE_FREE(sctppcbinfo.ipi_zone_ep, inp);
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_PCB, ENOBUFS);
+ SCTP_ZONE_FREE(sctppcbinfo.ipi_zone_ep, inp);
return (ENOBUFS);
}
inp->def_vrf_id = vrf_id;
@@ -2086,6 +2237,7 @@ sctp_move_pcb_and_assoc(struct sctp_inpcb *old_inp, struct sctp_inpcb *new_inp,
stcb->asoc.shut_guard_timer.ep = (void *)new_inp;
stcb->asoc.autoclose_timer.ep = (void *)new_inp;
stcb->asoc.delayed_event_timer.ep = (void *)new_inp;
+ stcb->asoc.delete_prim_timer.ep = (void *)new_inp;
/* now what about the nets? */
TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
net->pmtu_timer.ep = (void *)new_inp;
@@ -2410,8 +2562,10 @@ sctp_inpcb_bind(struct socket *so, struct sockaddr *addr,
*/
if (sctp_mobility_base == 0) {
sctp_mobility_feature_off(inp, SCTP_MOBILITY_BASE);
+ sctp_mobility_feature_off(inp, SCTP_MOBILITY_PRIM_DELETED);
} else {
sctp_mobility_feature_on(inp, SCTP_MOBILITY_BASE);
+ sctp_mobility_feature_off(inp, SCTP_MOBILITY_PRIM_DELETED);
}
/*
* set the automatic mobility_fasthandoff from kernel flag
@@ -2419,10 +2573,10 @@ sctp_inpcb_bind(struct socket *so, struct sockaddr *addr,
*/
if (sctp_mobility_fasthandoff == 0) {
sctp_mobility_feature_off(inp, SCTP_MOBILITY_FASTHANDOFF);
- sctp_mobility_feature_off(inp, SCTP_MOBILITY_DO_FASTHANDOFF);
+ sctp_mobility_feature_off(inp, SCTP_MOBILITY_PRIM_DELETED);
} else {
sctp_mobility_feature_on(inp, SCTP_MOBILITY_FASTHANDOFF);
- sctp_mobility_feature_off(inp, SCTP_MOBILITY_DO_FASTHANDOFF);
+ sctp_mobility_feature_off(inp, SCTP_MOBILITY_PRIM_DELETED);
}
} else {
/*
@@ -2466,7 +2620,7 @@ sctp_inpcb_bind(struct socket *so, struct sockaddr *addr,
* (Panda).
*/
ifa = sctp_find_ifa_by_addr((struct sockaddr *)&store_sa,
- vrf_id, 0);
+ vrf_id, SCTP_ADDR_NOT_LOCKED);
}
if (ifa == NULL) {
/* Can't find an interface with that address */
@@ -2625,6 +2779,10 @@ sctp_inpcb_free(struct sctp_inpcb *inp, int immediate, int from)
* via the sockets layer.
*/
inp->sctp_flags &= ~SCTP_PCB_FLAGS_CLOSE_IP;
+ /* socket is gone, so no more wakeups allowed */
+ inp->sctp_flags |= SCTP_PCB_FLAGS_DONT_WAKE;
+ inp->sctp_flags &= ~SCTP_PCB_FLAGS_WAKEINPUT;
+ inp->sctp_flags &= ~SCTP_PCB_FLAGS_WAKEOUTPUT;
}
sctp_timer_stop(SCTP_TIMER_TYPE_NEWCOOKIE, inp, NULL, NULL,
SCTP_FROM_SCTP_PCB + SCTP_LOC_1);
@@ -3039,7 +3197,7 @@ sctp_is_address_on_local_host(struct sockaddr *addr, uint32_t vrf_id)
{
struct sctp_ifa *sctp_ifa;
- sctp_ifa = sctp_find_ifa_by_addr(addr, vrf_id, 0);
+ sctp_ifa = sctp_find_ifa_by_addr(addr, vrf_id, SCTP_ADDR_NOT_LOCKED);
if (sctp_ifa) {
return (1);
} else {
@@ -3541,6 +3699,8 @@ sctp_aloc_assoc(struct sctp_inpcb *inp, struct sockaddr *firstaddr,
sctppcbinfo.hashasocmark)];
/* put it in the bucket in the vtag hash of assoc's for the system */
LIST_INSERT_HEAD(head, stcb, sctp_asocs);
+ sctp_delete_from_timewait(stcb->asoc.my_vtag);
+
SCTP_INP_INFO_WUNLOCK();
if ((err = sctp_add_remote_addr(stcb, firstaddr, SCTP_DO_SETSCOPE, SCTP_ALLOC_ASOC))) {
@@ -3570,6 +3730,7 @@ sctp_aloc_assoc(struct sctp_inpcb *inp, struct sockaddr *firstaddr,
SCTP_OS_TIMER_INIT(&asoc->shut_guard_timer.timer);
SCTP_OS_TIMER_INIT(&asoc->autoclose_timer.timer);
SCTP_OS_TIMER_INIT(&asoc->delayed_event_timer.timer);
+ SCTP_OS_TIMER_INIT(&asoc->delete_prim_timer.timer);
LIST_INSERT_HEAD(&inp->sctp_asoc_list, stcb, sctp_tcblist);
/* now file the port under the hash as well */
@@ -3597,6 +3758,26 @@ sctp_remove_net(struct sctp_tcb *stcb, struct sctp_nets *net)
struct sctp_nets *lnet;
lnet = TAILQ_FIRST(&asoc->nets);
+ /*
+ * Mobility adaptation Ideally, if deleted destination is
+ * the primary, it becomes a fast retransmission trigger by
+ * the subsequent SET PRIMARY. (by micchie)
+ */
+ if (sctp_is_mobility_feature_on(stcb->sctp_ep,
+ SCTP_MOBILITY_FASTHANDOFF)) {
+ SCTPDBG(SCTP_DEBUG_ASCONF1, "remove_net: primary dst is deleting\n");
+ if (asoc->deleted_primary != NULL) {
+ SCTPDBG(SCTP_DEBUG_ASCONF1, "remove_net: deleted primary may be already stored\n");
+ goto leave;
+ }
+ asoc->deleted_primary = net;
+ atomic_add_int(&net->ref_count, 1);
+ sctp_mobility_feature_on(stcb->sctp_ep,
+ SCTP_MOBILITY_PRIM_DELETED);
+ sctp_timer_start(SCTP_TIMER_TYPE_PRIM_DELETED,
+ stcb->sctp_ep, stcb, NULL);
+ }
+leave:
/* Try to find a confirmed primary */
asoc->primary_destination = sctp_find_alternate_net(stcb, lnet, 0);
}
@@ -3652,9 +3833,33 @@ sctp_del_remote_addr(struct sctp_tcb *stcb, struct sockaddr *remaddr)
return (-2);
}
+void
+sctp_delete_from_timewait(uint32_t tag)
+{
+ struct sctpvtaghead *chain;
+ struct sctp_tagblock *twait_block;
+ int found = 0;
+ int i;
+
+ chain = &sctppcbinfo.vtag_timewait[(tag % SCTP_STACK_VTAG_HASH_SIZE)];
+ if (!SCTP_LIST_EMPTY(chain)) {
+ LIST_FOREACH(twait_block, chain, sctp_nxt_tagblock) {
+ for (i = 0; i < SCTP_NUMBER_IN_VTAG_BLOCK; i++) {
+ if (twait_block->vtag_block[i].v_tag == tag) {
+ twait_block->vtag_block[i].tv_sec_at_expire = 0;
+ twait_block->vtag_block[i].v_tag = 0;
+ found = 1;
+ break;
+ }
+ }
+ if (found)
+ break;
+ }
+ }
+}
void
-sctp_add_vtag_to_timewait(struct sctp_inpcb *inp, uint32_t tag, uint32_t time)
+sctp_add_vtag_to_timewait(uint32_t tag, uint32_t time)
{
struct sctpvtaghead *chain;
struct sctp_tagblock *twait_block;
@@ -3843,6 +4048,9 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre
asoc->shut_guard_timer.self = NULL;
(void)SCTP_OS_TIMER_STOP(&asoc->delayed_event_timer.timer);
asoc->delayed_event_timer.self = NULL;
+ /* Mobility adaptation */
+ (void)SCTP_OS_TIMER_STOP(&asoc->delete_prim_timer.timer);
+ asoc->delete_prim_timer.self = NULL;
TAILQ_FOREACH(net, &asoc->nets, sctp_next) {
(void)SCTP_OS_TIMER_STOP(&net->fr_timer.timer);
net->fr_timer.self = NULL;
@@ -3999,7 +4207,7 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre
}
/* pull from vtag hash */
LIST_REMOVE(stcb, sctp_asocs);
- sctp_add_vtag_to_timewait(inp, asoc->my_vtag, SCTP_TIME_WAIT);
+ sctp_add_vtag_to_timewait(asoc->my_vtag, SCTP_TIME_WAIT);
/*
* Now restop the timers to be sure - this is paranoia at is finest!
@@ -4246,11 +4454,9 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre
SCTP_FREE(aparam, SCTP_M_ASC_ADDR);
}
while (!TAILQ_EMPTY(&asoc->asconf_ack_sent)) {
+ /* sa_ignore FREED_MEMORY */
aack = TAILQ_FIRST(&asoc->asconf_ack_sent);
TAILQ_REMOVE(&asoc->asconf_ack_sent, aack, next);
- if (aack->last_sent_to != NULL) {
- sctp_free_remote_addr(aack->last_sent_to);
- }
if (aack->data != NULL) {
sctp_m_freem(aack->data);
}
@@ -4696,6 +4902,7 @@ sctp_pcb_init()
* the sctp_init() funciton.
*/
int i;
+ struct timeval tv;
if (sctp_pcb_initialized != 0) {
/* error I was called twice */
@@ -4704,7 +4911,9 @@ sctp_pcb_init()
sctp_pcb_initialized = 1;
bzero(&sctpstat, sizeof(struct sctpstat));
- (void)SCTP_GETTIME_TIMEVAL(&sctpstat.sctps_discontinuitytime);
+ (void)SCTP_GETTIME_TIMEVAL(&tv);
+ sctpstat.sctps_discontinuitytime.tv_sec = (uint32_t) tv.tv_sec;
+ sctpstat.sctps_discontinuitytime.tv_usec = (uint32_t) tv.tv_usec;
/* init the empty list of (All) Endpoints */
LIST_INIT(&sctppcbinfo.listhead);
@@ -5542,7 +5751,15 @@ check_time_wait:
}
}
}
- /* Not found, ok to use the tag */
+ /*-
+ * Not found, ok to use the tag, add it to the time wait hash
+ * as well this will prevent two sucessive cookies from getting
+ * the same tag or two inits sent quickly on multi-processors.
+ * We only keep the tag for the life of a cookie and when we
+ * add this tag to the assoc hash we need to purge it from
+ * the t-wait hash.
+ */
+ sctp_add_vtag_to_timewait(tag, TICKS_TO_SEC(inp->sctp_ep.def_cookie_life));
SCTP_INP_INFO_WUNLOCK();
return (1);
}
diff --git a/sys/netinet/sctp_pcb.h b/sys/netinet/sctp_pcb.h
index 9235029..bc28eac 100644
--- a/sys/netinet/sctp_pcb.h
+++ b/sys/netinet/sctp_pcb.h
@@ -297,7 +297,7 @@ struct sctp_pcb {
int auto_close_time;
uint32_t initial_sequence_debug;
uint32_t adaptation_layer_indicator;
- char store_at;
+ uint32_t store_at;
uint8_t max_burst;
char current_secret_number;
char last_secret_number;
@@ -445,6 +445,18 @@ struct sctp_vrf *sctp_allocate_vrf(int vrfid);
struct sctp_vrf *sctp_find_vrf(uint32_t vrfid);
void sctp_free_vrf(struct sctp_vrf *vrf);
+/*-
+ * Change address state, can be used if
+ * O/S supports telling transports about
+ * changes to IFA/IFN's (link layer triggers).
+ * If a ifn goes down, we will do src-addr-selection
+ * and NOT use that, as a source address. This does
+ * not stop the routing system from routing out
+ * that interface, but we won't put it as a source.
+ */
+void sctp_mark_ifa_addr_down(uint32_t vrf_id, struct sockaddr *addr, const char *if_name, uint32_t ifn_index);
+void sctp_mark_ifa_addr_up(uint32_t vrf_id, struct sockaddr *addr, const char *if_name, uint32_t ifn_index);
+
struct sctp_ifa *
sctp_add_addr_to_vrf(uint32_t vrfid,
void *ifn, uint32_t ifn_index, uint32_t ifn_type,
@@ -460,7 +472,7 @@ void sctp_free_ifa(struct sctp_ifa *sctp_ifap);
void
sctp_del_addr_from_vrf(uint32_t vrfid, struct sockaddr *addr,
- uint32_t ifn_index);
+ uint32_t ifn_index, const char *if_name);
@@ -516,8 +528,11 @@ sctp_aloc_assoc(struct sctp_inpcb *, struct sockaddr *,
int sctp_free_assoc(struct sctp_inpcb *, struct sctp_tcb *, int, int);
+
+void sctp_delete_from_timewait(uint32_t);
+
void
- sctp_add_vtag_to_timewait(struct sctp_inpcb *, uint32_t, uint32_t);
+ sctp_add_vtag_to_timewait(uint32_t, uint32_t);
void sctp_add_local_addr_ep(struct sctp_inpcb *, struct sctp_ifa *, uint32_t);
diff --git a/sys/netinet/sctp_structs.h b/sys/netinet/sctp_structs.h
index 217f5a0..09e08f0 100644
--- a/sys/netinet/sctp_structs.h
+++ b/sys/netinet/sctp_structs.h
@@ -584,12 +584,15 @@ struct sctp_association {
struct sctp_timer shut_guard_timer; /* shutdown guard */
struct sctp_timer autoclose_timer; /* automatic close timer */
struct sctp_timer delayed_event_timer; /* timer for delayed events */
+ struct sctp_timer delete_prim_timer; /* deleting primary dst */
/* list of restricted local addresses */
struct sctpladdr sctp_restricted_addrs;
/* last local address pending deletion (waiting for an address add) */
struct sctp_ifa *asconf_addr_del_pending;
+ /* Deleted primary destination (used to stop timer) */
+ struct sctp_nets *deleted_primary;
struct sctpnetlisthead nets; /* remote address list */
diff --git a/sys/netinet/sctp_sysctl.c b/sys/netinet/sctp_sysctl.c
index 5b95b86..ec28f61 100644
--- a/sys/netinet/sctp_sysctl.c
+++ b/sys/netinet/sctp_sysctl.c
@@ -40,86 +40,69 @@ __FBSDID("$FreeBSD$");
/*
* sysctl tunable variables
*/
-uint32_t sctp_sendspace = (128 * 1024);
-uint32_t sctp_recvspace = 128 * (1024 +
-#ifdef INET6
- sizeof(struct sockaddr_in6)
-#else
- sizeof(struct sockaddr_in)
-#endif
-);
-uint32_t sctp_mbuf_threshold_count = SCTP_DEFAULT_MBUFS_IN_CHAIN;
-uint32_t sctp_auto_asconf = SCTP_DEFAULT_AUTO_ASCONF;
-uint32_t sctp_ecn_enable = 1;
-uint32_t sctp_ecn_nonce = 0;
-uint32_t sctp_strict_sacks = 0;
-uint32_t sctp_no_csum_on_loopback = 1;
-uint32_t sctp_strict_init = 1;
-uint32_t sctp_abort_if_one_2_one_hits_limit = 0;
-uint32_t sctp_strict_data_order = 0;
-
+uint32_t sctp_sendspace = SCTPCTL_MAXDGRAM_DEFAULT;
+uint32_t sctp_recvspace = SCTPCTL_RECVSPACE_DEFAULT;
+uint32_t sctp_auto_asconf = SCTPCTL_AUTOASCONF_DEFAULT;
+uint32_t sctp_ecn_enable = SCTPCTL_ECN_ENABLE_DEFAULT;
+uint32_t sctp_ecn_nonce = SCTPCTL_ECN_NONCE_DEFAULT;
+uint32_t sctp_strict_sacks = SCTPCTL_STRICT_SACKS_DEFAULT;
+uint32_t sctp_no_csum_on_loopback = SCTPCTL_LOOPBACK_NOCSUM_DEFAULT;
+uint32_t sctp_strict_init = SCTPCTL_STRICT_INIT_DEFAULT;
uint32_t sctp_peer_chunk_oh = SCTPCTL_PEER_CHKOH_DEFAULT;
-uint32_t sctp_max_burst_default = SCTP_DEF_MAX_BURST;
-uint32_t sctp_use_cwnd_based_maxburst = 1;
-uint32_t sctp_do_drain = 1;
-uint32_t sctp_hb_maxburst = SCTP_DEF_MAX_BURST;
-uint32_t sctp_logging_level = SCTPCTL_LOGGING_LEVEL_DEFAULT;
-
-
-uint32_t sctp_max_chunks_on_queue = SCTP_ASOC_MAX_CHUNKS_ON_QUEUE;
-uint32_t sctp_delayed_sack_time_default = SCTP_RECV_MSEC;
-uint32_t sctp_sack_freq_default = SCTP_DEFAULT_SACK_FREQ;
-uint32_t sctp_heartbeat_interval_default = SCTP_HB_DEFAULT_MSEC;
-uint32_t sctp_pmtu_raise_time_default = SCTP_DEF_PMTU_RAISE_SEC;
-uint32_t sctp_shutdown_guard_time_default = SCTP_DEF_MAX_SHUTDOWN_SEC;
-uint32_t sctp_secret_lifetime_default = SCTP_DEFAULT_SECRET_LIFE_SEC;
-uint32_t sctp_rto_max_default = SCTP_RTO_UPPER_BOUND;
-uint32_t sctp_rto_min_default = SCTP_RTO_LOWER_BOUND;
-uint32_t sctp_rto_initial_default = SCTP_RTO_INITIAL;
-uint32_t sctp_init_rto_max_default = SCTP_RTO_UPPER_BOUND;
-uint32_t sctp_valid_cookie_life_default = SCTP_DEFAULT_COOKIE_LIFE;
-uint32_t sctp_init_rtx_max_default = SCTP_DEF_MAX_INIT;
-uint32_t sctp_assoc_rtx_max_default = SCTP_DEF_MAX_SEND;
-uint32_t sctp_path_rtx_max_default = SCTP_DEF_MAX_PATH_RTX;
-uint32_t sctp_nr_outgoing_streams_default = SCTP_OSTREAM_INITIAL;
-uint32_t sctp_add_more_threshold = SCTP_DEFAULT_ADD_MORE;
-uint32_t sctp_asoc_free_resc_limit = SCTP_DEF_ASOC_RESC_LIMIT;
-uint32_t sctp_system_free_resc_limit = SCTP_DEF_SYSTEM_RESC_LIMIT;
-
-uint32_t sctp_min_split_point = SCTP_DEFAULT_SPLIT_POINT_MIN;
-uint32_t sctp_pcbtblsize = SCTP_PCBHASHSIZE;
-uint32_t sctp_hashtblsize = SCTP_TCBHASHSIZE;
-uint32_t sctp_chunkscale = SCTP_CHUNKQUEUE_SCALE;
-
-uint32_t sctp_cmt_on_off = 0;
-uint32_t sctp_cmt_use_dac = 0;
-uint32_t sctp_cmt_pf = 0;
+uint32_t sctp_max_burst_default = SCTPCTL_MAXBURST_DEFAULT;
+uint32_t sctp_max_chunks_on_queue = SCTPCTL_MAXCHUNKS_DEFAULT;
+uint32_t sctp_hashtblsize = SCTPCTL_TCBHASHSIZE_DEFAULT;
+uint32_t sctp_pcbtblsize = SCTPCTL_PCBHASHSIZE_DEFAULT;
+uint32_t sctp_min_split_point = SCTPCTL_MIN_SPLIT_POINT_DEFAULT;
+uint32_t sctp_chunkscale = SCTPCTL_CHUNKSCALE_DEFAULT;
+uint32_t sctp_delayed_sack_time_default = SCTPCTL_DELAYED_SACK_TIME_DEFAULT;
+uint32_t sctp_sack_freq_default = SCTPCTL_SACK_FREQ_DEFAULT;
+uint32_t sctp_system_free_resc_limit = SCTPCTL_SYS_RESOURCE_DEFAULT;
+uint32_t sctp_asoc_free_resc_limit = SCTPCTL_ASOC_RESOURCE_DEFAULT;
+uint32_t sctp_heartbeat_interval_default = SCTPCTL_HEARTBEAT_INTERVAL_DEFAULT;
+uint32_t sctp_pmtu_raise_time_default = SCTPCTL_PMTU_RAISE_TIME_DEFAULT;
+uint32_t sctp_shutdown_guard_time_default = SCTPCTL_SHUTDOWN_GUARD_TIME_DEFAULT;
+uint32_t sctp_secret_lifetime_default = SCTPCTL_SECRET_LIFETIME_DEFAULT;
+uint32_t sctp_rto_max_default = SCTPCTL_RTO_MAX_DEFAULT;
+uint32_t sctp_rto_min_default = SCTPCTL_RTO_MIN_DEFAULT;
+uint32_t sctp_rto_initial_default = SCTPCTL_RTO_INITIAL_DEFAULT;
+uint32_t sctp_init_rto_max_default = SCTPCTL_INIT_RTO_MAX_DEFAULT;
+uint32_t sctp_valid_cookie_life_default = SCTPCTL_VALID_COOKIE_LIFE_DEFAULT;
+uint32_t sctp_init_rtx_max_default = SCTPCTL_INIT_RTX_MAX_DEFAULT;
+uint32_t sctp_assoc_rtx_max_default = SCTPCTL_ASSOC_RTX_MAX_DEFAULT;
+uint32_t sctp_path_rtx_max_default = SCTPCTL_PATH_RTX_MAX_DEFAULT;
+uint32_t sctp_add_more_threshold = SCTPCTL_ADD_MORE_ON_OUTPUT_DEFAULT;
+uint32_t sctp_nr_outgoing_streams_default = SCTPCTL_OUTGOING_STREAMS_DEFAULT;
+uint32_t sctp_cmt_on_off = SCTPCTL_CMT_ON_OFF_DEFAULT;
+uint32_t sctp_cmt_use_dac = SCTPCTL_CMT_USE_DAC_DEFAULT;
+uint32_t sctp_cmt_pf = SCTPCTL_CMT_PF_DEFAULT;
+uint32_t sctp_use_cwnd_based_maxburst = SCTPCTL_CWND_MAXBURST_DEFAULT;
+uint32_t sctp_early_fr = SCTPCTL_EARLY_FAST_RETRAN_DEFAULT;
+uint32_t sctp_early_fr_msec = SCTPCTL_EARLY_FAST_RETRAN_MSEC_DEFAULT;
+uint32_t sctp_asconf_auth_nochk = SCTPCTL_ASCONF_AUTH_NOCHK_DEFAULT;
+uint32_t sctp_auth_disable = SCTPCTL_AUTH_DISABLE_DEFAULT;
+uint32_t sctp_nat_friendly = SCTPCTL_NAT_FRIENDLY_DEFAULT;
+uint32_t sctp_L2_abc_variable = SCTPCTL_ABC_L_VAR_DEFAULT;
+uint32_t sctp_mbuf_threshold_count = SCTPCTL_MAX_CHAINED_MBUFS_DEFAULT;
+uint32_t sctp_do_drain = SCTPCTL_DO_SCTP_DRAIN_DEFAULT;
+uint32_t sctp_hb_maxburst = SCTPCTL_HB_MAX_BURST_DEFAULT;
+uint32_t sctp_abort_if_one_2_one_hits_limit = SCTPCTL_ABORT_AT_LIMIT_DEFAULT;
+uint32_t sctp_strict_data_order = SCTPCTL_STRICT_DATA_ORDER_DEFAULT;
+uint32_t sctp_min_residual = SCTPCTL_MIN_RESIDUAL_DEFAULT;
uint32_t sctp_max_retran_chunk = SCTPCTL_MAX_RETRAN_CHUNK_DEFAULT;
-uint32_t sctp_mobility_base = SCTP_DEFAULT_MOBILITY_BASE;
-uint32_t sctp_mobility_fasthandoff = SCTP_DEFAULT_MOBILITY_FASTHANDOFF;
+uint32_t sctp_logging_level = SCTPCTL_LOGGING_LEVEL_DEFAULT;
/* JRS - Variable for default congestion control module */
uint32_t sctp_default_cc_module = SCTPCTL_DEFAULT_CC_MODULE_DEFAULT;
-
uint32_t sctp_default_frag_interleave = SCTPCTL_DEFAULT_FRAG_INTERLEAVE_DEFAULT;
-
-uint32_t sctp_L2_abc_variable = 1;
-uint32_t sctp_early_fr = 0;
-uint32_t sctp_early_fr_msec = SCTP_MINFR_MSEC_TIMER;
-uint32_t sctp_says_check_for_deadlock = 0;
-uint32_t sctp_asconf_auth_nochk = 0;
-uint32_t sctp_auth_disable = 0;
-uint32_t sctp_nat_friendly = 1;
-uint32_t sctp_min_residual = SCTPCTL_MIN_RESIDUAL_DEFAULT;;
-
-
-struct sctpstat sctpstat;
+uint32_t sctp_mobility_base = SCTPCTL_MOBILITY_BASE_DEFAULT;
+uint32_t sctp_mobility_fasthandoff = SCTPCTL_MOBILITY_FASTHANDOFF_DEFAULT;
#ifdef SCTP_DEBUG
-uint32_t sctp_debug_on = 0;
+uint32_t sctp_debug_on = SCTPCTL_DEBUG_DEFAULT;
#endif
-
+struct sctpstat sctpstat;
/* It returns an upper limit. No filtering is done here */
@@ -249,15 +232,14 @@ copy_out_local_addresses(struct sctp_inpcb *inp, struct sctp_tcb *stcb, struct s
continue;
} else
continue;
- memset((void *)&xladdr, 0, sizeof(union sctp_sockstore));
+ memset((void *)&xladdr, 0, sizeof(struct xsctp_laddr));
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)
+ if (error) {
return (error);
- else {
+ } else {
SCTP_INP_INFO_RLOCK();
SCTP_INP_RLOCK(inp);
}
@@ -268,30 +250,30 @@ copy_out_local_addresses(struct sctp_inpcb *inp, struct sctp_tcb *stcb, struct s
/* ignore if blacklisted at association level */
if (stcb && sctp_is_addr_restricted(stcb, laddr->ifa))
continue;
- memset((void *)&xladdr, 0, sizeof(union sctp_sockstore));
+ memset((void *)&xladdr, 0, sizeof(struct xsctp_laddr));
memcpy((void *)&xladdr.address, (const void *)&laddr->ifa->address, sizeof(union sctp_sockstore));
- xladdr.start_time = laddr->start_time;
+ xladdr.start_time.tv_sec = (uint32_t) laddr->start_time.tv_sec;
+ xladdr.start_time.tv_usec = (uint32_t) laddr->start_time.tv_usec;
SCTP_INP_RUNLOCK(inp);
SCTP_INP_INFO_RUNLOCK();
error = SYSCTL_OUT(req, &xladdr, sizeof(struct xsctp_laddr));
- if (error)
+ if (error) {
return (error);
- else {
+ } else {
SCTP_INP_INFO_RLOCK();
SCTP_INP_RLOCK(inp);
}
}
}
- memset((void *)&xladdr, 0, sizeof(union sctp_sockstore));
+ memset((void *)&xladdr, 0, sizeof(struct xsctp_laddr));
xladdr.last = 1;
SCTP_INP_RUNLOCK(inp);
SCTP_INP_INFO_RUNLOCK();
error = SYSCTL_OUT(req, &xladdr, sizeof(struct xsctp_laddr));
- if (error)
+ if (error) {
return (error);
-
- else {
+ } else {
SCTP_INP_INFO_RLOCK();
SCTP_INP_RLOCK(inp);
return (0);
@@ -362,8 +344,14 @@ sctp_assoclist(SYSCTL_HANDLER_ARGS)
xinpcb.total_recvs = inp->total_recvs;
xinpcb.total_nospaces = inp->total_nospaces;
xinpcb.fragmentation_point = inp->sctp_frag_point;
- xinpcb.qlen = inp->sctp_socket->so_qlen;
- xinpcb.maxqlen = inp->sctp_socket->so_qlimit;
+ if ((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) ||
+ (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE)) {
+ xinpcb.qlen = 0;
+ xinpcb.maxqlen = 0;
+ } else {
+ 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();
@@ -398,9 +386,10 @@ sctp_assoclist(SYSCTL_HANDLER_ARGS)
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.start_time.tv_sec = (uint32_t) stcb->asoc.start_time.tv_sec;
+ xstcb.start_time.tv_usec = (uint32_t) stcb->asoc.start_time.tv_usec;
+ xstcb.discontinuity_time.tv_sec = (uint32_t) stcb->asoc.discontinuity_time.tv_sec;
+ xstcb.discontinuity_time.tv_usec = (uint32_t) stcb->asoc.discontinuity_time.tv_usec;
xstcb.total_sends = stcb->total_sends;
xstcb.total_recvs = stcb->total_recvs;
xstcb.local_tag = stcb->asoc.my_vtag;
@@ -416,7 +405,7 @@ sctp_assoclist(SYSCTL_HANDLER_ARGS)
error = SYSCTL_OUT(req, &xstcb, sizeof(struct xsctp_tcb));
if (error) {
SCTP_INP_DECR_REF(inp);
- atomic_add_int(&stcb->asoc.refcnt, -1);
+ atomic_subtract_int(&stcb->asoc.refcnt, 1);
return error;
}
SCTP_INP_INFO_RLOCK();
@@ -424,7 +413,7 @@ sctp_assoclist(SYSCTL_HANDLER_ARGS)
error = copy_out_local_addresses(inp, stcb, req);
if (error) {
SCTP_INP_DECR_REF(inp);
- atomic_add_int(&stcb->asoc.refcnt, -1);
+ atomic_subtract_int(&stcb->asoc.refcnt, 1);
return error;
}
TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
@@ -440,19 +429,20 @@ sctp_assoclist(SYSCTL_HANDLER_ARGS)
xraddr.cwnd = net->cwnd;
xraddr.flight_size = net->flight_size;
xraddr.mtu = net->mtu;
- xraddr.start_time = net->start_time;
+ xraddr.start_time.tv_sec = (uint32_t) net->start_time.tv_sec;
+ xraddr.start_time.tv_usec = (uint32_t) net->start_time.tv_usec;
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);
+ atomic_subtract_int(&stcb->asoc.refcnt, 1);
return error;
}
SCTP_INP_INFO_RLOCK();
SCTP_INP_RLOCK(inp);
}
- atomic_add_int(&stcb->asoc.refcnt, -1);
+ atomic_subtract_int(&stcb->asoc.refcnt, 1);
memset((void *)&xraddr, 0, sizeof(struct xsctp_raddr));
xraddr.last = 1;
SCTP_INP_RUNLOCK(inp);
@@ -465,6 +455,7 @@ sctp_assoclist(SYSCTL_HANDLER_ARGS)
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));
@@ -474,7 +465,6 @@ sctp_assoclist(SYSCTL_HANDLER_ARGS)
return error;
}
SCTP_INP_INFO_RLOCK();
- SCTP_INP_DECR_REF(inp);
}
SCTP_INP_INFO_RUNLOCK();
@@ -484,244 +474,326 @@ sctp_assoclist(SYSCTL_HANDLER_ARGS)
return error;
}
+#define RANGECHK(var, min, max) \
+ if ((var) < (min)) { (var) = (min); } \
+ else if ((var) > (max)) { (var) = (max); }
+
+static int
+sysctl_sctp_check(SYSCTL_HANDLER_ARGS)
+{
+ int error;
+
+ error = sysctl_handle_int(oidp, oidp->oid_arg1, oidp->oid_arg2, req);
+ if (error == 0) {
+ RANGECHK(sctp_sendspace, SCTPCTL_MAXDGRAM_MIN, SCTPCTL_MAXDGRAM_MAX);
+ RANGECHK(sctp_recvspace, SCTPCTL_RECVSPACE_MIN, SCTPCTL_RECVSPACE_MAX);
+#if defined(__FreeBSD__) || defined(SCTP_APPLE_AUTO_ASCONF)
+ RANGECHK(sctp_auto_asconf, SCTPCTL_AUTOASCONF_MIN, SCTPCTL_AUTOASCONF_MAX);
+#endif
+ RANGECHK(sctp_ecn_enable, SCTPCTL_ECN_ENABLE_MIN, SCTPCTL_ECN_ENABLE_MAX);
+ RANGECHK(sctp_ecn_nonce, SCTPCTL_ECN_NONCE_MIN, SCTPCTL_ECN_NONCE_MAX);
+ RANGECHK(sctp_strict_sacks, SCTPCTL_STRICT_SACKS_MIN, SCTPCTL_STRICT_SACKS_MAX);
+ RANGECHK(sctp_no_csum_on_loopback, SCTPCTL_LOOPBACK_NOCSUM_MIN, SCTPCTL_LOOPBACK_NOCSUM_MAX);
+ RANGECHK(sctp_strict_init, SCTPCTL_STRICT_INIT_MIN, SCTPCTL_STRICT_INIT_MAX);
+ RANGECHK(sctp_peer_chunk_oh, SCTPCTL_PEER_CHKOH_MIN, SCTPCTL_PEER_CHKOH_MAX);
+ RANGECHK(sctp_max_burst_default, SCTPCTL_MAXBURST_MIN, SCTPCTL_MAXBURST_MAX);
+ RANGECHK(sctp_max_chunks_on_queue, SCTPCTL_MAXCHUNKS_MIN, SCTPCTL_MAXCHUNKS_MAX);
+ RANGECHK(sctp_hashtblsize, SCTPCTL_TCBHASHSIZE_MIN, SCTPCTL_TCBHASHSIZE_MAX);
+ RANGECHK(sctp_pcbtblsize, SCTPCTL_PCBHASHSIZE_MIN, SCTPCTL_PCBHASHSIZE_MAX);
+ RANGECHK(sctp_min_split_point, SCTPCTL_MIN_SPLIT_POINT_MIN, SCTPCTL_MIN_SPLIT_POINT_MAX);
+ RANGECHK(sctp_chunkscale, SCTPCTL_CHUNKSCALE_MIN, SCTPCTL_CHUNKSCALE_MAX);
+ RANGECHK(sctp_delayed_sack_time_default, SCTPCTL_DELAYED_SACK_TIME_MIN, SCTPCTL_DELAYED_SACK_TIME_MAX);
+ RANGECHK(sctp_sack_freq_default, SCTPCTL_SACK_FREQ_MIN, SCTPCTL_SACK_FREQ_MAX);
+ RANGECHK(sctp_system_free_resc_limit, SCTPCTL_SYS_RESOURCE_MIN, SCTPCTL_SYS_RESOURCE_MAX);
+ RANGECHK(sctp_asoc_free_resc_limit, SCTPCTL_ASOC_RESOURCE_MIN, SCTPCTL_ASOC_RESOURCE_MAX);
+ RANGECHK(sctp_heartbeat_interval_default, SCTPCTL_HEARTBEAT_INTERVAL_MIN, SCTPCTL_HEARTBEAT_INTERVAL_MAX);
+ RANGECHK(sctp_pmtu_raise_time_default, SCTPCTL_PMTU_RAISE_TIME_MIN, SCTPCTL_PMTU_RAISE_TIME_MAX);
+ RANGECHK(sctp_shutdown_guard_time_default, SCTPCTL_SHUTDOWN_GUARD_TIME_MIN, SCTPCTL_SHUTDOWN_GUARD_TIME_MAX);
+ RANGECHK(sctp_secret_lifetime_default, SCTPCTL_SECRET_LIFETIME_MIN, SCTPCTL_SECRET_LIFETIME_MAX);
+ RANGECHK(sctp_rto_max_default, SCTPCTL_RTO_MAX_MIN, SCTPCTL_RTO_MAX_MAX);
+ RANGECHK(sctp_rto_min_default, SCTPCTL_RTO_MIN_MIN, SCTPCTL_RTO_MIN_MAX);
+ RANGECHK(sctp_rto_initial_default, SCTPCTL_RTO_INITIAL_MIN, SCTPCTL_RTO_INITIAL_MAX);
+ RANGECHK(sctp_init_rto_max_default, SCTPCTL_INIT_RTO_MAX_MIN, SCTPCTL_INIT_RTO_MAX_MAX);
+ RANGECHK(sctp_valid_cookie_life_default, SCTPCTL_VALID_COOKIE_LIFE_MIN, SCTPCTL_VALID_COOKIE_LIFE_MAX);
+ RANGECHK(sctp_init_rtx_max_default, SCTPCTL_INIT_RTX_MAX_MIN, SCTPCTL_INIT_RTX_MAX_MAX);
+ RANGECHK(sctp_assoc_rtx_max_default, SCTPCTL_ASSOC_RTX_MAX_MIN, SCTPCTL_ASSOC_RTX_MAX_MAX);
+ RANGECHK(sctp_path_rtx_max_default, SCTPCTL_PATH_RTX_MAX_MIN, SCTPCTL_PATH_RTX_MAX_MAX);
+ RANGECHK(sctp_add_more_threshold, SCTPCTL_ADD_MORE_ON_OUTPUT_MIN, SCTPCTL_ADD_MORE_ON_OUTPUT_MAX);
+ RANGECHK(sctp_nr_outgoing_streams_default, SCTPCTL_OUTGOING_STREAMS_MIN, SCTPCTL_OUTGOING_STREAMS_MAX);
+ RANGECHK(sctp_cmt_on_off, SCTPCTL_CMT_ON_OFF_MIN, SCTPCTL_CMT_ON_OFF_MAX);
+ RANGECHK(sctp_cmt_use_dac, SCTPCTL_CMT_USE_DAC_MIN, SCTPCTL_CMT_USE_DAC_MAX);
+ RANGECHK(sctp_cmt_pf, SCTPCTL_CMT_PF_MIN, SCTPCTL_CMT_PF_MAX);
+ RANGECHK(sctp_use_cwnd_based_maxburst, SCTPCTL_CWND_MAXBURST_MIN, SCTPCTL_CWND_MAXBURST_MAX);
+ RANGECHK(sctp_early_fr, SCTPCTL_EARLY_FAST_RETRAN_MIN, SCTPCTL_EARLY_FAST_RETRAN_MAX);
+ RANGECHK(sctp_early_fr_msec, SCTPCTL_EARLY_FAST_RETRAN_MSEC_MIN, SCTPCTL_EARLY_FAST_RETRAN_MSEC_MAX);
+ RANGECHK(sctp_asconf_auth_nochk, SCTPCTL_ASCONF_AUTH_NOCHK_MIN, SCTPCTL_ASCONF_AUTH_NOCHK_MAX);
+ RANGECHK(sctp_auth_disable, SCTPCTL_AUTH_DISABLE_MIN, SCTPCTL_AUTH_DISABLE_MAX);
+ RANGECHK(sctp_nat_friendly, SCTPCTL_NAT_FRIENDLY_MIN, SCTPCTL_NAT_FRIENDLY_MAX);
+ RANGECHK(sctp_L2_abc_variable, SCTPCTL_ABC_L_VAR_MIN, SCTPCTL_ABC_L_VAR_MAX);
+ RANGECHK(sctp_mbuf_threshold_count, SCTPCTL_MAX_CHAINED_MBUFS_MIN, SCTPCTL_MAX_CHAINED_MBUFS_MAX);
+ RANGECHK(sctp_do_drain, SCTPCTL_DO_SCTP_DRAIN_MIN, SCTPCTL_DO_SCTP_DRAIN_MAX);
+ RANGECHK(sctp_hb_maxburst, SCTPCTL_HB_MAX_BURST_MIN, SCTPCTL_HB_MAX_BURST_MAX);
+ RANGECHK(sctp_abort_if_one_2_one_hits_limit, SCTPCTL_ABORT_AT_LIMIT_MIN, SCTPCTL_ABORT_AT_LIMIT_MAX);
+ RANGECHK(sctp_strict_data_order, SCTPCTL_STRICT_DATA_ORDER_MIN, SCTPCTL_STRICT_DATA_ORDER_MAX);
+ RANGECHK(sctp_min_residual, SCTPCTL_MIN_RESIDUAL_MIN, SCTPCTL_MIN_RESIDUAL_MAX);
+ RANGECHK(sctp_max_retran_chunk, SCTPCTL_MAX_RETRAN_CHUNK_MIN, SCTPCTL_MAX_RETRAN_CHUNK_MAX);
+ RANGECHK(sctp_logging_level, SCTPCTL_LOGGING_LEVEL_MIN, SCTPCTL_LOGGING_LEVEL_MAX);
+ RANGECHK(sctp_default_cc_module, SCTPCTL_DEFAULT_CC_MODULE_MIN, SCTPCTL_DEFAULT_CC_MODULE_MAX);
+ RANGECHK(sctp_default_frag_interleave, SCTPCTL_DEFAULT_FRAG_INTERLEAVE_MIN, SCTPCTL_DEFAULT_FRAG_INTERLEAVE_MAX);
+#if defined(__FreeBSD__) || defined(SCTP_APPLE_MOBILITY_BASE)
+ RANGECHK(sctp_mobility_base, SCTPCTL_MOBILITY_BASE_MIN, SCTPCTL_MOBILITY_BASE_MAX);
+#endif
+#if defined(__FreeBSD__) || defined(SCTP_APPLE_MOBILITY_FASTHANDOFF)
+ RANGECHK(sctp_mobility_fasthandoff, SCTPCTL_MOBILITY_FASTHANDOFF_MIN, SCTPCTL_MOBILITY_FASTHANDOFF_MAX);
+#endif
+#ifdef SCTP_DEBUG
+ RANGECHK(sctp_debug_on, SCTPCTL_DEBUG_MIN, SCTPCTL_DEBUG_MAX);
+#endif
+ }
+ return (error);
+}
/*
* sysctl definitions
*/
-SYSCTL_INT(_net_inet_sctp, OID_AUTO, sendspace, CTLFLAG_RW,
- &sctp_sendspace, 0, "Maximum outgoing SCTP buffer size");
+SYSCTL_PROC(_net_inet_sctp, OID_AUTO, sendspace, CTLTYPE_INT | CTLFLAG_RW,
+ &sctp_sendspace, 0, sysctl_sctp_check, "IU",
+ SCTPCTL_MAXDGRAM_DESC);
-SYSCTL_INT(_net_inet_sctp, OID_AUTO, recvspace, CTLFLAG_RW,
- &sctp_recvspace, 0, "Maximum incoming SCTP buffer size");
+SYSCTL_PROC(_net_inet_sctp, OID_AUTO, recvspace, CTLTYPE_INT | CTLFLAG_RW,
+ &sctp_recvspace, 0, sysctl_sctp_check, "IU",
+ SCTPCTL_RECVSPACE_DESC);
#if defined(__FreeBSD__) || defined(SCTP_APPLE_AUTO_ASCONF)
-SYSCTL_INT(_net_inet_sctp, OID_AUTO, auto_asconf, CTLFLAG_RW,
- &sctp_auto_asconf, 0, "Enable SCTP Auto-ASCONF");
+SYSCTL_PROC(_net_inet_sctp, OID_AUTO, auto_asconf, CTLTYPE_INT | CTLFLAG_RW,
+ &sctp_auto_asconf, 0, sysctl_sctp_check, "IU",
+ SCTPCTL_AUTOASCONF_DESC);
#endif
-SYSCTL_INT(_net_inet_sctp, OID_AUTO, ecn_enable, CTLFLAG_RW,
- &sctp_ecn_enable, 0, "Enable SCTP ECN");
-
-SYSCTL_INT(_net_inet_sctp, OID_AUTO, ecn_nonce, CTLFLAG_RW,
- &sctp_ecn_nonce, 0, "Enable SCTP ECN Nonce");
-
-SYSCTL_INT(_net_inet_sctp, OID_AUTO, strict_sacks, CTLFLAG_RW,
- &sctp_strict_sacks, 0, "Enable SCTP Strict SACK checking");
-
-SYSCTL_INT(_net_inet_sctp, OID_AUTO, loopback_nocsum, CTLFLAG_RW,
- &sctp_no_csum_on_loopback, 0,
- "Enable NO Csum on packets sent on loopback");
+SYSCTL_PROC(_net_inet_sctp, OID_AUTO, ecn_enable, CTLTYPE_INT | CTLFLAG_RW,
+ &sctp_ecn_enable, 0, sysctl_sctp_check, "IU",
+ SCTPCTL_ECN_ENABLE_DESC);
-SYSCTL_INT(_net_inet_sctp, OID_AUTO, strict_init, CTLFLAG_RW,
- &sctp_strict_init, 0,
- "Enable strict INIT/INIT-ACK singleton enforcement");
+SYSCTL_PROC(_net_inet_sctp, OID_AUTO, ecn_nonce, CTLTYPE_INT | CTLFLAG_RW,
+ &sctp_ecn_nonce, 0, sysctl_sctp_check, "IU",
+ SCTPCTL_ECN_NONCE_DESC);
-SYSCTL_INT(_net_inet_sctp, OID_AUTO, peer_chkoh, CTLFLAG_RW,
- &sctp_peer_chunk_oh, 0,
- "Amount to debit peers rwnd per chunk sent");
+SYSCTL_PROC(_net_inet_sctp, OID_AUTO, strict_sacks, CTLTYPE_INT | CTLFLAG_RW,
+ &sctp_strict_sacks, 0, sysctl_sctp_check, "IU",
+ SCTPCTL_STRICT_SACKS_DESC);
-SYSCTL_INT(_net_inet_sctp, OID_AUTO, maxburst, CTLFLAG_RW,
- &sctp_max_burst_default, 0,
- "Default max burst for sctp endpoints");
+SYSCTL_PROC(_net_inet_sctp, OID_AUTO, loopback_nocsum, CTLTYPE_INT | CTLFLAG_RW,
+ &sctp_no_csum_on_loopback, 0, sysctl_sctp_check, "IU",
+ SCTPCTL_LOOPBACK_NOCSUM_DESC);
-SYSCTL_INT(_net_inet_sctp, OID_AUTO, maxchunks, CTLFLAG_RW,
- &sctp_max_chunks_on_queue, 0,
- "Default max chunks on queue per asoc");
+SYSCTL_PROC(_net_inet_sctp, OID_AUTO, strict_init, CTLTYPE_INT | CTLFLAG_RW,
+ &sctp_strict_init, 0, sysctl_sctp_check, "IU",
+ SCTPCTL_STRICT_INIT_DESC);
-SYSCTL_INT(_net_inet_sctp, OID_AUTO, tcbhashsize, CTLFLAG_RW,
- &sctp_hashtblsize, 0,
- "Tuneable for Hash table sizes");
+SYSCTL_PROC(_net_inet_sctp, OID_AUTO, peer_chkoh, CTLTYPE_INT | CTLFLAG_RW,
+ &sctp_peer_chunk_oh, 0, sysctl_sctp_check, "IU",
+ SCTPCTL_PEER_CHKOH_DESC);
-SYSCTL_INT(_net_inet_sctp, OID_AUTO, min_split_point, CTLFLAG_RW,
- &sctp_min_split_point, 0,
- "Minimum size when splitting a chunk");
+SYSCTL_PROC(_net_inet_sctp, OID_AUTO, maxburst, CTLTYPE_INT | CTLFLAG_RW,
+ &sctp_max_burst_default, 0, sysctl_sctp_check, "IU",
+ SCTPCTL_MAXBURST_DESC);
-SYSCTL_INT(_net_inet_sctp, OID_AUTO, pcbhashsize, CTLFLAG_RW,
- &sctp_pcbtblsize, 0,
- "Tuneable for PCB Hash table sizes");
+SYSCTL_PROC(_net_inet_sctp, OID_AUTO, maxchunks, CTLTYPE_INT | CTLFLAG_RW,
+ &sctp_max_chunks_on_queue, 0, sysctl_sctp_check, "IU",
+ SCTPCTL_MAXCHUNKS_DESC);
-SYSCTL_INT(_net_inet_sctp, OID_AUTO, sys_resource, CTLFLAG_RW,
- &sctp_system_free_resc_limit, 0,
- "Max number of cached resources in the system");
+SYSCTL_PROC(_net_inet_sctp, OID_AUTO, tcbhashsize, CTLTYPE_INT | CTLFLAG_RW,
+ &sctp_hashtblsize, 0, sysctl_sctp_check, "IU",
+ SCTPCTL_TCBHASHSIZE_DESC);
-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_PROC(_net_inet_sctp, OID_AUTO, pcbhashsize, CTLTYPE_INT | CTLFLAG_RW,
+ &sctp_pcbtblsize, 0, sysctl_sctp_check, "IU",
+ SCTPCTL_PCBHASHSIZE_DESC);
-SYSCTL_INT(_net_inet_sctp, OID_AUTO, chunkscale, CTLFLAG_RW,
- &sctp_chunkscale, 0,
- "Tuneable for Scaling of number of chunks and messages");
+SYSCTL_PROC(_net_inet_sctp, OID_AUTO, min_split_point, CTLTYPE_INT | CTLFLAG_RW,
+ &sctp_min_split_point, 0, sysctl_sctp_check, "IU",
+ SCTPCTL_MIN_SPLIT_POINT_DESC);
-SYSCTL_UINT(_net_inet_sctp, OID_AUTO, delayed_sack_time, CTLFLAG_RW,
- &sctp_delayed_sack_time_default, 0,
- "Default delayed SACK timer in msec");
+SYSCTL_PROC(_net_inet_sctp, OID_AUTO, chunkscale, CTLTYPE_INT | CTLFLAG_RW,
+ &sctp_chunkscale, 0, sysctl_sctp_check, "IU",
+ SCTPCTL_CHUNKSCALE_DESC);
-SYSCTL_UINT(_net_inet_sctp, OID_AUTO, sack_freq, CTLFLAG_RW,
- &sctp_sack_freq_default, 0,
- "Default SACK frequency");
+SYSCTL_PROC(_net_inet_sctp, OID_AUTO, delayed_sack_time, CTLTYPE_INT | CTLFLAG_RW,
+ &sctp_delayed_sack_time_default, 0, sysctl_sctp_check, "IU",
+ SCTPCTL_DELAYED_SACK_TIME_DESC);
-SYSCTL_UINT(_net_inet_sctp, OID_AUTO, heartbeat_interval, CTLFLAG_RW,
- &sctp_heartbeat_interval_default, 0,
- "Default heartbeat interval in msec");
+SYSCTL_PROC(_net_inet_sctp, OID_AUTO, sack_freq, CTLTYPE_INT | CTLFLAG_RW,
+ &sctp_sack_freq_default, 0, sysctl_sctp_check, "IU",
+ SCTPCTL_SACK_FREQ_DESC);
-SYSCTL_UINT(_net_inet_sctp, OID_AUTO, pmtu_raise_time, CTLFLAG_RW,
- &sctp_pmtu_raise_time_default, 0,
- "Default PMTU raise timer in sec");
+SYSCTL_PROC(_net_inet_sctp, OID_AUTO, sys_resource, CTLTYPE_INT | CTLFLAG_RW,
+ &sctp_system_free_resc_limit, 0, sysctl_sctp_check, "IU",
+ SCTPCTL_SYS_RESOURCE_DESC);
-SYSCTL_UINT(_net_inet_sctp, OID_AUTO, shutdown_guard_time, CTLFLAG_RW,
- &sctp_shutdown_guard_time_default, 0,
- "Default shutdown guard timer in sec");
+SYSCTL_PROC(_net_inet_sctp, OID_AUTO, asoc_resource, CTLTYPE_INT | CTLFLAG_RW,
+ &sctp_asoc_free_resc_limit, 0, sysctl_sctp_check, "IU",
+ SCTPCTL_ASOC_RESOURCE_DESC);
-SYSCTL_UINT(_net_inet_sctp, OID_AUTO, secret_lifetime, CTLFLAG_RW,
- &sctp_secret_lifetime_default, 0,
- "Default secret lifetime in sec");
+SYSCTL_PROC(_net_inet_sctp, OID_AUTO, heartbeat_interval, CTLTYPE_INT | CTLFLAG_RW,
+ &sctp_heartbeat_interval_default, 0, sysctl_sctp_check, "IU",
+ SCTPCTL_HEARTBEAT_INTERVAL_DESC);
-SYSCTL_UINT(_net_inet_sctp, OID_AUTO, rto_max, CTLFLAG_RW,
- &sctp_rto_max_default, 0,
- "Default maximum retransmission timeout in msec");
+SYSCTL_PROC(_net_inet_sctp, OID_AUTO, pmtu_raise_time, CTLTYPE_INT | CTLFLAG_RW,
+ &sctp_pmtu_raise_time_default, 0, sysctl_sctp_check, "IU",
+ SCTPCTL_PMTU_RAISE_TIME_DESC);
-SYSCTL_UINT(_net_inet_sctp, OID_AUTO, rto_min, CTLFLAG_RW,
- &sctp_rto_min_default, 0,
- "Default minimum retransmission timeout in msec");
+SYSCTL_PROC(_net_inet_sctp, OID_AUTO, shutdown_guard_time, CTLTYPE_INT | CTLFLAG_RW,
+ &sctp_shutdown_guard_time_default, 0, sysctl_sctp_check, "IU",
+ SCTPCTL_SHUTDOWN_GUARD_TIME_DESC);
-SYSCTL_UINT(_net_inet_sctp, OID_AUTO, rto_initial, CTLFLAG_RW,
- &sctp_rto_initial_default, 0,
- "Default initial retransmission timeout in msec");
+SYSCTL_PROC(_net_inet_sctp, OID_AUTO, secret_lifetime, CTLTYPE_INT | CTLFLAG_RW,
+ &sctp_secret_lifetime_default, 0, sysctl_sctp_check, "IU",
+ SCTPCTL_SECRET_LIFETIME_DESC);
-SYSCTL_UINT(_net_inet_sctp, OID_AUTO, init_rto_max, CTLFLAG_RW,
- &sctp_init_rto_max_default, 0,
- "Default maximum retransmission timeout during association setup in msec");
+SYSCTL_PROC(_net_inet_sctp, OID_AUTO, rto_max, CTLTYPE_INT | CTLFLAG_RW,
+ &sctp_rto_max_default, 0, sysctl_sctp_check, "IU",
+ SCTPCTL_RTO_MAX_DESC);
-SYSCTL_UINT(_net_inet_sctp, OID_AUTO, valid_cookie_life, CTLFLAG_RW,
- &sctp_valid_cookie_life_default, 0,
- "Default cookie lifetime in ticks");
+SYSCTL_PROC(_net_inet_sctp, OID_AUTO, rto_min, CTLTYPE_INT | CTLFLAG_RW,
+ &sctp_rto_min_default, 0, sysctl_sctp_check, "IU",
+ SCTPCTL_RTO_MIN_DESC);
-SYSCTL_UINT(_net_inet_sctp, OID_AUTO, init_rtx_max, CTLFLAG_RW,
- &sctp_init_rtx_max_default, 0,
- "Default maximum number of retransmission for INIT chunks");
+SYSCTL_PROC(_net_inet_sctp, OID_AUTO, rto_initial, CTLTYPE_INT | CTLFLAG_RW,
+ &sctp_rto_initial_default, 0, sysctl_sctp_check, "IU",
+ SCTPCTL_RTO_INITIAL_DESC);
-SYSCTL_UINT(_net_inet_sctp, OID_AUTO, assoc_rtx_max, CTLFLAG_RW,
- &sctp_assoc_rtx_max_default, 0,
- "Default maximum number of retransmissions per association");
+SYSCTL_PROC(_net_inet_sctp, OID_AUTO, init_rto_max, CTLTYPE_INT | CTLFLAG_RW,
+ &sctp_init_rto_max_default, 0, sysctl_sctp_check, "IU",
+ SCTPCTL_INIT_RTO_MAX_DESC);
-SYSCTL_UINT(_net_inet_sctp, OID_AUTO, path_rtx_max, CTLFLAG_RW,
- &sctp_path_rtx_max_default, 0,
- "Default maximum of retransmissions per path");
+SYSCTL_PROC(_net_inet_sctp, OID_AUTO, valid_cookie_life, CTLTYPE_INT | CTLFLAG_RW,
+ &sctp_valid_cookie_life_default, 0, sysctl_sctp_check, "IU",
+ SCTPCTL_VALID_COOKIE_LIFE_DESC);
-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_PROC(_net_inet_sctp, OID_AUTO, init_rtx_max, CTLTYPE_INT | CTLFLAG_RW,
+ &sctp_init_rtx_max_default, 0, sysctl_sctp_check, "IU",
+ SCTPCTL_INIT_RTX_MAX_DESC);
-SYSCTL_UINT(_net_inet_sctp, OID_AUTO, outgoing_streams, CTLFLAG_RW,
- &sctp_nr_outgoing_streams_default, 0,
- "Default number of outgoing streams");
+SYSCTL_PROC(_net_inet_sctp, OID_AUTO, assoc_rtx_max, CTLTYPE_INT | CTLFLAG_RW,
+ &sctp_assoc_rtx_max_default, 0, sysctl_sctp_check, "IU",
+ SCTPCTL_ASSOC_RTX_MAX_DESC);
-SYSCTL_UINT(_net_inet_sctp, OID_AUTO, cmt_on_off, CTLFLAG_RW,
- &sctp_cmt_on_off, 0,
- "CMT ON/OFF flag");
+SYSCTL_PROC(_net_inet_sctp, OID_AUTO, path_rtx_max, CTLTYPE_INT | CTLFLAG_RW,
+ &sctp_path_rtx_max_default, 0, sysctl_sctp_check, "IU",
+ SCTPCTL_PATH_RTX_MAX_DESC);
-SYSCTL_UINT(_net_inet_sctp, OID_AUTO, cmt_pf, CTLFLAG_RW,
- &sctp_cmt_pf, 0,
- "CMT PF type flag");
+SYSCTL_PROC(_net_inet_sctp, OID_AUTO, add_more_on_output, CTLTYPE_INT | CTLFLAG_RW,
+ &sctp_add_more_threshold, 0, sysctl_sctp_check, "IU",
+ SCTPCTL_ADD_MORE_ON_OUTPUT_DESC);
-SYSCTL_UINT(_net_inet_sctp, OID_AUTO, default_cc_module, CTLFLAG_RW,
- &sctp_default_cc_module, 0,
- "Default congestion control module");
+SYSCTL_PROC(_net_inet_sctp, OID_AUTO, outgoing_streams, CTLTYPE_INT | CTLFLAG_RW,
+ &sctp_nr_outgoing_streams_default, 0, sysctl_sctp_check, "IU",
+ SCTPCTL_OUTGOING_STREAMS_DESC);
+SYSCTL_PROC(_net_inet_sctp, OID_AUTO, cmt_on_off, CTLTYPE_INT | CTLFLAG_RW,
+ &sctp_cmt_on_off, 0, sysctl_sctp_check, "IU",
+ SCTPCTL_CMT_ON_OFF_DESC);
-SYSCTL_UINT(_net_inet_sctp, OID_AUTO, default_frag_interleave, CTLFLAG_RW,
- &sctp_default_frag_interleave, 0,
- SCTPCTL_DEFAULT_FRAG_INTERLEAVE_DESC);
-
-SYSCTL_UINT(_net_inet_sctp, OID_AUTO, cwnd_maxburst, CTLFLAG_RW,
- &sctp_use_cwnd_based_maxburst, 0,
- "Use a CWND adjusting maxburst");
+SYSCTL_PROC(_net_inet_sctp, OID_AUTO, cmt_use_dac, CTLTYPE_INT | CTLFLAG_RW,
+ &sctp_cmt_use_dac, 0, sysctl_sctp_check, "IU",
+ SCTPCTL_CMT_USE_DAC_DESC);
-SYSCTL_UINT(_net_inet_sctp, OID_AUTO, early_fast_retran, CTLFLAG_RW,
- &sctp_early_fr, 0,
- "Early Fast Retransmit with timer");
+SYSCTL_PROC(_net_inet_sctp, OID_AUTO, cmt_pf, CTLTYPE_INT | CTLFLAG_RW,
+ &sctp_cmt_pf, 0, sysctl_sctp_check, "IU",
+ SCTPCTL_CMT_PF_DESC);
-SYSCTL_UINT(_net_inet_sctp, OID_AUTO, deadlock_detect, CTLFLAG_RW,
- &sctp_says_check_for_deadlock, 0,
- "SMP Deadlock detection on/off");
+SYSCTL_PROC(_net_inet_sctp, OID_AUTO, cwnd_maxburst, CTLTYPE_INT | CTLFLAG_RW,
+ &sctp_use_cwnd_based_maxburst, 0, sysctl_sctp_check, "IU",
+ SCTPCTL_CWND_MAXBURST_DESC);
-SYSCTL_UINT(_net_inet_sctp, OID_AUTO, early_fast_retran_msec, CTLFLAG_RW,
- &sctp_early_fr_msec, 0,
- "Early Fast Retransmit minimum timer value");
+SYSCTL_PROC(_net_inet_sctp, OID_AUTO, early_fast_retran, CTLTYPE_INT | CTLFLAG_RW,
+ &sctp_early_fr, 0, sysctl_sctp_check, "IU",
+ SCTPCTL_EARLY_FAST_RETRAN_DESC);
-SYSCTL_UINT(_net_inet_sctp, OID_AUTO, asconf_auth_nochk, CTLFLAG_RW,
- &sctp_asconf_auth_nochk, 0,
- "Disable SCTP ASCONF AUTH requirement");
+SYSCTL_PROC(_net_inet_sctp, OID_AUTO, early_fast_retran_msec, CTLTYPE_INT | CTLFLAG_RW,
+ &sctp_early_fr_msec, 0, sysctl_sctp_check, "IU",
+ SCTPCTL_EARLY_FAST_RETRAN_MSEC_DESC);
-SYSCTL_UINT(_net_inet_sctp, OID_AUTO, auth_disable, CTLFLAG_RW,
- &sctp_auth_disable, 0,
- "Disable SCTP AUTH function");
+SYSCTL_PROC(_net_inet_sctp, OID_AUTO, asconf_auth_nochk, CTLTYPE_INT | CTLFLAG_RW,
+ &sctp_asconf_auth_nochk, 0, sysctl_sctp_check, "IU",
+ SCTPCTL_ASCONF_AUTH_NOCHK_DESC);
-SYSCTL_UINT(_net_inet_sctp, OID_AUTO, nat_friendly, CTLFLAG_RW,
- &sctp_nat_friendly, 0,
- "SCTP NAT friendly operation");
+SYSCTL_PROC(_net_inet_sctp, OID_AUTO, auth_disable, CTLTYPE_INT | CTLFLAG_RW,
+ &sctp_auth_disable, 0, sysctl_sctp_check, "IU",
+ SCTPCTL_AUTH_DISABLE_DESC);
-SYSCTL_INT(_net_inet_sctp, OID_AUTO, abc_l_var, CTLFLAG_RW,
- &sctp_L2_abc_variable, 0,
- "SCTP ABC max increase per SACK (L)");
+SYSCTL_PROC(_net_inet_sctp, OID_AUTO, nat_friendly, CTLTYPE_INT | CTLFLAG_RW,
+ &sctp_nat_friendly, 0, sysctl_sctp_check, "IU",
+ SCTPCTL_NAT_FRIENDLY_DESC);
-SYSCTL_INT(_net_inet_sctp, OID_AUTO, max_chained_mbufs, CTLFLAG_RW,
- &sctp_mbuf_threshold_count, 0,
- "Default max number of small mbufs on a chain");
+SYSCTL_PROC(_net_inet_sctp, OID_AUTO, abc_l_var, CTLTYPE_INT | CTLFLAG_RW,
+ &sctp_L2_abc_variable, 0, sysctl_sctp_check, "IU",
+ SCTPCTL_ABC_L_VAR_DESC);
-SYSCTL_UINT(_net_inet_sctp, OID_AUTO, cmt_use_dac, CTLFLAG_RW,
- &sctp_cmt_use_dac, 0,
- "CMT DAC ON/OFF flag");
+SYSCTL_PROC(_net_inet_sctp, OID_AUTO, max_chained_mbufs, CTLTYPE_INT | CTLFLAG_RW,
+ &sctp_mbuf_threshold_count, 0, sysctl_sctp_check, "IU",
+ SCTPCTL_MAX_CHAINED_MBUFS_DESC);
-SYSCTL_INT(_net_inet_sctp, OID_AUTO, do_sctp_drain, CTLFLAG_RW,
- &sctp_do_drain, 0,
- "Should SCTP respond to the drain calls");
+SYSCTL_PROC(_net_inet_sctp, OID_AUTO, do_sctp_drain, CTLTYPE_INT | CTLFLAG_RW,
+ &sctp_do_drain, 0, sysctl_sctp_check, "IU",
+ SCTPCTL_DO_SCTP_DRAIN_DESC);
-SYSCTL_INT(_net_inet_sctp, OID_AUTO, hb_max_burst, CTLFLAG_RW,
- &sctp_hb_maxburst, 0,
- "Confirmation Heartbeat max burst?");
+SYSCTL_PROC(_net_inet_sctp, OID_AUTO, hb_max_burst, CTLTYPE_INT | CTLFLAG_RW,
+ &sctp_hb_maxburst, 0, sysctl_sctp_check, "IU",
+ SCTPCTL_HB_MAX_BURST_DESC);
-SYSCTL_INT(_net_inet_sctp, OID_AUTO, abort_at_limit, CTLFLAG_RW,
- &sctp_abort_if_one_2_one_hits_limit, 0,
- "When one-2-one hits qlimit abort");
+SYSCTL_PROC(_net_inet_sctp, OID_AUTO, abort_at_limit, CTLTYPE_INT | CTLFLAG_RW,
+ &sctp_abort_if_one_2_one_hits_limit, 0, sysctl_sctp_check, "IU",
+ SCTPCTL_ABORT_AT_LIMIT_DESC);
-SYSCTL_INT(_net_inet_sctp, OID_AUTO, strict_data_order, CTLFLAG_RW,
- &sctp_strict_data_order, 0,
- "Enforce strict data ordering, abort if control inside data");
-
-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, strict_data_order, CTLTYPE_INT | CTLFLAG_RW,
+ &sctp_strict_data_order, 0, sysctl_sctp_check, "IU",
+ SCTPCTL_STRICT_DATA_ORDER_DESC);
-SYSCTL_PROC(_net_inet_sctp, OID_AUTO, assoclist, CTLFLAG_RD,
- 0, 0, sctp_assoclist,
- "S,xassoc", "List of active SCTP associations");
-
-SYSCTL_INT(_net_inet_sctp, OID_AUTO, min_residual, CTLFLAG_RW,
- &sctp_min_residual, 0,
+SYSCTL_PROC(_net_inet_sctp, OID_AUTO, min_residual, CTLTYPE_INT | CTLFLAG_RW,
+ &sctp_min_residual, 0, sysctl_sctp_check, "IU",
SCTPCTL_MIN_RESIDUAL_DESC);
-SYSCTL_INT(_net_inet_sctp, OID_AUTO, max_retran_chunk, CTLFLAG_RW,
- &sctp_max_retran_chunk, 0,
+SYSCTL_PROC(_net_inet_sctp, OID_AUTO, max_retran_chunk, CTLTYPE_INT | CTLFLAG_RW,
+ &sctp_max_retran_chunk, 0, sysctl_sctp_check, "IU",
SCTPCTL_MAX_RETRAN_CHUNK_DESC);
-SYSCTL_INT(_net_inet_sctp, OID_AUTO, sctp_logging, CTLFLAG_RW,
- &sctp_logging_level, 0,
+SYSCTL_PROC(_net_inet_sctp, OID_AUTO, logging, CTLTYPE_INT | CTLFLAG_RW,
+ &sctp_logging_level, 0, sysctl_sctp_check, "IU",
SCTPCTL_LOGGING_LEVEL_DESC);
+SYSCTL_PROC(_net_inet_sctp, OID_AUTO, default_cc_module, CTLTYPE_INT | CTLFLAG_RW,
+ &sctp_default_cc_module, 0, sysctl_sctp_check, "IU",
+ SCTPCTL_DEFAULT_CC_MODULE_DESC);
+
+SYSCTL_PROC(_net_inet_sctp, OID_AUTO, default_frag_interleave, CTLTYPE_INT | CTLFLAG_RW,
+ &sctp_default_frag_interleave, 0, sysctl_sctp_check, "IU",
+ SCTPCTL_DEFAULT_FRAG_INTERLEAVE_DESC);
+
#if defined(__FreeBSD__) || defined(SCTP_APPLE_MOBILITY_BASE)
-SYSCTL_INT(_net_inet_sctp, OID_AUTO, mobility_base, CTLFLAG_RW,
- &sctp_mobility_base, 0, "Enable SCTP Mobility");
+SYSCTL_PROC(_net_inet_sctp, OID_AUTO, mobility_base, CTLTYPE_INT | CTLFLAG_RW,
+ &sctp_mobility_base, 0, sysctl_sctp_check, "IU",
+ SCTPCTL_MOBILITY_BASE_DESC);
#endif
#if defined(__FreeBSD__) || defined(SCTP_APPLE_MOBILITY_FASTHANDOFF)
-SYSCTL_INT(_net_inet_sctp, OID_AUTO, mobility_fasthandoff, CTLFLAG_RW,
- &sctp_mobility_fasthandoff, 0, "Enable SCTP fast handoff");
+SYSCTL_PROC(_net_inet_sctp, OID_AUTO, mobility_fasthandoff, CTLTYPE_INT | CTLFLAG_RW,
+ &sctp_mobility_fasthandoff, 0, sysctl_sctp_check, "IU",
+ SCTPCTL_MOBILITY_FASTHANDOFF_DESC);
#endif
-
#ifdef SCTP_DEBUG
-SYSCTL_INT(_net_inet_sctp, OID_AUTO, debug, CTLFLAG_RW,
- &sctp_debug_on, 0, "Configure debug output");
+SYSCTL_PROC(_net_inet_sctp, OID_AUTO, debug, CTLTYPE_INT | CTLFLAG_RW,
+ &sctp_debug_on, 0, sysctl_sctp_check, "IU",
+ SCTPCTL_DEBUG_DESC);
#endif /* SCTP_DEBUG */
+
+
+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");
diff --git a/sys/netinet/sctp_sysctl.h b/sys/netinet/sctp_sysctl.h
index 573f46b..cb83f4e 100644
--- a/sys/netinet/sctp_sysctl.h
+++ b/sys/netinet/sctp_sysctl.h
@@ -278,78 +278,76 @@ __FBSDID("$FreeBSD$");
#define SCTPCTL_CMT_ON_OFF_MAX 1
#define SCTPCTL_CMT_ON_OFF_DEFAULT 0
+/* cmt_use_dac: CMT DAC on/off flag */
+#define SCTPCTL_CMT_USE_DAC 35
+#define SCTPCTL_CMT_USE_DAC_DESC "CMT DAC on/off flag"
+#define SCTPCTL_CMT_USE_DAC_MIN 0
+#define SCTPCTL_CMT_USE_DAC_MAX 1
+#define SCTPCTL_CMT_USE_DAC_DEFAULT 0
+
+/* JRS 5/2107 - CMT PF type flag */
+#define SCTPCTL_CMT_PF 36
+#define SCTPCTL_CMT_PF_DESC "CMT PF type flag"
+#define SCTPCTL_CMT_PF_MIN 0
+#define SCTPCTL_CMT_PF_MAX 2
+#define SCTPCTL_CMT_PF_DEFAULT 0
+
/* cwnd_maxburst: Use a CWND adjusting maxburst */
-#define SCTPCTL_CWND_MAXBURST 35
+#define SCTPCTL_CWND_MAXBURST 37
#define SCTPCTL_CWND_MAXBURST_DESC "Use a CWND adjusting maxburst"
#define SCTPCTL_CWND_MAXBURST_MIN 0
#define SCTPCTL_CWND_MAXBURST_MAX 1
#define SCTPCTL_CWND_MAXBURST_DEFAULT 1
/* early_fast_retran: Early Fast Retransmit with timer */
-#define SCTPCTL_EARLY_FAST_RETRAN 36
+#define SCTPCTL_EARLY_FAST_RETRAN 38
#define SCTPCTL_EARLY_FAST_RETRAN_DESC "Early Fast Retransmit with timer"
#define SCTPCTL_EARLY_FAST_RETRAN_MIN 0
#define SCTPCTL_EARLY_FAST_RETRAN_MAX 0xFFFFFFFF
#define SCTPCTL_EARLY_FAST_RETRAN_DEFAULT 0
-/* deadlock_detect: SMP Deadlock detection on/off */
-#define SCTPCTL_DEADLOCK_DETECT 37
-#define SCTPCTL_DEADLOCK_DETECT_DESC "SMP Deadlock detection on/off"
-#define SCTPCTL_DEADLOCK_DETECT_MIN 0
-#define SCTPCTL_DEADLOCK_DETECT_MAX 1
-#define SCTPCTL_DEADLOCK_DETECT_DEFAULT 0
-
/* early_fast_retran_msec: Early Fast Retransmit minimum timer value */
-#define SCTPCTL_EARLY_FAST_RETRAN_MSEC 38
+#define SCTPCTL_EARLY_FAST_RETRAN_MSEC 39
#define SCTPCTL_EARLY_FAST_RETRAN_MSEC_DESC "Early Fast Retransmit minimum timer value"
#define SCTPCTL_EARLY_FAST_RETRAN_MSEC_MIN 0
#define SCTPCTL_EARLY_FAST_RETRAN_MSEC_MAX 0xFFFFFFFF
#define SCTPCTL_EARLY_FAST_RETRAN_MSEC_DEFAULT SCTP_MINFR_MSEC_TIMER
/* asconf_auth_nochk: Disable SCTP ASCONF AUTH requirement */
-#define SCTPCTL_ASCONF_AUTH_NOCHK 39
+#define SCTPCTL_ASCONF_AUTH_NOCHK 40
#define SCTPCTL_ASCONF_AUTH_NOCHK_DESC "Disable SCTP ASCONF AUTH requirement"
#define SCTPCTL_ASCONF_AUTH_NOCHK_MIN 0
#define SCTPCTL_ASCONF_AUTH_NOCHK_MAX 1
#define SCTPCTL_ASCONF_AUTH_NOCHK_DEFAULT 0
/* auth_disable: Disable SCTP AUTH function */
-#define SCTPCTL_AUTH_DISABLE 40
+#define SCTPCTL_AUTH_DISABLE 41
#define SCTPCTL_AUTH_DISABLE_DESC "Disable SCTP AUTH function"
#define SCTPCTL_AUTH_DISABLE_MIN 0
#define SCTPCTL_AUTH_DISABLE_MAX 1
#define SCTPCTL_AUTH_DISABLE_DEFAULT 0
/* nat_friendly: SCTP NAT friendly operation */
-#define SCTPCTL_NAT_FRIENDLY 41
+#define SCTPCTL_NAT_FRIENDLY 42
#define SCTPCTL_NAT_FRIENDLY_DESC "SCTP NAT friendly operation"
#define SCTPCTL_NAT_FRIENDLY_MIN 0
#define SCTPCTL_NAT_FRIENDLY_MAX 1
#define SCTPCTL_NAT_FRIENDLY_DEFAULT 1
-
-
/* abc_l_var: SCTP ABC max increase per SACK (L) */
-#define SCTPCTL_ABC_L_VAR 42
+#define SCTPCTL_ABC_L_VAR 43
#define SCTPCTL_ABC_L_VAR_DESC "SCTP ABC max increase per SACK (L)"
#define SCTPCTL_ABC_L_VAR_MIN 0
#define SCTPCTL_ABC_L_VAR_MAX 0xFFFFFFFF
#define SCTPCTL_ABC_L_VAR_DEFAULT 1
/* max_chained_mbufs: Default max number of small mbufs on a chain */
-#define SCTPCTL_MAX_CHAINED_MBUFS 43
+#define SCTPCTL_MAX_CHAINED_MBUFS 44
#define SCTPCTL_MAX_CHAINED_MBUFS_DESC "Default max number of small mbufs on a chain"
#define SCTPCTL_MAX_CHAINED_MBUFS_MIN 0
#define SCTPCTL_MAX_CHAINED_MBUFS_MAX 0xFFFFFFFF
#define SCTPCTL_MAX_CHAINED_MBUFS_DEFAULT SCTP_DEFAULT_MBUFS_IN_CHAIN
-/* cmt_use_dac: CMT DAC on/off flag */
-#define SCTPCTL_CMT_USE_DAC 44
-#define SCTPCTL_CMT_USE_DAC_DESC "CMT DAC on/off flag"
-#define SCTPCTL_CMT_USE_DAC_MIN 0
-#define SCTPCTL_CMT_USE_DAC_MAX 1
-#define SCTPCTL_CMT_USE_DAC_DEFAULT 0
-
/* do_sctp_drain: Should SCTP respond to the drain calls */
#define SCTPCTL_DO_SCTP_DRAIN 45
#define SCTPCTL_DO_SCTP_DRAIN_DESC "Should SCTP respond to the drain calls"
@@ -359,7 +357,7 @@ __FBSDID("$FreeBSD$");
/* hb_max_burst: Confirmation Heartbeat max burst? */
#define SCTPCTL_HB_MAX_BURST 46
-#define SCTPCTL_HB_MAX_BURST_DESC "Confirmation Heartbeat max burst?"
+#define SCTPCTL_HB_MAX_BURST_DESC "Confirmation Heartbeat max burst"
#define SCTPCTL_HB_MAX_BURST_MIN 1
#define SCTPCTL_HB_MAX_BURST_MAX 0xFFFFFFFF
#define SCTPCTL_HB_MAX_BURST_DEFAULT SCTP_DEF_MAX_BURST
@@ -399,183 +397,43 @@ __FBSDID("$FreeBSD$");
#define SCTPCTL_LOGGING_LEVEL_MAX 0xffffffff
#define SCTPCTL_LOGGING_LEVEL_DEFAULT 0
-/* JRS 5/2107 - CMT PF type flag */
-#define SCTPCTL_CMT_PF 52
-#define SCTPCTL_CMT_PF_DESC "CMT PF type flag"
-#define SCTPCTL_CMT_PF_MIN 0
-#define SCTPCTL_CMT_PF_MAX 2
-#define SCTPCTL_CMT_PF_DEFAULT 0
-
/* JRS - default congestion control module sysctl */
-#define SCTPCTL_DEFAULT_CC_MODULE 53
+#define SCTPCTL_DEFAULT_CC_MODULE 52
#define SCTPCTL_DEFAULT_CC_MODULE_DESC "Default congestion control module"
#define SCTPCTL_DEFAULT_CC_MODULE_MIN 0
#define SCTPCTL_DEFAULT_CC_MODULE_MAX 2
#define SCTPCTL_DEFAULT_CC_MODULE_DEFAULT 0
-
/* RRS - default fragment interleave */
-#define SCTPCTL_DEFAULT_FRAG_INTERLEAVE 54
+#define SCTPCTL_DEFAULT_FRAG_INTERLEAVE 53
#define SCTPCTL_DEFAULT_FRAG_INTERLEAVE_DESC "Default fragment interleave level"
#define SCTPCTL_DEFAULT_FRAG_INTERLEAVE_MIN 0
#define SCTPCTL_DEFAULT_FRAG_INTERLEAVE_MAX 2
#define SCTPCTL_DEFAULT_FRAG_INTERLEAVE_DEFAULT 1
/* mobility_base: Enable SCTP mobility support */
-#define SCTPCTL_MOBILITY_BASE 55
+#define SCTPCTL_MOBILITY_BASE 54
#define SCTPCTL_MOBILITY_BASE_DESC "Enable SCTP base mobility"
#define SCTPCTL_MOBILITY_BASE_MIN 0
#define SCTPCTL_MOBILITY_BASE_MAX 1
#define SCTPCTL_MOBILITY_BASE_DEFAULT SCTP_DEFAULT_MOBILITY_BASE
/* mobility_fasthandoff: Enable SCTP fast handoff support */
-#define SCTPCTL_MOBILITY_FASTHANDOFF 56
+#define SCTPCTL_MOBILITY_FASTHANDOFF 55
#define SCTPCTL_MOBILITY_FASTHANDOFF_DESC "Enable SCTP fast handoff"
#define SCTPCTL_MOBILITY_FASTHANDOFF_MIN 0
#define SCTPCTL_MOBILITY_FASTHANDOFF_MAX 1
#define SCTPCTL_MOBILITY_FASTHANDOFF_DEFAULT SCTP_DEFAULT_MOBILITY_FASTHANDOFF
-
-#ifdef SCTP_DEBUG
+#if defined(SCTP_DEBUG)
/* debug: Configure debug output */
-#define SCTPCTL_DEBUG 57
+#define SCTPCTL_DEBUG 56
#define SCTPCTL_DEBUG_DESC "Configure debug output"
#define SCTPCTL_DEBUG_MIN 0
#define SCTPCTL_DEBUG_MAX 0xFFFFFFFF
#define SCTPCTL_DEBUG_DEFAULT 0
-
-
-#define SCTPCTL_MAXID 57
-#else
-#define SCTPCTL_MAXID 58
#endif
-/*
- * Names for SCTP sysctl objects variables.
- * Must match the OIDs above.
- */
-#ifdef SCTP_DEBUG
-#define SCTPCTL_NAMES { \
- { 0, 0 }, \
- { "sendspace", CTLTYPE_INT }, \
- { "recvspace", CTLTYPE_INT }, \
- { "autoasconf", CTLTYPE_INT }, \
- { "ecn_enable", CTLTYPE_INT }, \
- { "ecn_nonce", CTLTYPE_INT }, \
- { "strict_sack", CTLTYPE_INT }, \
- { "looback_nocsum", CTLTYPE_INT }, \
- { "strict_init", CTLTYPE_INT }, \
- { "peer_chkoh", CTLTYPE_INT }, \
- { "maxburst", CTLTYPE_INT }, \
- { "maxchunks", CTLTYPE_INT }, \
- { "delayed_sack_time", CTLTYPE_INT }, \
- { "sack_freq", CTLTYPE_INT }, \
- { "heartbeat_interval", CTLTYPE_INT }, \
- { "pmtu_raise_time", CTLTYPE_INT }, \
- { "shutdown_guard_time", CTLTYPE_INT }, \
- { "secret_lifetime", CTLTYPE_INT }, \
- { "rto_max", CTLTYPE_INT }, \
- { "rto_min", CTLTYPE_INT }, \
- { "rto_initial", CTLTYPE_INT }, \
- { "init_rto_max", CTLTYPE_INT }, \
- { "valid_cookie_life", CTLTYPE_INT }, \
- { "init_rtx_max", CTLTYPE_INT }, \
- { "assoc_rtx_max", CTLTYPE_INT }, \
- { "path_rtx_max", CTLTYPE_INT }, \
- { "outgoing_streams", CTLTYPE_INT }, \
- { "cmt_on_off", CTLTYPE_INT }, \
- { "cmt_on_pf", CTLTYPE_INT }, \
- { "default_cc_module", CTLTYPE_INT }, \
- { "cwnd_maxburst", CTLTYPE_INT }, \
- { "early_fast_retran", CTLTYPE_INT }, \
- { "deadlock_detect", CTLTYPE_INT }, \
- { "early_fast_retran_msec", CTLTYPE_INT }, \
- { "asconf_auth_nochk", CTLTYPE_INT }, \
- { "auth_disable", CTLTYPE_INT }, \
- { "nat_friendly", CTLTYPE_INT }, \
- { "abc_l_var", CTLTYPE_INT }, \
- { "max_mbuf_chain", CTLTYPE_INT }, \
- { "cmt_use_dac", CTLTYPE_INT }, \
- { "do_sctp_drain", CTLTYPE_INT }, \
- { "warm_crc_table", CTLTYPE_INT }, \
- { "abort_at_limit", CTLTYPE_INT }, \
- { "strict_data_order", CTLTYPE_INT }, \
- { "tcbhashsize", CTLTYPE_INT }, \
- { "pcbhashsize", CTLTYPE_INT }, \
- { "chunkscale", CTLTYPE_INT }, \
- { "min_split_point", CTLTYPE_INT }, \
- { "add_more_on_output", CTLTYPE_INT }, \
- { "sys_resource", CTLTYPE_INT }, \
- { "asoc_resource", CTLTYPE_INT }, \
- { "min_residual", CTLTYPE_INT }, \
- { "max_retran_chunk", CTLTYPE_INT }, \
- { "sctp_logging", CTLTYPE_INT }, \
- { "frag_interleave", CTLTYPE_INT }, \
- { "mobility_base", CTLTYPE_INT }, \
- { "mobility_fasthandoff", CTLTYPE_INT }, \
- { "debug", CTLTYPE_INT }, \
-}
-#else
-#define SCTPCTL_NAMES { \
- { 0, 0 }, \
- { "sendspace", CTLTYPE_INT }, \
- { "recvspace", CTLTYPE_INT }, \
- { "autoasconf", CTLTYPE_INT }, \
- { "ecn_enable", CTLTYPE_INT }, \
- { "ecn_nonce", CTLTYPE_INT }, \
- { "strict_sack", CTLTYPE_INT }, \
- { "looback_nocsum", CTLTYPE_INT }, \
- { "strict_init", CTLTYPE_INT }, \
- { "peer_chkoh", CTLTYPE_INT }, \
- { "maxburst", CTLTYPE_INT }, \
- { "maxchunks", CTLTYPE_INT }, \
- { "delayed_sack_time", CTLTYPE_INT }, \
- { "sack_freq", CTLTYPE_INT }, \
- { "heartbeat_interval", CTLTYPE_INT }, \
- { "pmtu_raise_time", CTLTYPE_INT }, \
- { "shutdown_guard_time", CTLTYPE_INT }, \
- { "secret_lifetime", CTLTYPE_INT }, \
- { "rto_max", CTLTYPE_INT }, \
- { "rto_min", CTLTYPE_INT }, \
- { "rto_initial", CTLTYPE_INT }, \
- { "init_rto_max", CTLTYPE_INT }, \
- { "valid_cookie_life", CTLTYPE_INT }, \
- { "init_rtx_max", CTLTYPE_INT }, \
- { "assoc_rtx_max", CTLTYPE_INT }, \
- { "path_rtx_max", CTLTYPE_INT }, \
- { "outgoing_streams", CTLTYPE_INT }, \
- { "cmt_on_off", CTLTYPE_INT }, \
- { "cmt_on_pf", CTLTYPE_INT }, \
- { "default_cc_module", CTLTYPE_INT }, \
- { "cwnd_maxburst", CTLTYPE_INT }, \
- { "early_fast_retran", CTLTYPE_INT }, \
- { "deadlock_detect", CTLTYPE_INT }, \
- { "early_fast_retran_msec", CTLTYPE_INT }, \
- { "asconf_auth_nochk", CTLTYPE_INT }, \
- { "auth_disable", CTLTYPE_INT }, \
- { "nat_friendly", CTLTYPE_INT }, \
- { "abc_l_var", CTLTYPE_INT }, \
- { "max_mbuf_chain", CTLTYPE_INT }, \
- { "cmt_use_dac", CTLTYPE_INT }, \
- { "do_sctp_drain", CTLTYPE_INT }, \
- { "warm_crc_table", CTLTYPE_INT }, \
- { "abort_at_limit", CTLTYPE_INT }, \
- { "strict_data_order", CTLTYPE_INT }, \
- { "tcbhashsize", CTLTYPE_INT }, \
- { "pcbhashsize", CTLTYPE_INT }, \
- { "chunkscale", CTLTYPE_INT }, \
- { "min_split_point", CTLTYPE_INT }, \
- { "add_more_on_output", CTLTYPE_INT }, \
- { "sys_resource", CTLTYPE_INT }, \
- { "asoc_resource", CTLTYPE_INT }, \
- { "min_residual", CTLTYPE_INT }, \
- { "max_retran_chunk", CTLTYPE_INT }, \
- { "sctp_logging", CTLTYPE_INT }, \
- { "frag_interleave", CTLTYPE_INT }, \
- { "mobility_base", CTLTYPE_INT }, \
- { "mobility_fasthandoff", CTLTYPE_INT }, \
-}
-#endif
#if defined(_KERNEL)
@@ -617,24 +475,18 @@ extern uint32_t sctp_path_rtx_max_default;
extern uint32_t sctp_add_more_threshold;
extern uint32_t sctp_nr_outgoing_streams_default;
extern uint32_t sctp_cmt_on_off;
+extern uint32_t sctp_cmt_use_dac;
/* JRS 5/21/07 - CMT PF type flag variables */
extern uint32_t sctp_cmt_pf;
-
-/* JRS - Variable for the default congestion control module */
-extern uint32_t sctp_default_cc_module;
-extern uint32_t sctp_default_frag_interleave;
extern uint32_t sctp_use_cwnd_based_maxburst;
extern uint32_t sctp_early_fr;
-extern uint32_t sctp_use_rttvar_cc;
-extern uint32_t sctp_says_check_for_deadlock;
extern uint32_t sctp_early_fr_msec;
extern uint32_t sctp_asconf_auth_nochk;
extern uint32_t sctp_auth_disable;
extern uint32_t sctp_nat_friendly;
extern uint32_t sctp_L2_abc_variable;
extern uint32_t sctp_mbuf_threshold_count;
-extern uint32_t sctp_cmt_use_dac;
extern uint32_t sctp_do_drain;
extern uint32_t sctp_hb_maxburst;
extern uint32_t sctp_abort_if_one_2_one_hits_limit;
@@ -642,6 +494,10 @@ extern uint32_t sctp_strict_data_order;
extern uint32_t sctp_min_residual;
extern uint32_t sctp_max_retran_chunk;
extern uint32_t sctp_logging_level;
+
+/* JRS - Variable for the default congestion control module */
+extern uint32_t sctp_default_cc_module;
+extern uint32_t sctp_default_frag_interleave;
extern uint32_t sctp_mobility_base;
extern uint32_t sctp_mobility_fasthandoff;
@@ -652,8 +508,7 @@ extern uint32_t sctp_debug_on;
extern struct sctpstat sctpstat;
-
-#ifdef SYSCTL_DECL
+#if defined(SYSCTL_DECL)
SYSCTL_DECL(_net_inet_sctp);
#endif
diff --git a/sys/netinet/sctp_timer.c b/sys/netinet/sctp_timer.c
index 50550f8..b9d4b62 100644
--- a/sys/netinet/sctp_timer.c
+++ b/sys/netinet/sctp_timer.c
@@ -1388,6 +1388,24 @@ sctp_asconf_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
return (0);
}
+/* Mobility adaptation */
+int
+sctp_delete_prim_timer(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
+ struct sctp_nets *net)
+{
+ if (stcb->asoc.deleted_primary == NULL) {
+ SCTPDBG(SCTP_DEBUG_ASCONF1, "delete_prim_timer: deleted_primary is not stored...\n");
+ sctp_mobility_feature_off(inp, SCTP_MOBILITY_PRIM_DELETED);
+ return (0);
+ }
+ SCTPDBG(SCTP_DEBUG_ASCONF1, "delete_prim_timer: finished to keep deleted primary ");
+ SCTPDBG_ADDR(SCTP_DEBUG_ASCONF1, &stcb->asoc.deleted_primary->ro._l_addr.sa);
+ sctp_free_remote_addr(stcb->asoc.deleted_primary);
+ stcb->asoc.deleted_primary = NULL;
+ sctp_mobility_feature_off(inp, SCTP_MOBILITY_PRIM_DELETED);
+ return (0);
+}
+
/*
* For the shutdown and shutdown-ack, we do not keep one around on the
* control queue. This means we must generate a new one and call the general
diff --git a/sys/netinet/sctp_timer.h b/sys/netinet/sctp_timer.h
index 425d748..0a0f2f2 100644
--- a/sys/netinet/sctp_timer.h
+++ b/sys/netinet/sctp_timer.h
@@ -87,6 +87,10 @@ int
sctp_asconf_timer(struct sctp_inpcb *, struct sctp_tcb *,
struct sctp_nets *);
+int
+sctp_delete_prim_timer(struct sctp_inpcb *, struct sctp_tcb *,
+ struct sctp_nets *);
+
void
sctp_autoclose_timer(struct sctp_inpcb *, struct sctp_tcb *,
struct sctp_nets *net);
diff --git a/sys/netinet/sctp_uio.h b/sys/netinet/sctp_uio.h
index 56d6199..477ef58 100644
--- a/sys/netinet/sctp_uio.h
+++ b/sys/netinet/sctp_uio.h
@@ -41,7 +41,6 @@ __FBSDID("$FreeBSD$");
#endif
#include <sys/types.h>
#include <sys/socket.h>
-#include <sys/time.h>
#include <netinet/in.h>
typedef uint32_t sctp_assoc_t;
@@ -743,6 +742,11 @@ struct sctp_cwnd_log_req {
struct sctp_cwnd_log log[0];
};
+struct sctp_timeval {
+ uint32_t tv_sec;
+ uint32_t tv_usec;
+};
+
struct sctpstat {
/* MIB according to RFC 3873 */
uint32_t sctps_currestab; /* sctpStats 1 (Gauge32) */
@@ -845,6 +849,8 @@ struct sctpstat {
* fired */
uint32_t sctps_timoasconf; /* Number of times an asconf timer
* fired */
+ uint32_t sctps_timodelprim; /* Number of times a prim_deleted
+ * timer fired */
uint32_t sctps_timoautoclose; /* Number of times auto close timer
* fired */
uint32_t sctps_timoassockill; /* Number of asoc free timers expired */
@@ -921,7 +927,8 @@ struct sctpstat {
uint32_t sctps_fwdtsn_map_over; /* number of map array over-runs via
* fwd-tsn's */
- struct timeval sctps_discontinuitytime; /* sctpStats 18 (TimeStamp) */
+ struct sctp_timeval sctps_discontinuitytime; /* sctpStats 18
+ * (TimeStamp) */
};
#define SCTP_STAT_INCR(_x) SCTP_STAT_INCR_BY(_x,1)
@@ -984,14 +991,14 @@ struct xsctp_tcb {
uint32_t refcnt;
uint16_t local_port; /* sctpAssocEntry 3 */
uint16_t remote_port; /* sctpAssocEntry 4 */
- struct timeval start_time; /* sctpAssocEntry 16 */
- struct timeval discontinuity_time; /* sctpAssocEntry 17 */
+ struct sctp_timeval start_time; /* sctpAssocEntry 16 */
+ struct sctp_timeval discontinuity_time; /* sctpAssocEntry 17 */
};
struct xsctp_laddr {
union sctp_sockstore address; /* sctpAssocLocalAddrEntry 1/2 */
uint32_t last;
- struct timeval start_time; /* sctpAssocLocalAddrEntry 3 */
+ struct sctp_timeval start_time; /* sctpAssocLocalAddrEntry 3 */
};
struct xsctp_raddr {
@@ -1007,7 +1014,7 @@ struct xsctp_raddr {
uint8_t active; /* sctpAssocLocalRemEntry 3 */
uint8_t confirmed; /* */
uint8_t heartbeat_enabled; /* sctpAssocLocalRemEntry 4 */
- struct timeval start_time; /* sctpAssocLocalRemEntry 8 */
+ struct sctp_timeval start_time; /* sctpAssocLocalRemEntry 8 */
};
/*
diff --git a/sys/netinet/sctp_usrreq.c b/sys/netinet/sctp_usrreq.c
index bf11663..77f15ae 100644
--- a/sys/netinet/sctp_usrreq.c
+++ b/sys/netinet/sctp_usrreq.c
@@ -223,7 +223,7 @@ sctp_notify_mbuf(struct sctp_inpcb *inp,
void
sctp_notify(struct sctp_inpcb *inp,
- int error,
+ struct ip *ip,
struct sctphdr *sh,
struct sockaddr *to,
struct sctp_tcb *stcb,
@@ -234,110 +234,103 @@ sctp_notify(struct sctp_inpcb *inp,
#endif
/* protection */
+ int reason;
+ struct icmp *icmph;
+
+
if ((inp == NULL) || (stcb == NULL) || (net == NULL) ||
(sh == NULL) || (to == NULL)) {
+ if (stcb)
+ SCTP_TCB_UNLOCK(stcb);
return;
}
/* First job is to verify the vtag matches what I would send */
if (ntohl(sh->v_tag) != (stcb->asoc.peer_vtag)) {
+ SCTP_TCB_UNLOCK(stcb);
return;
}
- /* FIX ME FIX ME PROTOPT i.e. no SCTP should ALWAYS be an ABORT */
+ icmph = (struct icmp *)((caddr_t)ip - (sizeof(struct icmp) -
+ sizeof(struct ip)));
+ if (icmph->icmp_type != ICMP_UNREACH) {
+ /* We only care about unreachable */
+ SCTP_TCB_UNLOCK(stcb);
+ return;
+ }
+ if ((icmph->icmp_code == ICMP_UNREACH_NET) ||
+ (icmph->icmp_code == ICMP_UNREACH_HOST) ||
+ (icmph->icmp_code == ICMP_UNREACH_NET_UNKNOWN) ||
+ (icmph->icmp_code == ICMP_UNREACH_HOST_UNKNOWN) ||
+ (icmph->icmp_code == ICMP_UNREACH_ISOLATED) ||
+ (icmph->icmp_code == ICMP_UNREACH_NET_PROHIB) ||
+ (icmph->icmp_code == ICMP_UNREACH_HOST_PROHIB) ||
+ (icmph->icmp_code == ICMP_UNREACH_FILTER_PROHIB)) {
- if ((error == EHOSTUNREACH) || /* Host is not reachable */
- (error == EHOSTDOWN) || /* Host is down */
- (error == ECONNREFUSED) || /* Host refused the connection, (not
- * an abort?) */
- (error == ENOPROTOOPT) /* SCTP is not present on host */
- ) {
/*
* Hmm reachablity problems we must examine closely. If its
* not reachable, we may have lost a network. Or if there is
* NO protocol at the other end named SCTP. well we consider
* it a OOTB abort.
*/
- if ((error == EHOSTUNREACH) || (error == EHOSTDOWN)) {
- if (net->dest_state & SCTP_ADDR_REACHABLE) {
- /* Ok that destination is NOT reachable */
- SCTP_PRINTF("ICMP (thresh %d/%d) takes interface %p down\n",
- net->error_count,
- net->failure_threshold,
- net);
-
- net->dest_state &= ~SCTP_ADDR_REACHABLE;
- net->dest_state |= SCTP_ADDR_NOT_REACHABLE;
- /*
- * JRS 5/14/07 - If a destination is
- * unreachable, the PF bit is turned off.
- * This allows an unambiguous use of the PF
- * bit for destinations that are reachable
- * but potentially failed. If the
- * destination is set to the unreachable
- * state, also set the destination to the PF
- * state.
- */
- /*
- * Add debug message here if destination is
- * not in PF state.
- */
- /* Stop any running T3 timers here? */
- if (sctp_cmt_on_off && sctp_cmt_pf) {
- net->dest_state &= ~SCTP_ADDR_PF;
- SCTPDBG(SCTP_DEBUG_TIMER4, "Destination %p moved from PF to unreachable.\n",
- net);
- }
- net->error_count = net->failure_threshold + 1;
- sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN,
- stcb, SCTP_FAILED_THRESHOLD,
- (void *)net, SCTP_SO_NOT_LOCKED);
- }
- if (stcb) {
- SCTP_TCB_UNLOCK(stcb);
- }
- } else {
+ if (net->dest_state & SCTP_ADDR_REACHABLE) {
+ /* Ok that destination is NOT reachable */
+ SCTP_PRINTF("ICMP (thresh %d/%d) takes interface %p down\n",
+ net->error_count,
+ net->failure_threshold,
+ net);
+
+ net->dest_state &= ~SCTP_ADDR_REACHABLE;
+ net->dest_state |= SCTP_ADDR_NOT_REACHABLE;
/*
- * Here the peer is either playing tricks on us,
- * including an address that belongs to someone who
- * does not support SCTP OR was a userland
- * implementation that shutdown and now is dead. In
- * either case treat it like a OOTB abort with no
- * TCB
+ * JRS 5/14/07 - If a destination is unreachable,
+ * the PF bit is turned off. This allows an
+ * unambiguous use of the PF bit for destinations
+ * that are reachable but potentially failed. If the
+ * destination is set to the unreachable state, also
+ * set the destination to the PF state.
*/
- sctp_abort_notification(stcb, SCTP_PEER_FAULTY, SCTP_SO_NOT_LOCKED);
+ /*
+ * Add debug message here if destination is not in
+ * PF state.
+ */
+ /* Stop any running T3 timers here? */
+ if (sctp_cmt_on_off && sctp_cmt_pf) {
+ net->dest_state &= ~SCTP_ADDR_PF;
+ SCTPDBG(SCTP_DEBUG_TIMER4, "Destination %p moved from PF to unreachable.\n",
+ net);
+ }
+ net->error_count = net->failure_threshold + 1;
+ sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN,
+ stcb, SCTP_FAILED_THRESHOLD,
+ (void *)net, SCTP_SO_NOT_LOCKED);
+ }
+ SCTP_TCB_UNLOCK(stcb);
+ } else if ((icmph->icmp_code == ICMP_UNREACH_PROTOCOL) ||
+ (icmph->icmp_code == ICMP_UNREACH_PORT)) {
+ /*
+ * Here the peer is either playing tricks on us, including
+ * an address that belongs to someone who does not support
+ * SCTP OR was a userland implementation that shutdown and
+ * now is dead. In either case treat it like a OOTB abort
+ * with no TCB
+ */
+ reason = SCTP_PEER_FAULTY;
+ sctp_abort_notification(stcb, reason, 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);
+ 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);
+ (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.
- */
+ 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 */
- }
+ /* no need to unlock here, since the TCB is gone */
} else {
- /* Send all others to the app */
- if (stcb) {
- SCTP_TCB_UNLOCK(stcb);
- }
- if (inp->sctp_socket) {
-#ifdef SCTP_LOCK_LOGGING
- if (sctp_logging_level & SCTP_LOCK_LOGGING_ENABLE) {
- sctp_log_lock(inp, stcb, SCTP_LOG_LOCK_SOCK);
- }
-#endif
- SOCK_LOCK(inp->sctp_socket);
- inp->sctp_socket->so_error = error;
- sctp_sowwakeup(inp, inp->sctp_socket);
- SOCK_UNLOCK(inp->sctp_socket);
- }
+ SCTP_TCB_UNLOCK(stcb);
}
}
@@ -388,14 +381,7 @@ sctp_ctlinput(cmd, sa, vip)
&inp, &net, 1, vrf_id);
if (stcb != NULL && inp && (inp->sctp_socket != NULL)) {
if (cmd != PRC_MSGSIZE) {
- int cm;
-
- if (cmd == PRC_HOSTDEAD) {
- cm = EHOSTUNREACH;
- } else {
- cm = inetctlerrmap[cmd];
- }
- sctp_notify(inp, cm, sh,
+ sctp_notify(inp, ip, sh,
(struct sockaddr *)&to, stcb,
net);
} else {
@@ -1070,6 +1056,9 @@ sctp_fill_user_address(struct sockaddr_storage *ss, struct sockaddr *sa)
+/*
+ * NOTE: assumes addr lock is held
+ */
static size_t
sctp_fill_up_addresses_vrf(struct sctp_inpcb *inp,
struct sctp_tcb *stcb,
@@ -1235,12 +1224,17 @@ sctp_fill_up_addresses(struct sctp_inpcb *inp,
{
size_t size = 0;
+ SCTP_IPI_ADDR_LOCK();
/* fill up addresses for the endpoint's default vrf */
size = sctp_fill_up_addresses_vrf(inp, stcb, limit, sas,
inp->def_vrf_id);
+ SCTP_IPI_ADDR_UNLOCK();
return (size);
}
+/*
+ * NOTE: assumes addr lock is held
+ */
static int
sctp_count_max_addresses_vrf(struct sctp_inpcb *inp, uint32_t vrf_id)
{
@@ -1297,8 +1291,10 @@ sctp_count_max_addresses(struct sctp_inpcb *inp)
{
int cnt = 0;
+ SCTP_IPI_ADDR_LOCK();
/* count addresses for the endpoint's default VRF */
cnt = sctp_count_max_addresses_vrf(inp, inp->def_vrf_id);
+ SCTP_IPI_ADDR_UNLOCK();
return (cnt);
}
@@ -1655,9 +1651,9 @@ flags_out:
error = 0;
}
#endif
- if (error)
+ if (error) {
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
-
+ }
*optsize = sizeof(*av);
}
break;
@@ -3785,7 +3781,7 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
struct sctp_ifa *ifa;
ifa = sctp_find_ifa_by_addr((struct sockaddr *)&sspp->sspp_addr,
- stcb->asoc.vrf_id, 0);
+ stcb->asoc.vrf_id, SCTP_ADDR_NOT_LOCKED);
if (ifa == NULL) {
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
error = EINVAL;
diff --git a/sys/netinet/sctp_var.h b/sys/netinet/sctp_var.h
index aa847ed..8bc6ffd 100644
--- a/sys/netinet/sctp_var.h
+++ b/sys/netinet/sctp_var.h
@@ -307,7 +307,7 @@ void sctp_pcbinfo_cleanup(void);
int sctp_shutdown __P((struct socket *));
void sctp_notify
-__P((struct sctp_inpcb *, int, struct sctphdr *,
+__P((struct sctp_inpcb *, struct ip *ip, struct sctphdr *,
struct sockaddr *, struct sctp_tcb *,
struct sctp_nets *));
diff --git a/sys/netinet/sctputil.c b/sys/netinet/sctputil.c
index 31b9c06..05ab850 100644
--- a/sys/netinet/sctputil.c
+++ b/sys/netinet/sctputil.c
@@ -806,7 +806,7 @@ sctp_fill_random_store(struct sctp_pcb *m)
}
uint32_t
-sctp_select_initial_TSN(struct sctp_pcb *m)
+sctp_select_initial_TSN(struct sctp_pcb *inp)
{
/*
* A true implementation should use random selection process to get
@@ -815,27 +815,36 @@ sctp_select_initial_TSN(struct sctp_pcb *m)
*/
uint32_t x, *xp;
uint8_t *p;
+ int store_at, new_store;
- if (m->initial_sequence_debug != 0) {
+ if (inp->initial_sequence_debug != 0) {
uint32_t ret;
- ret = m->initial_sequence_debug;
- m->initial_sequence_debug++;
+ ret = inp->initial_sequence_debug;
+ inp->initial_sequence_debug++;
return (ret);
}
- if ((m->store_at + sizeof(u_long)) > SCTP_SIGNATURE_SIZE) {
+retry:
+ store_at = inp->store_at;
+ new_store = store_at + sizeof(uint32_t);
+ if (new_store >= (SCTP_SIGNATURE_SIZE - 3)) {
+ new_store = 0;
+ }
+ if (!atomic_cmpset_int(&inp->store_at, store_at, new_store)) {
+ goto retry;
+ }
+ if (new_store == 0) {
/* Refill the random store */
- sctp_fill_random_store(m);
+ sctp_fill_random_store(inp);
}
- p = &m->random_store[(int)m->store_at];
+ p = &inp->random_store[store_at];
xp = (uint32_t *) p;
x = *xp;
- m->store_at += sizeof(uint32_t);
return (x);
}
uint32_t
-sctp_select_a_tag(struct sctp_inpcb *m)
+sctp_select_a_tag(struct sctp_inpcb *inp)
{
u_long x, not_done;
struct timeval now;
@@ -843,12 +852,12 @@ sctp_select_a_tag(struct sctp_inpcb *m)
(void)SCTP_GETTIME_TIMEVAL(&now);
not_done = 1;
while (not_done) {
- x = sctp_select_initial_TSN(&m->sctp_ep);
+ x = sctp_select_initial_TSN(&inp->sctp_ep);
if (x == 0) {
/* we never use 0 */
continue;
}
- if (sctp_is_vtag_good(m, x, &now)) {
+ if (sctp_is_vtag_good(inp, x, &now)) {
not_done = 0;
}
}
@@ -1758,6 +1767,15 @@ sctp_timeout_handler(void *t)
#endif
sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_ASCONF_TMR, SCTP_SO_NOT_LOCKED);
break;
+ case SCTP_TIMER_TYPE_PRIM_DELETED:
+ if ((stcb == NULL) || (inp == NULL)) {
+ break;
+ }
+ if (sctp_delete_prim_timer(inp, stcb, net)) {
+ goto out_decr;
+ }
+ SCTP_STAT_INCR(sctps_timodelprim);
+ break;
case SCTP_TIMER_TYPE_AUTOCLOSE:
if ((stcb == NULL) || (inp == NULL)) {
@@ -2152,6 +2170,13 @@ sctp_timer_start(int t_type, struct sctp_inpcb *inp, struct sctp_tcb *stcb,
}
tmr = &stcb->asoc.asconf_timer;
break;
+ case SCTP_TIMER_TYPE_PRIM_DELETED:
+ if ((stcb == NULL) || (net != NULL)) {
+ return;
+ }
+ to_ticks = MSEC_TO_TICKS(stcb->asoc.initial_rto);
+ tmr = &stcb->asoc.delete_prim_timer;
+ break;
case SCTP_TIMER_TYPE_AUTOCLOSE:
if (stcb == NULL) {
return;
@@ -2330,6 +2355,12 @@ sctp_timer_stop(int t_type, struct sctp_inpcb *inp, struct sctp_tcb *stcb,
}
tmr = &stcb->asoc.asconf_timer;
break;
+ case SCTP_TIMER_TYPE_PRIM_DELETED:
+ if (stcb == NULL) {
+ return;
+ }
+ tmr = &stcb->asoc.delete_prim_timer;
+ break;
case SCTP_TIMER_TYPE_AUTOCLOSE:
if (stcb == NULL) {
return;
@@ -5629,6 +5660,11 @@ wait_some_more:
SOCKBUF_LOCK(&so->so_rcv);
hold_sblock = 1;
}
+ if ((copied_so_far) && (control->length == 0) &&
+ (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE))
+ ) {
+ goto release;
+ }
if (so->so_rcv.sb_cc <= control->held_length) {
error = sbwait(&so->so_rcv);
if (error) {
@@ -6339,9 +6375,11 @@ sctp_local_addr_count(struct sctp_tcb *stcb)
ipv4_addr_legal = 1;
}
+ SCTP_IPI_ADDR_LOCK();
vrf = sctp_find_vrf(stcb->asoc.vrf_id);
if (vrf == NULL) {
/* no vrf, no addresses */
+ SCTP_IPI_ADDR_UNLOCK();
return (0);
}
if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) {
@@ -6417,6 +6455,7 @@ sctp_local_addr_count(struct sctp_tcb *stcb)
count++;
}
}
+ SCTP_IPI_ADDR_UNLOCK();
return (count);
}
diff --git a/sys/netinet6/sctp6_usrreq.c b/sys/netinet6/sctp6_usrreq.c
index 2d4c82c..89bb51c 100644
--- a/sys/netinet6/sctp6_usrreq.c
+++ b/sys/netinet6/sctp6_usrreq.c
@@ -315,13 +315,124 @@ out:
}
+static void
+sctp6_notify(struct sctp_inpcb *inp,
+ struct icmp6_hdr *icmph,
+ struct sctphdr *sh,
+ struct sockaddr *to,
+ struct sctp_tcb *stcb,
+ struct sctp_nets *net)
+{
+#if defined (__APPLE__) || defined(SCTP_SO_LOCK_TESTING)
+ struct socket *so;
+
+#endif
+ /* protection */
+ int reason;
+
+
+ if ((inp == NULL) || (stcb == NULL) || (net == NULL) ||
+ (sh == NULL) || (to == NULL)) {
+ if (stcb)
+ SCTP_TCB_UNLOCK(stcb);
+ return;
+ }
+ /* First job is to verify the vtag matches what I would send */
+ if (ntohl(sh->v_tag) != (stcb->asoc.peer_vtag)) {
+ SCTP_TCB_UNLOCK(stcb);
+ return;
+ }
+ if (icmph->icmp6_type != ICMP_UNREACH) {
+ /* We only care about unreachable */
+ SCTP_TCB_UNLOCK(stcb);
+ return;
+ }
+ if ((icmph->icmp6_code == ICMP_UNREACH_NET) ||
+ (icmph->icmp6_code == ICMP_UNREACH_HOST) ||
+ (icmph->icmp6_code == ICMP_UNREACH_NET_UNKNOWN) ||
+ (icmph->icmp6_code == ICMP_UNREACH_HOST_UNKNOWN) ||
+ (icmph->icmp6_code == ICMP_UNREACH_ISOLATED) ||
+ (icmph->icmp6_code == ICMP_UNREACH_NET_PROHIB) ||
+ (icmph->icmp6_code == ICMP_UNREACH_HOST_PROHIB) ||
+ (icmph->icmp6_code == ICMP_UNREACH_FILTER_PROHIB)) {
+
+ /*
+ * Hmm reachablity problems we must examine closely. If its
+ * not reachable, we may have lost a network. Or if there is
+ * NO protocol at the other end named SCTP. well we consider
+ * it a OOTB abort.
+ */
+ if (net->dest_state & SCTP_ADDR_REACHABLE) {
+ /* Ok that destination is NOT reachable */
+ SCTP_PRINTF("ICMP (thresh %d/%d) takes interface %p down\n",
+ net->error_count,
+ net->failure_threshold,
+ net);
+
+ net->dest_state &= ~SCTP_ADDR_REACHABLE;
+ net->dest_state |= SCTP_ADDR_NOT_REACHABLE;
+ /*
+ * JRS 5/14/07 - If a destination is unreachable,
+ * the PF bit is turned off. This allows an
+ * unambiguous use of the PF bit for destinations
+ * that are reachable but potentially failed. If the
+ * destination is set to the unreachable state, also
+ * set the destination to the PF state.
+ */
+ /*
+ * Add debug message here if destination is not in
+ * PF state.
+ */
+ /* Stop any running T3 timers here? */
+ if (sctp_cmt_on_off && sctp_cmt_pf) {
+ net->dest_state &= ~SCTP_ADDR_PF;
+ SCTPDBG(SCTP_DEBUG_TIMER4, "Destination %p moved from PF to unreachable.\n",
+ net);
+ }
+ net->error_count = net->failure_threshold + 1;
+ sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN,
+ stcb, SCTP_FAILED_THRESHOLD,
+ (void *)net, SCTP_SO_NOT_LOCKED);
+ }
+ SCTP_TCB_UNLOCK(stcb);
+ } else if ((icmph->icmp6_code == ICMP_UNREACH_PROTOCOL) ||
+ (icmph->icmp6_code == ICMP_UNREACH_PORT)) {
+ /*
+ * Here the peer is either playing tricks on us, including
+ * an address that belongs to someone who does not support
+ * SCTP OR was a userland implementation that shutdown and
+ * now is dead. In either case treat it like a OOTB abort
+ * with no TCB
+ */
+ reason = SCTP_PEER_FAULTY;
+ sctp_abort_notification(stcb, reason, 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 {
+ SCTP_TCB_UNLOCK(stcb);
+ }
+}
+
+
+
void
sctp6_ctlinput(int cmd, struct sockaddr *pktdst, void *d)
{
struct sctphdr sh;
struct ip6ctlparam *ip6cp = NULL;
uint32_t vrf_id;
- int cm;
vrf_id = SCTP_DEFAULT_VRFID;
@@ -381,12 +492,7 @@ sctp6_ctlinput(int cmd, struct sockaddr *pktdst, void *d)
net);
/* inp's ref-count reduced && stcb unlocked */
} else {
- if (cmd == PRC_HOSTDEAD) {
- cm = EHOSTUNREACH;
- } else {
- cm = inet6ctlerrmap[cmd];
- }
- sctp_notify(inp, cm, &sh,
+ sctp6_notify(inp, ip6cp->ip6c_icmp6, &sh,
(struct sockaddr *)&final,
stcb, net);
/* inp's ref-count reduced && stcb unlocked */
@@ -489,8 +595,10 @@ sctp6_abort(struct socket *so)
uint32_t flags;
inp = (struct sctp_inpcb *)so->so_pcb;
- if (inp == 0)
+ if (inp == 0) {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
return;
+ }
sctp_must_try_again:
flags = inp->sctp_flags;
#ifdef SCTP_LOG_CLOSING
@@ -627,11 +735,12 @@ sctp6_bind(struct socket *so, struct sockaddr *addr, struct thread *p)
sin6_p = (struct sockaddr_in6 *)addr;
- if (IN6_IS_ADDR_V4MAPPED(&sin6_p->sin6_addr))
+ if (IN6_IS_ADDR_V4MAPPED(&sin6_p->sin6_addr)) {
/* can't bind v4-mapped addrs either! */
/* NOTE: we don't support SIIT */
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP6_USRREQ, EINVAL);
- return EINVAL;
+ return EINVAL;
+ }
}
}
error = sctp_inpcb_bind(so, addr, NULL, p);
OpenPOWER on IntegriCloud