aboutsummaryrefslogtreecommitdiffstats
path: root/net/sctp/socket.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/sctp/socket.c')
-rw-r--r--net/sctp/socket.c84
1 files changed, 77 insertions, 7 deletions
diff --git a/net/sctp/socket.c b/net/sctp/socket.c
index a1d026f12b0e..b4be473c68b0 100644
--- a/net/sctp/socket.c
+++ b/net/sctp/socket.c
@@ -2255,7 +2255,7 @@ static int sctp_setsockopt_peer_addr_params(struct sock *sk,
2255 return 0; 2255 return 0;
2256} 2256}
2257 2257
2258/* 7.1.24. Delayed Ack Timer (SCTP_DELAYED_ACK_TIME) 2258/* 7.1.23. Delayed Ack Timer (SCTP_DELAYED_ACK_TIME)
2259 * 2259 *
2260 * This options will get or set the delayed ack timer. The time is set 2260 * This options will get or set the delayed ack timer. The time is set
2261 * in milliseconds. If the assoc_id is 0, then this sets or gets the 2261 * in milliseconds. If the assoc_id is 0, then this sets or gets the
@@ -2792,6 +2792,46 @@ static int sctp_setsockopt_context(struct sock *sk, char __user *optval,
2792 return 0; 2792 return 0;
2793} 2793}
2794 2794
2795/*
2796 * 7.1.24. Get or set fragmented interleave (SCTP_FRAGMENT_INTERLEAVE)
2797 *
2798 * This options will at a minimum specify if the implementation is doing
2799 * fragmented interleave. Fragmented interleave, for a one to many
2800 * socket, is when subsequent calls to receive a message may return
2801 * parts of messages from different associations. Some implementations
2802 * may allow you to turn this value on or off. If so, when turned off,
2803 * no fragment interleave will occur (which will cause a head of line
2804 * blocking amongst multiple associations sharing the same one to many
2805 * socket). When this option is turned on, then each receive call may
2806 * come from a different association (thus the user must receive data
2807 * with the extended calls (e.g. sctp_recvmsg) to keep track of which
2808 * association each receive belongs to.
2809 *
2810 * This option takes a boolean value. A non-zero value indicates that
2811 * fragmented interleave is on. A value of zero indicates that
2812 * fragmented interleave is off.
2813 *
2814 * Note that it is important that an implementation that allows this
2815 * option to be turned on, have it off by default. Otherwise an unaware
2816 * application using the one to many model may become confused and act
2817 * incorrectly.
2818 */
2819static int sctp_setsockopt_fragment_interleave(struct sock *sk,
2820 char __user *optval,
2821 int optlen)
2822{
2823 int val;
2824
2825 if (optlen != sizeof(int))
2826 return -EINVAL;
2827 if (get_user(val, (int __user *)optval))
2828 return -EFAULT;
2829
2830 sctp_sk(sk)->frag_interleave = (val == 0) ? 0 : 1;
2831
2832 return 0;
2833}
2834
2795/* API 6.2 setsockopt(), getsockopt() 2835/* API 6.2 setsockopt(), getsockopt()
2796 * 2836 *
2797 * Applications use setsockopt() and getsockopt() to set or retrieve 2837 * Applications use setsockopt() and getsockopt() to set or retrieve
@@ -2906,7 +2946,9 @@ SCTP_STATIC int sctp_setsockopt(struct sock *sk, int level, int optname,
2906 case SCTP_CONTEXT: 2946 case SCTP_CONTEXT:
2907 retval = sctp_setsockopt_context(sk, optval, optlen); 2947 retval = sctp_setsockopt_context(sk, optval, optlen);
2908 break; 2948 break;
2909 2949 case SCTP_FRAGMENT_INTERLEAVE:
2950 retval = sctp_setsockopt_fragment_interleave(sk, optval, optlen);
2951 break;
2910 default: 2952 default:
2911 retval = -ENOPROTOOPT; 2953 retval = -ENOPROTOOPT;
2912 break; 2954 break;
@@ -3134,8 +3176,9 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk)
3134 sp->pf = sctp_get_pf_specific(sk->sk_family); 3176 sp->pf = sctp_get_pf_specific(sk->sk_family);
3135 3177
3136 /* Control variables for partial data delivery. */ 3178 /* Control variables for partial data delivery. */
3137 sp->pd_mode = 0; 3179 atomic_set(&sp->pd_mode, 0);
3138 skb_queue_head_init(&sp->pd_lobby); 3180 skb_queue_head_init(&sp->pd_lobby);
3181 sp->frag_interleave = 0;
3139 3182
3140 /* Create a per socket endpoint structure. Even if we 3183 /* Create a per socket endpoint structure. Even if we
3141 * change the data structure relationships, this may still 3184 * change the data structure relationships, this may still
@@ -3642,7 +3685,7 @@ static int sctp_getsockopt_peer_addr_params(struct sock *sk, int len,
3642 return 0; 3685 return 0;
3643} 3686}
3644 3687
3645/* 7.1.24. Delayed Ack Timer (SCTP_DELAYED_ACK_TIME) 3688/* 7.1.23. Delayed Ack Timer (SCTP_DELAYED_ACK_TIME)
3646 * 3689 *
3647 * This options will get or set the delayed ack timer. The time is set 3690 * This options will get or set the delayed ack timer. The time is set
3648 * in milliseconds. If the assoc_id is 0, then this sets or gets the 3691 * in milliseconds. If the assoc_id is 0, then this sets or gets the
@@ -4536,6 +4579,29 @@ static int sctp_getsockopt_maxseg(struct sock *sk, int len,
4536 return 0; 4579 return 0;
4537} 4580}
4538 4581
4582/*
4583 * 7.1.24. Get or set fragmented interleave (SCTP_FRAGMENT_INTERLEAVE)
4584 * (chapter and verse is quoted at sctp_setsockopt_fragment_interleave())
4585 */
4586static int sctp_getsockopt_fragment_interleave(struct sock *sk, int len,
4587 char __user *optval, int __user *optlen)
4588{
4589 int val;
4590
4591 if (len < sizeof(int))
4592 return -EINVAL;
4593
4594 len = sizeof(int);
4595
4596 val = sctp_sk(sk)->frag_interleave;
4597 if (put_user(len, optlen))
4598 return -EFAULT;
4599 if (copy_to_user(optval, &val, len))
4600 return -EFAULT;
4601
4602 return 0;
4603}
4604
4539SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname, 4605SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname,
4540 char __user *optval, int __user *optlen) 4606 char __user *optval, int __user *optlen)
4541{ 4607{
@@ -4648,6 +4714,10 @@ SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname,
4648 case SCTP_CONTEXT: 4714 case SCTP_CONTEXT:
4649 retval = sctp_getsockopt_context(sk, len, optval, optlen); 4715 retval = sctp_getsockopt_context(sk, len, optval, optlen);
4650 break; 4716 break;
4717 case SCTP_FRAGMENT_INTERLEAVE:
4718 retval = sctp_getsockopt_fragment_interleave(sk, len, optval,
4719 optlen);
4720 break;
4651 default: 4721 default:
4652 retval = -ENOPROTOOPT; 4722 retval = -ENOPROTOOPT;
4653 break; 4723 break;
@@ -5742,9 +5812,9 @@ static void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk,
5742 * 3) Peeling off non-partial delivery; move pd_lobby to receive_queue. 5812 * 3) Peeling off non-partial delivery; move pd_lobby to receive_queue.
5743 */ 5813 */
5744 skb_queue_head_init(&newsp->pd_lobby); 5814 skb_queue_head_init(&newsp->pd_lobby);
5745 sctp_sk(newsk)->pd_mode = assoc->ulpq.pd_mode; 5815 atomic_set(&sctp_sk(newsk)->pd_mode, assoc->ulpq.pd_mode);
5746 5816
5747 if (sctp_sk(oldsk)->pd_mode) { 5817 if (atomic_read(&sctp_sk(oldsk)->pd_mode)) {
5748 struct sk_buff_head *queue; 5818 struct sk_buff_head *queue;
5749 5819
5750 /* Decide which queue to move pd_lobby skbs to. */ 5820 /* Decide which queue to move pd_lobby skbs to. */
@@ -5770,7 +5840,7 @@ static void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk,
5770 * delivery to finish. 5840 * delivery to finish.
5771 */ 5841 */
5772 if (assoc->ulpq.pd_mode) 5842 if (assoc->ulpq.pd_mode)
5773 sctp_clear_pd(oldsk); 5843 sctp_clear_pd(oldsk, NULL);
5774 5844
5775 } 5845 }
5776 5846