summaryrefslogtreecommitdiffstats
path: root/sys/netinet
diff options
context:
space:
mode:
authorrrs <rrs@FreeBSD.org>2007-10-01 03:22:29 +0000
committerrrs <rrs@FreeBSD.org>2007-10-01 03:22:29 +0000
commitdfb6039bc1916c3c54f9056eccab33f9b48cb2dd (patch)
treedf107823c116a7a5ad3ea835f97e50936a6b26ee /sys/netinet
parentd60b8a3096c2760d921f7f4b6e99280cb82f8c7b (diff)
downloadFreeBSD-src-dfb6039bc1916c3c54f9056eccab33f9b48cb2dd.zip
FreeBSD-src-dfb6039bc1916c3c54f9056eccab33f9b48cb2dd.tar.gz
- Bug fix managing congestion parameter on immediate
retransmittion by handover event (fast mobility code) - Fixed problem of mobility code which is caused by remaining parameters in the deleted primary destination. - Add a missing lock. When a peer sends an INIT, and while we are processing it to send an INIT-ACK the socket is closed, we did not hold a lock to keep the socket from going away. Add protection for this case. - Fix so that arwnd is alway uses the minimal rwnd if the user has set the socket buffer smaller. Found this when the test org decided to see what happens when you set in a rwnd of 10 bytes (which is not allowed per RFC .. 4k is minimum). - Fixes so a cookie-echo ootb will NOT cause an abort to be sent. This was happening in a MPI collision case. - Examined all panics and unless there was no recovery, moved any that were not already to INVARANTS. Approved by: re@freebsd.org (gnn)
Diffstat (limited to 'sys/netinet')
-rw-r--r--sys/netinet/sctp_asconf.c13
-rw-r--r--sys/netinet/sctp_constants.h3
-rw-r--r--sys/netinet/sctp_indata.c9
-rw-r--r--sys/netinet/sctp_input.c86
-rw-r--r--sys/netinet/sctp_output.c41
-rw-r--r--sys/netinet/sctp_output.h2
-rw-r--r--sys/netinet/sctp_pcb.c9
-rw-r--r--sys/netinet/sctp_timer.c3
-rw-r--r--sys/netinet/sctp_usrreq.c10
-rw-r--r--sys/netinet/sctp_var.h6
-rw-r--r--sys/netinet/sctputil.c15
11 files changed, 147 insertions, 50 deletions
diff --git a/sys/netinet/sctp_asconf.c b/sys/netinet/sctp_asconf.c
index e8fcded..f9f3660 100644
--- a/sys/netinet/sctp_asconf.c
+++ b/sys/netinet/sctp_asconf.c
@@ -1018,7 +1018,6 @@ sctp_move_chunks_from_deleted_prim(struct sctp_tcb *stcb, struct sctp_nets *dst)
}
-extern int cur_oerr;
void
sctp_assoc_immediate_retrans(struct sctp_tcb *stcb, struct sctp_nets *dstnet)
@@ -1044,7 +1043,6 @@ sctp_assoc_immediate_retrans(struct sctp_tcb *stcb, struct sctp_nets *dstnet)
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) {
@@ -1086,9 +1084,16 @@ sctp_net_immediate_retrans(struct sctp_tcb *stcb, struct sctp_nets *net)
if (chk->sent < SCTP_DATAGRAM_RESEND) {
chk->sent = SCTP_DATAGRAM_RESEND;
sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt);
+ sctp_flight_size_decrease(chk);
+ sctp_total_flight_decrease(stcb, chk);
+ net->marked_retrans++;
+ stcb->asoc.marked_retrans++;
}
}
}
+ if (net->marked_retrans) {
+ sctp_chunk_output(stcb->sctp_ep, stcb, SCTP_OUTPUT_FROM_T3, SCTP_SO_NOT_LOCKED);
+ }
}
static void
@@ -1205,7 +1210,9 @@ sctp_asconf_addr_mgmt_ack(struct sctp_tcb *stcb, struct sctp_ifa *addr,
sctp_del_local_addr_restricted(stcb, addr);
if (sctp_is_mobility_feature_on(stcb->sctp_ep,
- SCTP_MOBILITY_BASE)) {
+ SCTP_MOBILITY_BASE) ||
+ sctp_is_mobility_feature_on(stcb->sctp_ep,
+ SCTP_MOBILITY_FASTHANDOFF)) {
sctp_path_check_and_react(stcb, addr);
return;
}
diff --git a/sys/netinet/sctp_constants.h b/sys/netinet/sctp_constants.h
index 2621251..fab56a3 100644
--- a/sys/netinet/sctp_constants.h
+++ b/sys/netinet/sctp_constants.h
@@ -1034,6 +1034,9 @@ __FBSDID("$FreeBSD$");
#define SCTP_SO_NOT_LOCKED 0
+#define SCTP_HOLDS_LOCK 1
+#define SCTP_NOT_LOCKED 0
+
/*-
* For address locks, do we hold the lock?
*/
diff --git a/sys/netinet/sctp_indata.c b/sys/netinet/sctp_indata.c
index 842aca6..e001a0c 100644
--- a/sys/netinet/sctp_indata.c
+++ b/sys/netinet/sctp_indata.c
@@ -1571,8 +1571,8 @@ sctp_process_a_data_chunk(struct sctp_tcb *stcb, struct sctp_association *asoc,
asoc->highest_tsn_inside_map, MAX_TSN)) {
/* Nope not in the valid range dump it */
- SCTPDBG(SCTP_DEBUG_INDATA1, "My rwnd overrun1:tsn:%lx rwnd %lu sbspace:%ld\n",
- (u_long)tsn, (u_long)asoc->my_rwnd,
+ SCTPDBG(SCTP_DEBUG_INDATA1, "My rwnd overrun1:tsn:%x rwnd %x sbspace:%x\n",
+ tsn, asoc->my_rwnd,
sctp_sbspace(&stcb->asoc, &stcb->sctp_socket->so_rcv));
sctp_set_rwnd(stcb, asoc);
if ((asoc->cnt_on_all_streams +
@@ -2325,7 +2325,12 @@ sctp_sack_check(struct sctp_tcb *stcb, int ok_to_sack, int was_a_gap, int *abort
}
slide_end = lgap >> 3;
if (slide_end < slide_from) {
+#ifdef INVARIANTS
panic("impossible slide");
+#else
+ printf("impossible slide?\n");
+ return;
+#endif
}
distance = (slide_end - slide_from) + 1;
if (sctp_logging_level & SCTP_MAP_LOGGING_ENABLE) {
diff --git a/sys/netinet/sctp_input.c b/sys/netinet/sctp_input.c
index d9d1024..10f305c 100644
--- a/sys/netinet/sctp_input.c
+++ b/sys/netinet/sctp_input.c
@@ -87,6 +87,12 @@ sctp_handle_init(struct mbuf *m, int iphlen, int offset, struct sctphdr *sh,
SCTPDBG(SCTP_DEBUG_INPUT2, "sctp_handle_init: handling INIT tcb:%p\n",
stcb);
+ if (stcb == NULL) {
+ SCTP_INP_RLOCK(inp);
+ if (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) {
+ goto outnow;
+ }
+ }
op_err = NULL;
init = &cp->init;
/* First are we accepting? */
@@ -102,7 +108,7 @@ sctp_handle_init(struct mbuf *m, int iphlen, int offset, struct sctphdr *sh,
vrf_id);
if (stcb)
*abort_no_unlock = 1;
- return;
+ goto outnow;
}
if (ntohs(cp->ch.chunk_length) < sizeof(struct sctp_init_chunk)) {
/* Invalid length */
@@ -111,7 +117,7 @@ sctp_handle_init(struct mbuf *m, int iphlen, int offset, struct sctphdr *sh,
vrf_id);
if (stcb)
*abort_no_unlock = 1;
- return;
+ goto outnow;
}
/* validate parameters */
if (init->initiate_tag == 0) {
@@ -121,7 +127,7 @@ sctp_handle_init(struct mbuf *m, int iphlen, int offset, struct sctphdr *sh,
vrf_id);
if (stcb)
*abort_no_unlock = 1;
- return;
+ goto outnow;
}
if (ntohl(init->a_rwnd) < SCTP_MIN_RWND) {
/* invalid parameter... send abort */
@@ -130,7 +136,7 @@ sctp_handle_init(struct mbuf *m, int iphlen, int offset, struct sctphdr *sh,
vrf_id);
if (stcb)
*abort_no_unlock = 1;
- return;
+ goto outnow;
}
if (init->num_inbound_streams == 0) {
/* protocol error... send abort */
@@ -139,7 +145,7 @@ sctp_handle_init(struct mbuf *m, int iphlen, int offset, struct sctphdr *sh,
vrf_id);
if (stcb)
*abort_no_unlock = 1;
- return;
+ goto outnow;
}
if (init->num_outbound_streams == 0) {
/* protocol error... send abort */
@@ -148,7 +154,7 @@ sctp_handle_init(struct mbuf *m, int iphlen, int offset, struct sctphdr *sh,
vrf_id);
if (stcb)
*abort_no_unlock = 1;
- return;
+ goto outnow;
}
init_limit = offset + ntohs(cp->ch.chunk_length);
if (sctp_validate_init_auth_params(m, offset + sizeof(*cp),
@@ -157,11 +163,16 @@ sctp_handle_init(struct mbuf *m, int iphlen, int offset, struct sctphdr *sh,
sctp_abort_association(inp, stcb, m, iphlen, sh, NULL, vrf_id);
if (stcb)
*abort_no_unlock = 1;
- return;
+ goto outnow;
}
/* send an INIT-ACK w/cookie */
SCTPDBG(SCTP_DEBUG_INPUT3, "sctp_handle_init: sending INIT-ACK\n");
- sctp_send_initiate_ack(inp, stcb, m, iphlen, offset, sh, cp, vrf_id);
+ sctp_send_initiate_ack(inp, stcb, m, iphlen, offset, sh, cp, vrf_id,
+ SCTP_HOLDS_LOCK);
+outnow:
+ if (stcb == NULL) {
+ SCTP_INP_RUNLOCK(inp);
+ }
}
/*
@@ -495,6 +506,7 @@ sctp_handle_heartbeat_ack(struct sctp_heartbeat_chunk *cp,
struct sockaddr_in6 *sin6;
struct sctp_nets *r_net;
struct timeval tv;
+ int req_prim = 0;
if (ntohs(cp->ch.chunk_length) != sizeof(struct sctp_heartbeat_chunk)) {
/* Invalid length */
@@ -549,28 +561,7 @@ 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);
- }
+ req_prim = 1;
}
sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_CONFIRMED,
stcb, 0, (void *)r_net, SCTP_SO_NOT_LOCKED);
@@ -610,6 +601,30 @@ sctp_handle_heartbeat_ack(struct sctp_heartbeat_chunk *cp,
}
/* Now lets do a RTO with this */
r_net->RTO = sctp_calculate_rto(stcb, &stcb->asoc, r_net, &tv, sctp_align_safe_nocopy);
+ /* Mobility adaptation */
+ if (req_prim) {
+ 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);
+ }
+ }
}
static void
@@ -630,6 +645,15 @@ sctp_handle_abort(struct sctp_abort_chunk *cp,
/* notify user of the abort and clean up... */
sctp_abort_notification(stcb, 0, SCTP_SO_NOT_LOCKED);
/* free the tcb */
+#if defined(SCTP_PANIC_ON_ABORT)
+ printf("stcb:%p state:%d rport:%d net:%p\n",
+ stcb, stcb->asoc.state, stcb->rport, net);
+ if (!(stcb->asoc.state & SCTP_STATE_CLOSED_SOCKET)) {
+ panic("Received an ABORT");
+ } else {
+ printf("No panic its in state %x closed\n", stcb->asoc.state);
+ }
+#endif
SCTP_STAT_INCR_COUNTER32(sctps_aborted);
if ((SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_OPEN) ||
(SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) {
@@ -1537,7 +1561,6 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset,
SCTP_STAT_INCR_COUNTER32(sctps_activeestab);
else
SCTP_STAT_INCR_COUNTER32(sctps_collisionestab);
- SCTP_STAT_INCR_COUNTER32(sctps_activeestab);
SCTP_STAT_INCR_GAUGE32(sctps_currestab);
} else if (SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) {
SCTP_STAT_INCR_COUNTER32(sctps_restartestab);
@@ -1548,7 +1571,6 @@ sctp_process_cookie_existing(struct mbuf *m, int iphlen, int offset,
if (asoc->state & SCTP_STATE_SHUTDOWN_PENDING) {
sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD,
stcb->sctp_ep, stcb, asoc->primary_destination);
-
}
sctp_stop_all_cookie_timers(stcb);
sctp_toss_old_cookies(stcb, asoc);
diff --git a/sys/netinet/sctp_output.c b/sys/netinet/sctp_output.c
index b7e040f..e80573e 100644
--- a/sys/netinet/sctp_output.c
+++ b/sys/netinet/sctp_output.c
@@ -4612,7 +4612,7 @@ sctp_are_there_new_addresses(struct sctp_association *asoc,
void
sctp_send_initiate_ack(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
struct mbuf *init_pkt, int iphlen, int offset, struct sctphdr *sh,
- struct sctp_init_chunk *init_chk, uint32_t vrf_id)
+ struct sctp_init_chunk *init_chk, uint32_t vrf_id, int hold_inp_lock)
{
struct sctp_association *asoc;
struct mbuf *m, *m_at, *m_tmp, *m_cookie, *op_err, *mp_last;
@@ -4636,6 +4636,7 @@ sctp_send_initiate_ack(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
int abort_flag, padval;
int num_ext;
int p_len;
+ struct socket *so;
if (stcb)
asoc = &stcb->asoc;
@@ -4947,6 +4948,9 @@ sctp_send_initiate_ack(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
} else {
uint32_t vtag, itsn;
+ if (hold_inp_lock) {
+ SCTP_INP_RUNLOCK(inp);
+ }
if (asoc) {
atomic_add_int(&asoc->refcnt, 1);
SCTP_TCB_UNLOCK(stcb);
@@ -4963,12 +4967,22 @@ sctp_send_initiate_ack(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
/* get a TSN to use too */
initackm_out->msg.init.initial_tsn = htonl(sctp_select_initial_TSN(&inp->sctp_ep));
}
+ if (hold_inp_lock) {
+ SCTP_INP_RLOCK(inp);
+ }
}
/* save away my tag to */
stc.my_vtag = initackm_out->msg.init.initiate_tag;
/* set up some of the credits. */
- initackm_out->msg.init.a_rwnd = htonl(max(SCTP_SB_LIMIT_RCV(inp->sctp_socket), SCTP_MINIMAL_RWND));
+ so = inp->sctp_socket;
+ if (so == NULL) {
+ /* memory problem */
+ sctp_m_freem(m);
+ return;
+ } else {
+ initackm_out->msg.init.a_rwnd = htonl(max(SCTP_SB_LIMIT_RCV(so), SCTP_MINIMAL_RWND));
+ }
/* set what I want */
his_limit = ntohs(init_chk->init.num_inbound_streams);
/* choose what I want */
@@ -10962,7 +10976,10 @@ sctp_lower_sosend(struct socket *so,
if (inp == NULL) {
SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP_OUTPUT, EFAULT);
error = EFAULT;
- goto out_unlocked;
+ if (i_pak) {
+ SCTP_RELEASE_PKT(i_pak);
+ }
+ return (error);
}
if ((uio == NULL) && (i_pak == NULL)) {
SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, EINVAL);
@@ -11193,6 +11210,11 @@ sctp_lower_sosend(struct socket *so,
}
/* get an asoc/stcb struct */
vrf_id = inp->def_vrf_id;
+#ifdef INVARIANTS
+ if (create_lock_applied == 0) {
+ panic("Error, should hold create lock and I don't?");
+ }
+#endif
stcb = sctp_aloc_assoc(inp, addr, 1, &error, 0, vrf_id,
p
);
@@ -11342,11 +11364,16 @@ sctp_lower_sosend(struct socket *so,
}
}
/* Keep the stcb from being freed under our feet */
- if (free_cnt_applied)
+ if (free_cnt_applied) {
+#ifdef INVARIANTS
panic("refcnt already incremented");
- atomic_add_int(&stcb->asoc.refcnt, 1);
- free_cnt_applied = 1;
-
+#else
+ printf("refcnt:1 already incremented?\n");
+#endif
+ } else {
+ atomic_add_int(&stcb->asoc.refcnt, 1);
+ free_cnt_applied = 1;
+ }
if (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) {
SCTP_LTRACE_ERR_RET(NULL, stcb, NULL, SCTP_FROM_SCTP_OUTPUT, ECONNRESET);
error = ECONNRESET;
diff --git a/sys/netinet/sctp_output.h b/sys/netinet/sctp_output.h
index 512522f..d37c163 100644
--- a/sys/netinet/sctp_output.h
+++ b/sys/netinet/sctp_output.h
@@ -84,7 +84,7 @@ sctp_send_initiate(struct sctp_inpcb *, struct sctp_tcb *, int
void
sctp_send_initiate_ack(struct sctp_inpcb *, struct sctp_tcb *,
struct mbuf *, int, int, struct sctphdr *, struct sctp_init_chunk *,
- uint32_t);
+ uint32_t, int);
struct mbuf *
sctp_arethere_unrecognized_parameters(struct mbuf *, int, int *,
diff --git a/sys/netinet/sctp_pcb.c b/sys/netinet/sctp_pcb.c
index a760976..b4666de 100644
--- a/sys/netinet/sctp_pcb.c
+++ b/sys/netinet/sctp_pcb.c
@@ -2908,6 +2908,9 @@ sctp_inpcb_free(struct sctp_inpcb *inp, int immediate, int from)
*ippp = htonl(SCTP_FROM_SCTP_PCB + SCTP_LOC_3);
}
asoc->sctp_ep->last_abort_code = SCTP_FROM_SCTP_PCB + SCTP_LOC_3;
+#if defined(SCTP_PANIC_ON_ABORT)
+ panic("inpcb_free does an abort");
+#endif
sctp_send_abort_tcb(asoc, op_err, SCTP_SO_LOCKED);
SCTP_STAT_INCR_COUNTER32(sctps_aborted);
if ((SCTP_GET_STATE(&asoc->asoc) == SCTP_STATE_OPEN) ||
@@ -2991,6 +2994,10 @@ sctp_inpcb_free(struct sctp_inpcb *inp, int immediate, int from)
*ippp = htonl(SCTP_FROM_SCTP_PCB + SCTP_LOC_5);
}
asoc->sctp_ep->last_abort_code = SCTP_FROM_SCTP_PCB + SCTP_LOC_5;
+#if defined(SCTP_PANIC_ON_ABORT)
+ panic("inpcb_free does an abort");
+#endif
+
sctp_send_abort_tcb(asoc, op_err, SCTP_SO_LOCKED);
SCTP_STAT_INCR_COUNTER32(sctps_aborted);
if ((SCTP_GET_STATE(&asoc->asoc) == SCTP_STATE_OPEN) ||
@@ -3822,6 +3829,8 @@ sctp_remove_net(struct sctp_tcb *stcb, struct sctp_nets *net)
}
asoc->deleted_primary = net;
atomic_add_int(&net->ref_count, 1);
+ memset(&net->lastsa, 0, sizeof(net->lastsa));
+ memset(&net->lastsv, 0, sizeof(net->lastsv));
sctp_mobility_feature_on(stcb->sctp_ep,
SCTP_MOBILITY_PRIM_DELETED);
sctp_timer_start(SCTP_TIMER_TYPE_PRIM_DELETED,
diff --git a/sys/netinet/sctp_timer.c b/sys/netinet/sctp_timer.c
index d90c56d..e9382a5 100644
--- a/sys/netinet/sctp_timer.c
+++ b/sys/netinet/sctp_timer.c
@@ -280,6 +280,9 @@ sctp_threshold_management(struct sctp_inpcb *inp, struct sctp_tcb *stcb,
*ippp = htonl(SCTP_FROM_SCTP_TIMER + SCTP_LOC_1);
}
inp->last_abort_code = SCTP_FROM_SCTP_TIMER + SCTP_LOC_1;
+ printf("Aborting association threshold:%d overall error count:%d\n",
+ threshold,
+ stcb->asoc.overall_error_count);
sctp_abort_an_association(inp, stcb, SCTP_FAILED_THRESHOLD, oper, SCTP_SO_NOT_LOCKED);
return (1);
}
diff --git a/sys/netinet/sctp_usrreq.c b/sys/netinet/sctp_usrreq.c
index 9d3c55b..20de9c3 100644
--- a/sys/netinet/sctp_usrreq.c
+++ b/sys/netinet/sctp_usrreq.c
@@ -792,6 +792,9 @@ sctp_disconnect(struct socket *so)
ph->param_type = htons(SCTP_CAUSE_USER_INITIATED_ABT);
ph->param_length = htons(SCTP_BUF_LEN(err));
}
+#if defined(SCTP_PANIC_ON_ABORT)
+ panic("disconnect does an abort");
+#endif
sctp_send_abort_tcb(stcb, err, SCTP_SO_LOCKED);
SCTP_STAT_INCR_COUNTER32(sctps_aborted);
}
@@ -883,6 +886,10 @@ sctp_disconnect(struct socket *so)
ippp = (uint32_t *) (ph + 1);
*ippp = htonl(SCTP_FROM_SCTP_USRREQ + SCTP_LOC_4);
}
+#if defined(SCTP_PANIC_ON_ABORT)
+ panic("disconnect does an abort");
+#endif
+
stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_USRREQ + SCTP_LOC_4;
sctp_send_abort_tcb(stcb, op_err, SCTP_SO_LOCKED);
SCTP_STAT_INCR_COUNTER32(sctps_aborted);
@@ -1023,6 +1030,9 @@ sctp_shutdown(struct socket *so)
ippp = (uint32_t *) (ph + 1);
*ippp = htonl(SCTP_FROM_SCTP_USRREQ + SCTP_LOC_6);
}
+#if defined(SCTP_PANIC_ON_ABORT)
+ panic("shutdown does an abort");
+#endif
stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_USRREQ + SCTP_LOC_6;
sctp_abort_an_association(stcb->sctp_ep, stcb,
SCTP_RESPONSE_TO_USER_REQ,
diff --git a/sys/netinet/sctp_var.h b/sys/netinet/sctp_var.h
index 8bc6ffd..c4af433 100644
--- a/sys/netinet/sctp_var.h
+++ b/sys/netinet/sctp_var.h
@@ -54,9 +54,11 @@ extern struct pr_usrreqs sctp_usrreqs;
#define sctp_is_mobility_feature_on(inp, feature) (inp->sctp_mobility_features & feature)
#define sctp_is_mobility_feature_off(inp, feature) ((inp->sctp_mobility_features & feature) == 0)
-#define sctp_sbspace(asoc, sb) ((long) (((sb)->sb_hiwat > (asoc)->sb_cc) ? ((sb)->sb_hiwat - (asoc)->sb_cc) : 0))
+#define sctp_maxspace(sb) (max((sb)->sb_hiwat,SCTP_MINIMAL_RWND))
-#define sctp_sbspace_failedmsgs(sb) ((long) (((sb)->sb_hiwat > (sb)->sb_cc) ? ((sb)->sb_hiwat - (sb)->sb_cc) : 0))
+#define sctp_sbspace(asoc, sb) ((long) (sctp_maxspace(sb) > (asoc)->sb_cc) ? (sctp_maxspace(sb) - (asoc)->sb_cc) : 0)
+
+#define sctp_sbspace_failedmsgs(sb) ((long) ((sctp_maxspace(sb) > (sb)->sb_cc) ? (sctp_maxspace(sb) - (sb)->sb_cc) : 0))
#define sctp_sbspace_sub(a,b) ((a > b) ? (a - b) : 0)
diff --git a/sys/netinet/sctputil.c b/sys/netinet/sctputil.c
index 19cb066..09a0e20 100644
--- a/sys/netinet/sctputil.c
+++ b/sys/netinet/sctputil.c
@@ -3962,6 +3962,9 @@ sctp_handle_ootb(struct mbuf *m, int iphlen, int offset, struct sctphdr *sh,
break;
}
switch (ch->chunk_type) {
+ case SCTP_COOKIE_ECHO:
+ /* We hit here only if the assoc is being freed */
+ return;
case SCTP_PACKET_DROPPED:
/* we don't respond to pkt-dropped */
return;
@@ -5265,10 +5268,16 @@ found_one:
* to increment, we need to use the atomic add to
* the refcnt
*/
- if (freecnt_applied)
+ if (freecnt_applied) {
+#ifdef INVARIANTS
panic("refcnt already incremented");
- atomic_add_int(&stcb->asoc.refcnt, 1);
- freecnt_applied = 1;
+#else
+ printf("refcnt already incremented?\n");
+#endif
+ } else {
+ atomic_add_int(&stcb->asoc.refcnt, 1);
+ freecnt_applied = 1;
+ }
/*
* Setup to remember how much we have not yet told
* the peer our rwnd has opened up. Note we grab the
OpenPOWER on IntegriCloud