diff options
Diffstat (limited to 'net/sctp/socket.c')
-rw-r--r-- | net/sctp/socket.c | 95 |
1 files changed, 70 insertions, 25 deletions
diff --git a/net/sctp/socket.c b/net/sctp/socket.c index deb82e35a107..6766913a53e6 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c | |||
@@ -658,11 +658,15 @@ static int sctp_bindx_rem(struct sock *sk, struct sockaddr *addrs, int addrcnt) | |||
658 | goto err_bindx_rem; | 658 | goto err_bindx_rem; |
659 | } | 659 | } |
660 | 660 | ||
661 | if (sa_addr->v4.sin_port != htons(bp->port)) { | 661 | if (sa_addr->v4.sin_port && |
662 | sa_addr->v4.sin_port != htons(bp->port)) { | ||
662 | retval = -EINVAL; | 663 | retval = -EINVAL; |
663 | goto err_bindx_rem; | 664 | goto err_bindx_rem; |
664 | } | 665 | } |
665 | 666 | ||
667 | if (!sa_addr->v4.sin_port) | ||
668 | sa_addr->v4.sin_port = htons(bp->port); | ||
669 | |||
666 | /* FIXME - There is probably a need to check if sk->sk_saddr and | 670 | /* FIXME - There is probably a need to check if sk->sk_saddr and |
667 | * sk->sk_rcv_addr are currently set to one of the addresses to | 671 | * sk->sk_rcv_addr are currently set to one of the addresses to |
668 | * be removed. This is something which needs to be looked into | 672 | * be removed. This is something which needs to be looked into |
@@ -1492,7 +1496,7 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk, | |||
1492 | struct sctp_chunk *chunk; | 1496 | struct sctp_chunk *chunk; |
1493 | union sctp_addr to; | 1497 | union sctp_addr to; |
1494 | struct sockaddr *msg_name = NULL; | 1498 | struct sockaddr *msg_name = NULL; |
1495 | struct sctp_sndrcvinfo default_sinfo = { 0 }; | 1499 | struct sctp_sndrcvinfo default_sinfo; |
1496 | struct sctp_sndrcvinfo *sinfo; | 1500 | struct sctp_sndrcvinfo *sinfo; |
1497 | struct sctp_initmsg *sinit; | 1501 | struct sctp_initmsg *sinit; |
1498 | sctp_assoc_t associd = 0; | 1502 | sctp_assoc_t associd = 0; |
@@ -1756,6 +1760,7 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk, | |||
1756 | /* If the user didn't specify SNDRCVINFO, make up one with | 1760 | /* If the user didn't specify SNDRCVINFO, make up one with |
1757 | * some defaults. | 1761 | * some defaults. |
1758 | */ | 1762 | */ |
1763 | memset(&default_sinfo, 0, sizeof(default_sinfo)); | ||
1759 | default_sinfo.sinfo_stream = asoc->default_stream; | 1764 | default_sinfo.sinfo_stream = asoc->default_stream; |
1760 | default_sinfo.sinfo_flags = asoc->default_flags; | 1765 | default_sinfo.sinfo_flags = asoc->default_flags; |
1761 | default_sinfo.sinfo_ppid = asoc->default_ppid; | 1766 | default_sinfo.sinfo_ppid = asoc->default_ppid; |
@@ -1786,12 +1791,10 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk, | |||
1786 | goto out_free; | 1791 | goto out_free; |
1787 | } | 1792 | } |
1788 | 1793 | ||
1789 | if (sinfo) { | 1794 | /* Check for invalid stream. */ |
1790 | /* Check for invalid stream. */ | 1795 | if (sinfo->sinfo_stream >= asoc->c.sinit_num_ostreams) { |
1791 | if (sinfo->sinfo_stream >= asoc->c.sinit_num_ostreams) { | 1796 | err = -EINVAL; |
1792 | err = -EINVAL; | 1797 | goto out_free; |
1793 | goto out_free; | ||
1794 | } | ||
1795 | } | 1798 | } |
1796 | 1799 | ||
1797 | timeo = sock_sndtimeo(sk, msg->msg_flags & MSG_DONTWAIT); | 1800 | timeo = sock_sndtimeo(sk, msg->msg_flags & MSG_DONTWAIT); |
@@ -2283,7 +2286,7 @@ static int sctp_apply_peer_addr_params(struct sctp_paddrparams *params, | |||
2283 | trans->param_flags = | 2286 | trans->param_flags = |
2284 | (trans->param_flags & ~SPP_PMTUD) | pmtud_change; | 2287 | (trans->param_flags & ~SPP_PMTUD) | pmtud_change; |
2285 | if (update) { | 2288 | if (update) { |
2286 | sctp_transport_pmtu(trans); | 2289 | sctp_transport_pmtu(trans, sctp_opt2sk(sp)); |
2287 | sctp_assoc_sync_pmtu(asoc); | 2290 | sctp_assoc_sync_pmtu(asoc); |
2288 | } | 2291 | } |
2289 | } else if (asoc) { | 2292 | } else if (asoc) { |
@@ -3215,14 +3218,9 @@ static int sctp_setsockopt_hmac_ident(struct sock *sk, | |||
3215 | if (optlen < sizeof(struct sctp_hmacalgo)) | 3218 | if (optlen < sizeof(struct sctp_hmacalgo)) |
3216 | return -EINVAL; | 3219 | return -EINVAL; |
3217 | 3220 | ||
3218 | hmacs = kmalloc(optlen, GFP_KERNEL); | 3221 | hmacs= memdup_user(optval, optlen); |
3219 | if (!hmacs) | 3222 | if (IS_ERR(hmacs)) |
3220 | return -ENOMEM; | 3223 | return PTR_ERR(hmacs); |
3221 | |||
3222 | if (copy_from_user(hmacs, optval, optlen)) { | ||
3223 | err = -EFAULT; | ||
3224 | goto out; | ||
3225 | } | ||
3226 | 3224 | ||
3227 | idents = hmacs->shmac_num_idents; | 3225 | idents = hmacs->shmac_num_idents; |
3228 | if (idents == 0 || idents > SCTP_AUTH_NUM_HMACS || | 3226 | if (idents == 0 || idents > SCTP_AUTH_NUM_HMACS || |
@@ -3257,14 +3255,9 @@ static int sctp_setsockopt_auth_key(struct sock *sk, | |||
3257 | if (optlen <= sizeof(struct sctp_authkey)) | 3255 | if (optlen <= sizeof(struct sctp_authkey)) |
3258 | return -EINVAL; | 3256 | return -EINVAL; |
3259 | 3257 | ||
3260 | authkey = kmalloc(optlen, GFP_KERNEL); | 3258 | authkey= memdup_user(optval, optlen); |
3261 | if (!authkey) | 3259 | if (IS_ERR(authkey)) |
3262 | return -ENOMEM; | 3260 | return PTR_ERR(authkey); |
3263 | |||
3264 | if (copy_from_user(authkey, optval, optlen)) { | ||
3265 | ret = -EFAULT; | ||
3266 | goto out; | ||
3267 | } | ||
3268 | 3261 | ||
3269 | if (authkey->sca_keylength > optlen - sizeof(struct sctp_authkey)) { | 3262 | if (authkey->sca_keylength > optlen - sizeof(struct sctp_authkey)) { |
3270 | ret = -EINVAL; | 3263 | ret = -EINVAL; |
@@ -5283,6 +5276,55 @@ static int sctp_getsockopt_assoc_number(struct sock *sk, int len, | |||
5283 | return 0; | 5276 | return 0; |
5284 | } | 5277 | } |
5285 | 5278 | ||
5279 | /* | ||
5280 | * 8.2.6. Get the Current Identifiers of Associations | ||
5281 | * (SCTP_GET_ASSOC_ID_LIST) | ||
5282 | * | ||
5283 | * This option gets the current list of SCTP association identifiers of | ||
5284 | * the SCTP associations handled by a one-to-many style socket. | ||
5285 | */ | ||
5286 | static int sctp_getsockopt_assoc_ids(struct sock *sk, int len, | ||
5287 | char __user *optval, int __user *optlen) | ||
5288 | { | ||
5289 | struct sctp_sock *sp = sctp_sk(sk); | ||
5290 | struct sctp_association *asoc; | ||
5291 | struct sctp_assoc_ids *ids; | ||
5292 | u32 num = 0; | ||
5293 | |||
5294 | if (sctp_style(sk, TCP)) | ||
5295 | return -EOPNOTSUPP; | ||
5296 | |||
5297 | if (len < sizeof(struct sctp_assoc_ids)) | ||
5298 | return -EINVAL; | ||
5299 | |||
5300 | list_for_each_entry(asoc, &(sp->ep->asocs), asocs) { | ||
5301 | num++; | ||
5302 | } | ||
5303 | |||
5304 | if (len < sizeof(struct sctp_assoc_ids) + sizeof(sctp_assoc_t) * num) | ||
5305 | return -EINVAL; | ||
5306 | |||
5307 | len = sizeof(struct sctp_assoc_ids) + sizeof(sctp_assoc_t) * num; | ||
5308 | |||
5309 | ids = kmalloc(len, GFP_KERNEL); | ||
5310 | if (unlikely(!ids)) | ||
5311 | return -ENOMEM; | ||
5312 | |||
5313 | ids->gaids_number_of_ids = num; | ||
5314 | num = 0; | ||
5315 | list_for_each_entry(asoc, &(sp->ep->asocs), asocs) { | ||
5316 | ids->gaids_assoc_id[num++] = asoc->assoc_id; | ||
5317 | } | ||
5318 | |||
5319 | if (put_user(len, optlen) || copy_to_user(optval, ids, len)) { | ||
5320 | kfree(ids); | ||
5321 | return -EFAULT; | ||
5322 | } | ||
5323 | |||
5324 | kfree(ids); | ||
5325 | return 0; | ||
5326 | } | ||
5327 | |||
5286 | SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname, | 5328 | SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname, |
5287 | char __user *optval, int __user *optlen) | 5329 | char __user *optval, int __user *optlen) |
5288 | { | 5330 | { |
@@ -5415,6 +5457,9 @@ SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname, | |||
5415 | case SCTP_GET_ASSOC_NUMBER: | 5457 | case SCTP_GET_ASSOC_NUMBER: |
5416 | retval = sctp_getsockopt_assoc_number(sk, len, optval, optlen); | 5458 | retval = sctp_getsockopt_assoc_number(sk, len, optval, optlen); |
5417 | break; | 5459 | break; |
5460 | case SCTP_GET_ASSOC_ID_LIST: | ||
5461 | retval = sctp_getsockopt_assoc_ids(sk, len, optval, optlen); | ||
5462 | break; | ||
5418 | default: | 5463 | default: |
5419 | retval = -ENOPROTOOPT; | 5464 | retval = -ENOPROTOOPT; |
5420 | break; | 5465 | break; |