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.
*/ */
/* Find which transport's congestion variables /* First, try to determine if we want to actually lower
* need to be adjusted. * 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. */ /* 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);
asoc->last_cwr_tsn = lowest_tsn;
}
/* Save away a rough idea of when we last sent out a CWR. /* Always try to quiet the other end. In case of lost CWR,
* We compare against this value (see above) to decide if * resend last_cwr_tsn.
* 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;
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
...@@ -1050,7 +1031,7 @@ static void sctp_cmd_assoc_failed(sctp_cmd_seq_t *commands, ...@@ -1050,7 +1031,7 @@ static void sctp_cmd_assoc_failed(sctp_cmd_seq_t *commands,
if (event_type == SCTP_EVENT_T_PRIMITIVE) if (event_type == SCTP_EVENT_T_PRIMITIVE)
error = SCTP_ERROR_USER_ABORT; error = SCTP_ERROR_USER_ABORT;
if (chunk && (SCTP_CID_ABORT == chunk->chunk_hdr->type) && if (chunk && (SCTP_CID_ABORT == chunk->chunk_hdr->type) &&
(ntohs(chunk->chunk_hdr->length) >= (sizeof(struct sctp_chunkhdr) + (ntohs(chunk->chunk_hdr->length) >= (sizeof(struct sctp_chunkhdr) +
sizeof(struct sctp_errhdr)))) { sizeof(struct sctp_errhdr)))) {
......
...@@ -866,9 +866,9 @@ sctp_disposition_t sctp_sf_backbeat_8_3(const sctp_endpoint_t *ep, ...@@ -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 /* Helper function to send out an abort for the restart
* condition. * 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_chunk_t *init,
sctp_cmd_seq_t *commands) sctp_cmd_seq_t *commands)
{ {
int len; int len;
sctp_packet_t *pkt; sctp_packet_t *pkt;
...@@ -882,7 +882,7 @@ static int sctp_sf_send_restart_abort(sockaddr_storage_t *ssa, ...@@ -882,7 +882,7 @@ static int sctp_sf_send_restart_abort(sockaddr_storage_t *ssa,
*/ */
errhdr = (sctp_errhdr_t *)buffer; errhdr = (sctp_errhdr_t *)buffer;
addrparm = (sctp_addr_param_t *)errhdr->variable; addrparm = (sctp_addr_param_t *)errhdr->variable;
/* Copy into a parm format. */ /* Copy into a parm format. */
len = sockaddr2sctp_addr(ssa, addrparm); len = sockaddr2sctp_addr(ssa, addrparm);
len += sizeof(sctp_errhdr_t); len += sizeof(sctp_errhdr_t);
...@@ -898,7 +898,7 @@ static int sctp_sf_send_restart_abort(sockaddr_storage_t *ssa, ...@@ -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); pkt = sctp_abort_pkt_new(ep, NULL, init, errhdr, len);
if (!pkt) if (!pkt)
goto out; goto out;
sctp_add_cmd_sf(commands, SCTP_CMD_SEND_PKT, SCTP_PACKET(pkt)); 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, ...@@ -907,18 +907,18 @@ static int sctp_sf_send_restart_abort(sockaddr_storage_t *ssa,
out: out:
/* Even if there is no memory, treat as a failure so /* Even if there is no memory, treat as a failure so
* the packet will get dropped. * the packet will get dropped.
*/ */
return 0; 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. * are being added as we may be under a takeover attack.
*/ */
static int sctp_sf_check_restart_addrs(const sctp_association_t *new_asoc, static int sctp_sf_check_restart_addrs(const sctp_association_t *new_asoc,
const sctp_association_t *asoc, const sctp_association_t *asoc,
sctp_chunk_t *init, sctp_chunk_t *init,
sctp_cmd_seq_t *commands) sctp_cmd_seq_t *commands)
{ {
sctp_transport_t *new_addr, *addr; sctp_transport_t *new_addr, *addr;
struct list_head *pos, *pos2; struct list_head *pos, *pos2;
...@@ -957,8 +957,8 @@ static int sctp_sf_check_restart_addrs(const sctp_association_t *new_asoc, ...@@ -957,8 +957,8 @@ static int sctp_sf_check_restart_addrs(const sctp_association_t *new_asoc,
if (!found && new_addr) { if (!found && new_addr) {
sctp_sf_send_restart_abort(&new_addr->ipaddr, init, commands); 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; return found;
} }
...@@ -1054,7 +1054,7 @@ static char sctp_tietags_compare(sctp_association_t *new_asoc, ...@@ -1054,7 +1054,7 @@ static char sctp_tietags_compare(sctp_association_t *new_asoc,
*/ */
static sctp_disposition_t sctp_sf_do_unexpected_init( static sctp_disposition_t sctp_sf_do_unexpected_init(
const sctp_endpoint_t *ep, const sctp_endpoint_t *ep,
const sctp_association_t *asoc, const sctp_association_t *asoc,
const sctp_subtype_t type, const sctp_subtype_t type,
void *arg, sctp_cmd_seq_t *commands) void *arg, sctp_cmd_seq_t *commands)
{ {
...@@ -1131,10 +1131,10 @@ static sctp_disposition_t sctp_sf_do_unexpected_init( ...@@ -1131,10 +1131,10 @@ static sctp_disposition_t sctp_sf_do_unexpected_init(
/* Make sure no new addresses are being added during the /* Make sure no new addresses are being added during the
* restart. Do not do this check for COOKIE-WAIT state, * restart. Do not do this check for COOKIE-WAIT state,
* since there are no peer addresses to check against. * 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 (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)) { commands)) {
retval = SCTP_DISPOSITION_CONSUME; retval = SCTP_DISPOSITION_CONSUME;
goto cleanup_asoc; goto cleanup_asoc;
...@@ -1334,9 +1334,9 @@ static sctp_disposition_t sctp_sf_do_dupcook_a(const sctp_endpoint_t *ep, ...@@ -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. * since you'd have to get inside the cookie.
*/ */
if (!sctp_sf_check_restart_addrs(new_asoc, asoc, chunk, commands)) { 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; return SCTP_DISPOSITION_CONSUME;
} }
/* For now, fail any unsent/unacked data. Consider the optional /* For now, fail any unsent/unacked data. Consider the optional
* choice of resending of this data. * 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, ...@@ -1543,7 +1543,7 @@ sctp_disposition_t sctp_sf_do_5_2_4_dupcook(const sctp_endpoint_t *ep,
* are in good shape. * are in good shape.
*/ */
chunk->subh.cookie_hdr = (sctp_signed_cookie_t *)chunk->skb->data; 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)); sizeof(sctp_chunkhdr_t));
/* In RFC 2960 5.2.4 3, if both Verification Tags in the State Cookie /* 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, ...@@ -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(ntohl(ecne->lowest_tsn)));
SCTP_U32(ecne->lowest_tsn));
}
return SCTP_DISPOSITION_CONSUME; return SCTP_DISPOSITION_CONSUME;
} }
...@@ -2642,7 +2635,7 @@ sctp_disposition_t sctp_sf_operr_notify(const sctp_endpoint_t *ep, ...@@ -2642,7 +2635,7 @@ sctp_disposition_t sctp_sf_operr_notify(const sctp_endpoint_t *ep,
sctp_ulpevent_t *ev; sctp_ulpevent_t *ev;
while (chunk->chunk_end > chunk->skb->data) { 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); GFP_ATOMIC);
if (!ev) if (!ev)
goto nomem; 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