diff options
author | rrs <rrs@FreeBSD.org> | 2007-10-01 03:22:29 +0000 |
---|---|---|
committer | rrs <rrs@FreeBSD.org> | 2007-10-01 03:22:29 +0000 |
commit | dfb6039bc1916c3c54f9056eccab33f9b48cb2dd (patch) | |
tree | df107823c116a7a5ad3ea835f97e50936a6b26ee /sys/netinet/sctp_input.c | |
parent | d60b8a3096c2760d921f7f4b6e99280cb82f8c7b (diff) | |
download | FreeBSD-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/sctp_input.c')
-rw-r--r-- | sys/netinet/sctp_input.c | 86 |
1 files changed, 54 insertions, 32 deletions
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); |