Commit d6b6fece authored by Jon Grimm's avatar Jon Grimm

[SCTP] Bundle SACK with outgoing DATA.

If we are sending DATA, bundle a SACK.  Otherwise, we end up 
always waiting for the delayed SACK rules (timer or every other
packet rule) to kick in.   
parent c219cdce
......@@ -421,6 +421,15 @@ static inline __s32 sctp_jitter(__u32 rto)
return ret;
}
/* Break down data chunks at this point. */
static inline int sctp_frag_point(int pmtu)
{
pmtu -= SCTP_IP_OVERHEAD + sizeof(struct sctp_data_chunk);
pmtu -= sizeof(struct sctp_sack_chunk);
return pmtu;
}
/* Walk through a list of TLV parameters. Don't trust the
* individual parameter lengths and instead depend on
* the chunk length to indicate when to stop. Make sure
......
......@@ -590,13 +590,16 @@ struct sctp_packet {
/* This packet should advertise ECN capability to the network
* via the ECT bit.
*/
int ecn_capable;
char ecn_capable;
/* This packet contains a COOKIE-ECHO chunk. */
int has_cookie_echo;
char has_cookie_echo;
/* This packet containsa SACK chunk. */
char has_sack;
/* SCTP cannot fragment this packet. So let ip fragment it. */
int ipfragok;
char ipfragok;
int malloced;
};
......
......@@ -421,8 +421,7 @@ struct sctp_transport *sctp_assoc_add_peer(struct sctp_association *asoc,
SCTP_DEBUG_PRINTK("sctp_assoc_add_peer:association %p PMTU set to "
"%d\n", asoc, asoc->pmtu);
asoc->frag_point = asoc->pmtu;
asoc->frag_point -= SCTP_IP_OVERHEAD + sizeof(struct sctp_data_chunk);
asoc->frag_point = sctp_frag_point(asoc->pmtu);
/* The asoc->peer.port might not be meaningful yet, but
* initialize the packet structure anyway.
......@@ -658,31 +657,20 @@ int sctp_cmp_addr_exact(const union sctp_addr *ss1,
}
/* Return an ecne chunk to get prepended to a packet.
* Note: We are sly and return a shared, prealloced chunk.
* Note: We are sly and return a shared, prealloced chunk. FIXME:
* No we don't, but we could/should.
*/
sctp_chunk_t *sctp_get_ecne_prepend(sctp_association_t *asoc)
sctp_chunk_t *sctp_get_ecne_prepend(struct sctp_association *asoc)
{
sctp_chunk_t *chunk;
int need_ecne;
__u32 lowest_tsn;
/* Can be called from task or bh. Both need_ecne and
* last_ecne_tsn are written during bh.
*/
need_ecne = asoc->need_ecne;
lowest_tsn = asoc->last_ecne_tsn;
if (need_ecne) {
chunk = sctp_make_ecne(asoc, lowest_tsn);
struct sctp_chunk *chunk;
/* ECNE is not mandatory to the flow. Being unable to
* alloc mem is not deadly. We are just unable to help
* out the network. If we run out of memory, just return
* NULL.
/* Send ECNE if needed.
* Not being able to allocate a chunk here is not deadly.
*/
} else {
if (asoc->need_ecne)
chunk = sctp_make_ecne(asoc, asoc->last_ecne_tsn);
else
chunk = NULL;
}
return chunk;
}
......@@ -986,8 +974,7 @@ void sctp_assoc_sync_pmtu(sctp_association_t *asoc)
if (pmtu) {
asoc->pmtu = pmtu;
asoc->frag_point = pmtu - (SCTP_IP_OVERHEAD +
sizeof(sctp_data_chunk_t));
asoc->frag_point = sctp_frag_point(pmtu);
}
SCTP_DEBUG_PRINTK("%s: asoc:%p, pmtu:%d, frag_point:%d\n",
......
......@@ -79,6 +79,7 @@ struct sctp_packet *sctp_packet_config(struct sctp_packet *packet,
packet->ecn_capable = ecn_capable;
packet->get_prepend_chunk = prepend_handler;
packet->has_cookie_echo = 0;
packet->has_sack = 0;
packet->ipfragok = 0;
/* We might need to call the prepend_handler right away. */
......@@ -100,6 +101,7 @@ struct sctp_packet *sctp_packet_init(struct sctp_packet *packet,
packet->ecn_capable = 0;
packet->get_prepend_chunk = NULL;
packet->has_cookie_echo = 0;
packet->has_sack = 0;
packet->ipfragok = 0;
packet->malloced = 0;
sctp_packet_reset(packet);
......@@ -155,6 +157,37 @@ sctp_xmit_t sctp_packet_transmit_chunk(struct sctp_packet *packet,
return retval;
}
/* Try to bundle a SACK with the packet. */
static sctp_xmit_t sctp_packet_bundle_sack(struct sctp_packet *pkt,
struct sctp_chunk *chunk)
{
sctp_xmit_t retval = SCTP_XMIT_OK;
/* If sending DATA and haven't aleady bundled a SACK, try to
* bundle one in to the packet.
*/
if (sctp_chunk_is_data(chunk) && !pkt->has_sack &&
!pkt->has_cookie_echo) {
struct sctp_association *asoc;
asoc = pkt->transport->asoc;
if (asoc->a_rwnd > asoc->rwnd) {
struct sctp_chunk *sack;
asoc->a_rwnd = asoc->rwnd;
sack = sctp_make_sack(asoc);
if (sack) {
struct timer_list *timer;
retval = sctp_packet_append_chunk(pkt, sack);
asoc->peer.sack_needed = 0;
timer = &asoc->timers[SCTP_EVENT_TIMEOUT_SACK];
if (timer_pending(timer) && del_timer(timer))
sctp_association_put(asoc);
}
}
}
return retval;
}
/* Append a chunk to the offered packet reporting back any inability to do
* so.
*/
......@@ -167,6 +200,10 @@ sctp_xmit_t sctp_packet_append_chunk(struct sctp_packet *packet,
size_t pmtu;
int too_big;
retval = sctp_packet_bundle_sack(packet, chunk);
if (retval != SCTP_XMIT_OK)
goto finish;
pmtu = ((packet->transport->asoc) ?
(packet->transport->asoc->pmtu) :
(packet->transport->pmtu));
......@@ -216,9 +253,10 @@ sctp_xmit_t sctp_packet_append_chunk(struct sctp_packet *packet,
retval = sctp_packet_append_data(packet, chunk);
if (SCTP_XMIT_OK != retval)
goto finish;
} else if (SCTP_CID_COOKIE_ECHO == chunk->chunk_hdr->type) {
} else if (SCTP_CID_COOKIE_ECHO == chunk->chunk_hdr->type)
packet->has_cookie_echo = 1;
}
else if (SCTP_CID_SACK == chunk->chunk_hdr->type)
packet->has_sack = 1;
/* It is OK to send this chunk. */
__skb_queue_tail(&packet->chunks, (struct sk_buff *)chunk);
......
......@@ -876,7 +876,7 @@ int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)
start_timer = 0;
queue = &q->out;
while (NULL != (chunk = sctp_outq_dequeue_data(q))) {
while (chunk = sctp_outq_dequeue_data(q)) {
/* RFC 2960 6.5 Every DATA chunk MUST carry a valid
* stream identifier.
*/
......@@ -891,9 +891,7 @@ int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)
if (ev)
sctp_ulpq_tail_event(&asoc->ulpq, ev);
/* Free the chunk. This chunk is not on any
* list yet, just free it.
*/
/* Free the chunk. */
sctp_free_chunk(chunk);
continue;
}
......
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