aboutsummaryrefslogtreecommitdiffstats
path: root/net/sctp/socket.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/sctp/socket.c')
-rw-r--r--net/sctp/socket.c95
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 */
5286static 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
5286SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname, 5328SCTP_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;