aboutsummaryrefslogtreecommitdiffstats
path: root/net/sctp/socket.c
diff options
context:
space:
mode:
authorSridhar Samudrala <sri@us.ibm.com>2006-12-13 19:26:26 -0500
committerDavid S. Miller <davem@sunset.davemloft.net>2006-12-13 19:48:27 -0500
commit29c7cf96186ac14ce7380633f690fc39732ff03a (patch)
treeccc95adc0e1185469e77a1adcae1d300d0b534d1 /net/sctp/socket.c
parent6931ba7cef3991fbb970997d33e24139ccdc3c2c (diff)
[SCTP]: Handle address add/delete events in a more efficient way.
Currently in SCTP, we maintain a local address list by rebuilding the whole list from the device list whenever we get a address add/delete event. This patch fixes it by only adding/deleting the address for which we receive the event. Also removed the sctp_local_addr_lock() which is no longer needed as we now use list_for_each_safe() to traverse this list. This fixes the bugs in sctp_copy_laddrs_xxx() routines where we do copy_to_user() while holding this lock. Signed-off-by: Sridhar Samudrala <sri@us.ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/sctp/socket.c')
-rw-r--r--net/sctp/socket.c34
1 files changed, 10 insertions, 24 deletions
diff --git a/net/sctp/socket.c b/net/sctp/socket.c
index 1e8132b8c4d9..fa29eae83e91 100644
--- a/net/sctp/socket.c
+++ b/net/sctp/socket.c
@@ -3821,10 +3821,9 @@ static int sctp_getsockopt_local_addrs_num_old(struct sock *sk, int len,
3821 sctp_assoc_t id; 3821 sctp_assoc_t id;
3822 struct sctp_bind_addr *bp; 3822 struct sctp_bind_addr *bp;
3823 struct sctp_association *asoc; 3823 struct sctp_association *asoc;
3824 struct list_head *pos; 3824 struct list_head *pos, *temp;
3825 struct sctp_sockaddr_entry *addr; 3825 struct sctp_sockaddr_entry *addr;
3826 rwlock_t *addr_lock; 3826 rwlock_t *addr_lock;
3827 unsigned long flags;
3828 int cnt = 0; 3827 int cnt = 0;
3829 3828
3830 if (len != sizeof(sctp_assoc_t)) 3829 if (len != sizeof(sctp_assoc_t))
@@ -3859,8 +3858,7 @@ static int sctp_getsockopt_local_addrs_num_old(struct sock *sk, int len,
3859 addr = list_entry(bp->address_list.next, 3858 addr = list_entry(bp->address_list.next,
3860 struct sctp_sockaddr_entry, list); 3859 struct sctp_sockaddr_entry, list);
3861 if (sctp_is_any(&addr->a)) { 3860 if (sctp_is_any(&addr->a)) {
3862 sctp_spin_lock_irqsave(&sctp_local_addr_lock, flags); 3861 list_for_each_safe(pos, temp, &sctp_local_addr_list) {
3863 list_for_each(pos, &sctp_local_addr_list) {
3864 addr = list_entry(pos, 3862 addr = list_entry(pos,
3865 struct sctp_sockaddr_entry, 3863 struct sctp_sockaddr_entry,
3866 list); 3864 list);
@@ -3869,8 +3867,6 @@ static int sctp_getsockopt_local_addrs_num_old(struct sock *sk, int len,
3869 continue; 3867 continue;
3870 cnt++; 3868 cnt++;
3871 } 3869 }
3872 sctp_spin_unlock_irqrestore(&sctp_local_addr_lock,
3873 flags);
3874 } else { 3870 } else {
3875 cnt = 1; 3871 cnt = 1;
3876 } 3872 }
@@ -3892,15 +3888,13 @@ done:
3892static int sctp_copy_laddrs_to_user_old(struct sock *sk, __u16 port, int max_addrs, 3888static int sctp_copy_laddrs_to_user_old(struct sock *sk, __u16 port, int max_addrs,
3893 void __user *to) 3889 void __user *to)
3894{ 3890{
3895 struct list_head *pos; 3891 struct list_head *pos, *next;
3896 struct sctp_sockaddr_entry *addr; 3892 struct sctp_sockaddr_entry *addr;
3897 unsigned long flags;
3898 union sctp_addr temp; 3893 union sctp_addr temp;
3899 int cnt = 0; 3894 int cnt = 0;
3900 int addrlen; 3895 int addrlen;
3901 3896
3902 sctp_spin_lock_irqsave(&sctp_local_addr_lock, flags); 3897 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); 3898 addr = list_entry(pos, struct sctp_sockaddr_entry, list);
3905 if ((PF_INET == sk->sk_family) && 3899 if ((PF_INET == sk->sk_family) &&
3906 (AF_INET6 == addr->a.sa.sa_family)) 3900 (AF_INET6 == addr->a.sa.sa_family))
@@ -3909,16 +3903,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), 3903 sctp_get_pf_specific(sk->sk_family)->addr_v4map(sctp_sk(sk),
3910 &temp); 3904 &temp);
3911 addrlen = sctp_get_af_specific(temp.sa.sa_family)->sockaddr_len; 3905 addrlen = sctp_get_af_specific(temp.sa.sa_family)->sockaddr_len;
3912 if (copy_to_user(to, &temp, addrlen)) { 3906 if (copy_to_user(to, &temp, addrlen))
3913 sctp_spin_unlock_irqrestore(&sctp_local_addr_lock,
3914 flags);
3915 return -EFAULT; 3907 return -EFAULT;
3916 } 3908
3917 to += addrlen; 3909 to += addrlen;
3918 cnt ++; 3910 cnt ++;
3919 if (cnt >= max_addrs) break; 3911 if (cnt >= max_addrs) break;
3920 } 3912 }
3921 sctp_spin_unlock_irqrestore(&sctp_local_addr_lock, flags);
3922 3913
3923 return cnt; 3914 return cnt;
3924} 3915}
@@ -3926,15 +3917,13 @@ static int sctp_copy_laddrs_to_user_old(struct sock *sk, __u16 port, int max_add
3926static int sctp_copy_laddrs_to_user(struct sock *sk, __u16 port, 3917static int sctp_copy_laddrs_to_user(struct sock *sk, __u16 port,
3927 void __user **to, size_t space_left) 3918 void __user **to, size_t space_left)
3928{ 3919{
3929 struct list_head *pos; 3920 struct list_head *pos, *next;
3930 struct sctp_sockaddr_entry *addr; 3921 struct sctp_sockaddr_entry *addr;
3931 unsigned long flags;
3932 union sctp_addr temp; 3922 union sctp_addr temp;
3933 int cnt = 0; 3923 int cnt = 0;
3934 int addrlen; 3924 int addrlen;
3935 3925
3936 sctp_spin_lock_irqsave(&sctp_local_addr_lock, flags); 3926 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); 3927 addr = list_entry(pos, struct sctp_sockaddr_entry, list);
3939 if ((PF_INET == sk->sk_family) && 3928 if ((PF_INET == sk->sk_family) &&
3940 (AF_INET6 == addr->a.sa.sa_family)) 3929 (AF_INET6 == addr->a.sa.sa_family))
@@ -3945,16 +3934,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; 3934 addrlen = sctp_get_af_specific(temp.sa.sa_family)->sockaddr_len;
3946 if(space_left<addrlen) 3935 if(space_left<addrlen)
3947 return -ENOMEM; 3936 return -ENOMEM;
3948 if (copy_to_user(*to, &temp, addrlen)) { 3937 if (copy_to_user(*to, &temp, addrlen))
3949 sctp_spin_unlock_irqrestore(&sctp_local_addr_lock,
3950 flags);
3951 return -EFAULT; 3938 return -EFAULT;
3952 } 3939
3953 *to += addrlen; 3940 *to += addrlen;
3954 cnt ++; 3941 cnt ++;
3955 space_left -= addrlen; 3942 space_left -= addrlen;
3956 } 3943 }
3957 sctp_spin_unlock_irqrestore(&sctp_local_addr_lock, flags);
3958 3944
3959 return cnt; 3945 return cnt;
3960} 3946}