#include <linux/fcntl.h>
#include <linux/poll.h>
#include <linux/init.h>
-#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/in.h>
/* Initialize the maximum mumber of new data packets that can be sent
* in a burst.
*/
- asoc->max_burst = sctp_max_burst;
+ asoc->max_burst = sp->max_burst;
/* initialize association timers */
asoc->timeouts[SCTP_EVENT_TIMEOUT_NONE] = 0;
* If the 'T5-shutdown-guard' timer is used, it SHOULD be set to the
* recommended value of 5 times 'RTO.Max'.
*/
- asoc->timeouts[SCTP_EVENT_TIMEOUT_T5_SHUTDOWN_GUARD]
+ asoc->timeouts[SCTP_EVENT_TIMEOUT_T5_SHUTDOWN_GUARD]
= 5 * asoc->rto_max;
asoc->timeouts[SCTP_EVENT_TIMEOUT_HEARTBEAT] = 0;
asoc->timeouts[SCTP_EVENT_TIMEOUT_SACK] = asoc->sackdelay;
asoc->timeouts[SCTP_EVENT_TIMEOUT_AUTOCLOSE] =
sp->autoclose * HZ;
-
+
/* Initilizes the timers */
for (i = SCTP_EVENT_TIMEOUT_NONE; i < SCTP_NUM_TIMEOUT_TYPES; ++i) {
init_timer(&asoc->timers[i]);
/* Record the transition on the transport. */
switch (command) {
case SCTP_TRANSPORT_UP:
+ /* If we are moving from UNCONFIRMED state due
+ * to heartbeat success, report the SCTP_ADDR_CONFIRMED
+ * state to the user, otherwise report SCTP_ADDR_AVAILABLE.
+ */
+ if (SCTP_UNCONFIRMED == transport->state &&
+ SCTP_HEARTBEAT_SUCCESS == error)
+ spc_state = SCTP_ADDR_CONFIRMED;
+ else
+ spc_state = SCTP_ADDR_AVAILABLE;
transport->state = SCTP_ACTIVE;
- spc_state = SCTP_ADDR_AVAILABLE;
break;
case SCTP_TRANSPORT_DOWN:
default:
return;
- };
+ }
/* Generate and send a SCTP_PEER_ADDR_CHANGE notification to the
* user.
trans = list_entry(pos, struct sctp_transport, transports);
if (!sctp_assoc_lookup_paddr(new, &trans->ipaddr))
sctp_assoc_del_peer(asoc, &trans->ipaddr);
+
+ if (asoc->state >= SCTP_STATE_ESTABLISHED)
+ sctp_transport_reset(trans);
}
/* If the case is A (association restart), use
*/
sctp_ssnmap_clear(asoc->ssnmap);
+ /* Flush the ULP reassembly and ordered queue.
+ * Any data there will now be stale and will
+ * cause problems.
+ */
+ sctp_ulpq_flush(&asoc->ulpq);
+
+ /* reset the overall association error count so
+ * that the restarted association doesn't get torn
+ * down on the next retransmission timer.
+ */
+ asoc->overall_error_count = 0;
+
} else {
/* Add any peer addresses from the new association. */
list_for_each(pos, &new->peer.transport_addr_list) {
asoc->ssnmap = new->ssnmap;
new->ssnmap = NULL;
}
+
+ if (!asoc->assoc_id) {
+ /* get a new association id since we don't have one
+ * yet.
+ */
+ sctp_assoc_set_id(asoc, GFP_ATOMIC);
+ }
}
}
asoc->ep->base.bind_addr.port, gfp);
}
-/* Lookup laddr in the bind address list of an association. */
-int sctp_assoc_lookup_laddr(struct sctp_association *asoc,
+/* Lookup laddr in the bind address list of an association. */
+int sctp_assoc_lookup_laddr(struct sctp_association *asoc,
const union sctp_addr *laddr)
{
int found;
sctp_read_lock(&asoc->base.addr_lock);
if ((asoc->base.bind_addr.port == ntohs(laddr->v4.sin_port)) &&
sctp_bind_addr_match(&asoc->base.bind_addr, laddr,
- sctp_sk(asoc->base.sk))) {
+ sctp_sk(asoc->base.sk))) {
found = 1;
goto out;
}
sctp_read_unlock(&asoc->base.addr_lock);
return found;
}
+
+/* Set an association id for a given association */
+int sctp_assoc_set_id(struct sctp_association *asoc, gfp_t gfp)
+{
+ int assoc_id;
+ int error = 0;
+retry:
+ if (unlikely(!idr_pre_get(&sctp_assocs_id, gfp)))
+ return -ENOMEM;
+
+ spin_lock_bh(&sctp_assocs_id_lock);
+ error = idr_get_new_above(&sctp_assocs_id, (void *)asoc,
+ 1, &assoc_id);
+ spin_unlock_bh(&sctp_assocs_id_lock);
+ if (error == -EAGAIN)
+ goto retry;
+ else if (error)
+ return error;
+
+ asoc->assoc_id = (sctp_assoc_t) assoc_id;
+ return error;
+}