- 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)
This commit is contained in:
Randall Stewart 2007-10-01 03:22:29 +00:00
parent 55aaf894e8
commit d55b0b1b09
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=172396
11 changed files with 147 additions and 50 deletions

View File

@ -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;
}

View File

@ -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?
*/

View File

@ -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) {

View File

@ -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);

View File

@ -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;

View File

@ -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 *,

View File

@ -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,

View File

@ -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);
}

View File

@ -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,

View File

@ -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)

View File

@ -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 @@ sctp_sorecvmsg(struct socket *so,
* 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