Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d364d927 authored by Wei Yongjun's avatar Wei Yongjun Committed by David S. Miller
Browse files

sctp: Bring SCTP_DELAYED_ACK socket option into API compliance



Brings delayed_ack socket option set/get into line with the latest ietf
socket extensions API draft, while maintaining backwards compatibility.

Signed-off-by: default avatarWei Yongjun <yjwei@cn.fujitsu.com>
Signed-off-by: default avatarVlad Yasevich <vladislav.yasevich@hp.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 5c5e1289
Loading
Loading
Loading
Loading
+4 −0
Original line number Original line Diff line number Diff line
@@ -300,6 +300,7 @@ struct sctp_sock {


	/* The default SACK delay timeout for new associations. */
	/* The default SACK delay timeout for new associations. */
	__u32 sackdelay;
	__u32 sackdelay;
	__u32 sackfreq;


	/* Flags controlling Heartbeat, SACK delay, and Path MTU Discovery. */
	/* Flags controlling Heartbeat, SACK delay, and Path MTU Discovery. */
	__u32 param_flags;
	__u32 param_flags;
@@ -938,6 +939,7 @@ struct sctp_transport {


	/* SACK delay timeout */
	/* SACK delay timeout */
	unsigned long sackdelay;
	unsigned long sackdelay;
	__u32 sackfreq;


	/* 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.
@@ -1542,6 +1544,7 @@ struct sctp_association {
		 *             : SACK's are not delayed (see Section 6).
		 *             : SACK's are not delayed (see Section 6).
		 */
		 */
		__u8    sack_needed;     /* Do we need to sack the peer? */
		__u8    sack_needed;     /* Do we need to sack the peer? */
		__u32	sack_cnt;


		/* These are capabilities which our peer advertised.  */
		/* These are capabilities which our peer advertised.  */
		__u8	ecn_capable;	 /* Can peer do ECN? */
		__u8	ecn_capable;	 /* Can peer do ECN? */
@@ -1651,6 +1654,7 @@ struct sctp_association {


	/* SACK delay timeout */
	/* SACK delay timeout */
	unsigned long sackdelay;
	unsigned long sackdelay;
	__u32 sackfreq;




	unsigned long timeouts[SCTP_NUM_TIMEOUT_TYPES];
	unsigned long timeouts[SCTP_NUM_TIMEOUT_TYPES];
+21 −7
Original line number Original line Diff line number Diff line
@@ -93,8 +93,9 @@ enum sctp_optname {
#define SCTP_STATUS SCTP_STATUS
#define SCTP_STATUS SCTP_STATUS
	SCTP_GET_PEER_ADDR_INFO,
	SCTP_GET_PEER_ADDR_INFO,
#define SCTP_GET_PEER_ADDR_INFO SCTP_GET_PEER_ADDR_INFO
#define SCTP_GET_PEER_ADDR_INFO SCTP_GET_PEER_ADDR_INFO
	SCTP_DELAYED_ACK_TIME,
	SCTP_DELAYED_ACK,
#define SCTP_DELAYED_ACK_TIME SCTP_DELAYED_ACK_TIME
#define SCTP_DELAYED_ACK_TIME SCTP_DELAYED_ACK
#define SCTP_DELAYED_ACK SCTP_DELAYED_ACK
	SCTP_CONTEXT,	/* Receive Context */
	SCTP_CONTEXT,	/* Receive Context */
#define SCTP_CONTEXT SCTP_CONTEXT
#define SCTP_CONTEXT SCTP_CONTEXT
	SCTP_FRAGMENT_INTERLEAVE,
	SCTP_FRAGMENT_INTERLEAVE,
@@ -618,13 +619,26 @@ struct sctp_authkeyid {
};
};




/* 7.1.23. Delayed Ack Timer (SCTP_DELAYED_ACK_TIME)
/*
 * 7.1.23.  Get or set delayed ack timer (SCTP_DELAYED_SACK)
 *
 *
 *   This options will get or set the delayed ack timer.  The time is set
 * This option will effect the way delayed acks are performed.  This
 *   in milliseconds.  If the assoc_id is 0, then this sets or gets the
 * option allows you to get or set the delayed ack time, in
 *   endpoints default delayed ack timer value.  If the assoc_id field is
 * milliseconds.  It also allows changing the delayed ack frequency.
 *   non-zero, then the set or get effects the specified association.
 * 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;
};

struct sctp_assoc_value {
struct sctp_assoc_value {
    sctp_assoc_t            assoc_id;
    sctp_assoc_t            assoc_id;
    uint32_t                assoc_value;
    uint32_t                assoc_value;
+3 −0
Original line number Original line Diff line number Diff line
@@ -136,6 +136,7 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a


	/* Set association default SACK delay */
	/* Set association default SACK delay */
	asoc->sackdelay = msecs_to_jiffies(sp->sackdelay);
	asoc->sackdelay = msecs_to_jiffies(sp->sackdelay);
	asoc->sackfreq = sp->sackfreq;


	/* Set the association default flags controlling
	/* Set the association default flags controlling
	 * Heartbeat, SACK delay, and Path MTU Discovery.
	 * Heartbeat, SACK delay, and Path MTU Discovery.
@@ -261,6 +262,7 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a
	 * already received one packet.]
	 * already received one packet.]
	 */
	 */
	asoc->peer.sack_needed = 1;
	asoc->peer.sack_needed = 1;
	asoc->peer.sack_cnt = 0;


	/* Assume that the peer will tell us if he recognizes ASCONF
	/* Assume that the peer will tell us if he recognizes ASCONF
	 * as part of INIT exchange.
	 * as part of INIT exchange.
@@ -615,6 +617,7 @@ struct sctp_transport *sctp_assoc_add_peer(struct sctp_association *asoc,
	 * association configured value.
	 * association configured value.
	 */
	 */
	peer->sackdelay = asoc->sackdelay;
	peer->sackdelay = asoc->sackdelay;
	peer->sackfreq = asoc->sackfreq;


	/* Enable/disable heartbeat, SACK delay, and path MTU discovery
	/* Enable/disable heartbeat, SACK delay, and path MTU discovery
	 * based on association setting.
	 * based on association setting.
+13 −4
Original line number Original line Diff line number Diff line
@@ -190,20 +190,28 @@ static int sctp_gen_sack(struct sctp_association *asoc, int force,
	 * unacknowledged DATA chunk. ...
	 * unacknowledged DATA chunk. ...
	 */
	 */
	if (!asoc->peer.sack_needed) {
	if (!asoc->peer.sack_needed) {
		/* We will need a SACK for the next packet.  */
		asoc->peer.sack_cnt++;
		asoc->peer.sack_needed = 1;


		/* Set the SACK delay timeout based on the
		/* Set the SACK delay timeout based on the
		 * SACK delay for the last transport
		 * SACK delay for the last transport
		 * data was received from, or the default
		 * data was received from, or the default
		 * for the association.
		 * for the association.
		 */
		 */
		if (trans)
		if (trans) {
			/* We will need a SACK for the next packet.  */
			if (asoc->peer.sack_cnt >= trans->sackfreq - 1)
				asoc->peer.sack_needed = 1;

			asoc->timeouts[SCTP_EVENT_TIMEOUT_SACK] =
			asoc->timeouts[SCTP_EVENT_TIMEOUT_SACK] =
				trans->sackdelay;
				trans->sackdelay;
		else
		} else {
			/* We will need a SACK for the next packet.  */
			if (asoc->peer.sack_cnt >= asoc->sackfreq - 1)
				asoc->peer.sack_needed = 1;

			asoc->timeouts[SCTP_EVENT_TIMEOUT_SACK] =
			asoc->timeouts[SCTP_EVENT_TIMEOUT_SACK] =
				asoc->sackdelay;
				asoc->sackdelay;
		}


		/* Restart the SACK timer. */
		/* Restart the SACK timer. */
		sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_RESTART,
		sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_RESTART,
@@ -216,6 +224,7 @@ static int sctp_gen_sack(struct sctp_association *asoc, int force,
			goto nomem;
			goto nomem;


		asoc->peer.sack_needed = 0;
		asoc->peer.sack_needed = 0;
		asoc->peer.sack_cnt = 0;


		sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(sack));
		sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(sack));


+153 −89
Original line number Original line Diff line number Diff line
@@ -2305,74 +2305,98 @@ static int sctp_setsockopt_peer_addr_params(struct sock *sk,
	return 0;
	return 0;
}
}


/* 7.1.23. Delayed Ack Timer (SCTP_DELAYED_ACK_TIME)
/*
 *
 * 7.1.23.  Get or set delayed ack timer (SCTP_DELAYED_SACK)
 *   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
 * This option will effect the way delayed acks are performed.  This
 *   endpoints default delayed ack timer value.  If the assoc_id field is
 * option allows you to get or set the delayed ack time, in
 *   non-zero, then the set or get effects the specified association.
 * milliseconds.  It also allows changing the delayed ack frequency.
 *
 * Changing the frequency to 1 disables the delayed sack algorithm.  If
 *   struct sctp_assoc_value {
 * the assoc_id is 0, then this sets or gets the endpoints default
 *       sctp_assoc_t            assoc_id;
 * values.  If the assoc_id field is non-zero, then the set or get
 *       uint32_t                assoc_value;
 * 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
 * sack_assoc_id -  This parameter, indicates which association the user
 *                   user is preforming an action upon. Note that if
 *    is performing an action upon.  Note that if this field's value is
 *                   this field's value is zero then the endpoints
 *    zero then the endpoints default value is changed (effecting future
 *                   default value is changed (effecting future
 *    associations only).
 *    associations only).
 *
 *
 *     assoc_value - This parameter contains the number of milliseconds
 * sack_delay -  This parameter contains the number of milliseconds that
 *                   that the user is requesting the delayed ACK timer
 *    the user is requesting the delayed ACK timer be set to.  Note that
 *                   be set to. Note that this value is defined in
 *    this value is defined in the standard to be between 200 and 500
 *                   the standard to be between 200 and 500 milliseconds.
 *    milliseconds.
 *
 *
 *                   Note: a value of zero will leave the value alone,
 * sack_freq -  This parameter contains the number of packets that must
 *                   but disable SACK delay. A non-zero value will also
 *    be received before a sack is sent without waiting for the delay
 *                   enable SACK 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)
					    char __user *optval, int optlen)
{
{
	struct sctp_assoc_value  params;
	struct sctp_sack_info    params;
	struct sctp_transport   *trans = NULL;
	struct sctp_transport   *trans = NULL;
	struct sctp_association *asoc = NULL;
	struct sctp_association *asoc = NULL;
	struct sctp_sock        *sp = sctp_sk(sk);
	struct sctp_sock        *sp = sctp_sk(sk);


	if (optlen != sizeof(struct sctp_assoc_value))
	if (optlen == sizeof(struct sctp_sack_info)) {
		return - EINVAL;
		if (copy_from_user(&params, 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(&params, optval, optlen))
		if (copy_from_user(&params, optval, optlen))
			return -EFAULT;
			return -EFAULT;


		if (params.sack_delay == 0)
			params.sack_freq = 1;
		else
			params.sack_freq = 0;
	} else
		return - EINVAL;

	/* Validate value parameter. */
	/* Validate value parameter. */
	if (params.assoc_value > 500)
	if (params.sack_delay > 500)
		return -EINVAL;
		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
	 * to many style socket, and an association was not found, then
	 * the id was invalid.
	 * the id was invalid.
	 */
	 */
	asoc = sctp_id2assoc(sk, params.assoc_id);
	asoc = sctp_id2assoc(sk, params.sack_assoc_id);
	if (!asoc && params.assoc_id && sctp_style(sk, UDP))
	if (!asoc && params.sack_assoc_id && sctp_style(sk, UDP))
		return -EINVAL;
		return -EINVAL;


	if (params.assoc_value) {
	if (params.sack_delay) {
		if (asoc) {
		if (asoc) {
			asoc->sackdelay =
			asoc->sackdelay =
				msecs_to_jiffies(params.assoc_value);
				msecs_to_jiffies(params.sack_delay);
			asoc->param_flags =
			asoc->param_flags =
				(asoc->param_flags & ~SPP_SACKDELAY) |
				(asoc->param_flags & ~SPP_SACKDELAY) |
				SPP_SACKDELAY_ENABLE;
				SPP_SACKDELAY_ENABLE;
		} else {
		} else {
			sp->sackdelay = params.assoc_value;
			sp->sackdelay = params.sack_delay;
			sp->param_flags =
			sp->param_flags =
				(sp->param_flags & ~SPP_SACKDELAY) |
				(sp->param_flags & ~SPP_SACKDELAY) |
				SPP_SACKDELAY_ENABLE;
				SPP_SACKDELAY_ENABLE;
		}
		}
	} else {
	}

	if (params.sack_freq == 1) {
		if (asoc) {
		if (asoc) {
			asoc->param_flags =
			asoc->param_flags =
				(asoc->param_flags & ~SPP_SACKDELAY) |
				(asoc->param_flags & ~SPP_SACKDELAY) |
@@ -2382,22 +2406,40 @@ static int sctp_setsockopt_delayed_ack_time(struct sock *sk,
				(sp->param_flags & ~SPP_SACKDELAY) |
				(sp->param_flags & ~SPP_SACKDELAY) |
				SPP_SACKDELAY_DISABLE;
				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 change is for association, also apply to each transport. */
	if (asoc) {
	if (asoc) {
		list_for_each_entry(trans, &asoc->peer.transport_addr_list,
		list_for_each_entry(trans, &asoc->peer.transport_addr_list,
				transports) {
				transports) {
			if (params.assoc_value) {
			if (params.sack_delay) {
				trans->sackdelay =
				trans->sackdelay =
					msecs_to_jiffies(params.assoc_value);
					msecs_to_jiffies(params.sack_delay);
				trans->param_flags =
				trans->param_flags =
					(trans->param_flags & ~SPP_SACKDELAY) |
					(trans->param_flags & ~SPP_SACKDELAY) |
					SPP_SACKDELAY_ENABLE;
					SPP_SACKDELAY_ENABLE;
			} else {
			}
			if (params.sack_delay == 1) {
				trans->param_flags =
				trans->param_flags =
					(trans->param_flags & ~SPP_SACKDELAY) |
					(trans->param_flags & ~SPP_SACKDELAY) |
					SPP_SACKDELAY_DISABLE;
					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);
		retval = sctp_setsockopt_peer_addr_params(sk, optval, optlen);
		break;
		break;


	case SCTP_DELAYED_ACK_TIME:
	case SCTP_DELAYED_ACK:
		retval = sctp_setsockopt_delayed_ack_time(sk, optval, optlen);
		retval = sctp_setsockopt_delayed_ack(sk, optval, optlen);
		break;
		break;
	case SCTP_PARTIAL_DELIVERY_POINT:
	case SCTP_PARTIAL_DELIVERY_POINT:
		retval = sctp_setsockopt_partial_delivery_point(sk, optval, optlen);
		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->pathmaxrxt  = sctp_max_retrans_path;
	sp->pathmtu     = 0; // allow default discovery
	sp->pathmtu     = 0; // allow default discovery
	sp->sackdelay   = sctp_sack_timeout;
	sp->sackdelay   = sctp_sack_timeout;
	sp->sackfreq	= 3;
	sp->param_flags = SPP_HB_ENABLE |
	sp->param_flags = SPP_HB_ENABLE |
			  SPP_PMTUD_ENABLE |
			  SPP_PMTUD_ENABLE |
			  SPP_SACKDELAY_ENABLE;
			  SPP_SACKDELAY_ENABLE;
@@ -3999,70 +4042,91 @@ static int sctp_getsockopt_peer_addr_params(struct sock *sk, int len,
	return 0;
	return 0;
}
}


/* 7.1.23. Delayed Ack Timer (SCTP_DELAYED_ACK_TIME)
/*
 *
 * 7.1.23.  Get or set delayed ack timer (SCTP_DELAYED_SACK)
 *   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
 * This option will effect the way delayed acks are performed.  This
 *   endpoints default delayed ack timer value.  If the assoc_id field is
 * option allows you to get or set the delayed ack time, in
 *   non-zero, then the set or get effects the specified association.
 * milliseconds.  It also allows changing the delayed ack frequency.
 *
 * Changing the frequency to 1 disables the delayed sack algorithm.  If
 *   struct sctp_assoc_value {
 * the assoc_id is 0, then this sets or gets the endpoints default
 *       sctp_assoc_t            assoc_id;
 * values.  If the assoc_id field is non-zero, then the set or get
 *       uint32_t                assoc_value;
 * 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
 * sack_assoc_id -  This parameter, indicates which association the user
 *                   user is preforming an action upon. Note that if
 *    is performing an action upon.  Note that if this field's value is
 *                   this field's value is zero then the endpoints
 *    zero then the endpoints default value is changed (effecting future
 *                   default value is changed (effecting future
 *    associations only).
 *    associations only).
 *
 *
 *     assoc_value - This parameter contains the number of milliseconds
 * sack_delay -  This parameter contains the number of milliseconds that
 *                   that the user is requesting the delayed ACK timer
 *    the user is requesting the delayed ACK timer be set to.  Note that
 *                   be set to. Note that this value is defined in
 *    this value is defined in the standard to be between 200 and 500
 *                   the standard to be between 200 and 500 milliseconds.
 *    milliseconds.
 *
 *
 *                   Note: a value of zero will leave the value alone,
 * sack_freq -  This parameter contains the number of packets that must
 *                   but disable SACK delay. A non-zero value will also
 *    be received before a sack is sent without waiting for the delay
 *                   enable SACK 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,
					    char __user *optval,
					    int __user *optlen)
					    int __user *optlen)
{
{
	struct sctp_assoc_value  params;
	struct sctp_sack_info    params;
	struct sctp_association *asoc = NULL;
	struct sctp_association *asoc = NULL;
	struct sctp_sock        *sp = sctp_sk(sk);
	struct sctp_sock        *sp = sctp_sk(sk);


	if (len < sizeof(struct sctp_assoc_value))
	if (len >= sizeof(struct sctp_sack_info)) {
		return - EINVAL;
		len = sizeof(struct sctp_sack_info);

	len = sizeof(struct sctp_assoc_value);


		if (copy_from_user(&params, optval, len))
		if (copy_from_user(&params, optval, len))
			return -EFAULT;
			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(&params, 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
	 * to many style socket, and an association was not found, then
	 * the id was invalid.
	 * the id was invalid.
	 */
	 */
	asoc = sctp_id2assoc(sk, params.assoc_id);
	asoc = sctp_id2assoc(sk, params.sack_assoc_id);
	if (!asoc && params.assoc_id && sctp_style(sk, UDP))
	if (!asoc && params.sack_assoc_id && sctp_style(sk, UDP))
		return -EINVAL;
		return -EINVAL;


	if (asoc) {
	if (asoc) {
		/* Fetch association values. */
		/* Fetch association values. */
		if (asoc->param_flags & SPP_SACKDELAY_ENABLE)
		if (asoc->param_flags & SPP_SACKDELAY_ENABLE) {
			params.assoc_value = jiffies_to_msecs(
			params.sack_delay = jiffies_to_msecs(
				asoc->sackdelay);
				asoc->sackdelay);
		else
			params.sack_freq = asoc->sackfreq;
			params.assoc_value = 0;

		} else {
			params.sack_delay = 0;
			params.sack_freq = 1;
		}
	} else {
	} else {
		/* Fetch socket values. */
		/* Fetch socket values. */
		if (sp->param_flags & SPP_SACKDELAY_ENABLE)
		if (sp->param_flags & SPP_SACKDELAY_ENABLE) {
			params.assoc_value  = sp->sackdelay;
			params.sack_delay  = sp->sackdelay;
		else
			params.sack_freq = sp->sackfreq;
			params.assoc_value  = 0;
		} else {
			params.sack_delay  = 0;
			params.sack_freq = 1;
		}
	}
	}


	if (copy_to_user(optval, &params, len))
	if (copy_to_user(optval, &params, 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,
		retval = sctp_getsockopt_peer_addr_params(sk, len, optval,
							  optlen);
							  optlen);
		break;
		break;
	case SCTP_DELAYED_ACK_TIME:
	case SCTP_DELAYED_ACK:
		retval = sctp_getsockopt_delayed_ack_time(sk, len, optval,
		retval = sctp_getsockopt_delayed_ack(sk, len, optval,
							  optlen);
							  optlen);
		break;
		break;
	case SCTP_INITMSG:
	case SCTP_INITMSG: