diff options
Diffstat (limited to 'net/sctp/socket.c')
-rw-r--r-- | net/sctp/socket.c | 137 |
1 files changed, 55 insertions, 82 deletions
diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 01c6364245b7..772fbfb4bfda 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c | |||
@@ -353,6 +353,7 @@ SCTP_STATIC int sctp_do_bind(struct sock *sk, union sctp_addr *addr, int len) | |||
353 | * The function sctp_get_port_local() does duplicate address | 353 | * The function sctp_get_port_local() does duplicate address |
354 | * detection. | 354 | * detection. |
355 | */ | 355 | */ |
356 | addr->v4.sin_port = htons(snum); | ||
356 | if ((ret = sctp_get_port_local(sk, addr))) { | 357 | if ((ret = sctp_get_port_local(sk, addr))) { |
357 | if (ret == (long) sk) { | 358 | if (ret == (long) sk) { |
358 | /* This endpoint has a conflicting address. */ | 359 | /* This endpoint has a conflicting address. */ |
@@ -366,14 +367,10 @@ SCTP_STATIC int sctp_do_bind(struct sock *sk, union sctp_addr *addr, int len) | |||
366 | if (!bp->port) | 367 | if (!bp->port) |
367 | bp->port = inet_sk(sk)->num; | 368 | bp->port = inet_sk(sk)->num; |
368 | 369 | ||
369 | /* Add the address to the bind address list. */ | 370 | /* Add the address to the bind address list. |
370 | sctp_local_bh_disable(); | 371 | * Use GFP_ATOMIC since BHs will be disabled. |
371 | sctp_write_lock(&ep->base.addr_lock); | 372 | */ |
372 | |||
373 | /* Use GFP_ATOMIC since BHs are disabled. */ | ||
374 | ret = sctp_add_bind_addr(bp, addr, 1, GFP_ATOMIC); | 373 | ret = sctp_add_bind_addr(bp, addr, 1, GFP_ATOMIC); |
375 | sctp_write_unlock(&ep->base.addr_lock); | ||
376 | sctp_local_bh_enable(); | ||
377 | 374 | ||
378 | /* Copy back into socket for getsockname() use. */ | 375 | /* Copy back into socket for getsockname() use. */ |
379 | if (!ret) { | 376 | if (!ret) { |
@@ -543,15 +540,12 @@ static int sctp_send_asconf_add_ip(struct sock *sk, | |||
543 | if (i < addrcnt) | 540 | if (i < addrcnt) |
544 | continue; | 541 | continue; |
545 | 542 | ||
546 | /* Use the first address in bind addr list of association as | 543 | /* Use the first valid address in bind addr list of |
547 | * Address Parameter of ASCONF CHUNK. | 544 | * association as Address Parameter of ASCONF CHUNK. |
548 | */ | 545 | */ |
549 | sctp_read_lock(&asoc->base.addr_lock); | ||
550 | bp = &asoc->base.bind_addr; | 546 | bp = &asoc->base.bind_addr; |
551 | p = bp->address_list.next; | 547 | p = bp->address_list.next; |
552 | laddr = list_entry(p, struct sctp_sockaddr_entry, list); | 548 | laddr = list_entry(p, struct sctp_sockaddr_entry, list); |
553 | sctp_read_unlock(&asoc->base.addr_lock); | ||
554 | |||
555 | chunk = sctp_make_asconf_update_ip(asoc, &laddr->a, addrs, | 549 | chunk = sctp_make_asconf_update_ip(asoc, &laddr->a, addrs, |
556 | addrcnt, SCTP_PARAM_ADD_IP); | 550 | addrcnt, SCTP_PARAM_ADD_IP); |
557 | if (!chunk) { | 551 | if (!chunk) { |
@@ -566,8 +560,6 @@ static int sctp_send_asconf_add_ip(struct sock *sk, | |||
566 | /* Add the new addresses to the bind address list with | 560 | /* Add the new addresses to the bind address list with |
567 | * use_as_src set to 0. | 561 | * use_as_src set to 0. |
568 | */ | 562 | */ |
569 | sctp_local_bh_disable(); | ||
570 | sctp_write_lock(&asoc->base.addr_lock); | ||
571 | addr_buf = addrs; | 563 | addr_buf = addrs; |
572 | for (i = 0; i < addrcnt; i++) { | 564 | for (i = 0; i < addrcnt; i++) { |
573 | addr = (union sctp_addr *)addr_buf; | 565 | addr = (union sctp_addr *)addr_buf; |
@@ -577,8 +569,6 @@ static int sctp_send_asconf_add_ip(struct sock *sk, | |||
577 | GFP_ATOMIC); | 569 | GFP_ATOMIC); |
578 | addr_buf += af->sockaddr_len; | 570 | addr_buf += af->sockaddr_len; |
579 | } | 571 | } |
580 | sctp_write_unlock(&asoc->base.addr_lock); | ||
581 | sctp_local_bh_enable(); | ||
582 | } | 572 | } |
583 | 573 | ||
584 | out: | 574 | out: |
@@ -650,13 +640,7 @@ static int sctp_bindx_rem(struct sock *sk, struct sockaddr *addrs, int addrcnt) | |||
650 | * socket routing and failover schemes. Refer to comments in | 640 | * socket routing and failover schemes. Refer to comments in |
651 | * sctp_do_bind(). -daisy | 641 | * sctp_do_bind(). -daisy |
652 | */ | 642 | */ |
653 | sctp_local_bh_disable(); | 643 | retval = sctp_del_bind_addr(bp, sa_addr, call_rcu); |
654 | sctp_write_lock(&ep->base.addr_lock); | ||
655 | |||
656 | retval = sctp_del_bind_addr(bp, sa_addr); | ||
657 | |||
658 | sctp_write_unlock(&ep->base.addr_lock); | ||
659 | sctp_local_bh_enable(); | ||
660 | 644 | ||
661 | addr_buf += af->sockaddr_len; | 645 | addr_buf += af->sockaddr_len; |
662 | err_bindx_rem: | 646 | err_bindx_rem: |
@@ -747,14 +731,16 @@ static int sctp_send_asconf_del_ip(struct sock *sk, | |||
747 | * make sure that we do not delete all the addresses in the | 731 | * make sure that we do not delete all the addresses in the |
748 | * association. | 732 | * association. |
749 | */ | 733 | */ |
750 | sctp_read_lock(&asoc->base.addr_lock); | ||
751 | bp = &asoc->base.bind_addr; | 734 | bp = &asoc->base.bind_addr; |
752 | laddr = sctp_find_unmatch_addr(bp, (union sctp_addr *)addrs, | 735 | laddr = sctp_find_unmatch_addr(bp, (union sctp_addr *)addrs, |
753 | addrcnt, sp); | 736 | addrcnt, sp); |
754 | sctp_read_unlock(&asoc->base.addr_lock); | ||
755 | if (!laddr) | 737 | if (!laddr) |
756 | continue; | 738 | continue; |
757 | 739 | ||
740 | /* We do not need RCU protection throughout this loop | ||
741 | * because this is done under a socket lock from the | ||
742 | * setsockopt call. | ||
743 | */ | ||
758 | chunk = sctp_make_asconf_update_ip(asoc, laddr, addrs, addrcnt, | 744 | chunk = sctp_make_asconf_update_ip(asoc, laddr, addrs, addrcnt, |
759 | SCTP_PARAM_DEL_IP); | 745 | SCTP_PARAM_DEL_IP); |
760 | if (!chunk) { | 746 | if (!chunk) { |
@@ -765,23 +751,16 @@ static int sctp_send_asconf_del_ip(struct sock *sk, | |||
765 | /* Reset use_as_src flag for the addresses in the bind address | 751 | /* Reset use_as_src flag for the addresses in the bind address |
766 | * list that are to be deleted. | 752 | * list that are to be deleted. |
767 | */ | 753 | */ |
768 | sctp_local_bh_disable(); | ||
769 | sctp_write_lock(&asoc->base.addr_lock); | ||
770 | addr_buf = addrs; | 754 | addr_buf = addrs; |
771 | for (i = 0; i < addrcnt; i++) { | 755 | for (i = 0; i < addrcnt; i++) { |
772 | laddr = (union sctp_addr *)addr_buf; | 756 | laddr = (union sctp_addr *)addr_buf; |
773 | af = sctp_get_af_specific(laddr->v4.sin_family); | 757 | af = sctp_get_af_specific(laddr->v4.sin_family); |
774 | list_for_each(pos1, &bp->address_list) { | 758 | list_for_each_entry(saddr, &bp->address_list, list) { |
775 | saddr = list_entry(pos1, | ||
776 | struct sctp_sockaddr_entry, | ||
777 | list); | ||
778 | if (sctp_cmp_addr_exact(&saddr->a, laddr)) | 759 | if (sctp_cmp_addr_exact(&saddr->a, laddr)) |
779 | saddr->use_as_src = 0; | 760 | saddr->use_as_src = 0; |
780 | } | 761 | } |
781 | addr_buf += af->sockaddr_len; | 762 | addr_buf += af->sockaddr_len; |
782 | } | 763 | } |
783 | sctp_write_unlock(&asoc->base.addr_lock); | ||
784 | sctp_local_bh_enable(); | ||
785 | 764 | ||
786 | /* Update the route and saddr entries for all the transports | 765 | /* Update the route and saddr entries for all the transports |
787 | * as some of the addresses in the bind address list are | 766 | * as some of the addresses in the bind address list are |
@@ -4058,9 +4037,7 @@ static int sctp_getsockopt_local_addrs_num_old(struct sock *sk, int len, | |||
4058 | sctp_assoc_t id; | 4037 | sctp_assoc_t id; |
4059 | struct sctp_bind_addr *bp; | 4038 | struct sctp_bind_addr *bp; |
4060 | struct sctp_association *asoc; | 4039 | struct sctp_association *asoc; |
4061 | struct list_head *pos, *temp; | ||
4062 | struct sctp_sockaddr_entry *addr; | 4040 | struct sctp_sockaddr_entry *addr; |
4063 | rwlock_t *addr_lock; | ||
4064 | int cnt = 0; | 4041 | int cnt = 0; |
4065 | 4042 | ||
4066 | if (len < sizeof(sctp_assoc_t)) | 4043 | if (len < sizeof(sctp_assoc_t)) |
@@ -4077,17 +4054,13 @@ static int sctp_getsockopt_local_addrs_num_old(struct sock *sk, int len, | |||
4077 | */ | 4054 | */ |
4078 | if (0 == id) { | 4055 | if (0 == id) { |
4079 | bp = &sctp_sk(sk)->ep->base.bind_addr; | 4056 | bp = &sctp_sk(sk)->ep->base.bind_addr; |
4080 | addr_lock = &sctp_sk(sk)->ep->base.addr_lock; | ||
4081 | } else { | 4057 | } else { |
4082 | asoc = sctp_id2assoc(sk, id); | 4058 | asoc = sctp_id2assoc(sk, id); |
4083 | if (!asoc) | 4059 | if (!asoc) |
4084 | return -EINVAL; | 4060 | return -EINVAL; |
4085 | bp = &asoc->base.bind_addr; | 4061 | bp = &asoc->base.bind_addr; |
4086 | addr_lock = &asoc->base.addr_lock; | ||
4087 | } | 4062 | } |
4088 | 4063 | ||
4089 | sctp_read_lock(addr_lock); | ||
4090 | |||
4091 | /* If the endpoint is bound to 0.0.0.0 or ::0, count the valid | 4064 | /* If the endpoint is bound to 0.0.0.0 or ::0, count the valid |
4092 | * addresses from the global local address list. | 4065 | * addresses from the global local address list. |
4093 | */ | 4066 | */ |
@@ -4095,27 +4068,33 @@ static int sctp_getsockopt_local_addrs_num_old(struct sock *sk, int len, | |||
4095 | addr = list_entry(bp->address_list.next, | 4068 | addr = list_entry(bp->address_list.next, |
4096 | struct sctp_sockaddr_entry, list); | 4069 | struct sctp_sockaddr_entry, list); |
4097 | if (sctp_is_any(&addr->a)) { | 4070 | if (sctp_is_any(&addr->a)) { |
4098 | list_for_each_safe(pos, temp, &sctp_local_addr_list) { | 4071 | rcu_read_lock(); |
4099 | addr = list_entry(pos, | 4072 | list_for_each_entry_rcu(addr, |
4100 | struct sctp_sockaddr_entry, | 4073 | &sctp_local_addr_list, list) { |
4101 | list); | 4074 | if (!addr->valid) |
4075 | continue; | ||
4076 | |||
4102 | if ((PF_INET == sk->sk_family) && | 4077 | if ((PF_INET == sk->sk_family) && |
4103 | (AF_INET6 == addr->a.sa.sa_family)) | 4078 | (AF_INET6 == addr->a.sa.sa_family)) |
4104 | continue; | 4079 | continue; |
4080 | |||
4105 | cnt++; | 4081 | cnt++; |
4106 | } | 4082 | } |
4083 | rcu_read_unlock(); | ||
4107 | } else { | 4084 | } else { |
4108 | cnt = 1; | 4085 | cnt = 1; |
4109 | } | 4086 | } |
4110 | goto done; | 4087 | goto done; |
4111 | } | 4088 | } |
4112 | 4089 | ||
4113 | list_for_each(pos, &bp->address_list) { | 4090 | /* Protection on the bound address list is not needed, |
4091 | * since in the socket option context we hold the socket lock, | ||
4092 | * so there is no way that the bound address list can change. | ||
4093 | */ | ||
4094 | list_for_each_entry(addr, &bp->address_list, list) { | ||
4114 | cnt ++; | 4095 | cnt ++; |
4115 | } | 4096 | } |
4116 | |||
4117 | done: | 4097 | done: |
4118 | sctp_read_unlock(addr_lock); | ||
4119 | return cnt; | 4098 | return cnt; |
4120 | } | 4099 | } |
4121 | 4100 | ||
@@ -4126,14 +4105,16 @@ static int sctp_copy_laddrs_old(struct sock *sk, __u16 port, | |||
4126 | int max_addrs, void *to, | 4105 | int max_addrs, void *to, |
4127 | int *bytes_copied) | 4106 | int *bytes_copied) |
4128 | { | 4107 | { |
4129 | struct list_head *pos, *next; | ||
4130 | struct sctp_sockaddr_entry *addr; | 4108 | struct sctp_sockaddr_entry *addr; |
4131 | union sctp_addr temp; | 4109 | union sctp_addr temp; |
4132 | int cnt = 0; | 4110 | int cnt = 0; |
4133 | int addrlen; | 4111 | int addrlen; |
4134 | 4112 | ||
4135 | list_for_each_safe(pos, next, &sctp_local_addr_list) { | 4113 | rcu_read_lock(); |
4136 | addr = list_entry(pos, struct sctp_sockaddr_entry, list); | 4114 | list_for_each_entry_rcu(addr, &sctp_local_addr_list, list) { |
4115 | if (!addr->valid) | ||
4116 | continue; | ||
4117 | |||
4137 | if ((PF_INET == sk->sk_family) && | 4118 | if ((PF_INET == sk->sk_family) && |
4138 | (AF_INET6 == addr->a.sa.sa_family)) | 4119 | (AF_INET6 == addr->a.sa.sa_family)) |
4139 | continue; | 4120 | continue; |
@@ -4148,6 +4129,7 @@ static int sctp_copy_laddrs_old(struct sock *sk, __u16 port, | |||
4148 | cnt ++; | 4129 | cnt ++; |
4149 | if (cnt >= max_addrs) break; | 4130 | if (cnt >= max_addrs) break; |
4150 | } | 4131 | } |
4132 | rcu_read_unlock(); | ||
4151 | 4133 | ||
4152 | return cnt; | 4134 | return cnt; |
4153 | } | 4135 | } |
@@ -4155,14 +4137,16 @@ static int sctp_copy_laddrs_old(struct sock *sk, __u16 port, | |||
4155 | static int sctp_copy_laddrs(struct sock *sk, __u16 port, void *to, | 4137 | static int sctp_copy_laddrs(struct sock *sk, __u16 port, void *to, |
4156 | size_t space_left, int *bytes_copied) | 4138 | size_t space_left, int *bytes_copied) |
4157 | { | 4139 | { |
4158 | struct list_head *pos, *next; | ||
4159 | struct sctp_sockaddr_entry *addr; | 4140 | struct sctp_sockaddr_entry *addr; |
4160 | union sctp_addr temp; | 4141 | union sctp_addr temp; |
4161 | int cnt = 0; | 4142 | int cnt = 0; |
4162 | int addrlen; | 4143 | int addrlen; |
4163 | 4144 | ||
4164 | list_for_each_safe(pos, next, &sctp_local_addr_list) { | 4145 | rcu_read_lock(); |
4165 | addr = list_entry(pos, struct sctp_sockaddr_entry, list); | 4146 | list_for_each_entry_rcu(addr, &sctp_local_addr_list, list) { |
4147 | if (!addr->valid) | ||
4148 | continue; | ||
4149 | |||
4166 | if ((PF_INET == sk->sk_family) && | 4150 | if ((PF_INET == sk->sk_family) && |
4167 | (AF_INET6 == addr->a.sa.sa_family)) | 4151 | (AF_INET6 == addr->a.sa.sa_family)) |
4168 | continue; | 4152 | continue; |
@@ -4170,8 +4154,10 @@ static int sctp_copy_laddrs(struct sock *sk, __u16 port, void *to, | |||
4170 | sctp_get_pf_specific(sk->sk_family)->addr_v4map(sctp_sk(sk), | 4154 | sctp_get_pf_specific(sk->sk_family)->addr_v4map(sctp_sk(sk), |
4171 | &temp); | 4155 | &temp); |
4172 | addrlen = sctp_get_af_specific(temp.sa.sa_family)->sockaddr_len; | 4156 | addrlen = sctp_get_af_specific(temp.sa.sa_family)->sockaddr_len; |
4173 | if (space_left < addrlen) | 4157 | if (space_left < addrlen) { |
4174 | return -ENOMEM; | 4158 | cnt = -ENOMEM; |
4159 | break; | ||
4160 | } | ||
4175 | memcpy(to, &temp, addrlen); | 4161 | memcpy(to, &temp, addrlen); |
4176 | 4162 | ||
4177 | to += addrlen; | 4163 | to += addrlen; |
@@ -4179,6 +4165,7 @@ static int sctp_copy_laddrs(struct sock *sk, __u16 port, void *to, | |||
4179 | space_left -= addrlen; | 4165 | space_left -= addrlen; |
4180 | *bytes_copied += addrlen; | 4166 | *bytes_copied += addrlen; |
4181 | } | 4167 | } |
4168 | rcu_read_unlock(); | ||
4182 | 4169 | ||
4183 | return cnt; | 4170 | return cnt; |
4184 | } | 4171 | } |
@@ -4191,7 +4178,6 @@ static int sctp_getsockopt_local_addrs_old(struct sock *sk, int len, | |||
4191 | { | 4178 | { |
4192 | struct sctp_bind_addr *bp; | 4179 | struct sctp_bind_addr *bp; |
4193 | struct sctp_association *asoc; | 4180 | struct sctp_association *asoc; |
4194 | struct list_head *pos; | ||
4195 | int cnt = 0; | 4181 | int cnt = 0; |
4196 | struct sctp_getaddrs_old getaddrs; | 4182 | struct sctp_getaddrs_old getaddrs; |
4197 | struct sctp_sockaddr_entry *addr; | 4183 | struct sctp_sockaddr_entry *addr; |
@@ -4199,7 +4185,6 @@ static int sctp_getsockopt_local_addrs_old(struct sock *sk, int len, | |||
4199 | union sctp_addr temp; | 4185 | union sctp_addr temp; |
4200 | struct sctp_sock *sp = sctp_sk(sk); | 4186 | struct sctp_sock *sp = sctp_sk(sk); |
4201 | int addrlen; | 4187 | int addrlen; |
4202 | rwlock_t *addr_lock; | ||
4203 | int err = 0; | 4188 | int err = 0; |
4204 | void *addrs; | 4189 | void *addrs; |
4205 | void *buf; | 4190 | void *buf; |
@@ -4221,13 +4206,11 @@ static int sctp_getsockopt_local_addrs_old(struct sock *sk, int len, | |||
4221 | */ | 4206 | */ |
4222 | if (0 == getaddrs.assoc_id) { | 4207 | if (0 == getaddrs.assoc_id) { |
4223 | bp = &sctp_sk(sk)->ep->base.bind_addr; | 4208 | bp = &sctp_sk(sk)->ep->base.bind_addr; |
4224 | addr_lock = &sctp_sk(sk)->ep->base.addr_lock; | ||
4225 | } else { | 4209 | } else { |
4226 | asoc = sctp_id2assoc(sk, getaddrs.assoc_id); | 4210 | asoc = sctp_id2assoc(sk, getaddrs.assoc_id); |
4227 | if (!asoc) | 4211 | if (!asoc) |
4228 | return -EINVAL; | 4212 | return -EINVAL; |
4229 | bp = &asoc->base.bind_addr; | 4213 | bp = &asoc->base.bind_addr; |
4230 | addr_lock = &asoc->base.addr_lock; | ||
4231 | } | 4214 | } |
4232 | 4215 | ||
4233 | to = getaddrs.addrs; | 4216 | to = getaddrs.addrs; |
@@ -4241,8 +4224,6 @@ static int sctp_getsockopt_local_addrs_old(struct sock *sk, int len, | |||
4241 | if (!addrs) | 4224 | if (!addrs) |
4242 | return -ENOMEM; | 4225 | return -ENOMEM; |
4243 | 4226 | ||
4244 | sctp_read_lock(addr_lock); | ||
4245 | |||
4246 | /* If the endpoint is bound to 0.0.0.0 or ::0, get the valid | 4227 | /* If the endpoint is bound to 0.0.0.0 or ::0, get the valid |
4247 | * addresses from the global local address list. | 4228 | * addresses from the global local address list. |
4248 | */ | 4229 | */ |
@@ -4258,8 +4239,11 @@ static int sctp_getsockopt_local_addrs_old(struct sock *sk, int len, | |||
4258 | } | 4239 | } |
4259 | 4240 | ||
4260 | buf = addrs; | 4241 | buf = addrs; |
4261 | list_for_each(pos, &bp->address_list) { | 4242 | /* Protection on the bound address list is not needed since |
4262 | addr = list_entry(pos, struct sctp_sockaddr_entry, list); | 4243 | * in the socket option context we hold a socket lock and |
4244 | * thus the bound address list can't change. | ||
4245 | */ | ||
4246 | list_for_each_entry(addr, &bp->address_list, list) { | ||
4263 | memcpy(&temp, &addr->a, sizeof(temp)); | 4247 | memcpy(&temp, &addr->a, sizeof(temp)); |
4264 | sctp_get_pf_specific(sk->sk_family)->addr_v4map(sp, &temp); | 4248 | sctp_get_pf_specific(sk->sk_family)->addr_v4map(sp, &temp); |
4265 | addrlen = sctp_get_af_specific(temp.sa.sa_family)->sockaddr_len; | 4249 | addrlen = sctp_get_af_specific(temp.sa.sa_family)->sockaddr_len; |
@@ -4271,8 +4255,6 @@ static int sctp_getsockopt_local_addrs_old(struct sock *sk, int len, | |||
4271 | } | 4255 | } |
4272 | 4256 | ||
4273 | copy_getaddrs: | 4257 | copy_getaddrs: |
4274 | sctp_read_unlock(addr_lock); | ||
4275 | |||
4276 | /* copy the entire address list into the user provided space */ | 4258 | /* copy the entire address list into the user provided space */ |
4277 | if (copy_to_user(to, addrs, bytes_copied)) { | 4259 | if (copy_to_user(to, addrs, bytes_copied)) { |
4278 | err = -EFAULT; | 4260 | err = -EFAULT; |
@@ -4294,7 +4276,6 @@ static int sctp_getsockopt_local_addrs(struct sock *sk, int len, | |||
4294 | { | 4276 | { |
4295 | struct sctp_bind_addr *bp; | 4277 | struct sctp_bind_addr *bp; |
4296 | struct sctp_association *asoc; | 4278 | struct sctp_association *asoc; |
4297 | struct list_head *pos; | ||
4298 | int cnt = 0; | 4279 | int cnt = 0; |
4299 | struct sctp_getaddrs getaddrs; | 4280 | struct sctp_getaddrs getaddrs; |
4300 | struct sctp_sockaddr_entry *addr; | 4281 | struct sctp_sockaddr_entry *addr; |
@@ -4302,7 +4283,6 @@ static int sctp_getsockopt_local_addrs(struct sock *sk, int len, | |||
4302 | union sctp_addr temp; | 4283 | union sctp_addr temp; |
4303 | struct sctp_sock *sp = sctp_sk(sk); | 4284 | struct sctp_sock *sp = sctp_sk(sk); |
4304 | int addrlen; | 4285 | int addrlen; |
4305 | rwlock_t *addr_lock; | ||
4306 | int err = 0; | 4286 | int err = 0; |
4307 | size_t space_left; | 4287 | size_t space_left; |
4308 | int bytes_copied = 0; | 4288 | int bytes_copied = 0; |
@@ -4323,13 +4303,11 @@ static int sctp_getsockopt_local_addrs(struct sock *sk, int len, | |||
4323 | */ | 4303 | */ |
4324 | if (0 == getaddrs.assoc_id) { | 4304 | if (0 == getaddrs.assoc_id) { |
4325 | bp = &sctp_sk(sk)->ep->base.bind_addr; | 4305 | bp = &sctp_sk(sk)->ep->base.bind_addr; |
4326 | addr_lock = &sctp_sk(sk)->ep->base.addr_lock; | ||
4327 | } else { | 4306 | } else { |
4328 | asoc = sctp_id2assoc(sk, getaddrs.assoc_id); | 4307 | asoc = sctp_id2assoc(sk, getaddrs.assoc_id); |
4329 | if (!asoc) | 4308 | if (!asoc) |
4330 | return -EINVAL; | 4309 | return -EINVAL; |
4331 | bp = &asoc->base.bind_addr; | 4310 | bp = &asoc->base.bind_addr; |
4332 | addr_lock = &asoc->base.addr_lock; | ||
4333 | } | 4311 | } |
4334 | 4312 | ||
4335 | to = optval + offsetof(struct sctp_getaddrs,addrs); | 4313 | to = optval + offsetof(struct sctp_getaddrs,addrs); |
@@ -4339,8 +4317,6 @@ static int sctp_getsockopt_local_addrs(struct sock *sk, int len, | |||
4339 | if (!addrs) | 4317 | if (!addrs) |
4340 | return -ENOMEM; | 4318 | return -ENOMEM; |
4341 | 4319 | ||
4342 | sctp_read_lock(addr_lock); | ||
4343 | |||
4344 | /* If the endpoint is bound to 0.0.0.0 or ::0, get the valid | 4320 | /* If the endpoint is bound to 0.0.0.0 or ::0, get the valid |
4345 | * addresses from the global local address list. | 4321 | * addresses from the global local address list. |
4346 | */ | 4322 | */ |
@@ -4352,21 +4328,24 @@ static int sctp_getsockopt_local_addrs(struct sock *sk, int len, | |||
4352 | space_left, &bytes_copied); | 4328 | space_left, &bytes_copied); |
4353 | if (cnt < 0) { | 4329 | if (cnt < 0) { |
4354 | err = cnt; | 4330 | err = cnt; |
4355 | goto error_lock; | 4331 | goto out; |
4356 | } | 4332 | } |
4357 | goto copy_getaddrs; | 4333 | goto copy_getaddrs; |
4358 | } | 4334 | } |
4359 | } | 4335 | } |
4360 | 4336 | ||
4361 | buf = addrs; | 4337 | buf = addrs; |
4362 | list_for_each(pos, &bp->address_list) { | 4338 | /* Protection on the bound address list is not needed since |
4363 | addr = list_entry(pos, struct sctp_sockaddr_entry, list); | 4339 | * in the socket option context we hold a socket lock and |
4340 | * thus the bound address list can't change. | ||
4341 | */ | ||
4342 | list_for_each_entry(addr, &bp->address_list, list) { | ||
4364 | memcpy(&temp, &addr->a, sizeof(temp)); | 4343 | memcpy(&temp, &addr->a, sizeof(temp)); |
4365 | sctp_get_pf_specific(sk->sk_family)->addr_v4map(sp, &temp); | 4344 | sctp_get_pf_specific(sk->sk_family)->addr_v4map(sp, &temp); |
4366 | addrlen = sctp_get_af_specific(temp.sa.sa_family)->sockaddr_len; | 4345 | addrlen = sctp_get_af_specific(temp.sa.sa_family)->sockaddr_len; |
4367 | if (space_left < addrlen) { | 4346 | if (space_left < addrlen) { |
4368 | err = -ENOMEM; /*fixme: right error?*/ | 4347 | err = -ENOMEM; /*fixme: right error?*/ |
4369 | goto error_lock; | 4348 | goto out; |
4370 | } | 4349 | } |
4371 | memcpy(buf, &temp, addrlen); | 4350 | memcpy(buf, &temp, addrlen); |
4372 | buf += addrlen; | 4351 | buf += addrlen; |
@@ -4376,8 +4355,6 @@ static int sctp_getsockopt_local_addrs(struct sock *sk, int len, | |||
4376 | } | 4355 | } |
4377 | 4356 | ||
4378 | copy_getaddrs: | 4357 | copy_getaddrs: |
4379 | sctp_read_unlock(addr_lock); | ||
4380 | |||
4381 | if (copy_to_user(to, addrs, bytes_copied)) { | 4358 | if (copy_to_user(to, addrs, bytes_copied)) { |
4382 | err = -EFAULT; | 4359 | err = -EFAULT; |
4383 | goto out; | 4360 | goto out; |
@@ -4388,12 +4365,6 @@ copy_getaddrs: | |||
4388 | } | 4365 | } |
4389 | if (put_user(bytes_copied, optlen)) | 4366 | if (put_user(bytes_copied, optlen)) |
4390 | err = -EFAULT; | 4367 | err = -EFAULT; |
4391 | |||
4392 | goto out; | ||
4393 | |||
4394 | error_lock: | ||
4395 | sctp_read_unlock(addr_lock); | ||
4396 | |||
4397 | out: | 4368 | out: |
4398 | kfree(addrs); | 4369 | kfree(addrs); |
4399 | return err; | 4370 | return err; |
@@ -5202,6 +5173,7 @@ SCTP_STATIC int sctp_seqpacket_listen(struct sock *sk, int backlog) | |||
5202 | 5173 | ||
5203 | sctp_unhash_endpoint(ep); | 5174 | sctp_unhash_endpoint(ep); |
5204 | sk->sk_state = SCTP_SS_CLOSED; | 5175 | sk->sk_state = SCTP_SS_CLOSED; |
5176 | return 0; | ||
5205 | } | 5177 | } |
5206 | 5178 | ||
5207 | /* Return if we are already listening. */ | 5179 | /* Return if we are already listening. */ |
@@ -5249,6 +5221,7 @@ SCTP_STATIC int sctp_stream_listen(struct sock *sk, int backlog) | |||
5249 | 5221 | ||
5250 | sctp_unhash_endpoint(ep); | 5222 | sctp_unhash_endpoint(ep); |
5251 | sk->sk_state = SCTP_SS_CLOSED; | 5223 | sk->sk_state = SCTP_SS_CLOSED; |
5224 | return 0; | ||
5252 | } | 5225 | } |
5253 | 5226 | ||
5254 | if (sctp_sstate(sk, LISTENING)) | 5227 | if (sctp_sstate(sk, LISTENING)) |