diff options
Diffstat (limited to 'net/sctp/socket.c')
-rw-r--r-- | net/sctp/socket.c | 118 |
1 files changed, 94 insertions, 24 deletions
diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 1e8132b8c4d9..bdd8bd428b64 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c | |||
@@ -2746,6 +2746,46 @@ static int sctp_setsockopt_adaption_layer(struct sock *sk, char __user *optval, | |||
2746 | return 0; | 2746 | return 0; |
2747 | } | 2747 | } |
2748 | 2748 | ||
2749 | /* | ||
2750 | * 7.1.29. Set or Get the default context (SCTP_CONTEXT) | ||
2751 | * | ||
2752 | * The context field in the sctp_sndrcvinfo structure is normally only | ||
2753 | * used when a failed message is retrieved holding the value that was | ||
2754 | * sent down on the actual send call. This option allows the setting of | ||
2755 | * a default context on an association basis that will be received on | ||
2756 | * reading messages from the peer. This is especially helpful in the | ||
2757 | * one-2-many model for an application to keep some reference to an | ||
2758 | * internal state machine that is processing messages on the | ||
2759 | * association. Note that the setting of this value only effects | ||
2760 | * received messages from the peer and does not effect the value that is | ||
2761 | * saved with outbound messages. | ||
2762 | */ | ||
2763 | static int sctp_setsockopt_context(struct sock *sk, char __user *optval, | ||
2764 | int optlen) | ||
2765 | { | ||
2766 | struct sctp_assoc_value params; | ||
2767 | struct sctp_sock *sp; | ||
2768 | struct sctp_association *asoc; | ||
2769 | |||
2770 | if (optlen != sizeof(struct sctp_assoc_value)) | ||
2771 | return -EINVAL; | ||
2772 | if (copy_from_user(¶ms, optval, optlen)) | ||
2773 | return -EFAULT; | ||
2774 | |||
2775 | sp = sctp_sk(sk); | ||
2776 | |||
2777 | if (params.assoc_id != 0) { | ||
2778 | asoc = sctp_id2assoc(sk, params.assoc_id); | ||
2779 | if (!asoc) | ||
2780 | return -EINVAL; | ||
2781 | asoc->default_rcv_context = params.assoc_value; | ||
2782 | } else { | ||
2783 | sp->default_rcv_context = params.assoc_value; | ||
2784 | } | ||
2785 | |||
2786 | return 0; | ||
2787 | } | ||
2788 | |||
2749 | /* API 6.2 setsockopt(), getsockopt() | 2789 | /* API 6.2 setsockopt(), getsockopt() |
2750 | * | 2790 | * |
2751 | * Applications use setsockopt() and getsockopt() to set or retrieve | 2791 | * Applications use setsockopt() and getsockopt() to set or retrieve |
@@ -2857,6 +2897,9 @@ SCTP_STATIC int sctp_setsockopt(struct sock *sk, int level, int optname, | |||
2857 | case SCTP_ADAPTION_LAYER: | 2897 | case SCTP_ADAPTION_LAYER: |
2858 | retval = sctp_setsockopt_adaption_layer(sk, optval, optlen); | 2898 | retval = sctp_setsockopt_adaption_layer(sk, optval, optlen); |
2859 | break; | 2899 | break; |
2900 | case SCTP_CONTEXT: | ||
2901 | retval = sctp_setsockopt_context(sk, optval, optlen); | ||
2902 | break; | ||
2860 | 2903 | ||
2861 | default: | 2904 | default: |
2862 | retval = -ENOPROTOOPT; | 2905 | retval = -ENOPROTOOPT; |
@@ -3016,6 +3059,8 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk) | |||
3016 | sp->default_context = 0; | 3059 | sp->default_context = 0; |
3017 | sp->default_timetolive = 0; | 3060 | sp->default_timetolive = 0; |
3018 | 3061 | ||
3062 | sp->default_rcv_context = 0; | ||
3063 | |||
3019 | /* Initialize default setup parameters. These parameters | 3064 | /* Initialize default setup parameters. These parameters |
3020 | * can be modified with the SCTP_INITMSG socket option or | 3065 | * can be modified with the SCTP_INITMSG socket option or |
3021 | * overridden by the SCTP_INIT CMSG. | 3066 | * overridden by the SCTP_INIT CMSG. |
@@ -3821,10 +3866,9 @@ static int sctp_getsockopt_local_addrs_num_old(struct sock *sk, int len, | |||
3821 | sctp_assoc_t id; | 3866 | sctp_assoc_t id; |
3822 | struct sctp_bind_addr *bp; | 3867 | struct sctp_bind_addr *bp; |
3823 | struct sctp_association *asoc; | 3868 | struct sctp_association *asoc; |
3824 | struct list_head *pos; | 3869 | struct list_head *pos, *temp; |
3825 | struct sctp_sockaddr_entry *addr; | 3870 | struct sctp_sockaddr_entry *addr; |
3826 | rwlock_t *addr_lock; | 3871 | rwlock_t *addr_lock; |
3827 | unsigned long flags; | ||
3828 | int cnt = 0; | 3872 | int cnt = 0; |
3829 | 3873 | ||
3830 | if (len != sizeof(sctp_assoc_t)) | 3874 | if (len != sizeof(sctp_assoc_t)) |
@@ -3859,8 +3903,7 @@ static int sctp_getsockopt_local_addrs_num_old(struct sock *sk, int len, | |||
3859 | addr = list_entry(bp->address_list.next, | 3903 | addr = list_entry(bp->address_list.next, |
3860 | struct sctp_sockaddr_entry, list); | 3904 | struct sctp_sockaddr_entry, list); |
3861 | if (sctp_is_any(&addr->a)) { | 3905 | if (sctp_is_any(&addr->a)) { |
3862 | sctp_spin_lock_irqsave(&sctp_local_addr_lock, flags); | 3906 | list_for_each_safe(pos, temp, &sctp_local_addr_list) { |
3863 | list_for_each(pos, &sctp_local_addr_list) { | ||
3864 | addr = list_entry(pos, | 3907 | addr = list_entry(pos, |
3865 | struct sctp_sockaddr_entry, | 3908 | struct sctp_sockaddr_entry, |
3866 | list); | 3909 | list); |
@@ -3869,8 +3912,6 @@ static int sctp_getsockopt_local_addrs_num_old(struct sock *sk, int len, | |||
3869 | continue; | 3912 | continue; |
3870 | cnt++; | 3913 | cnt++; |
3871 | } | 3914 | } |
3872 | sctp_spin_unlock_irqrestore(&sctp_local_addr_lock, | ||
3873 | flags); | ||
3874 | } else { | 3915 | } else { |
3875 | cnt = 1; | 3916 | cnt = 1; |
3876 | } | 3917 | } |
@@ -3892,15 +3933,13 @@ done: | |||
3892 | static int sctp_copy_laddrs_to_user_old(struct sock *sk, __u16 port, int max_addrs, | 3933 | static int sctp_copy_laddrs_to_user_old(struct sock *sk, __u16 port, int max_addrs, |
3893 | void __user *to) | 3934 | void __user *to) |
3894 | { | 3935 | { |
3895 | struct list_head *pos; | 3936 | struct list_head *pos, *next; |
3896 | struct sctp_sockaddr_entry *addr; | 3937 | struct sctp_sockaddr_entry *addr; |
3897 | unsigned long flags; | ||
3898 | union sctp_addr temp; | 3938 | union sctp_addr temp; |
3899 | int cnt = 0; | 3939 | int cnt = 0; |
3900 | int addrlen; | 3940 | int addrlen; |
3901 | 3941 | ||
3902 | sctp_spin_lock_irqsave(&sctp_local_addr_lock, flags); | 3942 | list_for_each_safe(pos, next, &sctp_local_addr_list) { |
3903 | list_for_each(pos, &sctp_local_addr_list) { | ||
3904 | addr = list_entry(pos, struct sctp_sockaddr_entry, list); | 3943 | addr = list_entry(pos, struct sctp_sockaddr_entry, list); |
3905 | if ((PF_INET == sk->sk_family) && | 3944 | if ((PF_INET == sk->sk_family) && |
3906 | (AF_INET6 == addr->a.sa.sa_family)) | 3945 | (AF_INET6 == addr->a.sa.sa_family)) |
@@ -3909,16 +3948,13 @@ static int sctp_copy_laddrs_to_user_old(struct sock *sk, __u16 port, int max_add | |||
3909 | sctp_get_pf_specific(sk->sk_family)->addr_v4map(sctp_sk(sk), | 3948 | sctp_get_pf_specific(sk->sk_family)->addr_v4map(sctp_sk(sk), |
3910 | &temp); | 3949 | &temp); |
3911 | addrlen = sctp_get_af_specific(temp.sa.sa_family)->sockaddr_len; | 3950 | addrlen = sctp_get_af_specific(temp.sa.sa_family)->sockaddr_len; |
3912 | if (copy_to_user(to, &temp, addrlen)) { | 3951 | if (copy_to_user(to, &temp, addrlen)) |
3913 | sctp_spin_unlock_irqrestore(&sctp_local_addr_lock, | ||
3914 | flags); | ||
3915 | return -EFAULT; | 3952 | return -EFAULT; |
3916 | } | 3953 | |
3917 | to += addrlen; | 3954 | to += addrlen; |
3918 | cnt ++; | 3955 | cnt ++; |
3919 | if (cnt >= max_addrs) break; | 3956 | if (cnt >= max_addrs) break; |
3920 | } | 3957 | } |
3921 | sctp_spin_unlock_irqrestore(&sctp_local_addr_lock, flags); | ||
3922 | 3958 | ||
3923 | return cnt; | 3959 | return cnt; |
3924 | } | 3960 | } |
@@ -3926,15 +3962,13 @@ static int sctp_copy_laddrs_to_user_old(struct sock *sk, __u16 port, int max_add | |||
3926 | static int sctp_copy_laddrs_to_user(struct sock *sk, __u16 port, | 3962 | static int sctp_copy_laddrs_to_user(struct sock *sk, __u16 port, |
3927 | void __user **to, size_t space_left) | 3963 | void __user **to, size_t space_left) |
3928 | { | 3964 | { |
3929 | struct list_head *pos; | 3965 | struct list_head *pos, *next; |
3930 | struct sctp_sockaddr_entry *addr; | 3966 | struct sctp_sockaddr_entry *addr; |
3931 | unsigned long flags; | ||
3932 | union sctp_addr temp; | 3967 | union sctp_addr temp; |
3933 | int cnt = 0; | 3968 | int cnt = 0; |
3934 | int addrlen; | 3969 | int addrlen; |
3935 | 3970 | ||
3936 | sctp_spin_lock_irqsave(&sctp_local_addr_lock, flags); | 3971 | list_for_each_safe(pos, next, &sctp_local_addr_list) { |
3937 | list_for_each(pos, &sctp_local_addr_list) { | ||
3938 | addr = list_entry(pos, struct sctp_sockaddr_entry, list); | 3972 | addr = list_entry(pos, struct sctp_sockaddr_entry, list); |
3939 | if ((PF_INET == sk->sk_family) && | 3973 | if ((PF_INET == sk->sk_family) && |
3940 | (AF_INET6 == addr->a.sa.sa_family)) | 3974 | (AF_INET6 == addr->a.sa.sa_family)) |
@@ -3945,16 +3979,13 @@ static int sctp_copy_laddrs_to_user(struct sock *sk, __u16 port, | |||
3945 | addrlen = sctp_get_af_specific(temp.sa.sa_family)->sockaddr_len; | 3979 | addrlen = sctp_get_af_specific(temp.sa.sa_family)->sockaddr_len; |
3946 | if(space_left<addrlen) | 3980 | if(space_left<addrlen) |
3947 | return -ENOMEM; | 3981 | return -ENOMEM; |
3948 | if (copy_to_user(*to, &temp, addrlen)) { | 3982 | if (copy_to_user(*to, &temp, addrlen)) |
3949 | sctp_spin_unlock_irqrestore(&sctp_local_addr_lock, | ||
3950 | flags); | ||
3951 | return -EFAULT; | 3983 | return -EFAULT; |
3952 | } | 3984 | |
3953 | *to += addrlen; | 3985 | *to += addrlen; |
3954 | cnt ++; | 3986 | cnt ++; |
3955 | space_left -= addrlen; | 3987 | space_left -= addrlen; |
3956 | } | 3988 | } |
3957 | sctp_spin_unlock_irqrestore(&sctp_local_addr_lock, flags); | ||
3958 | 3989 | ||
3959 | return cnt; | 3990 | return cnt; |
3960 | } | 3991 | } |
@@ -4435,6 +4466,42 @@ static int sctp_getsockopt_mappedv4(struct sock *sk, int len, | |||
4435 | } | 4466 | } |
4436 | 4467 | ||
4437 | /* | 4468 | /* |
4469 | * 7.1.29. Set or Get the default context (SCTP_CONTEXT) | ||
4470 | * (chapter and verse is quoted at sctp_setsockopt_context()) | ||
4471 | */ | ||
4472 | static int sctp_getsockopt_context(struct sock *sk, int len, | ||
4473 | char __user *optval, int __user *optlen) | ||
4474 | { | ||
4475 | struct sctp_assoc_value params; | ||
4476 | struct sctp_sock *sp; | ||
4477 | struct sctp_association *asoc; | ||
4478 | |||
4479 | if (len != sizeof(struct sctp_assoc_value)) | ||
4480 | return -EINVAL; | ||
4481 | |||
4482 | if (copy_from_user(¶ms, optval, len)) | ||
4483 | return -EFAULT; | ||
4484 | |||
4485 | sp = sctp_sk(sk); | ||
4486 | |||
4487 | if (params.assoc_id != 0) { | ||
4488 | asoc = sctp_id2assoc(sk, params.assoc_id); | ||
4489 | if (!asoc) | ||
4490 | return -EINVAL; | ||
4491 | params.assoc_value = asoc->default_rcv_context; | ||
4492 | } else { | ||
4493 | params.assoc_value = sp->default_rcv_context; | ||
4494 | } | ||
4495 | |||
4496 | if (put_user(len, optlen)) | ||
4497 | return -EFAULT; | ||
4498 | if (copy_to_user(optval, ¶ms, len)) | ||
4499 | return -EFAULT; | ||
4500 | |||
4501 | return 0; | ||
4502 | } | ||
4503 | |||
4504 | /* | ||
4438 | * 7.1.17 Set the maximum fragrmentation size (SCTP_MAXSEG) | 4505 | * 7.1.17 Set the maximum fragrmentation size (SCTP_MAXSEG) |
4439 | * | 4506 | * |
4440 | * This socket option specifies the maximum size to put in any outgoing | 4507 | * This socket option specifies the maximum size to put in any outgoing |
@@ -4572,6 +4639,9 @@ SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname, | |||
4572 | retval = sctp_getsockopt_adaption_layer(sk, len, optval, | 4639 | retval = sctp_getsockopt_adaption_layer(sk, len, optval, |
4573 | optlen); | 4640 | optlen); |
4574 | break; | 4641 | break; |
4642 | case SCTP_CONTEXT: | ||
4643 | retval = sctp_getsockopt_context(sk, len, optval, optlen); | ||
4644 | break; | ||
4575 | default: | 4645 | default: |
4576 | retval = -ENOPROTOOPT; | 4646 | retval = -ENOPROTOOPT; |
4577 | break; | 4647 | break; |