|
@@ -2305,74 +2305,98 @@ static int sctp_setsockopt_peer_addr_params(struct sock *sk,
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-/* 7.1.23. Delayed Ack Timer (SCTP_DELAYED_ACK_TIME)
|
|
|
- *
|
|
|
- * This options will get or set the delayed ack timer. The time is set
|
|
|
- * in milliseconds. If the assoc_id is 0, then this sets or gets the
|
|
|
- * endpoints default delayed ack timer value. If the assoc_id field is
|
|
|
- * non-zero, then the set or get effects the specified association.
|
|
|
- *
|
|
|
- * struct sctp_assoc_value {
|
|
|
- * sctp_assoc_t assoc_id;
|
|
|
- * uint32_t assoc_value;
|
|
|
- * };
|
|
|
- *
|
|
|
- * assoc_id - This parameter, indicates which association the
|
|
|
- * user is preforming an action upon. Note that if
|
|
|
- * this field's value is zero then the endpoints
|
|
|
- * default value is changed (effecting future
|
|
|
- * associations only).
|
|
|
- *
|
|
|
- * assoc_value - This parameter contains the number of milliseconds
|
|
|
- * that the user is requesting the delayed ACK timer
|
|
|
- * be set to. Note that this value is defined in
|
|
|
- * the standard to be between 200 and 500 milliseconds.
|
|
|
- *
|
|
|
- * Note: a value of zero will leave the value alone,
|
|
|
- * but disable SACK delay. A non-zero value will also
|
|
|
- * enable SACK delay.
|
|
|
+/*
|
|
|
+ * 7.1.23. Get or set delayed ack timer (SCTP_DELAYED_SACK)
|
|
|
+ *
|
|
|
+ * This option will effect the way delayed acks are performed. This
|
|
|
+ * option allows you to get or set the delayed ack time, in
|
|
|
+ * milliseconds. It also allows changing the delayed ack frequency.
|
|
|
+ * Changing the frequency to 1 disables the delayed sack algorithm. If
|
|
|
+ * the assoc_id is 0, then this sets or gets the endpoints default
|
|
|
+ * values. If the assoc_id field is non-zero, then the set or get
|
|
|
+ * effects the specified association for the one to many model (the
|
|
|
+ * assoc_id field is ignored by the one to one model). Note that if
|
|
|
+ * sack_delay or sack_freq are 0 when setting this option, then the
|
|
|
+ * current values will remain unchanged.
|
|
|
+ *
|
|
|
+ * struct sctp_sack_info {
|
|
|
+ * sctp_assoc_t sack_assoc_id;
|
|
|
+ * uint32_t sack_delay;
|
|
|
+ * uint32_t sack_freq;
|
|
|
+ * };
|
|
|
+ *
|
|
|
+ * sack_assoc_id - This parameter, indicates which association the user
|
|
|
+ * is performing an action upon. Note that if this field's value is
|
|
|
+ * zero then the endpoints default value is changed (effecting future
|
|
|
+ * associations only).
|
|
|
+ *
|
|
|
+ * sack_delay - This parameter contains the number of milliseconds that
|
|
|
+ * the user is requesting the delayed ACK timer be set to. Note that
|
|
|
+ * this value is defined in the standard to be between 200 and 500
|
|
|
+ * milliseconds.
|
|
|
+ *
|
|
|
+ * sack_freq - This parameter contains the number of packets that must
|
|
|
+ * be received before a sack is sent without waiting for the delay
|
|
|
+ * timer to expire. The default value for this is 2, setting this
|
|
|
+ * value to 1 will disable the delayed sack algorithm.
|
|
|
*/
|
|
|
|
|
|
-static int sctp_setsockopt_delayed_ack_time(struct sock *sk,
|
|
|
+static int sctp_setsockopt_delayed_ack(struct sock *sk,
|
|
|
char __user *optval, int optlen)
|
|
|
{
|
|
|
- struct sctp_assoc_value params;
|
|
|
+ struct sctp_sack_info params;
|
|
|
struct sctp_transport *trans = NULL;
|
|
|
struct sctp_association *asoc = NULL;
|
|
|
struct sctp_sock *sp = sctp_sk(sk);
|
|
|
|
|
|
- if (optlen != sizeof(struct sctp_assoc_value))
|
|
|
- return - EINVAL;
|
|
|
+ if (optlen == sizeof(struct sctp_sack_info)) {
|
|
|
+ if (copy_from_user(¶ms, optval, optlen))
|
|
|
+ return -EFAULT;
|
|
|
|
|
|
- if (copy_from_user(¶ms, optval, optlen))
|
|
|
- return -EFAULT;
|
|
|
+ if (params.sack_delay == 0 && params.sack_freq == 0)
|
|
|
+ return 0;
|
|
|
+ } else if (optlen == sizeof(struct sctp_assoc_value)) {
|
|
|
+ printk(KERN_WARNING "SCTP: Use of struct sctp_sack_info "
|
|
|
+ "in delayed_ack socket option deprecated\n");
|
|
|
+ printk(KERN_WARNING "SCTP: struct sctp_sack_info instead\n");
|
|
|
+ if (copy_from_user(¶ms, optval, optlen))
|
|
|
+ return -EFAULT;
|
|
|
+
|
|
|
+ if (params.sack_delay == 0)
|
|
|
+ params.sack_freq = 1;
|
|
|
+ else
|
|
|
+ params.sack_freq = 0;
|
|
|
+ } else
|
|
|
+ return - EINVAL;
|
|
|
|
|
|
/* Validate value parameter. */
|
|
|
- if (params.assoc_value > 500)
|
|
|
+ if (params.sack_delay > 500)
|
|
|
return -EINVAL;
|
|
|
|
|
|
- /* Get association, if assoc_id != 0 and the socket is a one
|
|
|
+ /* Get association, if sack_assoc_id != 0 and the socket is a one
|
|
|
* to many style socket, and an association was not found, then
|
|
|
* the id was invalid.
|
|
|
*/
|
|
|
- asoc = sctp_id2assoc(sk, params.assoc_id);
|
|
|
- if (!asoc && params.assoc_id && sctp_style(sk, UDP))
|
|
|
+ asoc = sctp_id2assoc(sk, params.sack_assoc_id);
|
|
|
+ if (!asoc && params.sack_assoc_id && sctp_style(sk, UDP))
|
|
|
return -EINVAL;
|
|
|
|
|
|
- if (params.assoc_value) {
|
|
|
+ if (params.sack_delay) {
|
|
|
if (asoc) {
|
|
|
asoc->sackdelay =
|
|
|
- msecs_to_jiffies(params.assoc_value);
|
|
|
+ msecs_to_jiffies(params.sack_delay);
|
|
|
asoc->param_flags =
|
|
|
(asoc->param_flags & ~SPP_SACKDELAY) |
|
|
|
SPP_SACKDELAY_ENABLE;
|
|
|
} else {
|
|
|
- sp->sackdelay = params.assoc_value;
|
|
|
+ sp->sackdelay = params.sack_delay;
|
|
|
sp->param_flags =
|
|
|
(sp->param_flags & ~SPP_SACKDELAY) |
|
|
|
SPP_SACKDELAY_ENABLE;
|
|
|
}
|
|
|
- } else {
|
|
|
+ }
|
|
|
+
|
|
|
+ if (params.sack_freq == 1) {
|
|
|
if (asoc) {
|
|
|
asoc->param_flags =
|
|
|
(asoc->param_flags & ~SPP_SACKDELAY) |
|
|
@@ -2382,22 +2406,40 @@ static int sctp_setsockopt_delayed_ack_time(struct sock *sk,
|
|
|
(sp->param_flags & ~SPP_SACKDELAY) |
|
|
|
SPP_SACKDELAY_DISABLE;
|
|
|
}
|
|
|
+ } else if (params.sack_freq > 1) {
|
|
|
+ if (asoc) {
|
|
|
+ asoc->sackfreq = params.sack_freq;
|
|
|
+ asoc->param_flags =
|
|
|
+ (asoc->param_flags & ~SPP_SACKDELAY) |
|
|
|
+ SPP_SACKDELAY_ENABLE;
|
|
|
+ } else {
|
|
|
+ sp->sackfreq = params.sack_freq;
|
|
|
+ sp->param_flags =
|
|
|
+ (sp->param_flags & ~SPP_SACKDELAY) |
|
|
|
+ SPP_SACKDELAY_ENABLE;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
/* If change is for association, also apply to each transport. */
|
|
|
if (asoc) {
|
|
|
list_for_each_entry(trans, &asoc->peer.transport_addr_list,
|
|
|
transports) {
|
|
|
- if (params.assoc_value) {
|
|
|
+ if (params.sack_delay) {
|
|
|
trans->sackdelay =
|
|
|
- msecs_to_jiffies(params.assoc_value);
|
|
|
+ msecs_to_jiffies(params.sack_delay);
|
|
|
trans->param_flags =
|
|
|
(trans->param_flags & ~SPP_SACKDELAY) |
|
|
|
SPP_SACKDELAY_ENABLE;
|
|
|
- } else {
|
|
|
+ }
|
|
|
+ if (params.sack_delay == 1) {
|
|
|
trans->param_flags =
|
|
|
(trans->param_flags & ~SPP_SACKDELAY) |
|
|
|
SPP_SACKDELAY_DISABLE;
|
|
|
+ } else if (params.sack_freq > 1) {
|
|
|
+ trans->sackfreq = params.sack_freq;
|
|
|
+ trans->param_flags =
|
|
|
+ (trans->param_flags & ~SPP_SACKDELAY) |
|
|
|
+ SPP_SACKDELAY_ENABLE;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
@@ -3186,8 +3228,8 @@ SCTP_STATIC int sctp_setsockopt(struct sock *sk, int level, int optname,
|
|
|
retval = sctp_setsockopt_peer_addr_params(sk, optval, optlen);
|
|
|
break;
|
|
|
|
|
|
- case SCTP_DELAYED_ACK_TIME:
|
|
|
- retval = sctp_setsockopt_delayed_ack_time(sk, optval, optlen);
|
|
|
+ case SCTP_DELAYED_ACK:
|
|
|
+ retval = sctp_setsockopt_delayed_ack(sk, optval, optlen);
|
|
|
break;
|
|
|
case SCTP_PARTIAL_DELIVERY_POINT:
|
|
|
retval = sctp_setsockopt_partial_delivery_point(sk, optval, optlen);
|
|
@@ -3446,6 +3488,7 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk)
|
|
|
sp->pathmaxrxt = sctp_max_retrans_path;
|
|
|
sp->pathmtu = 0; // allow default discovery
|
|
|
sp->sackdelay = sctp_sack_timeout;
|
|
|
+ sp->sackfreq = 3;
|
|
|
sp->param_flags = SPP_HB_ENABLE |
|
|
|
SPP_PMTUD_ENABLE |
|
|
|
SPP_SACKDELAY_ENABLE;
|
|
@@ -3999,70 +4042,91 @@ static int sctp_getsockopt_peer_addr_params(struct sock *sk, int len,
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-/* 7.1.23. Delayed Ack Timer (SCTP_DELAYED_ACK_TIME)
|
|
|
- *
|
|
|
- * This options will get or set the delayed ack timer. The time is set
|
|
|
- * in milliseconds. If the assoc_id is 0, then this sets or gets the
|
|
|
- * endpoints default delayed ack timer value. If the assoc_id field is
|
|
|
- * non-zero, then the set or get effects the specified association.
|
|
|
- *
|
|
|
- * struct sctp_assoc_value {
|
|
|
- * sctp_assoc_t assoc_id;
|
|
|
- * uint32_t assoc_value;
|
|
|
- * };
|
|
|
+/*
|
|
|
+ * 7.1.23. Get or set delayed ack timer (SCTP_DELAYED_SACK)
|
|
|
+ *
|
|
|
+ * This option will effect the way delayed acks are performed. This
|
|
|
+ * option allows you to get or set the delayed ack time, in
|
|
|
+ * milliseconds. It also allows changing the delayed ack frequency.
|
|
|
+ * Changing the frequency to 1 disables the delayed sack algorithm. If
|
|
|
+ * the assoc_id is 0, then this sets or gets the endpoints default
|
|
|
+ * values. If the assoc_id field is non-zero, then the set or get
|
|
|
+ * effects the specified association for the one to many model (the
|
|
|
+ * assoc_id field is ignored by the one to one model). Note that if
|
|
|
+ * sack_delay or sack_freq are 0 when setting this option, then the
|
|
|
+ * current values will remain unchanged.
|
|
|
+ *
|
|
|
+ * struct sctp_sack_info {
|
|
|
+ * sctp_assoc_t sack_assoc_id;
|
|
|
+ * uint32_t sack_delay;
|
|
|
+ * uint32_t sack_freq;
|
|
|
+ * };
|
|
|
*
|
|
|
- * assoc_id - This parameter, indicates which association the
|
|
|
- * user is preforming an action upon. Note that if
|
|
|
- * this field's value is zero then the endpoints
|
|
|
- * default value is changed (effecting future
|
|
|
- * associations only).
|
|
|
+ * sack_assoc_id - This parameter, indicates which association the user
|
|
|
+ * is performing an action upon. Note that if this field's value is
|
|
|
+ * zero then the endpoints default value is changed (effecting future
|
|
|
+ * associations only).
|
|
|
*
|
|
|
- * assoc_value - This parameter contains the number of milliseconds
|
|
|
- * that the user is requesting the delayed ACK timer
|
|
|
- * be set to. Note that this value is defined in
|
|
|
- * the standard to be between 200 and 500 milliseconds.
|
|
|
+ * sack_delay - This parameter contains the number of milliseconds that
|
|
|
+ * the user is requesting the delayed ACK timer be set to. Note that
|
|
|
+ * this value is defined in the standard to be between 200 and 500
|
|
|
+ * milliseconds.
|
|
|
*
|
|
|
- * Note: a value of zero will leave the value alone,
|
|
|
- * but disable SACK delay. A non-zero value will also
|
|
|
- * enable SACK delay.
|
|
|
+ * sack_freq - This parameter contains the number of packets that must
|
|
|
+ * be received before a sack is sent without waiting for the delay
|
|
|
+ * timer to expire. The default value for this is 2, setting this
|
|
|
+ * value to 1 will disable the delayed sack algorithm.
|
|
|
*/
|
|
|
-static int sctp_getsockopt_delayed_ack_time(struct sock *sk, int len,
|
|
|
+static int sctp_getsockopt_delayed_ack(struct sock *sk, int len,
|
|
|
char __user *optval,
|
|
|
int __user *optlen)
|
|
|
{
|
|
|
- struct sctp_assoc_value params;
|
|
|
+ struct sctp_sack_info params;
|
|
|
struct sctp_association *asoc = NULL;
|
|
|
struct sctp_sock *sp = sctp_sk(sk);
|
|
|
|
|
|
- if (len < sizeof(struct sctp_assoc_value))
|
|
|
- return - EINVAL;
|
|
|
+ if (len >= sizeof(struct sctp_sack_info)) {
|
|
|
+ len = sizeof(struct sctp_sack_info);
|
|
|
|
|
|
- len = sizeof(struct sctp_assoc_value);
|
|
|
-
|
|
|
- if (copy_from_user(¶ms, optval, len))
|
|
|
- return -EFAULT;
|
|
|
+ if (copy_from_user(¶ms, optval, len))
|
|
|
+ return -EFAULT;
|
|
|
+ } else if (len == sizeof(struct sctp_assoc_value)) {
|
|
|
+ printk(KERN_WARNING "SCTP: Use of struct sctp_sack_info "
|
|
|
+ "in delayed_ack socket option deprecated\n");
|
|
|
+ printk(KERN_WARNING "SCTP: struct sctp_sack_info instead\n");
|
|
|
+ if (copy_from_user(¶ms, optval, len))
|
|
|
+ return -EFAULT;
|
|
|
+ } else
|
|
|
+ return - EINVAL;
|
|
|
|
|
|
- /* Get association, if assoc_id != 0 and the socket is a one
|
|
|
+ /* Get association, if sack_assoc_id != 0 and the socket is a one
|
|
|
* to many style socket, and an association was not found, then
|
|
|
* the id was invalid.
|
|
|
*/
|
|
|
- asoc = sctp_id2assoc(sk, params.assoc_id);
|
|
|
- if (!asoc && params.assoc_id && sctp_style(sk, UDP))
|
|
|
+ asoc = sctp_id2assoc(sk, params.sack_assoc_id);
|
|
|
+ if (!asoc && params.sack_assoc_id && sctp_style(sk, UDP))
|
|
|
return -EINVAL;
|
|
|
|
|
|
if (asoc) {
|
|
|
/* Fetch association values. */
|
|
|
- if (asoc->param_flags & SPP_SACKDELAY_ENABLE)
|
|
|
- params.assoc_value = jiffies_to_msecs(
|
|
|
+ if (asoc->param_flags & SPP_SACKDELAY_ENABLE) {
|
|
|
+ params.sack_delay = jiffies_to_msecs(
|
|
|
asoc->sackdelay);
|
|
|
- else
|
|
|
- params.assoc_value = 0;
|
|
|
+ params.sack_freq = asoc->sackfreq;
|
|
|
+
|
|
|
+ } else {
|
|
|
+ params.sack_delay = 0;
|
|
|
+ params.sack_freq = 1;
|
|
|
+ }
|
|
|
} else {
|
|
|
/* Fetch socket values. */
|
|
|
- if (sp->param_flags & SPP_SACKDELAY_ENABLE)
|
|
|
- params.assoc_value = sp->sackdelay;
|
|
|
- else
|
|
|
- params.assoc_value = 0;
|
|
|
+ if (sp->param_flags & SPP_SACKDELAY_ENABLE) {
|
|
|
+ params.sack_delay = sp->sackdelay;
|
|
|
+ params.sack_freq = sp->sackfreq;
|
|
|
+ } else {
|
|
|
+ params.sack_delay = 0;
|
|
|
+ params.sack_freq = 1;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
if (copy_to_user(optval, ¶ms, len))
|
|
@@ -5218,8 +5282,8 @@ SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname,
|
|
|
retval = sctp_getsockopt_peer_addr_params(sk, len, optval,
|
|
|
optlen);
|
|
|
break;
|
|
|
- case SCTP_DELAYED_ACK_TIME:
|
|
|
- retval = sctp_getsockopt_delayed_ack_time(sk, len, optval,
|
|
|
+ case SCTP_DELAYED_ACK:
|
|
|
+ retval = sctp_getsockopt_delayed_ack(sk, len, optval,
|
|
|
optlen);
|
|
|
break;
|
|
|
case SCTP_INITMSG:
|