aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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 94d407f9ec9b..a97b07d0c1b0 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 fb51dd4fca16..e75f5de2793f 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 017f303dbfdd..86006dad58e6 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 8b5aaf960904..e0aa30483078 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 5d65b78c3d4c..c059a4dee811 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 52881d2f0d67..5179e75cf2eb 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 904f79ccf07a..bcc50452578a 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 3b60f85976fa..64eb8259606d 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 30fc1cb8bfa7..e7830fcedc98 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 92350295ff5e..bc28eac98eb8 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 217f5a0b3726..09e08f057ae0 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 5b95b860726d..ec28f6140b53 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 573f46bc1529..cb83f4e2bee1 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 50550f8d7bdd..b9d4b62a4c68 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 425d748376b6..0a0f2f28ed85 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 56d61996f49c..477ef582832f 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 bf11663ad2a7..77f15ae7b6fe 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 aa847edd76fa..8bc6ffdca823 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 31b9c06ef079..05ab85097ac7 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 2d4c82c7d7cc..89bb51c5af75 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);