Commit 52ccb8e9 authored by Frank Filz's avatar Frank Filz Committed by David S. Miller

[SCTP]: Update SCTP_PEER_ADDR_PARAMS socket option to the latest api draft.

This patch adds support to set/get heartbeat interval, maximum number of
retransmissions, pathmtu, sackdelay time for a particular transport/
association/socket as per the latest SCTP sockets api draft11.
Signed-off-by: default avatarFrank Filz <ffilz@us.ibm.com>
Signed-off-by: default avatarSridhar Samudrala <sri@us.ibm.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent fd966255
...@@ -277,6 +277,24 @@ struct sctp_sock { ...@@ -277,6 +277,24 @@ struct sctp_sock {
__u32 default_context; __u32 default_context;
__u32 default_timetolive; __u32 default_timetolive;
/* Heartbeat interval: The endpoint sends out a Heartbeat chunk to
* the destination address every heartbeat interval. This value
* will be inherited by all new associations.
*/
__u32 hbinterval;
/* This is the max_retrans value for new associations. */
__u16 pathmaxrxt;
/* The initial Path MTU to use for new associations. */
__u32 pathmtu;
/* The default SACK delay timeout for new associations. */
__u32 sackdelay;
/* Flags controling Heartbeat, SACK delay, and Path MTU Discovery. */
__u32 param_flags;
struct sctp_initmsg initmsg; struct sctp_initmsg initmsg;
struct sctp_rtoinfo rtoinfo; struct sctp_rtoinfo rtoinfo;
struct sctp_paddrparams paddrparam; struct sctp_paddrparams paddrparam;
...@@ -845,9 +863,6 @@ struct sctp_transport { ...@@ -845,9 +863,6 @@ struct sctp_transport {
/* Data that has been sent, but not acknowledged. */ /* Data that has been sent, but not acknowledged. */
__u32 flight_size; __u32 flight_size;
/* PMTU : The current known path MTU. */
__u32 pmtu;
/* Destination */ /* Destination */
struct dst_entry *dst; struct dst_entry *dst;
/* Source address. */ /* Source address. */
...@@ -862,7 +877,22 @@ struct sctp_transport { ...@@ -862,7 +877,22 @@ struct sctp_transport {
/* Heartbeat interval: The endpoint sends out a Heartbeat chunk to /* Heartbeat interval: The endpoint sends out a Heartbeat chunk to
* the destination address every heartbeat interval. * the destination address every heartbeat interval.
*/ */
int hb_interval; __u32 hbinterval;
/* This is the max_retrans value for the transport and will
* be initialized from the assocs value. This can be changed
* using SCTP_SET_PEER_ADDR_PARAMS socket option.
*/
__u16 pathmaxrxt;
/* PMTU : The current known path MTU. */
__u32 pathmtu;
/* SACK delay timeout */
__u32 sackdelay;
/* Flags controling Heartbeat, SACK delay, and Path MTU Discovery. */
__u32 param_flags;
/* When was the last time (in jiffies) that we heard from this /* When was the last time (in jiffies) that we heard from this
* transport? We use this to pick new active and retran paths. * transport? We use this to pick new active and retran paths.
...@@ -882,22 +912,11 @@ struct sctp_transport { ...@@ -882,22 +912,11 @@ struct sctp_transport {
*/ */
int state; int state;
/* hb_allowed : The current heartbeat state of this destination,
* : i.e. ALLOW-HB, NO-HEARTBEAT, etc.
*/
int hb_allowed;
/* These are the error stats for this destination. */ /* These are the error stats for this destination. */
/* Error count : The current error count for this destination. */ /* Error count : The current error count for this destination. */
unsigned short error_count; unsigned short error_count;
/* This is the max_retrans value for the transport and will
* be initialized to proto.max_retrans.path. This can be changed
* using SCTP_SET_PEER_ADDR_PARAMS socket option.
*/
int max_retrans;
/* Per : A timer used by each destination. /* Per : A timer used by each destination.
* Destination : * Destination :
* Timer : * Timer :
...@@ -1502,6 +1521,28 @@ struct sctp_association { ...@@ -1502,6 +1521,28 @@ struct sctp_association {
/* The largest timeout or RTO value to use in attempting an INIT */ /* The largest timeout or RTO value to use in attempting an INIT */
__u16 max_init_timeo; __u16 max_init_timeo;
/* Heartbeat interval: The endpoint sends out a Heartbeat chunk to
* the destination address every heartbeat interval. This value
* will be inherited by all new transports.
*/
__u32 hbinterval;
/* This is the max_retrans value for new transports in the
* association.
*/
__u16 pathmaxrxt;
/* Association : The smallest PMTU discovered for all of the
* PMTU : peer's transport addresses.
*/
__u32 pathmtu;
/* SACK delay timeout */
__u32 sackdelay;
/* Flags controling Heartbeat, SACK delay, and Path MTU Discovery. */
__u32 param_flags;
int timeouts[SCTP_NUM_TIMEOUT_TYPES]; int timeouts[SCTP_NUM_TIMEOUT_TYPES];
struct timer_list timers[SCTP_NUM_TIMEOUT_TYPES]; struct timer_list timers[SCTP_NUM_TIMEOUT_TYPES];
...@@ -1571,11 +1612,6 @@ struct sctp_association { ...@@ -1571,11 +1612,6 @@ struct sctp_association {
*/ */
wait_queue_head_t wait; wait_queue_head_t wait;
/* Association : The smallest PMTU discovered for all of the
* PMTU : peer's transport addresses.
*/
__u32 pmtu;
/* The message size at which SCTP fragmentation will occur. */ /* The message size at which SCTP fragmentation will occur. */
__u32 frag_point; __u32 frag_point;
......
...@@ -503,11 +503,27 @@ struct sctp_setadaption { ...@@ -503,11 +503,27 @@ struct sctp_setadaption {
* unreachable. The following structure is used to access and modify an * unreachable. The following structure is used to access and modify an
* address's parameters: * address's parameters:
*/ */
enum sctp_spp_flags {
SPP_HB_ENABLE = 1, /*Enable heartbeats*/
SPP_HB_DISABLE = 2, /*Disable heartbeats*/
SPP_HB = SPP_HB_ENABLE | SPP_HB_DISABLE,
SPP_HB_DEMAND = 4, /*Send heartbeat immediately*/
SPP_PMTUD_ENABLE = 8, /*Enable PMTU discovery*/
SPP_PMTUD_DISABLE = 16, /*Disable PMTU discovery*/
SPP_PMTUD = SPP_PMTUD_ENABLE | SPP_PMTUD_DISABLE,
SPP_SACKDELAY_ENABLE = 32, /*Enable SACK*/
SPP_SACKDELAY_DISABLE = 64, /*Disable SACK*/
SPP_SACKDELAY = SPP_SACKDELAY_ENABLE | SPP_SACKDELAY_DISABLE,
};
struct sctp_paddrparams { struct sctp_paddrparams {
sctp_assoc_t spp_assoc_id; sctp_assoc_t spp_assoc_id;
struct sockaddr_storage spp_address; struct sockaddr_storage spp_address;
__u32 spp_hbinterval; __u32 spp_hbinterval;
__u16 spp_pathmaxrxt; __u16 spp_pathmaxrxt;
__u32 spp_pathmtu;
__u32 spp_sackdelay;
__u32 spp_flags;
} __attribute__((packed, aligned(4))); } __attribute__((packed, aligned(4)));
/* /*
......
...@@ -110,7 +110,6 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a ...@@ -110,7 +110,6 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a
asoc->cookie_life.tv_sec = sp->assocparams.sasoc_cookie_life / 1000; asoc->cookie_life.tv_sec = sp->assocparams.sasoc_cookie_life / 1000;
asoc->cookie_life.tv_usec = (sp->assocparams.sasoc_cookie_life % 1000) asoc->cookie_life.tv_usec = (sp->assocparams.sasoc_cookie_life % 1000)
* 1000; * 1000;
asoc->pmtu = 0;
asoc->frag_point = 0; asoc->frag_point = 0;
/* Set the association max_retrans and RTO values from the /* Set the association max_retrans and RTO values from the
...@@ -123,6 +122,25 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a ...@@ -123,6 +122,25 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a
asoc->overall_error_count = 0; asoc->overall_error_count = 0;
/* Initialize the association's heartbeat interval based on the
* sock configured value.
*/
asoc->hbinterval = msecs_to_jiffies(sp->hbinterval);
/* Initialize path max retrans value. */
asoc->pathmaxrxt = sp->pathmaxrxt;
/* Initialize default path MTU. */
asoc->pathmtu = sp->pathmtu;
/* Set association default SACK delay */
asoc->sackdelay = msecs_to_jiffies(sp->sackdelay);
/* Set the association default flags controlling
* Heartbeat, SACK delay, and Path MTU Discovery.
*/
asoc->param_flags = sp->param_flags;
/* Initialize the maximum mumber of new data packets that can be sent /* Initialize the maximum mumber of new data packets that can be sent
* in a burst. * in a burst.
*/ */
...@@ -144,8 +162,7 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a ...@@ -144,8 +162,7 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a
= 5 * asoc->rto_max; = 5 * asoc->rto_max;
asoc->timeouts[SCTP_EVENT_TIMEOUT_HEARTBEAT] = 0; asoc->timeouts[SCTP_EVENT_TIMEOUT_HEARTBEAT] = 0;
asoc->timeouts[SCTP_EVENT_TIMEOUT_SACK] = asoc->timeouts[SCTP_EVENT_TIMEOUT_SACK] = asoc->sackdelay;
SCTP_DEFAULT_TIMEOUT_SACK;
asoc->timeouts[SCTP_EVENT_TIMEOUT_AUTOCLOSE] = asoc->timeouts[SCTP_EVENT_TIMEOUT_AUTOCLOSE] =
sp->autoclose * HZ; sp->autoclose * HZ;
...@@ -540,23 +557,46 @@ struct sctp_transport *sctp_assoc_add_peer(struct sctp_association *asoc, ...@@ -540,23 +557,46 @@ struct sctp_transport *sctp_assoc_add_peer(struct sctp_association *asoc,
sctp_transport_set_owner(peer, asoc); sctp_transport_set_owner(peer, asoc);
/* Initialize the peer's heartbeat interval based on the
* association configured value.
*/
peer->hbinterval = asoc->hbinterval;
/* Set the path max_retrans. */
peer->pathmaxrxt = asoc->pathmaxrxt;
/* Initialize the peer's SACK delay timeout based on the
* association configured value.
*/
peer->sackdelay = asoc->sackdelay;
/* Enable/disable heartbeat, SACK delay, and path MTU discovery
* based on association setting.
*/
peer->param_flags = asoc->param_flags;
/* Initialize the pmtu of the transport. */ /* Initialize the pmtu of the transport. */
sctp_transport_pmtu(peer); if (peer->param_flags & SPP_PMTUD_ENABLE)
sctp_transport_pmtu(peer);
else if (asoc->pathmtu)
peer->pathmtu = asoc->pathmtu;
else
peer->pathmtu = SCTP_DEFAULT_MAXSEGMENT;
/* If this is the first transport addr on this association, /* If this is the first transport addr on this association,
* initialize the association PMTU to the peer's PMTU. * initialize the association PMTU to the peer's PMTU.
* If not and the current association PMTU is higher than the new * If not and the current association PMTU is higher than the new
* peer's PMTU, reset the association PMTU to the new peer's PMTU. * peer's PMTU, reset the association PMTU to the new peer's PMTU.
*/ */
if (asoc->pmtu) if (asoc->pathmtu)
asoc->pmtu = min_t(int, peer->pmtu, asoc->pmtu); asoc->pathmtu = min_t(int, peer->pathmtu, asoc->pathmtu);
else else
asoc->pmtu = peer->pmtu; asoc->pathmtu = peer->pathmtu;
SCTP_DEBUG_PRINTK("sctp_assoc_add_peer:association %p PMTU set to " SCTP_DEBUG_PRINTK("sctp_assoc_add_peer:association %p PMTU set to "
"%d\n", asoc, asoc->pmtu); "%d\n", asoc, asoc->pathmtu);
asoc->frag_point = sctp_frag_point(sp, asoc->pmtu); asoc->frag_point = sctp_frag_point(sp, asoc->pathmtu);
/* The asoc->peer.port might not be meaningful yet, but /* The asoc->peer.port might not be meaningful yet, but
* initialize the packet structure anyway. * initialize the packet structure anyway.
...@@ -574,7 +614,7 @@ struct sctp_transport *sctp_assoc_add_peer(struct sctp_association *asoc, ...@@ -574,7 +614,7 @@ struct sctp_transport *sctp_assoc_add_peer(struct sctp_association *asoc,
* (for example, implementations MAY use the size of the * (for example, implementations MAY use the size of the
* receiver advertised window). * receiver advertised window).
*/ */
peer->cwnd = min(4*asoc->pmtu, max_t(__u32, 2*asoc->pmtu, 4380)); peer->cwnd = min(4*asoc->pathmtu, max_t(__u32, 2*asoc->pathmtu, 4380));
/* At this point, we may not have the receiver's advertised window, /* At this point, we may not have the receiver's advertised window,
* so initialize ssthresh to the default value and it will be set * so initialize ssthresh to the default value and it will be set
...@@ -585,17 +625,6 @@ struct sctp_transport *sctp_assoc_add_peer(struct sctp_association *asoc, ...@@ -585,17 +625,6 @@ struct sctp_transport *sctp_assoc_add_peer(struct sctp_association *asoc,
peer->partial_bytes_acked = 0; peer->partial_bytes_acked = 0;
peer->flight_size = 0; peer->flight_size = 0;
/* By default, enable heartbeat for peer address. */
peer->hb_allowed = 1;
/* Initialize the peer's heartbeat interval based on the
* sock configured value.
*/
peer->hb_interval = msecs_to_jiffies(sp->paddrparam.spp_hbinterval);
/* Set the path max_retrans. */
peer->max_retrans = sp->paddrparam.spp_pathmaxrxt;
/* Set the transport's RTO.initial value */ /* Set the transport's RTO.initial value */
peer->rto = asoc->rto_initial; peer->rto = asoc->rto_initial;
...@@ -1155,18 +1184,18 @@ void sctp_assoc_sync_pmtu(struct sctp_association *asoc) ...@@ -1155,18 +1184,18 @@ void sctp_assoc_sync_pmtu(struct sctp_association *asoc)
/* Get the lowest pmtu of all the transports. */ /* Get the lowest pmtu of all the transports. */
list_for_each(pos, &asoc->peer.transport_addr_list) { list_for_each(pos, &asoc->peer.transport_addr_list) {
t = list_entry(pos, struct sctp_transport, transports); t = list_entry(pos, struct sctp_transport, transports);
if (!pmtu || (t->pmtu < pmtu)) if (!pmtu || (t->pathmtu < pmtu))
pmtu = t->pmtu; pmtu = t->pathmtu;
} }
if (pmtu) { if (pmtu) {
struct sctp_sock *sp = sctp_sk(asoc->base.sk); struct sctp_sock *sp = sctp_sk(asoc->base.sk);
asoc->pmtu = pmtu; asoc->pathmtu = pmtu;
asoc->frag_point = sctp_frag_point(sp, pmtu); asoc->frag_point = sctp_frag_point(sp, pmtu);
} }
SCTP_DEBUG_PRINTK("%s: asoc:%p, pmtu:%d, frag_point:%d\n", SCTP_DEBUG_PRINTK("%s: asoc:%p, pmtu:%d, frag_point:%d\n",
__FUNCTION__, asoc, asoc->pmtu, asoc->frag_point); __FUNCTION__, asoc, asoc->pathmtu, asoc->frag_point);
} }
/* Should we send a SACK to update our peer? */ /* Should we send a SACK to update our peer? */
...@@ -1179,7 +1208,7 @@ static inline int sctp_peer_needs_update(struct sctp_association *asoc) ...@@ -1179,7 +1208,7 @@ static inline int sctp_peer_needs_update(struct sctp_association *asoc)
case SCTP_STATE_SHUTDOWN_SENT: case SCTP_STATE_SHUTDOWN_SENT:
if ((asoc->rwnd > asoc->a_rwnd) && if ((asoc->rwnd > asoc->a_rwnd) &&
((asoc->rwnd - asoc->a_rwnd) >= ((asoc->rwnd - asoc->a_rwnd) >=
min_t(__u32, (asoc->base.sk->sk_rcvbuf >> 1), asoc->pmtu))) min_t(__u32, (asoc->base.sk->sk_rcvbuf >> 1), asoc->pathmtu)))
return 1; return 1;
break; break;
default: default:
......
...@@ -305,18 +305,36 @@ int sctp_backlog_rcv(struct sock *sk, struct sk_buff *skb) ...@@ -305,18 +305,36 @@ int sctp_backlog_rcv(struct sock *sk, struct sk_buff *skb)
void sctp_icmp_frag_needed(struct sock *sk, struct sctp_association *asoc, void sctp_icmp_frag_needed(struct sock *sk, struct sctp_association *asoc,
struct sctp_transport *t, __u32 pmtu) struct sctp_transport *t, __u32 pmtu)
{ {
if (unlikely(pmtu < SCTP_DEFAULT_MINSEGMENT)) { if (sock_owned_by_user(sk) || !t || (t->pathmtu == pmtu))
printk(KERN_WARNING "%s: Reported pmtu %d too low, " return;
"using default minimum of %d\n", __FUNCTION__, pmtu,
SCTP_DEFAULT_MINSEGMENT);
pmtu = SCTP_DEFAULT_MINSEGMENT;
}
if (!sock_owned_by_user(sk) && t && (t->pmtu != pmtu)) { if (t->param_flags & SPP_PMTUD_ENABLE) {
t->pmtu = pmtu; if (unlikely(pmtu < SCTP_DEFAULT_MINSEGMENT)) {
printk(KERN_WARNING "%s: Reported pmtu %d too low, "
"using default minimum of %d\n",
__FUNCTION__, pmtu,
SCTP_DEFAULT_MINSEGMENT);
/* Use default minimum segment size and disable
* pmtu discovery on this transport.
*/
t->pathmtu = SCTP_DEFAULT_MINSEGMENT;
t->param_flags = (t->param_flags & ~SPP_HB) |
SPP_PMTUD_DISABLE;
} else {
t->pathmtu = pmtu;
}
/* Update association pmtu. */
sctp_assoc_sync_pmtu(asoc); sctp_assoc_sync_pmtu(asoc);
sctp_retransmit(&asoc->outqueue, t, SCTP_RTXR_PMTUD);
} }
/* Retransmit with the new pmtu setting.
* Normally, if PMTU discovery is disabled, an ICMP Fragmentation
* Needed will never be sent, but if a message was sent before
* PMTU discovery was disabled that was larger than the PMTU, it
* would not be fragmented, so it must be re-transmitted fragmented.
*/
sctp_retransmit(&asoc->outqueue, t, SCTP_RTXR_PMTUD);
} }
/* /*
......
...@@ -234,8 +234,8 @@ sctp_xmit_t sctp_packet_append_chunk(struct sctp_packet *packet, ...@@ -234,8 +234,8 @@ sctp_xmit_t sctp_packet_append_chunk(struct sctp_packet *packet,
goto finish; goto finish;
pmtu = ((packet->transport->asoc) ? pmtu = ((packet->transport->asoc) ?
(packet->transport->asoc->pmtu) : (packet->transport->asoc->pathmtu) :
(packet->transport->pmtu)); (packet->transport->pathmtu));
too_big = (psize + chunk_len > pmtu); too_big = (psize + chunk_len > pmtu);
...@@ -482,7 +482,9 @@ int sctp_packet_transmit(struct sctp_packet *packet) ...@@ -482,7 +482,9 @@ int sctp_packet_transmit(struct sctp_packet *packet)
if (!dst || (dst->obsolete > 1)) { if (!dst || (dst->obsolete > 1)) {
dst_release(dst); dst_release(dst);
sctp_transport_route(tp, NULL, sctp_sk(sk)); sctp_transport_route(tp, NULL, sctp_sk(sk));
sctp_assoc_sync_pmtu(asoc); if (asoc->param_flags & SPP_PMTUD_ENABLE) {
sctp_assoc_sync_pmtu(asoc);
}
} }
nskb->dst = dst_clone(tp->dst); nskb->dst = dst_clone(tp->dst);
...@@ -492,7 +494,10 @@ int sctp_packet_transmit(struct sctp_packet *packet) ...@@ -492,7 +494,10 @@ int sctp_packet_transmit(struct sctp_packet *packet)
SCTP_DEBUG_PRINTK("***sctp_transmit_packet*** skb len %d\n", SCTP_DEBUG_PRINTK("***sctp_transmit_packet*** skb len %d\n",
nskb->len); nskb->len);
(*tp->af_specific->sctp_xmit)(nskb, tp, packet->ipfragok); if (tp->param_flags & SPP_PMTUD_ENABLE)
(*tp->af_specific->sctp_xmit)(nskb, tp, packet->ipfragok);
else
(*tp->af_specific->sctp_xmit)(nskb, tp, 1);
out: out:
packet->size = packet->overhead; packet->size = packet->overhead;
...@@ -577,7 +582,7 @@ static sctp_xmit_t sctp_packet_append_data(struct sctp_packet *packet, ...@@ -577,7 +582,7 @@ static sctp_xmit_t sctp_packet_append_data(struct sctp_packet *packet,
* if ((flightsize + Max.Burst * MTU) < cwnd) * if ((flightsize + Max.Burst * MTU) < cwnd)
* cwnd = flightsize + Max.Burst * MTU * cwnd = flightsize + Max.Burst * MTU
*/ */
max_burst_bytes = asoc->max_burst * asoc->pmtu; max_burst_bytes = asoc->max_burst * asoc->pathmtu;
if ((transport->flight_size + max_burst_bytes) < transport->cwnd) { if ((transport->flight_size + max_burst_bytes) < transport->cwnd) {
transport->cwnd = transport->flight_size + max_burst_bytes; transport->cwnd = transport->flight_size + max_burst_bytes;
SCTP_DEBUG_PRINTK("%s: cwnd limited by max_burst: " SCTP_DEBUG_PRINTK("%s: cwnd limited by max_burst: "
...@@ -622,7 +627,7 @@ static sctp_xmit_t sctp_packet_append_data(struct sctp_packet *packet, ...@@ -622,7 +627,7 @@ static sctp_xmit_t sctp_packet_append_data(struct sctp_packet *packet,
* data will fit or delay in hopes of bundling a full * data will fit or delay in hopes of bundling a full
* sized packet. * sized packet.
*/ */
if (len < asoc->pmtu - packet->overhead) { if (len < asoc->pathmtu - packet->overhead) {
retval = SCTP_XMIT_NAGLE_DELAY; retval = SCTP_XMIT_NAGLE_DELAY;
goto finish; goto finish;
} }
......
...@@ -157,9 +157,12 @@ static int sctp_gen_sack(struct sctp_association *asoc, int force, ...@@ -157,9 +157,12 @@ static int sctp_gen_sack(struct sctp_association *asoc, int force,
{ {
__u32 ctsn, max_tsn_seen; __u32 ctsn, max_tsn_seen;
struct sctp_chunk *sack; struct sctp_chunk *sack;
struct sctp_transport *trans = asoc->peer.last_data_from;
int error = 0; int error = 0;
if (force) if (force ||
(!trans && (asoc->param_flags & SPP_SACKDELAY_DISABLE)) ||
(trans && (trans->param_flags & SPP_SACKDELAY_DISABLE)))
asoc->peer.sack_needed = 1; asoc->peer.sack_needed = 1;
ctsn = sctp_tsnmap_get_ctsn(&asoc->peer.tsn_map); ctsn = sctp_tsnmap_get_ctsn(&asoc->peer.tsn_map);
...@@ -189,7 +192,22 @@ static int sctp_gen_sack(struct sctp_association *asoc, int force, ...@@ -189,7 +192,22 @@ static int sctp_gen_sack(struct sctp_association *asoc, int force,
if (!asoc->peer.sack_needed) { if (!asoc->peer.sack_needed) {
/* We will need a SACK for the next packet. */ /* We will need a SACK for the next packet. */
asoc->peer.sack_needed = 1; asoc->peer.sack_needed = 1;
goto out;
/* Set the SACK delay timeout based on the
* SACK delay for the last transport
* data was received from, or the default
* for the association.
*/
if (trans)
asoc->timeouts[SCTP_EVENT_TIMEOUT_SACK] =
trans->sackdelay;
else
asoc->timeouts[SCTP_EVENT_TIMEOUT_SACK] =
asoc->sackdelay;
/* Restart the SACK timer. */
sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_RESTART,
SCTP_TO(SCTP_EVENT_TIMEOUT_SACK));
} else { } else {
if (asoc->a_rwnd > asoc->rwnd) if (asoc->a_rwnd > asoc->rwnd)
asoc->a_rwnd = asoc->rwnd; asoc->a_rwnd = asoc->rwnd;
...@@ -205,7 +223,7 @@ static int sctp_gen_sack(struct sctp_association *asoc, int force, ...@@ -205,7 +223,7 @@ static int sctp_gen_sack(struct sctp_association *asoc, int force,
sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP, sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP,
SCTP_TO(SCTP_EVENT_TIMEOUT_SACK)); SCTP_TO(SCTP_EVENT_TIMEOUT_SACK));
} }
out:
return error; return error;
nomem: nomem:
error = -ENOMEM; error = -ENOMEM;
...@@ -415,7 +433,7 @@ static void sctp_do_8_2_transport_strike(struct sctp_association *asoc, ...@@ -415,7 +433,7 @@ static void sctp_do_8_2_transport_strike(struct sctp_association *asoc,
asoc->overall_error_count++; asoc->overall_error_count++;
if (transport->state != SCTP_INACTIVE && if (transport->state != SCTP_INACTIVE &&
(transport->error_count++ >= transport->max_retrans)) { (transport->error_count++ >= transport->pathmaxrxt)) {
SCTP_DEBUG_PRINTK_IPADDR("transport_strike:association %p", SCTP_DEBUG_PRINTK_IPADDR("transport_strike:association %p",
" transport IP: port:%d failed.\n", " transport IP: port:%d failed.\n",
asoc, asoc,
......
...@@ -900,7 +900,7 @@ sctp_disposition_t sctp_sf_sendbeat_8_3(const struct sctp_endpoint *ep, ...@@ -900,7 +900,7 @@ sctp_disposition_t sctp_sf_sendbeat_8_3(const struct sctp_endpoint *ep,
* HEARTBEAT is sent (see Section 8.3). * HEARTBEAT is sent (see Section 8.3).
*/ */
if (transport->hb_allowed) { if (transport->param_flags & SPP_HB_ENABLE) {
if (SCTP_DISPOSITION_NOMEM == if (SCTP_DISPOSITION_NOMEM ==
sctp_sf_heartbeat(ep, asoc, type, arg, sctp_sf_heartbeat(ep, asoc, type, arg,
commands)) commands))
...@@ -1051,7 +1051,7 @@ sctp_disposition_t sctp_sf_backbeat_8_3(const struct sctp_endpoint *ep, ...@@ -1051,7 +1051,7 @@ sctp_disposition_t sctp_sf_backbeat_8_3(const struct sctp_endpoint *ep,
return SCTP_DISPOSITION_DISCARD; return SCTP_DISPOSITION_DISCARD;
} }
max_interval = link->hb_interval + link->rto; max_interval = link->hbinterval + link->rto;
/* Check if the timestamp looks valid. */ /* Check if the timestamp looks valid. */
if (time_after(hbinfo->sent_at, jiffies) || if (time_after(hbinfo->sent_at, jiffies) ||
...@@ -2691,14 +2691,9 @@ sctp_disposition_t sctp_sf_eat_data_6_2(const struct sctp_endpoint *ep, ...@@ -2691,14 +2691,9 @@ sctp_disposition_t sctp_sf_eat_data_6_2(const struct sctp_endpoint *ep,
* document allow. However, an SCTP transmitter MUST NOT be * document allow. However, an SCTP transmitter MUST NOT be
* more aggressive than the following algorithms allow. * more aggressive than the following algorithms allow.
*/ */
if (chunk->end_of_packet) { if (chunk->end_of_packet)
sctp_add_cmd_sf(commands, SCTP_CMD_GEN_SACK, SCTP_NOFORCE()); sctp_add_cmd_sf(commands, SCTP_CMD_GEN_SACK, SCTP_NOFORCE());
/* Start the SACK timer. */
sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_RESTART,
SCTP_TO(SCTP_EVENT_TIMEOUT_SACK));
}
return SCTP_DISPOSITION_CONSUME; return SCTP_DISPOSITION_CONSUME;
discard_force: discard_force:
...@@ -2721,13 +2716,9 @@ sctp_disposition_t sctp_sf_eat_data_6_2(const struct sctp_endpoint *ep, ...@@ -2721,13 +2716,9 @@ sctp_disposition_t sctp_sf_eat_data_6_2(const struct sctp_endpoint *ep,
return SCTP_DISPOSITION_DISCARD; return SCTP_DISPOSITION_DISCARD;
discard_noforce: discard_noforce:
if (chunk->end_of_packet) { if (chunk->end_of_packet)
sctp_add_cmd_sf(commands, SCTP_CMD_GEN_SACK, SCTP_NOFORCE()); sctp_add_cmd_sf(commands, SCTP_CMD_GEN_SACK, SCTP_NOFORCE());
/* Start the SACK timer. */
sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_RESTART,
SCTP_TO(SCTP_EVENT_TIMEOUT_SACK));
}
return SCTP_DISPOSITION_DISCARD; return SCTP_DISPOSITION_DISCARD;
consume: consume:
return SCTP_DISPOSITION_CONSUME; return SCTP_DISPOSITION_CONSUME;
...@@ -3442,9 +3433,6 @@ sctp_disposition_t sctp_sf_eat_fwd_tsn(const struct sctp_endpoint *ep, ...@@ -3442,9 +3433,6 @@ sctp_disposition_t sctp_sf_eat_fwd_tsn(const struct sctp_endpoint *ep,
* send another. * send another.
*/ */
sctp_add_cmd_sf(commands, SCTP_CMD_GEN_SACK, SCTP_NOFORCE()); sctp_add_cmd_sf(commands, SCTP_CMD_GEN_SACK, SCTP_NOFORCE());
/* Start the SACK timer. */
sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_RESTART,
SCTP_TO(SCTP_EVENT_TIMEOUT_SACK));
return SCTP_DISPOSITION_CONSUME; return SCTP_DISPOSITION_CONSUME;
......
This diff is collapsed.
...@@ -86,10 +86,13 @@ static struct sctp_transport *sctp_transport_init(struct sctp_transport *peer, ...@@ -86,10 +86,13 @@ static struct sctp_transport *sctp_transport_init(struct sctp_transport *peer,
peer->init_sent_count = 0; peer->init_sent_count = 0;
peer->state = SCTP_ACTIVE; peer->state = SCTP_ACTIVE;
peer->hb_allowed = 0; peer->param_flags = SPP_HB_DISABLE |
SPP_PMTUD_ENABLE |
SPP_SACKDELAY_ENABLE;
peer->hbinterval = 0;
/* Initialize the default path max_retrans. */ /* Initialize the default path max_retrans. */
peer->max_retrans = sctp_max_retrans_path; peer->pathmaxrxt = sctp_max_retrans_path;
peer->error_count = 0; peer->error_count = 0;
INIT_LIST_HEAD(&peer->transmitted); INIT_LIST_HEAD(&peer->transmitted);
...@@ -229,10 +232,10 @@ void sctp_transport_pmtu(struct sctp_transport *transport) ...@@ -229,10 +232,10 @@ void sctp_transport_pmtu(struct sctp_transport *transport)
dst = transport->af_specific->get_dst(NULL, &transport->ipaddr, NULL); dst = transport->af_specific->get_dst(NULL, &transport->ipaddr, NULL);
if (dst) { if (dst) {
transport->pmtu = dst_mtu(dst); transport->pathmtu = dst_mtu(dst);
dst_release(dst); dst_release(dst);
} else } else
transport->pmtu = SCTP_DEFAULT_MAXSEGMENT; transport->pathmtu = SCTP_DEFAULT_MAXSEGMENT;
} }
/* Caches the dst entry and source address for a transport's destination /* Caches the dst entry and source address for a transport's destination
...@@ -254,8 +257,11 @@ void sctp_transport_route(struct sctp_transport *transport, ...@@ -254,8 +257,11 @@ void sctp_transport_route(struct sctp_transport *transport,
af->get_saddr(asoc, dst, daddr, &transport->saddr); af->get_saddr(asoc, dst, daddr, &transport->saddr);
transport->dst = dst; transport->dst = dst;
if ((transport->param_flags & SPP_PMTUD_DISABLE) && transport->pathmtu) {
return;
}
if (dst) { if (dst) {
transport->pmtu = dst_mtu(dst); transport->pathmtu = dst_mtu(dst);
/* Initialize sk->sk_rcv_saddr, if the transport is the /* Initialize sk->sk_rcv_saddr, if the transport is the
* association's active path for getsockname(). * association's active path for getsockname().
...@@ -264,7 +270,7 @@ void sctp_transport_route(struct sctp_transport *transport, ...@@ -264,7 +270,7 @@ void sctp_transport_route(struct sctp_transport *transport,
opt->pf->af->to_sk_saddr(&transport->saddr, opt->pf->af->to_sk_saddr(&transport->saddr,
asoc->base.sk); asoc->base.sk);
} else } else
transport->pmtu = SCTP_DEFAULT_MAXSEGMENT; transport->pathmtu = SCTP_DEFAULT_MAXSEGMENT;
} }
/* Hold a reference to a transport. */ /* Hold a reference to a transport. */
...@@ -369,7 +375,7 @@ void sctp_transport_raise_cwnd(struct sctp_transport *transport, ...@@ -369,7 +375,7 @@ void sctp_transport_raise_cwnd(struct sctp_transport *transport,
ssthresh = transport->ssthresh; ssthresh = transport->ssthresh;
pba = transport->partial_bytes_acked; pba = transport->partial_bytes_acked;
pmtu = transport->asoc->pmtu; pmtu = transport->asoc->pathmtu;
if (cwnd <= ssthresh) { if (cwnd <= ssthresh) {
/* RFC 2960 7.2.1, sctpimpguide-05 2.14.2 When cwnd is less /* RFC 2960 7.2.1, sctpimpguide-05 2.14.2 When cwnd is less
...@@ -441,8 +447,8 @@ void sctp_transport_lower_cwnd(struct sctp_transport *transport, ...@@ -441,8 +447,8 @@ void sctp_transport_lower_cwnd(struct sctp_transport *transport,
* partial_bytes_acked = 0 * partial_bytes_acked = 0
*/ */
transport->ssthresh = max(transport->cwnd/2, transport->ssthresh = max(transport->cwnd/2,
4*transport->asoc->pmtu); 4*transport->asoc->pathmtu);
transport->cwnd = transport->asoc->pmtu; transport->cwnd = transport->asoc->pathmtu;
break; break;
case SCTP_LOWER_CWND_FAST_RTX: case SCTP_LOWER_CWND_FAST_RTX:
...@@ -459,7 +465,7 @@ void sctp_transport_lower_cwnd(struct sctp_transport *transport, ...@@ -459,7 +465,7 @@ void sctp_transport_lower_cwnd(struct sctp_transport *transport,
* partial_bytes_acked = 0 * partial_bytes_acked = 0
*/ */
transport->ssthresh = max(transport->cwnd/2, transport->ssthresh = max(transport->cwnd/2,
4*transport->asoc->pmtu); 4*transport->asoc->pathmtu);
transport->cwnd = transport->ssthresh; transport->cwnd = transport->ssthresh;
break; break;
...@@ -479,7 +485,7 @@ void sctp_transport_lower_cwnd(struct sctp_transport *transport, ...@@ -479,7 +485,7 @@ void sctp_transport_lower_cwnd(struct sctp_transport *transport,
if ((jiffies - transport->last_time_ecne_reduced) > if ((jiffies - transport->last_time_ecne_reduced) >
transport->rtt) { transport->rtt) {
transport->ssthresh = max(transport->cwnd/2, transport->ssthresh = max(transport->cwnd/2,
4*transport->asoc->pmtu); 4*transport->asoc->pathmtu);
transport->cwnd = transport->ssthresh; transport->cwnd = transport->ssthresh;
transport->last_time_ecne_reduced = jiffies; transport->last_time_ecne_reduced = jiffies;
} }
...@@ -496,7 +502,7 @@ void sctp_transport_lower_cwnd(struct sctp_transport *transport, ...@@ -496,7 +502,7 @@ void sctp_transport_lower_cwnd(struct sctp_transport *transport,
*/ */
if ((jiffies - transport->last_time_used) > transport->rto) if ((jiffies - transport->last_time_used) > transport->rto)
transport->cwnd = max(transport->cwnd/2, transport->cwnd = max(transport->cwnd/2,
4*transport->asoc->pmtu); 4*transport->asoc->pathmtu);
break; break;
}; };
...@@ -511,7 +517,7 @@ void sctp_transport_lower_cwnd(struct sctp_transport *transport, ...@@ -511,7 +517,7 @@ void sctp_transport_lower_cwnd(struct sctp_transport *transport,
unsigned long sctp_transport_timeout(struct sctp_transport *t) unsigned long sctp_transport_timeout(struct sctp_transport *t)
{ {
unsigned long timeout; unsigned long timeout;
timeout = t->hb_interval + t->rto + sctp_jitter(t->rto); timeout = t->hbinterval + t->rto + sctp_jitter(t->rto);
timeout += jiffies; timeout += jiffies;
return timeout; return timeout;
} }
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