aboutsummaryrefslogtreecommitdiffstats
path: root/net/sctp/socket.c
diff options
context:
space:
mode:
authorVlad Yasevich <vladislav.yasevich@hp.com>2007-04-20 15:23:15 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2007-04-26 01:27:59 -0400
commitb6e1331f3ce25a56edb956054eaf8011654686cb (patch)
tree63995f7e1de7d717df69cb4d138bce3fa4fe77ba /net/sctp/socket.c
parentc95e939508e64863a1c5c73a9e1a908784e06820 (diff)
[SCTP]: Implement SCTP_FRAGMENT_INTERLEAVE socket option
This option was introduced in draft-ietf-tsvwg-sctpsocket-13. It prevents head-of-line blocking in the case of one-to-many endpoint. Applications enabling this option really must enable SCTP_SNDRCV event so that they would know where the data belongs. Based on an earlier patch by Ivan Skytte Jørgensen. Additionally, this functionality now permits multiple associations on the same endpoint to enter Partial Delivery. Applications should be extra careful, when using this functionality, to track EOR indicators. Signed-off-by: Vlad Yasevich <vladislav.yasevich@hp.com> Signed-off-by: David S. Miller <davem@davemloft.net>
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