diff options
| -rw-r--r-- | include/net/sctp/user.h | 23 | ||||
| -rw-r--r-- | net/sctp/socket.c | 252 |
2 files changed, 243 insertions, 32 deletions
diff --git a/include/net/sctp/user.h b/include/net/sctp/user.h index f6328aeddcce..e81ab52755fb 100644 --- a/include/net/sctp/user.h +++ b/include/net/sctp/user.h | |||
| @@ -103,16 +103,20 @@ enum sctp_optname { | |||
| 103 | #define SCTP_SOCKOPT_BINDX_REM SCTP_SOCKOPT_BINDX_REM | 103 | #define SCTP_SOCKOPT_BINDX_REM SCTP_SOCKOPT_BINDX_REM |
| 104 | SCTP_SOCKOPT_PEELOFF, /* peel off association. */ | 104 | SCTP_SOCKOPT_PEELOFF, /* peel off association. */ |
| 105 | #define SCTP_SOCKOPT_PEELOFF SCTP_SOCKOPT_PEELOFF | 105 | #define SCTP_SOCKOPT_PEELOFF SCTP_SOCKOPT_PEELOFF |
| 106 | SCTP_GET_PEER_ADDRS_NUM, /* Get number of peer addresss. */ | 106 | SCTP_GET_PEER_ADDRS_NUM_OLD, /* Get number of peer addresss. */ |
| 107 | #define SCTP_GET_PEER_ADDRS_NUM SCTP_GET_PEER_ADDRS_NUM | 107 | #define SCTP_GET_PEER_ADDRS_NUM_OLD SCTP_GET_PEER_ADDRS_NUM_OLD |
| 108 | SCTP_GET_PEER_ADDRS_OLD, /* Get all peer addresss. */ | ||
| 109 | #define SCTP_GET_PEER_ADDRS_OLD SCTP_GET_PEER_ADDRS_OLD | ||
| 110 | SCTP_GET_LOCAL_ADDRS_NUM_OLD, /* Get number of local addresss. */ | ||
| 111 | #define SCTP_GET_LOCAL_ADDRS_NUM_OLD SCTP_GET_LOCAL_ADDRS_NUM_OLD | ||
| 112 | SCTP_GET_LOCAL_ADDRS_OLD, /* Get all local addresss. */ | ||
| 113 | #define SCTP_GET_LOCAL_ADDRS_OLD SCTP_GET_LOCAL_ADDRS_OLD | ||
| 114 | SCTP_SOCKOPT_CONNECTX, /* CONNECTX requests. */ | ||
| 115 | #define SCTP_SOCKOPT_CONNECTX SCTP_SOCKOPT_CONNECTX | ||
| 108 | SCTP_GET_PEER_ADDRS, /* Get all peer addresss. */ | 116 | SCTP_GET_PEER_ADDRS, /* Get all peer addresss. */ |
| 109 | #define SCTP_GET_PEER_ADDRS SCTP_GET_PEER_ADDRS | 117 | #define SCTP_GET_PEER_ADDRS SCTP_GET_PEER_ADDRS |
| 110 | SCTP_GET_LOCAL_ADDRS_NUM, /* Get number of local addresss. */ | ||
| 111 | #define SCTP_GET_LOCAL_ADDRS_NUM SCTP_GET_LOCAL_ADDRS_NUM | ||
| 112 | SCTP_GET_LOCAL_ADDRS, /* Get all local addresss. */ | 118 | SCTP_GET_LOCAL_ADDRS, /* Get all local addresss. */ |
| 113 | #define SCTP_GET_LOCAL_ADDRS SCTP_GET_LOCAL_ADDRS | 119 | #define SCTP_GET_LOCAL_ADDRS SCTP_GET_LOCAL_ADDRS |
| 114 | SCTP_SOCKOPT_CONNECTX, /* CONNECTX requests. */ | ||
| 115 | #define SCTP_SOCKOPT_CONNECTX SCTP_SOCKOPT_CONNECTX | ||
| 116 | }; | 120 | }; |
| 117 | 121 | ||
| 118 | /* | 122 | /* |
| @@ -559,11 +563,16 @@ struct sctp_status { | |||
| 559 | * SCTP_GET_LOCAL_ADDRS socket options used internally to implement | 563 | * SCTP_GET_LOCAL_ADDRS socket options used internally to implement |
| 560 | * sctp_getpaddrs() and sctp_getladdrs() API. | 564 | * sctp_getpaddrs() and sctp_getladdrs() API. |
| 561 | */ | 565 | */ |
| 562 | struct sctp_getaddrs { | 566 | struct sctp_getaddrs_old { |
| 563 | sctp_assoc_t assoc_id; | 567 | sctp_assoc_t assoc_id; |
| 564 | int addr_num; | 568 | int addr_num; |
| 565 | struct sockaddr __user *addrs; | 569 | struct sockaddr __user *addrs; |
| 566 | }; | 570 | }; |
| 571 | struct sctp_getaddrs { | ||
| 572 | sctp_assoc_t assoc_id; /*input*/ | ||
| 573 | __u32 addr_num; /*output*/ | ||
| 574 | __u8 addrs[0]; /*output, variable size*/ | ||
| 575 | }; | ||
| 567 | 576 | ||
| 568 | /* These are bit fields for msghdr->msg_flags. See section 5.1. */ | 577 | /* These are bit fields for msghdr->msg_flags. See section 5.1. */ |
| 569 | /* On user space Linux, these live in <bits/socket.h> as an enum. */ | 578 | /* On user space Linux, these live in <bits/socket.h> as an enum. */ |
diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 91ec8c936913..02e068d3450d 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c | |||
| @@ -3159,8 +3159,9 @@ static int sctp_getsockopt_initmsg(struct sock *sk, int len, char __user *optval | |||
| 3159 | return 0; | 3159 | return 0; |
| 3160 | } | 3160 | } |
| 3161 | 3161 | ||
| 3162 | static int sctp_getsockopt_peer_addrs_num(struct sock *sk, int len, | 3162 | static int sctp_getsockopt_peer_addrs_num_old(struct sock *sk, int len, |
| 3163 | char __user *optval, int __user *optlen) | 3163 | char __user *optval, |
| 3164 | int __user *optlen) | ||
| 3164 | { | 3165 | { |
| 3165 | sctp_assoc_t id; | 3166 | sctp_assoc_t id; |
| 3166 | struct sctp_association *asoc; | 3167 | struct sctp_association *asoc; |
| @@ -3185,23 +3186,28 @@ static int sctp_getsockopt_peer_addrs_num(struct sock *sk, int len, | |||
| 3185 | return cnt; | 3186 | return cnt; |
| 3186 | } | 3187 | } |
| 3187 | 3188 | ||
| 3188 | static int sctp_getsockopt_peer_addrs(struct sock *sk, int len, | 3189 | /* |
| 3189 | char __user *optval, int __user *optlen) | 3190 | * Old API for getting list of peer addresses. Does not work for 32-bit |
| 3191 | * programs running on a 64-bit kernel | ||
| 3192 | */ | ||
| 3193 | static int sctp_getsockopt_peer_addrs_old(struct sock *sk, int len, | ||
| 3194 | char __user *optval, | ||
| 3195 | int __user *optlen) | ||
| 3190 | { | 3196 | { |
| 3191 | struct sctp_association *asoc; | 3197 | struct sctp_association *asoc; |
| 3192 | struct list_head *pos; | 3198 | struct list_head *pos; |
| 3193 | int cnt = 0; | 3199 | int cnt = 0; |
| 3194 | struct sctp_getaddrs getaddrs; | 3200 | struct sctp_getaddrs_old getaddrs; |
| 3195 | struct sctp_transport *from; | 3201 | struct sctp_transport *from; |
| 3196 | void __user *to; | 3202 | void __user *to; |
| 3197 | union sctp_addr temp; | 3203 | union sctp_addr temp; |
| 3198 | struct sctp_sock *sp = sctp_sk(sk); | 3204 | struct sctp_sock *sp = sctp_sk(sk); |
| 3199 | int addrlen; | 3205 | int addrlen; |
| 3200 | 3206 | ||
| 3201 | if (len != sizeof(struct sctp_getaddrs)) | 3207 | if (len != sizeof(struct sctp_getaddrs_old)) |
| 3202 | return -EINVAL; | 3208 | return -EINVAL; |
| 3203 | 3209 | ||
| 3204 | if (copy_from_user(&getaddrs, optval, sizeof(struct sctp_getaddrs))) | 3210 | if (copy_from_user(&getaddrs, optval, sizeof(struct sctp_getaddrs_old))) |
| 3205 | return -EFAULT; | 3211 | return -EFAULT; |
| 3206 | 3212 | ||
| 3207 | if (getaddrs.addr_num <= 0) return -EINVAL; | 3213 | if (getaddrs.addr_num <= 0) return -EINVAL; |
| @@ -3225,15 +3231,69 @@ static int sctp_getsockopt_peer_addrs(struct sock *sk, int len, | |||
| 3225 | if (cnt >= getaddrs.addr_num) break; | 3231 | if (cnt >= getaddrs.addr_num) break; |
| 3226 | } | 3232 | } |
| 3227 | getaddrs.addr_num = cnt; | 3233 | getaddrs.addr_num = cnt; |
| 3228 | if (copy_to_user(optval, &getaddrs, sizeof(struct sctp_getaddrs))) | 3234 | if (copy_to_user(optval, &getaddrs, sizeof(struct sctp_getaddrs_old))) |
| 3235 | return -EFAULT; | ||
| 3236 | |||
| 3237 | return 0; | ||
| 3238 | } | ||
| 3239 | |||
| 3240 | static int sctp_getsockopt_peer_addrs(struct sock *sk, int len, | ||
| 3241 | char __user *optval, int __user *optlen) | ||
| 3242 | { | ||
| 3243 | struct sctp_association *asoc; | ||
| 3244 | struct list_head *pos; | ||
| 3245 | int cnt = 0; | ||
| 3246 | struct sctp_getaddrs getaddrs; | ||
| 3247 | struct sctp_transport *from; | ||
| 3248 | void __user *to; | ||
| 3249 | union sctp_addr temp; | ||
| 3250 | struct sctp_sock *sp = sctp_sk(sk); | ||
| 3251 | int addrlen; | ||
| 3252 | size_t space_left; | ||
| 3253 | int bytes_copied; | ||
| 3254 | |||
| 3255 | if (len < sizeof(struct sctp_getaddrs)) | ||
| 3256 | return -EINVAL; | ||
| 3257 | |||
| 3258 | if (copy_from_user(&getaddrs, optval, sizeof(struct sctp_getaddrs))) | ||
| 3259 | return -EFAULT; | ||
| 3260 | |||
| 3261 | /* For UDP-style sockets, id specifies the association to query. */ | ||
| 3262 | asoc = sctp_id2assoc(sk, getaddrs.assoc_id); | ||
| 3263 | if (!asoc) | ||
| 3264 | return -EINVAL; | ||
| 3265 | |||
| 3266 | to = optval + offsetof(struct sctp_getaddrs,addrs); | ||
| 3267 | space_left = len - sizeof(struct sctp_getaddrs) - | ||
| 3268 | offsetof(struct sctp_getaddrs,addrs); | ||
| 3269 | |||
| 3270 | list_for_each(pos, &asoc->peer.transport_addr_list) { | ||
| 3271 | from = list_entry(pos, struct sctp_transport, transports); | ||
| 3272 | memcpy(&temp, &from->ipaddr, sizeof(temp)); | ||
| 3273 | sctp_get_pf_specific(sk->sk_family)->addr_v4map(sp, &temp); | ||
| 3274 | addrlen = sctp_get_af_specific(sk->sk_family)->sockaddr_len; | ||
| 3275 | if(space_left < addrlen) | ||
| 3276 | return -ENOMEM; | ||
| 3277 | temp.v4.sin_port = htons(temp.v4.sin_port); | ||
| 3278 | if (copy_to_user(to, &temp, addrlen)) | ||
| 3279 | return -EFAULT; | ||
| 3280 | to += addrlen; | ||
| 3281 | cnt++; | ||
| 3282 | space_left -= addrlen; | ||
| 3283 | } | ||
| 3284 | |||
| 3285 | if (put_user(cnt, &((struct sctp_getaddrs __user *)optval)->addr_num)) | ||
| 3286 | return -EFAULT; | ||
| 3287 | bytes_copied = ((char __user *)to) - optval; | ||
| 3288 | if (put_user(bytes_copied, optlen)) | ||
| 3229 | return -EFAULT; | 3289 | return -EFAULT; |
| 3230 | 3290 | ||
| 3231 | return 0; | 3291 | return 0; |
| 3232 | } | 3292 | } |
| 3233 | 3293 | ||
| 3234 | static int sctp_getsockopt_local_addrs_num(struct sock *sk, int len, | 3294 | static int sctp_getsockopt_local_addrs_num_old(struct sock *sk, int len, |
| 3235 | char __user *optval, | 3295 | char __user *optval, |
| 3236 | int __user *optlen) | 3296 | int __user *optlen) |
| 3237 | { | 3297 | { |
| 3238 | sctp_assoc_t id; | 3298 | sctp_assoc_t id; |
| 3239 | struct sctp_bind_addr *bp; | 3299 | struct sctp_bind_addr *bp; |
| @@ -3306,8 +3366,8 @@ done: | |||
| 3306 | /* Helper function that copies local addresses to user and returns the number | 3366 | /* Helper function that copies local addresses to user and returns the number |
| 3307 | * of addresses copied. | 3367 | * of addresses copied. |
| 3308 | */ | 3368 | */ |
| 3309 | static int sctp_copy_laddrs_to_user(struct sock *sk, __u16 port, int max_addrs, | 3369 | static int sctp_copy_laddrs_to_user_old(struct sock *sk, __u16 port, int max_addrs, |
| 3310 | void __user *to) | 3370 | void __user *to) |
| 3311 | { | 3371 | { |
| 3312 | struct list_head *pos; | 3372 | struct list_head *pos; |
| 3313 | struct sctp_sockaddr_entry *addr; | 3373 | struct sctp_sockaddr_entry *addr; |
| @@ -3341,14 +3401,54 @@ static int sctp_copy_laddrs_to_user(struct sock *sk, __u16 port, int max_addrs, | |||
| 3341 | return cnt; | 3401 | return cnt; |
| 3342 | } | 3402 | } |
| 3343 | 3403 | ||
| 3344 | static int sctp_getsockopt_local_addrs(struct sock *sk, int len, | 3404 | static int sctp_copy_laddrs_to_user(struct sock *sk, __u16 port, |
| 3345 | char __user *optval, int __user *optlen) | 3405 | void * __user *to, size_t space_left) |
| 3406 | { | ||
| 3407 | struct list_head *pos; | ||
| 3408 | struct sctp_sockaddr_entry *addr; | ||
| 3409 | unsigned long flags; | ||
| 3410 | union sctp_addr temp; | ||
| 3411 | int cnt = 0; | ||
| 3412 | int addrlen; | ||
| 3413 | |||
| 3414 | sctp_spin_lock_irqsave(&sctp_local_addr_lock, flags); | ||
| 3415 | list_for_each(pos, &sctp_local_addr_list) { | ||
| 3416 | addr = list_entry(pos, struct sctp_sockaddr_entry, list); | ||
| 3417 | if ((PF_INET == sk->sk_family) && | ||
| 3418 | (AF_INET6 == addr->a.sa.sa_family)) | ||
| 3419 | continue; | ||
| 3420 | memcpy(&temp, &addr->a, sizeof(temp)); | ||
| 3421 | sctp_get_pf_specific(sk->sk_family)->addr_v4map(sctp_sk(sk), | ||
| 3422 | &temp); | ||
| 3423 | addrlen = sctp_get_af_specific(temp.sa.sa_family)->sockaddr_len; | ||
| 3424 | if(space_left<addrlen) | ||
| 3425 | return -ENOMEM; | ||
| 3426 | temp.v4.sin_port = htons(port); | ||
| 3427 | if (copy_to_user(*to, &temp, addrlen)) { | ||
| 3428 | sctp_spin_unlock_irqrestore(&sctp_local_addr_lock, | ||
| 3429 | flags); | ||
| 3430 | return -EFAULT; | ||
| 3431 | } | ||
| 3432 | *to += addrlen; | ||
| 3433 | cnt ++; | ||
| 3434 | space_left -= addrlen; | ||
| 3435 | } | ||
| 3436 | sctp_spin_unlock_irqrestore(&sctp_local_addr_lock, flags); | ||
| 3437 | |||
| 3438 | return cnt; | ||
| 3439 | } | ||
| 3440 | |||
| 3441 | /* Old API for getting list of local addresses. Does not work for 32-bit | ||
| 3442 | * programs running on a 64-bit kernel | ||
| 3443 | */ | ||
| 3444 | static int sctp_getsockopt_local_addrs_old(struct sock *sk, int len, | ||
| 3445 | char __user *optval, int __user *optlen) | ||
| 3346 | { | 3446 | { |
| 3347 | struct sctp_bind_addr *bp; | 3447 | struct sctp_bind_addr *bp; |
| 3348 | struct sctp_association *asoc; | 3448 | struct sctp_association *asoc; |
| 3349 | struct list_head *pos; | 3449 | struct list_head *pos; |
| 3350 | int cnt = 0; | 3450 | int cnt = 0; |
| 3351 | struct sctp_getaddrs getaddrs; | 3451 | struct sctp_getaddrs_old getaddrs; |
| 3352 | struct sctp_sockaddr_entry *addr; | 3452 | struct sctp_sockaddr_entry *addr; |
| 3353 | void __user *to; | 3453 | void __user *to; |
| 3354 | union sctp_addr temp; | 3454 | union sctp_addr temp; |
| @@ -3357,10 +3457,10 @@ static int sctp_getsockopt_local_addrs(struct sock *sk, int len, | |||
| 3357 | rwlock_t *addr_lock; | 3457 | rwlock_t *addr_lock; |
| 3358 | int err = 0; | 3458 | int err = 0; |
| 3359 | 3459 | ||
| 3360 | if (len != sizeof(struct sctp_getaddrs)) | 3460 | if (len != sizeof(struct sctp_getaddrs_old)) |
| 3361 | return -EINVAL; | 3461 | return -EINVAL; |
| 3362 | 3462 | ||
| 3363 | if (copy_from_user(&getaddrs, optval, sizeof(struct sctp_getaddrs))) | 3463 | if (copy_from_user(&getaddrs, optval, sizeof(struct sctp_getaddrs_old))) |
| 3364 | return -EFAULT; | 3464 | return -EFAULT; |
| 3365 | 3465 | ||
| 3366 | if (getaddrs.addr_num <= 0) return -EINVAL; | 3466 | if (getaddrs.addr_num <= 0) return -EINVAL; |
| @@ -3392,8 +3492,9 @@ static int sctp_getsockopt_local_addrs(struct sock *sk, int len, | |||
| 3392 | addr = list_entry(bp->address_list.next, | 3492 | addr = list_entry(bp->address_list.next, |
| 3393 | struct sctp_sockaddr_entry, list); | 3493 | struct sctp_sockaddr_entry, list); |
| 3394 | if (sctp_is_any(&addr->a)) { | 3494 | if (sctp_is_any(&addr->a)) { |
| 3395 | cnt = sctp_copy_laddrs_to_user(sk, bp->port, | 3495 | cnt = sctp_copy_laddrs_to_user_old(sk, bp->port, |
| 3396 | getaddrs.addr_num, to); | 3496 | getaddrs.addr_num, |
| 3497 | to); | ||
| 3397 | if (cnt < 0) { | 3498 | if (cnt < 0) { |
| 3398 | err = cnt; | 3499 | err = cnt; |
| 3399 | goto unlock; | 3500 | goto unlock; |
| @@ -3419,7 +3520,7 @@ static int sctp_getsockopt_local_addrs(struct sock *sk, int len, | |||
| 3419 | 3520 | ||
| 3420 | copy_getaddrs: | 3521 | copy_getaddrs: |
| 3421 | getaddrs.addr_num = cnt; | 3522 | getaddrs.addr_num = cnt; |
| 3422 | if (copy_to_user(optval, &getaddrs, sizeof(struct sctp_getaddrs))) | 3523 | if (copy_to_user(optval, &getaddrs, sizeof(struct sctp_getaddrs_old))) |
| 3423 | err = -EFAULT; | 3524 | err = -EFAULT; |
| 3424 | 3525 | ||
| 3425 | unlock: | 3526 | unlock: |
| @@ -3427,6 +3528,99 @@ unlock: | |||
| 3427 | return err; | 3528 | return err; |
| 3428 | } | 3529 | } |
| 3429 | 3530 | ||
| 3531 | static int sctp_getsockopt_local_addrs(struct sock *sk, int len, | ||
| 3532 | char __user *optval, int __user *optlen) | ||
| 3533 | { | ||
| 3534 | struct sctp_bind_addr *bp; | ||
| 3535 | struct sctp_association *asoc; | ||
| 3536 | struct list_head *pos; | ||
| 3537 | int cnt = 0; | ||
| 3538 | struct sctp_getaddrs getaddrs; | ||
| 3539 | struct sctp_sockaddr_entry *addr; | ||
| 3540 | void __user *to; | ||
| 3541 | union sctp_addr temp; | ||
| 3542 | struct sctp_sock *sp = sctp_sk(sk); | ||
| 3543 | int addrlen; | ||
| 3544 | rwlock_t *addr_lock; | ||
| 3545 | int err = 0; | ||
| 3546 | size_t space_left; | ||
| 3547 | int bytes_copied; | ||
| 3548 | |||
| 3549 | if (len <= sizeof(struct sctp_getaddrs)) | ||
| 3550 | return -EINVAL; | ||
| 3551 | |||
| 3552 | if (copy_from_user(&getaddrs, optval, sizeof(struct sctp_getaddrs))) | ||
| 3553 | return -EFAULT; | ||
| 3554 | |||
| 3555 | /* | ||
| 3556 | * For UDP-style sockets, id specifies the association to query. | ||
| 3557 | * If the id field is set to the value '0' then the locally bound | ||
| 3558 | * addresses are returned without regard to any particular | ||
| 3559 | * association. | ||
| 3560 | */ | ||
| 3561 | if (0 == getaddrs.assoc_id) { | ||
| 3562 | bp = &sctp_sk(sk)->ep->base.bind_addr; | ||
| 3563 | addr_lock = &sctp_sk(sk)->ep->base.addr_lock; | ||
| 3564 | } else { | ||
| 3565 | asoc = sctp_id2assoc(sk, getaddrs.assoc_id); | ||
| 3566 | if (!asoc) | ||
| 3567 | return -EINVAL; | ||
| 3568 | bp = &asoc->base.bind_addr; | ||
| 3569 | addr_lock = &asoc->base.addr_lock; | ||
| 3570 | } | ||
| 3571 | |||
| 3572 | to = optval + offsetof(struct sctp_getaddrs,addrs); | ||
| 3573 | space_left = len - sizeof(struct sctp_getaddrs) - | ||
| 3574 | offsetof(struct sctp_getaddrs,addrs); | ||
| 3575 | |||
| 3576 | sctp_read_lock(addr_lock); | ||
| 3577 | |||
| 3578 | /* If the endpoint is bound to 0.0.0.0 or ::0, get the valid | ||
| 3579 | * addresses from the global local address list. | ||
| 3580 | */ | ||
| 3581 | if (sctp_list_single_entry(&bp->address_list)) { | ||
| 3582 | addr = list_entry(bp->address_list.next, | ||
| 3583 | struct sctp_sockaddr_entry, list); | ||
| 3584 | if (sctp_is_any(&addr->a)) { | ||
| 3585 | cnt = sctp_copy_laddrs_to_user(sk, bp->port, | ||
| 3586 | &to, space_left); | ||
| 3587 | if (cnt < 0) { | ||
| 3588 | err = cnt; | ||
| 3589 | goto unlock; | ||
| 3590 | } | ||
| 3591 | goto copy_getaddrs; | ||
| 3592 | } | ||
| 3593 | } | ||
| 3594 | |||
| 3595 | list_for_each(pos, &bp->address_list) { | ||
| 3596 | addr = list_entry(pos, struct sctp_sockaddr_entry, list); | ||
| 3597 | memcpy(&temp, &addr->a, sizeof(temp)); | ||
| 3598 | sctp_get_pf_specific(sk->sk_family)->addr_v4map(sp, &temp); | ||
| 3599 | addrlen = sctp_get_af_specific(temp.sa.sa_family)->sockaddr_len; | ||
| 3600 | if(space_left < addrlen) | ||
| 3601 | return -ENOMEM; /*fixme: right error?*/ | ||
| 3602 | temp.v4.sin_port = htons(temp.v4.sin_port); | ||
| 3603 | if (copy_to_user(to, &temp, addrlen)) { | ||
| 3604 | err = -EFAULT; | ||
| 3605 | goto unlock; | ||
| 3606 | } | ||
| 3607 | to += addrlen; | ||
| 3608 | cnt ++; | ||
| 3609 | space_left -= addrlen; | ||
| 3610 | } | ||
| 3611 | |||
| 3612 | copy_getaddrs: | ||
| 3613 | if (put_user(cnt, &((struct sctp_getaddrs __user *)optval)->addr_num)) | ||
| 3614 | return -EFAULT; | ||
| 3615 | bytes_copied = ((char __user *)to) - optval; | ||
| 3616 | if (put_user(bytes_copied, optlen)) | ||
| 3617 | return -EFAULT; | ||
| 3618 | |||
| 3619 | unlock: | ||
| 3620 | sctp_read_unlock(addr_lock); | ||
| 3621 | return err; | ||
| 3622 | } | ||
| 3623 | |||
| 3430 | /* 7.1.10 Set Primary Address (SCTP_PRIMARY_ADDR) | 3624 | /* 7.1.10 Set Primary Address (SCTP_PRIMARY_ADDR) |
| 3431 | * | 3625 | * |
| 3432 | * Requests that the local SCTP stack use the enclosed peer address as | 3626 | * Requests that the local SCTP stack use the enclosed peer address as |
| @@ -3807,12 +4001,20 @@ SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname, | |||
| 3807 | case SCTP_INITMSG: | 4001 | case SCTP_INITMSG: |
| 3808 | retval = sctp_getsockopt_initmsg(sk, len, optval, optlen); | 4002 | retval = sctp_getsockopt_initmsg(sk, len, optval, optlen); |
| 3809 | break; | 4003 | break; |
| 3810 | case SCTP_GET_PEER_ADDRS_NUM: | 4004 | case SCTP_GET_PEER_ADDRS_NUM_OLD: |
| 3811 | retval = sctp_getsockopt_peer_addrs_num(sk, len, optval, | 4005 | retval = sctp_getsockopt_peer_addrs_num_old(sk, len, optval, |
| 4006 | optlen); | ||
| 4007 | break; | ||
| 4008 | case SCTP_GET_LOCAL_ADDRS_NUM_OLD: | ||
| 4009 | retval = sctp_getsockopt_local_addrs_num_old(sk, len, optval, | ||
| 4010 | optlen); | ||
| 4011 | break; | ||
| 4012 | case SCTP_GET_PEER_ADDRS_OLD: | ||
| 4013 | retval = sctp_getsockopt_peer_addrs_old(sk, len, optval, | ||
| 3812 | optlen); | 4014 | optlen); |
| 3813 | break; | 4015 | break; |
| 3814 | case SCTP_GET_LOCAL_ADDRS_NUM: | 4016 | case SCTP_GET_LOCAL_ADDRS_OLD: |
| 3815 | retval = sctp_getsockopt_local_addrs_num(sk, len, optval, | 4017 | retval = sctp_getsockopt_local_addrs_old(sk, len, optval, |
| 3816 | optlen); | 4018 | optlen); |
| 3817 | break; | 4019 | break; |
| 3818 | case SCTP_GET_PEER_ADDRS: | 4020 | case SCTP_GET_PEER_ADDRS: |
