Commit cca1b32f authored by Jon Grimm's avatar Jon Grimm

sctp: Always respond to ECNE sender. (jgrimm)

Handle lost CWR case, by always sending CWR whether
we've actually lowered our cwnd vars or not.  Otherwise,
the peer will keep sending ECNEs forever.  
parent d8f3637a
......@@ -208,7 +208,7 @@ sctp_association_t *sctp_association_init(sctp_association_t *asoc,
asoc->ctsn_ack_point = asoc->next_tsn - 1;
asoc->highest_sacked = asoc->ctsn_ack_point;
asoc->last_cwr_tsn = asoc->ctsn_ack_point;
asoc->unack_data = 0;
SCTP_DEBUG_PRINTK("myctsnap for %s INIT as 0x%x.\n",
......
......@@ -598,10 +598,7 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype,
/* A helper function for delayed processing of INET ECN CE bit. */
static void sctp_do_ecn_ce_work(sctp_association_t *asoc, __u32 lowest_tsn)
{
/*
* Save the TSN away for comparison when we receive CWR
* Note: dp->TSN is expected in host endian
*/
/* Save the TSN away for comparison when we receive CWR */
asoc->last_ecne_tsn = lowest_tsn;
asoc->need_ecne = 1;
......@@ -624,7 +621,6 @@ static sctp_chunk_t *sctp_do_ecn_ecne_work(sctp_association_t *asoc,
sctp_chunk_t *chunk)
{
sctp_chunk_t *repl;
sctp_transport_t *transport;
/* Our previously transmitted packet ran into some congestion
* so we should take action by reducing cwnd and ssthresh
......@@ -632,43 +628,28 @@ static sctp_chunk_t *sctp_do_ecn_ecne_work(sctp_association_t *asoc,
* sending a CWR.
*/
/* Find which transport's congestion variables
* need to be adjusted.
/* First, try to determine if we want to actually lower
* our cwnd variables. Only lower them if the ECNE looks more
* recent than the last response.
*/
if (TSN_lt(asoc->last_cwr_tsn, lowest_tsn)) {
sctp_transport_t *transport;
transport = sctp_assoc_lookup_tsn(asoc, lowest_tsn);
/* Find which transport's congestion variables
* need to be adjusted.
*/
transport = sctp_assoc_lookup_tsn(asoc, lowest_tsn);
/* Update the congestion variables. */
if (transport)
sctp_transport_lower_cwnd(transport, SCTP_LOWER_CWND_ECNE);
/* Update the congestion variables. */
if (transport)
sctp_transport_lower_cwnd(transport,
SCTP_LOWER_CWND_ECNE);
asoc->last_cwr_tsn = lowest_tsn;
}
/* Save away a rough idea of when we last sent out a CWR.
* We compare against this value (see above) to decide if
* this is a fairly new request.
* Note that this is not a perfect solution. We may
* have moved beyond the window (several times) by the
* next time we get an ECNE. However, it is cute. This idea
* came from Randy's reference code.
*
* Here's what RFC 2960 has to say about CWR. This is NOT
* what we do.
*
* RFC 2960 Appendix A
*
* CWR:
*
* RFC 2481 details a specific bit for a sender to send in
* the header of its next outbound TCP segment to indicate
* to its peer that it has reduced its congestion window.
* This is termed the CWR bit. For SCTP the same
* indication is made by including the CWR chunk. This
* chunk contains one data element, i.e. the TSN number
* that was sent in the ECNE chunk. This element
* represents the lowest TSN number in the datagram that
* was originally marked with the CE bit.
/* Always try to quiet the other end. In case of lost CWR,
* resend last_cwr_tsn.
*/
asoc->last_cwr_tsn = asoc->next_tsn - 1;
repl = sctp_make_cwr(asoc, asoc->last_cwr_tsn, chunk);
/* If we run out of memory, it will look like a lost CWR. We'll
......@@ -1050,7 +1031,7 @@ static void sctp_cmd_assoc_failed(sctp_cmd_seq_t *commands,
if (event_type == SCTP_EVENT_T_PRIMITIVE)
error = SCTP_ERROR_USER_ABORT;
if (chunk && (SCTP_CID_ABORT == chunk->chunk_hdr->type) &&
(ntohs(chunk->chunk_hdr->length) >= (sizeof(struct sctp_chunkhdr) +
sizeof(struct sctp_errhdr)))) {
......
......@@ -866,9 +866,9 @@ sctp_disposition_t sctp_sf_backbeat_8_3(const sctp_endpoint_t *ep,
/* Helper function to send out an abort for the restart
* condition.
*/
static int sctp_sf_send_restart_abort(sockaddr_storage_t *ssa,
static int sctp_sf_send_restart_abort(sockaddr_storage_t *ssa,
sctp_chunk_t *init,
sctp_cmd_seq_t *commands)
sctp_cmd_seq_t *commands)
{
int len;
sctp_packet_t *pkt;
......@@ -882,7 +882,7 @@ static int sctp_sf_send_restart_abort(sockaddr_storage_t *ssa,
*/
errhdr = (sctp_errhdr_t *)buffer;
addrparm = (sctp_addr_param_t *)errhdr->variable;
/* Copy into a parm format. */
len = sockaddr2sctp_addr(ssa, addrparm);
len += sizeof(sctp_errhdr_t);
......@@ -898,7 +898,7 @@ static int sctp_sf_send_restart_abort(sockaddr_storage_t *ssa,
*/
pkt = sctp_abort_pkt_new(ep, NULL, init, errhdr, len);
if (!pkt)
if (!pkt)
goto out;
sctp_add_cmd_sf(commands, SCTP_CMD_SEND_PKT, SCTP_PACKET(pkt));
......@@ -907,18 +907,18 @@ static int sctp_sf_send_restart_abort(sockaddr_storage_t *ssa,
out:
/* Even if there is no memory, treat as a failure so
* the packet will get dropped.
* the packet will get dropped.
*/
return 0;
}
/* A restart is occuring, check to make sure no new addresses
/* A restart is occuring, check to make sure no new addresses
* are being added as we may be under a takeover attack.
*/
static int sctp_sf_check_restart_addrs(const sctp_association_t *new_asoc,
const sctp_association_t *asoc,
sctp_chunk_t *init,
sctp_cmd_seq_t *commands)
sctp_cmd_seq_t *commands)
{
sctp_transport_t *new_addr, *addr;
struct list_head *pos, *pos2;
......@@ -957,8 +957,8 @@ static int sctp_sf_check_restart_addrs(const sctp_association_t *new_asoc,
if (!found && new_addr) {
sctp_sf_send_restart_abort(&new_addr->ipaddr, init, commands);
}
/* Return success if all addresses were found. */
/* Return success if all addresses were found. */
return found;
}
......@@ -1054,7 +1054,7 @@ static char sctp_tietags_compare(sctp_association_t *new_asoc,
*/
static sctp_disposition_t sctp_sf_do_unexpected_init(
const sctp_endpoint_t *ep,
const sctp_association_t *asoc,
const sctp_association_t *asoc,
const sctp_subtype_t type,
void *arg, sctp_cmd_seq_t *commands)
{
......@@ -1131,10 +1131,10 @@ static sctp_disposition_t sctp_sf_do_unexpected_init(
/* Make sure no new addresses are being added during the
* restart. Do not do this check for COOKIE-WAIT state,
* since there are no peer addresses to check against.
* Upon return an ABORT will have been sent if needed.
* Upon return an ABORT will have been sent if needed.
*/
if (asoc->state != SCTP_STATE_COOKIE_WAIT) {
if (!sctp_sf_check_restart_addrs(new_asoc, asoc, chunk,
if (!sctp_sf_check_restart_addrs(new_asoc, asoc, chunk,
commands)) {
retval = SCTP_DISPOSITION_CONSUME;
goto cleanup_asoc;
......@@ -1334,9 +1334,9 @@ static sctp_disposition_t sctp_sf_do_dupcook_a(const sctp_endpoint_t *ep,
* since you'd have to get inside the cookie.
*/
if (!sctp_sf_check_restart_addrs(new_asoc, asoc, chunk, commands)) {
printk("cookie echo check\n");
printk("cookie echo check\n");
return SCTP_DISPOSITION_CONSUME;
}
}
/* For now, fail any unsent/unacked data. Consider the optional
* choice of resending of this data.
......@@ -1543,7 +1543,7 @@ sctp_disposition_t sctp_sf_do_5_2_4_dupcook(const sctp_endpoint_t *ep,
* are in good shape.
*/
chunk->subh.cookie_hdr = (sctp_signed_cookie_t *)chunk->skb->data;
skb_pull(chunk->skb, ntohs(chunk->chunk_hdr->length) -
skb_pull(chunk->skb, ntohs(chunk->chunk_hdr->length) -
sizeof(sctp_chunkhdr_t));
/* In RFC 2960 5.2.4 3, if both Verification Tags in the State Cookie
......@@ -2099,18 +2099,11 @@ sctp_disposition_t sctp_sf_do_ecne(const sctp_endpoint_t *ep,
ecne = (sctp_ecnehdr_t *) chunk->skb->data;
skb_pull(chunk->skb, sizeof(sctp_ecnehdr_t));
ecne->lowest_tsn = ntohl(ecne->lowest_tsn);
/* Casting away the const, as we are just modifying the spinlock,
* not the association itself. This should go away in the near
* future when we move to an endpoint based lock.
*/
/* If this is a newer ECNE than the last CWR packet we sent out */
if (TSN_lt(asoc->last_cwr_tsn, ecne->lowest_tsn)) {
sctp_add_cmd_sf(commands, SCTP_CMD_ECN_ECNE,
SCTP_U32(ecne->lowest_tsn));
}
sctp_add_cmd_sf(commands, SCTP_CMD_ECN_ECNE,
SCTP_U32(ntohl(ecne->lowest_tsn)));
return SCTP_DISPOSITION_CONSUME;
}
......@@ -2642,7 +2635,7 @@ sctp_disposition_t sctp_sf_operr_notify(const sctp_endpoint_t *ep,
sctp_ulpevent_t *ev;
while (chunk->chunk_end > chunk->skb->data) {
ev = sctp_ulpevent_make_remote_error(asoc, chunk, 0,
ev = sctp_ulpevent_make_remote_error(asoc, chunk, 0,
GFP_ATOMIC);
if (!ev)
goto nomem;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment