aboutsummaryrefslogtreecommitdiff
path: root/sys/netinet/sctp_input.c
diff options
context:
space:
mode:
authorRandall Stewart <rrs@FreeBSD.org>2007-10-01 03:22:29 +0000
committerRandall Stewart <rrs@FreeBSD.org>2007-10-01 03:22:29 +0000
commitd55b0b1b096c24d4b89eeecc87666268e097cfe4 (patch)
treedf107823c116a7a5ad3ea835f97e50936a6b26ee /sys/netinet/sctp_input.c
parent55aaf894e8a76fe780757ef6d9d1119c367946cf (diff)
downloadsrc-d55b0b1b096c24d4b89eeecc87666268e097cfe4.tar.gz
src-d55b0b1b096c24d4b89eeecc87666268e097cfe4.zip
- 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)
Notes
Notes: svn path=/head/; revision=172396
Diffstat (limited to 'sys/netinet/sctp_input.c')
-rw-r--r--sys/netinet/sctp_input.c86
1 files changed, 54 insertions, 32 deletions
diff --git a/sys/netinet/sctp_input.c b/sys/netinet/sctp_input.c
index d9d10249f576..10f305cddd82 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);