diff options
Diffstat (limited to 'net/sctp/socket.c')
| -rw-r--r-- | net/sctp/socket.c | 47 |
1 files changed, 32 insertions, 15 deletions
diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 9e91d6e5df63..981aaf8b6ace 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c | |||
| @@ -64,6 +64,7 @@ | |||
| 64 | #include <linux/crypto.h> | 64 | #include <linux/crypto.h> |
| 65 | #include <linux/slab.h> | 65 | #include <linux/slab.h> |
| 66 | #include <linux/file.h> | 66 | #include <linux/file.h> |
| 67 | #include <linux/compat.h> | ||
| 67 | 68 | ||
| 68 | #include <net/ip.h> | 69 | #include <net/ip.h> |
| 69 | #include <net/icmp.h> | 70 | #include <net/icmp.h> |
| @@ -1368,11 +1369,19 @@ static int sctp_setsockopt_connectx(struct sock *sk, | |||
| 1368 | /* | 1369 | /* |
| 1369 | * New (hopefully final) interface for the API. | 1370 | * New (hopefully final) interface for the API. |
| 1370 | * We use the sctp_getaddrs_old structure so that use-space library | 1371 | * We use the sctp_getaddrs_old structure so that use-space library |
| 1371 | * can avoid any unnecessary allocations. The only defferent part | 1372 | * can avoid any unnecessary allocations. The only different part |
| 1372 | * is that we store the actual length of the address buffer into the | 1373 | * is that we store the actual length of the address buffer into the |
| 1373 | * addrs_num structure member. That way we can re-use the existing | 1374 | * addrs_num structure member. That way we can re-use the existing |
| 1374 | * code. | 1375 | * code. |
| 1375 | */ | 1376 | */ |
| 1377 | #ifdef CONFIG_COMPAT | ||
| 1378 | struct compat_sctp_getaddrs_old { | ||
| 1379 | sctp_assoc_t assoc_id; | ||
| 1380 | s32 addr_num; | ||
| 1381 | compat_uptr_t addrs; /* struct sockaddr * */ | ||
| 1382 | }; | ||
| 1383 | #endif | ||
| 1384 | |||
| 1376 | static int sctp_getsockopt_connectx3(struct sock *sk, int len, | 1385 | static int sctp_getsockopt_connectx3(struct sock *sk, int len, |
| 1377 | char __user *optval, | 1386 | char __user *optval, |
| 1378 | int __user *optlen) | 1387 | int __user *optlen) |
| @@ -1381,16 +1390,30 @@ static int sctp_getsockopt_connectx3(struct sock *sk, int len, | |||
| 1381 | sctp_assoc_t assoc_id = 0; | 1390 | sctp_assoc_t assoc_id = 0; |
| 1382 | int err = 0; | 1391 | int err = 0; |
| 1383 | 1392 | ||
| 1384 | if (len < sizeof(param)) | 1393 | #ifdef CONFIG_COMPAT |
| 1385 | return -EINVAL; | 1394 | if (is_compat_task()) { |
| 1395 | struct compat_sctp_getaddrs_old param32; | ||
| 1386 | 1396 | ||
| 1387 | if (copy_from_user(¶m, optval, sizeof(param))) | 1397 | if (len < sizeof(param32)) |
| 1388 | return -EFAULT; | 1398 | return -EINVAL; |
| 1399 | if (copy_from_user(¶m32, optval, sizeof(param32))) | ||
| 1400 | return -EFAULT; | ||
| 1389 | 1401 | ||
| 1390 | err = __sctp_setsockopt_connectx(sk, | 1402 | param.assoc_id = param32.assoc_id; |
| 1391 | (struct sockaddr __user *)param.addrs, | 1403 | param.addr_num = param32.addr_num; |
| 1392 | param.addr_num, &assoc_id); | 1404 | param.addrs = compat_ptr(param32.addrs); |
| 1405 | } else | ||
| 1406 | #endif | ||
| 1407 | { | ||
| 1408 | if (len < sizeof(param)) | ||
| 1409 | return -EINVAL; | ||
| 1410 | if (copy_from_user(¶m, optval, sizeof(param))) | ||
| 1411 | return -EFAULT; | ||
| 1412 | } | ||
| 1393 | 1413 | ||
| 1414 | err = __sctp_setsockopt_connectx(sk, (struct sockaddr __user *) | ||
| 1415 | param.addrs, param.addr_num, | ||
| 1416 | &assoc_id); | ||
| 1394 | if (err == 0 || err == -EINPROGRESS) { | 1417 | if (err == 0 || err == -EINPROGRESS) { |
| 1395 | if (copy_to_user(optval, &assoc_id, sizeof(assoc_id))) | 1418 | if (copy_to_user(optval, &assoc_id, sizeof(assoc_id))) |
| 1396 | return -EFAULT; | 1419 | return -EFAULT; |
| @@ -2092,12 +2115,6 @@ static int sctp_recvmsg(struct kiocb *iocb, struct sock *sk, | |||
| 2092 | sctp_skb_pull(skb, copied); | 2115 | sctp_skb_pull(skb, copied); |
| 2093 | skb_queue_head(&sk->sk_receive_queue, skb); | 2116 | skb_queue_head(&sk->sk_receive_queue, skb); |
| 2094 | 2117 | ||
| 2095 | /* When only partial message is copied to the user, increase | ||
| 2096 | * rwnd by that amount. If all the data in the skb is read, | ||
| 2097 | * rwnd is updated when the event is freed. | ||
| 2098 | */ | ||
| 2099 | if (!sctp_ulpevent_is_notification(event)) | ||
| 2100 | sctp_assoc_rwnd_increase(event->asoc, copied); | ||
| 2101 | goto out; | 2118 | goto out; |
| 2102 | } else if ((event->msg_flags & MSG_NOTIFICATION) || | 2119 | } else if ((event->msg_flags & MSG_NOTIFICATION) || |
| 2103 | (event->msg_flags & MSG_EOR)) | 2120 | (event->msg_flags & MSG_EOR)) |
