diff options
Diffstat (limited to 'net/sctp/socket.c')
-rw-r--r-- | net/sctp/socket.c | 84 |
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 | */ | ||
2819 | static 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 | */ | ||
4586 | static 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 | |||
4539 | SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname, | 4605 | SCTP_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 | ||