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, ...@@ -208,7 +208,7 @@ sctp_association_t *sctp_association_init(sctp_association_t *asoc,
asoc->ctsn_ack_point = asoc->next_tsn - 1; asoc->ctsn_ack_point = asoc->next_tsn - 1;
asoc->highest_sacked = asoc->ctsn_ack_point; asoc->highest_sacked = asoc->ctsn_ack_point;
asoc->last_cwr_tsn = asoc->ctsn_ack_point;
asoc->unack_data = 0; asoc->unack_data = 0;
SCTP_DEBUG_PRINTK("myctsnap for %s INIT as 0x%x.\n", 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, ...@@ -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. */ /* 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) static void sctp_do_ecn_ce_work(sctp_association_t *asoc, __u32 lowest_tsn)
{ {
/* /* Save the TSN away for comparison when we receive CWR */
* Save the TSN away for comparison when we receive CWR
* Note: dp->TSN is expected in host endian
*/
asoc->last_ecne_tsn = lowest_tsn; asoc->last_ecne_tsn = lowest_tsn;
asoc->need_ecne = 1; asoc->need_ecne = 1;
...@@ -624,7 +621,6 @@ static sctp_chunk_t *sctp_do_ecn_ecne_work(sctp_association_t *asoc, ...@@ -624,7 +621,6 @@ static sctp_chunk_t *sctp_do_ecn_ecne_work(sctp_association_t *asoc,
sctp_chunk_t *chunk) sctp_chunk_t *chunk)
{ {
sctp_chunk_t *repl; sctp_chunk_t *repl;
sctp_transport_t *transport;
/* Our previously transmitted packet ran into some congestion /* Our previously transmitted packet ran into some congestion
* so we should take action by reducing cwnd and ssthresh * 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, ...@@ -632,43 +628,28 @@ static sctp_chunk_t *sctp_do_ecn_ecne_work(sctp_association_t *asoc,
* sending a CWR. * sending a CWR.
*/ */
/* 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;
/* Find which transport's congestion variables /* Find which transport's congestion variables
* need to be adjusted. * need to be adjusted.
*/ */
transport = sctp_assoc_lookup_tsn(asoc, lowest_tsn); transport = sctp_assoc_lookup_tsn(asoc, lowest_tsn);
/* Update the congestion variables. */ /* Update the congestion variables. */
if (transport) if (transport)
sctp_transport_lower_cwnd(transport, SCTP_LOWER_CWND_ECNE); sctp_transport_lower_cwnd(transport,
SCTP_LOWER_CWND_ECNE);
/* Save away a rough idea of when we last sent out a CWR. asoc->last_cwr_tsn = lowest_tsn;
* 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.
*/
asoc->last_cwr_tsn = asoc->next_tsn - 1;
/* Always try to quiet the other end. In case of lost CWR,
* resend last_cwr_tsn.
*/
repl = sctp_make_cwr(asoc, asoc->last_cwr_tsn, chunk); 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 /* If we run out of memory, it will look like a lost CWR. We'll
......
...@@ -2099,18 +2099,11 @@ sctp_disposition_t sctp_sf_do_ecne(const sctp_endpoint_t *ep, ...@@ -2099,18 +2099,11 @@ sctp_disposition_t sctp_sf_do_ecne(const sctp_endpoint_t *ep,
ecne = (sctp_ecnehdr_t *) chunk->skb->data; ecne = (sctp_ecnehdr_t *) chunk->skb->data;
skb_pull(chunk->skb, sizeof(sctp_ecnehdr_t)); 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 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_add_cmd_sf(commands, SCTP_CMD_ECN_ECNE,
SCTP_U32(ecne->lowest_tsn)); SCTP_U32(ntohl(ecne->lowest_tsn)));
}
return SCTP_DISPOSITION_CONSUME; return SCTP_DISPOSITION_CONSUME;
} }
......
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