diff options
| author | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-04-30 11:14:42 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-04-30 11:14:42 -0400 |
| commit | 152a6a9da1bd3ed5dcbbf6ff17c7ebde0eb9a754 (patch) | |
| tree | cad354802870b7d4bc0402a6a6da44bd1f610bc6 /net/sctp/socket.c | |
| parent | cd9bb7e7367c03400d6e918fd3502820fc3b9084 (diff) | |
| parent | 80787ebc2bbd8e675d8b9ff8cfa40f15134feebe (diff) | |
Merge master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6
* master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6: (21 commits)
[IPV4] SNMP: Support OutMcastPkts and OutBcastPkts
[IPV4] SNMP: Support InMcastPkts and InBcastPkts
[IPV4] SNMP: Support InTruncatedPkts
[IPV4] SNMP: Support InNoRoutes
[SNMP]: Add definitions for {In,Out}BcastPkts
[TCP] FRTO: RFC4138 allows Nagle override when new data must be sent
[TCP] FRTO: Delay skb available check until it's mandatory
[XFRM]: Restrict upper layer information by bundle.
[TCP]: Catch skb with S+L bugs earlier
[PATCH] INET : IPV4 UDP lookups converted to a 2 pass algo
[L2TP]: Add the ability to autoload a pppox protocol module.
[SKB]: Introduce skb_queue_walk_safe()
[AF_IUCV/IUCV]: smp_call_function deadlock
[IPV6]: Fix slab corruption running ip6sic
[TCP]: Update references in two old comments
[XFRM]: Export SPD info
[IPV6]: Track device renames in snmp6.
[SCTP]: Fix sctp_getsockopt_local_addrs_old() to use local storage.
[NET]: Remove NETIF_F_INTERNAL_STATS, default to internal stats.
[NETPOLL]: Remove CONFIG_NETPOLL_RX
...
Diffstat (limited to 'net/sctp/socket.c')
| -rw-r--r-- | net/sctp/socket.c | 96 |
1 files changed, 60 insertions, 36 deletions
diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 11938fb20395..2fc0a92caa78 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c | |||
| @@ -3987,7 +3987,7 @@ static int sctp_getsockopt_peer_addrs(struct sock *sk, int len, | |||
| 3987 | memcpy(&temp, &from->ipaddr, sizeof(temp)); | 3987 | memcpy(&temp, &from->ipaddr, sizeof(temp)); |
| 3988 | sctp_get_pf_specific(sk->sk_family)->addr_v4map(sp, &temp); | 3988 | sctp_get_pf_specific(sk->sk_family)->addr_v4map(sp, &temp); |
| 3989 | addrlen = sctp_get_af_specific(sk->sk_family)->sockaddr_len; | 3989 | addrlen = sctp_get_af_specific(sk->sk_family)->sockaddr_len; |
| 3990 | if(space_left < addrlen) | 3990 | if (space_left < addrlen) |
| 3991 | return -ENOMEM; | 3991 | return -ENOMEM; |
| 3992 | if (copy_to_user(to, &temp, addrlen)) | 3992 | if (copy_to_user(to, &temp, addrlen)) |
| 3993 | return -EFAULT; | 3993 | return -EFAULT; |
| @@ -4076,8 +4076,9 @@ done: | |||
| 4076 | /* Helper function that copies local addresses to user and returns the number | 4076 | /* Helper function that copies local addresses to user and returns the number |
| 4077 | * of addresses copied. | 4077 | * of addresses copied. |
| 4078 | */ | 4078 | */ |
| 4079 | static int sctp_copy_laddrs_to_user_old(struct sock *sk, __u16 port, int max_addrs, | 4079 | static int sctp_copy_laddrs_old(struct sock *sk, __u16 port, |
| 4080 | void __user *to) | 4080 | int max_addrs, void *to, |
| 4081 | int *bytes_copied) | ||
| 4081 | { | 4082 | { |
| 4082 | struct list_head *pos, *next; | 4083 | struct list_head *pos, *next; |
| 4083 | struct sctp_sockaddr_entry *addr; | 4084 | struct sctp_sockaddr_entry *addr; |
| @@ -4094,10 +4095,10 @@ static int sctp_copy_laddrs_to_user_old(struct sock *sk, __u16 port, int max_add | |||
| 4094 | sctp_get_pf_specific(sk->sk_family)->addr_v4map(sctp_sk(sk), | 4095 | sctp_get_pf_specific(sk->sk_family)->addr_v4map(sctp_sk(sk), |
| 4095 | &temp); | 4096 | &temp); |
| 4096 | addrlen = sctp_get_af_specific(temp.sa.sa_family)->sockaddr_len; | 4097 | addrlen = sctp_get_af_specific(temp.sa.sa_family)->sockaddr_len; |
| 4097 | if (copy_to_user(to, &temp, addrlen)) | 4098 | memcpy(to, &temp, addrlen); |
| 4098 | return -EFAULT; | ||
| 4099 | 4099 | ||
| 4100 | to += addrlen; | 4100 | to += addrlen; |
| 4101 | *bytes_copied += addrlen; | ||
| 4101 | cnt ++; | 4102 | cnt ++; |
| 4102 | if (cnt >= max_addrs) break; | 4103 | if (cnt >= max_addrs) break; |
| 4103 | } | 4104 | } |
| @@ -4105,8 +4106,8 @@ static int sctp_copy_laddrs_to_user_old(struct sock *sk, __u16 port, int max_add | |||
| 4105 | return cnt; | 4106 | return cnt; |
| 4106 | } | 4107 | } |
| 4107 | 4108 | ||
| 4108 | static int sctp_copy_laddrs_to_user(struct sock *sk, __u16 port, | 4109 | static int sctp_copy_laddrs(struct sock *sk, __u16 port, void *to, |
| 4109 | void __user **to, size_t space_left) | 4110 | size_t space_left, int *bytes_copied) |
| 4110 | { | 4111 | { |
| 4111 | struct list_head *pos, *next; | 4112 | struct list_head *pos, *next; |
| 4112 | struct sctp_sockaddr_entry *addr; | 4113 | struct sctp_sockaddr_entry *addr; |
| @@ -4123,14 +4124,14 @@ static int sctp_copy_laddrs_to_user(struct sock *sk, __u16 port, | |||
| 4123 | sctp_get_pf_specific(sk->sk_family)->addr_v4map(sctp_sk(sk), | 4124 | sctp_get_pf_specific(sk->sk_family)->addr_v4map(sctp_sk(sk), |
| 4124 | &temp); | 4125 | &temp); |
| 4125 | addrlen = sctp_get_af_specific(temp.sa.sa_family)->sockaddr_len; | 4126 | addrlen = sctp_get_af_specific(temp.sa.sa_family)->sockaddr_len; |
| 4126 | if(space_left<addrlen) | 4127 | if (space_left < addrlen) |
| 4127 | return -ENOMEM; | 4128 | return -ENOMEM; |
| 4128 | if (copy_to_user(*to, &temp, addrlen)) | 4129 | memcpy(to, &temp, addrlen); |
| 4129 | return -EFAULT; | ||
| 4130 | 4130 | ||
| 4131 | *to += addrlen; | 4131 | to += addrlen; |
| 4132 | cnt ++; | 4132 | cnt ++; |
| 4133 | space_left -= addrlen; | 4133 | space_left -= addrlen; |
| 4134 | bytes_copied += addrlen; | ||
| 4134 | } | 4135 | } |
| 4135 | 4136 | ||
| 4136 | return cnt; | 4137 | return cnt; |
| @@ -4154,6 +4155,8 @@ static int sctp_getsockopt_local_addrs_old(struct sock *sk, int len, | |||
| 4154 | int addrlen; | 4155 | int addrlen; |
| 4155 | rwlock_t *addr_lock; | 4156 | rwlock_t *addr_lock; |
| 4156 | int err = 0; | 4157 | int err = 0; |
| 4158 | void *addrs; | ||
| 4159 | int bytes_copied = 0; | ||
| 4157 | 4160 | ||
| 4158 | if (len != sizeof(struct sctp_getaddrs_old)) | 4161 | if (len != sizeof(struct sctp_getaddrs_old)) |
| 4159 | return -EINVAL; | 4162 | return -EINVAL; |
| @@ -4181,6 +4184,15 @@ static int sctp_getsockopt_local_addrs_old(struct sock *sk, int len, | |||
| 4181 | 4184 | ||
| 4182 | to = getaddrs.addrs; | 4185 | to = getaddrs.addrs; |
| 4183 | 4186 | ||
| 4187 | /* Allocate space for a local instance of packed array to hold all | ||
| 4188 | * the data. We store addresses here first and then put write them | ||
| 4189 | * to the user in one shot. | ||
| 4190 | */ | ||
| 4191 | addrs = kmalloc(sizeof(union sctp_addr) * getaddrs.addr_num, | ||
| 4192 | GFP_KERNEL); | ||
| 4193 | if (!addrs) | ||
| 4194 | return -ENOMEM; | ||
| 4195 | |||
| 4184 | sctp_read_lock(addr_lock); | 4196 | sctp_read_lock(addr_lock); |
| 4185 | 4197 | ||
| 4186 | /* If the endpoint is bound to 0.0.0.0 or ::0, get the valid | 4198 | /* If the endpoint is bound to 0.0.0.0 or ::0, get the valid |
| @@ -4190,13 +4202,9 @@ static int sctp_getsockopt_local_addrs_old(struct sock *sk, int len, | |||
| 4190 | addr = list_entry(bp->address_list.next, | 4202 | addr = list_entry(bp->address_list.next, |
| 4191 | struct sctp_sockaddr_entry, list); | 4203 | struct sctp_sockaddr_entry, list); |
| 4192 | if (sctp_is_any(&addr->a)) { | 4204 | if (sctp_is_any(&addr->a)) { |
| 4193 | cnt = sctp_copy_laddrs_to_user_old(sk, bp->port, | 4205 | cnt = sctp_copy_laddrs_old(sk, bp->port, |
| 4194 | getaddrs.addr_num, | 4206 | getaddrs.addr_num, |
| 4195 | to); | 4207 | addrs, &bytes_copied); |
| 4196 | if (cnt < 0) { | ||
| 4197 | err = cnt; | ||
| 4198 | goto unlock; | ||
| 4199 | } | ||
| 4200 | goto copy_getaddrs; | 4208 | goto copy_getaddrs; |
| 4201 | } | 4209 | } |
| 4202 | } | 4210 | } |
| @@ -4206,22 +4214,29 @@ static int sctp_getsockopt_local_addrs_old(struct sock *sk, int len, | |||
| 4206 | memcpy(&temp, &addr->a, sizeof(temp)); | 4214 | memcpy(&temp, &addr->a, sizeof(temp)); |
| 4207 | sctp_get_pf_specific(sk->sk_family)->addr_v4map(sp, &temp); | 4215 | sctp_get_pf_specific(sk->sk_family)->addr_v4map(sp, &temp); |
| 4208 | addrlen = sctp_get_af_specific(temp.sa.sa_family)->sockaddr_len; | 4216 | addrlen = sctp_get_af_specific(temp.sa.sa_family)->sockaddr_len; |
| 4209 | if (copy_to_user(to, &temp, addrlen)) { | 4217 | memcpy(addrs, &temp, addrlen); |
| 4210 | err = -EFAULT; | ||
| 4211 | goto unlock; | ||
| 4212 | } | ||
| 4213 | to += addrlen; | 4218 | to += addrlen; |
| 4219 | bytes_copied += addrlen; | ||
| 4214 | cnt ++; | 4220 | cnt ++; |
| 4215 | if (cnt >= getaddrs.addr_num) break; | 4221 | if (cnt >= getaddrs.addr_num) break; |
| 4216 | } | 4222 | } |
| 4217 | 4223 | ||
| 4218 | copy_getaddrs: | 4224 | copy_getaddrs: |
| 4225 | sctp_read_unlock(addr_lock); | ||
| 4226 | |||
| 4227 | /* copy the entire address list into the user provided space */ | ||
| 4228 | if (copy_to_user(to, addrs, bytes_copied)) { | ||
| 4229 | err = -EFAULT; | ||
| 4230 | goto error; | ||
| 4231 | } | ||
| 4232 | |||
| 4233 | /* copy the leading structure back to user */ | ||
| 4219 | getaddrs.addr_num = cnt; | 4234 | getaddrs.addr_num = cnt; |
| 4220 | if (copy_to_user(optval, &getaddrs, sizeof(struct sctp_getaddrs_old))) | 4235 | if (copy_to_user(optval, &getaddrs, sizeof(struct sctp_getaddrs_old))) |
| 4221 | err = -EFAULT; | 4236 | err = -EFAULT; |
| 4222 | 4237 | ||
| 4223 | unlock: | 4238 | error: |
| 4224 | sctp_read_unlock(addr_lock); | 4239 | kfree(addrs); |
| 4225 | return err; | 4240 | return err; |
| 4226 | } | 4241 | } |
| 4227 | 4242 | ||
| @@ -4241,7 +4256,8 @@ static int sctp_getsockopt_local_addrs(struct sock *sk, int len, | |||
| 4241 | rwlock_t *addr_lock; | 4256 | rwlock_t *addr_lock; |
| 4242 | int err = 0; | 4257 | int err = 0; |
| 4243 | size_t space_left; | 4258 | size_t space_left; |
| 4244 | int bytes_copied; | 4259 | int bytes_copied = 0; |
| 4260 | void *addrs; | ||
| 4245 | 4261 | ||
| 4246 | if (len <= sizeof(struct sctp_getaddrs)) | 4262 | if (len <= sizeof(struct sctp_getaddrs)) |
| 4247 | return -EINVAL; | 4263 | return -EINVAL; |
| @@ -4269,6 +4285,9 @@ static int sctp_getsockopt_local_addrs(struct sock *sk, int len, | |||
| 4269 | to = optval + offsetof(struct sctp_getaddrs,addrs); | 4285 | to = optval + offsetof(struct sctp_getaddrs,addrs); |
| 4270 | space_left = len - sizeof(struct sctp_getaddrs) - | 4286 | space_left = len - sizeof(struct sctp_getaddrs) - |
| 4271 | offsetof(struct sctp_getaddrs,addrs); | 4287 | offsetof(struct sctp_getaddrs,addrs); |
| 4288 | addrs = kmalloc(space_left, GFP_KERNEL); | ||
| 4289 | if (!addrs) | ||
| 4290 | return -ENOMEM; | ||
| 4272 | 4291 | ||
| 4273 | sctp_read_lock(addr_lock); | 4292 | sctp_read_lock(addr_lock); |
| 4274 | 4293 | ||
| @@ -4279,11 +4298,11 @@ static int sctp_getsockopt_local_addrs(struct sock *sk, int len, | |||
| 4279 | addr = list_entry(bp->address_list.next, | 4298 | addr = list_entry(bp->address_list.next, |
| 4280 | struct sctp_sockaddr_entry, list); | 4299 | struct sctp_sockaddr_entry, list); |
| 4281 | if (sctp_is_any(&addr->a)) { | 4300 | if (sctp_is_any(&addr->a)) { |
| 4282 | cnt = sctp_copy_laddrs_to_user(sk, bp->port, | 4301 | cnt = sctp_copy_laddrs(sk, bp->port, addrs, |
| 4283 | &to, space_left); | 4302 | space_left, &bytes_copied); |
| 4284 | if (cnt < 0) { | 4303 | if (cnt < 0) { |
| 4285 | err = cnt; | 4304 | err = cnt; |
| 4286 | goto unlock; | 4305 | goto error; |
| 4287 | } | 4306 | } |
| 4288 | goto copy_getaddrs; | 4307 | goto copy_getaddrs; |
| 4289 | } | 4308 | } |
| @@ -4294,26 +4313,31 @@ static int sctp_getsockopt_local_addrs(struct sock *sk, int len, | |||
| 4294 | memcpy(&temp, &addr->a, sizeof(temp)); | 4313 | memcpy(&temp, &addr->a, sizeof(temp)); |
| 4295 | sctp_get_pf_specific(sk->sk_family)->addr_v4map(sp, &temp); | 4314 | sctp_get_pf_specific(sk->sk_family)->addr_v4map(sp, &temp); |
| 4296 | addrlen = sctp_get_af_specific(temp.sa.sa_family)->sockaddr_len; | 4315 | addrlen = sctp_get_af_specific(temp.sa.sa_family)->sockaddr_len; |
| 4297 | if(space_left < addrlen) | 4316 | if (space_left < addrlen) { |
| 4298 | return -ENOMEM; /*fixme: right error?*/ | 4317 | err = -ENOMEM; /*fixme: right error?*/ |
| 4299 | if (copy_to_user(to, &temp, addrlen)) { | 4318 | goto error; |
| 4300 | err = -EFAULT; | ||
| 4301 | goto unlock; | ||
| 4302 | } | 4319 | } |
| 4320 | memcpy(addrs, &temp, addrlen); | ||
| 4303 | to += addrlen; | 4321 | to += addrlen; |
| 4322 | bytes_copied += addrlen; | ||
| 4304 | cnt ++; | 4323 | cnt ++; |
| 4305 | space_left -= addrlen; | 4324 | space_left -= addrlen; |
| 4306 | } | 4325 | } |
| 4307 | 4326 | ||
| 4308 | copy_getaddrs: | 4327 | copy_getaddrs: |
| 4328 | sctp_read_unlock(addr_lock); | ||
| 4329 | |||
| 4330 | if (copy_to_user(to, addrs, bytes_copied)) { | ||
| 4331 | err = -EFAULT; | ||
| 4332 | goto error; | ||
| 4333 | } | ||
| 4309 | if (put_user(cnt, &((struct sctp_getaddrs __user *)optval)->addr_num)) | 4334 | if (put_user(cnt, &((struct sctp_getaddrs __user *)optval)->addr_num)) |
| 4310 | return -EFAULT; | 4335 | return -EFAULT; |
| 4311 | bytes_copied = ((char __user *)to) - optval; | ||
| 4312 | if (put_user(bytes_copied, optlen)) | 4336 | if (put_user(bytes_copied, optlen)) |
| 4313 | return -EFAULT; | 4337 | return -EFAULT; |
| 4314 | 4338 | ||
| 4315 | unlock: | 4339 | error: |
| 4316 | sctp_read_unlock(addr_lock); | 4340 | kfree(addrs); |
| 4317 | return err; | 4341 | return err; |
| 4318 | } | 4342 | } |
| 4319 | 4343 | ||
