diff options
Diffstat (limited to 'net/sctp/socket.c')
-rw-r--r-- | net/sctp/socket.c | 131 |
1 files changed, 101 insertions, 30 deletions
diff --git a/net/sctp/socket.c b/net/sctp/socket.c index deb82e35a107..d3ccf7973c59 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 |
@@ -1380,6 +1384,7 @@ SCTP_STATIC void sctp_close(struct sock *sk, long timeout) | |||
1380 | struct sctp_endpoint *ep; | 1384 | struct sctp_endpoint *ep; |
1381 | struct sctp_association *asoc; | 1385 | struct sctp_association *asoc; |
1382 | struct list_head *pos, *temp; | 1386 | struct list_head *pos, *temp; |
1387 | unsigned int data_was_unread; | ||
1383 | 1388 | ||
1384 | SCTP_DEBUG_PRINTK("sctp_close(sk: 0x%p, timeout:%ld)\n", sk, timeout); | 1389 | SCTP_DEBUG_PRINTK("sctp_close(sk: 0x%p, timeout:%ld)\n", sk, timeout); |
1385 | 1390 | ||
@@ -1389,6 +1394,10 @@ SCTP_STATIC void sctp_close(struct sock *sk, long timeout) | |||
1389 | 1394 | ||
1390 | ep = sctp_sk(sk)->ep; | 1395 | ep = sctp_sk(sk)->ep; |
1391 | 1396 | ||
1397 | /* Clean up any skbs sitting on the receive queue. */ | ||
1398 | data_was_unread = sctp_queue_purge_ulpevents(&sk->sk_receive_queue); | ||
1399 | data_was_unread += sctp_queue_purge_ulpevents(&sctp_sk(sk)->pd_lobby); | ||
1400 | |||
1392 | /* Walk all associations on an endpoint. */ | 1401 | /* Walk all associations on an endpoint. */ |
1393 | list_for_each_safe(pos, temp, &ep->asocs) { | 1402 | list_for_each_safe(pos, temp, &ep->asocs) { |
1394 | asoc = list_entry(pos, struct sctp_association, asocs); | 1403 | asoc = list_entry(pos, struct sctp_association, asocs); |
@@ -1406,7 +1415,9 @@ SCTP_STATIC void sctp_close(struct sock *sk, long timeout) | |||
1406 | } | 1415 | } |
1407 | } | 1416 | } |
1408 | 1417 | ||
1409 | if (sock_flag(sk, SOCK_LINGER) && !sk->sk_lingertime) { | 1418 | if (data_was_unread || !skb_queue_empty(&asoc->ulpq.lobby) || |
1419 | !skb_queue_empty(&asoc->ulpq.reasm) || | ||
1420 | (sock_flag(sk, SOCK_LINGER) && !sk->sk_lingertime)) { | ||
1410 | struct sctp_chunk *chunk; | 1421 | struct sctp_chunk *chunk; |
1411 | 1422 | ||
1412 | chunk = sctp_make_abort_user(asoc, NULL, 0); | 1423 | chunk = sctp_make_abort_user(asoc, NULL, 0); |
@@ -1416,10 +1427,6 @@ SCTP_STATIC void sctp_close(struct sock *sk, long timeout) | |||
1416 | sctp_primitive_SHUTDOWN(asoc, NULL); | 1427 | sctp_primitive_SHUTDOWN(asoc, NULL); |
1417 | } | 1428 | } |
1418 | 1429 | ||
1419 | /* Clean up any skbs sitting on the receive queue. */ | ||
1420 | sctp_queue_purge_ulpevents(&sk->sk_receive_queue); | ||
1421 | sctp_queue_purge_ulpevents(&sctp_sk(sk)->pd_lobby); | ||
1422 | |||
1423 | /* On a TCP-style socket, block for at most linger_time if set. */ | 1430 | /* On a TCP-style socket, block for at most linger_time if set. */ |
1424 | if (sctp_style(sk, TCP) && timeout) | 1431 | if (sctp_style(sk, TCP) && timeout) |
1425 | sctp_wait_for_close(sk, timeout); | 1432 | sctp_wait_for_close(sk, timeout); |
@@ -1492,7 +1499,7 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk, | |||
1492 | struct sctp_chunk *chunk; | 1499 | struct sctp_chunk *chunk; |
1493 | union sctp_addr to; | 1500 | union sctp_addr to; |
1494 | struct sockaddr *msg_name = NULL; | 1501 | struct sockaddr *msg_name = NULL; |
1495 | struct sctp_sndrcvinfo default_sinfo = { 0 }; | 1502 | struct sctp_sndrcvinfo default_sinfo; |
1496 | struct sctp_sndrcvinfo *sinfo; | 1503 | struct sctp_sndrcvinfo *sinfo; |
1497 | struct sctp_initmsg *sinit; | 1504 | struct sctp_initmsg *sinit; |
1498 | sctp_assoc_t associd = 0; | 1505 | sctp_assoc_t associd = 0; |
@@ -1756,6 +1763,7 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk, | |||
1756 | /* If the user didn't specify SNDRCVINFO, make up one with | 1763 | /* If the user didn't specify SNDRCVINFO, make up one with |
1757 | * some defaults. | 1764 | * some defaults. |
1758 | */ | 1765 | */ |
1766 | memset(&default_sinfo, 0, sizeof(default_sinfo)); | ||
1759 | default_sinfo.sinfo_stream = asoc->default_stream; | 1767 | default_sinfo.sinfo_stream = asoc->default_stream; |
1760 | default_sinfo.sinfo_flags = asoc->default_flags; | 1768 | default_sinfo.sinfo_flags = asoc->default_flags; |
1761 | default_sinfo.sinfo_ppid = asoc->default_ppid; | 1769 | default_sinfo.sinfo_ppid = asoc->default_ppid; |
@@ -1786,12 +1794,10 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk, | |||
1786 | goto out_free; | 1794 | goto out_free; |
1787 | } | 1795 | } |
1788 | 1796 | ||
1789 | if (sinfo) { | 1797 | /* Check for invalid stream. */ |
1790 | /* Check for invalid stream. */ | 1798 | if (sinfo->sinfo_stream >= asoc->c.sinit_num_ostreams) { |
1791 | if (sinfo->sinfo_stream >= asoc->c.sinit_num_ostreams) { | 1799 | err = -EINVAL; |
1792 | err = -EINVAL; | 1800 | goto out_free; |
1793 | goto out_free; | ||
1794 | } | ||
1795 | } | 1801 | } |
1796 | 1802 | ||
1797 | timeo = sock_sndtimeo(sk, msg->msg_flags & MSG_DONTWAIT); | 1803 | timeo = sock_sndtimeo(sk, msg->msg_flags & MSG_DONTWAIT); |
@@ -2070,10 +2076,33 @@ static int sctp_setsockopt_disable_fragments(struct sock *sk, | |||
2070 | static int sctp_setsockopt_events(struct sock *sk, char __user *optval, | 2076 | static int sctp_setsockopt_events(struct sock *sk, char __user *optval, |
2071 | unsigned int optlen) | 2077 | unsigned int optlen) |
2072 | { | 2078 | { |
2079 | struct sctp_association *asoc; | ||
2080 | struct sctp_ulpevent *event; | ||
2081 | |||
2073 | if (optlen > sizeof(struct sctp_event_subscribe)) | 2082 | if (optlen > sizeof(struct sctp_event_subscribe)) |
2074 | return -EINVAL; | 2083 | return -EINVAL; |
2075 | if (copy_from_user(&sctp_sk(sk)->subscribe, optval, optlen)) | 2084 | if (copy_from_user(&sctp_sk(sk)->subscribe, optval, optlen)) |
2076 | return -EFAULT; | 2085 | return -EFAULT; |
2086 | |||
2087 | /* | ||
2088 | * At the time when a user app subscribes to SCTP_SENDER_DRY_EVENT, | ||
2089 | * if there is no data to be sent or retransmit, the stack will | ||
2090 | * immediately send up this notification. | ||
2091 | */ | ||
2092 | if (sctp_ulpevent_type_enabled(SCTP_SENDER_DRY_EVENT, | ||
2093 | &sctp_sk(sk)->subscribe)) { | ||
2094 | asoc = sctp_id2assoc(sk, 0); | ||
2095 | |||
2096 | if (asoc && sctp_outq_is_empty(&asoc->outqueue)) { | ||
2097 | event = sctp_ulpevent_make_sender_dry_event(asoc, | ||
2098 | GFP_ATOMIC); | ||
2099 | if (!event) | ||
2100 | return -ENOMEM; | ||
2101 | |||
2102 | sctp_ulpq_tail_event(&asoc->ulpq, event); | ||
2103 | } | ||
2104 | } | ||
2105 | |||
2077 | return 0; | 2106 | return 0; |
2078 | } | 2107 | } |
2079 | 2108 | ||
@@ -2283,7 +2312,7 @@ static int sctp_apply_peer_addr_params(struct sctp_paddrparams *params, | |||
2283 | trans->param_flags = | 2312 | trans->param_flags = |
2284 | (trans->param_flags & ~SPP_PMTUD) | pmtud_change; | 2313 | (trans->param_flags & ~SPP_PMTUD) | pmtud_change; |
2285 | if (update) { | 2314 | if (update) { |
2286 | sctp_transport_pmtu(trans); | 2315 | sctp_transport_pmtu(trans, sctp_opt2sk(sp)); |
2287 | sctp_assoc_sync_pmtu(asoc); | 2316 | sctp_assoc_sync_pmtu(asoc); |
2288 | } | 2317 | } |
2289 | } else if (asoc) { | 2318 | } else if (asoc) { |
@@ -3215,14 +3244,9 @@ static int sctp_setsockopt_hmac_ident(struct sock *sk, | |||
3215 | if (optlen < sizeof(struct sctp_hmacalgo)) | 3244 | if (optlen < sizeof(struct sctp_hmacalgo)) |
3216 | return -EINVAL; | 3245 | return -EINVAL; |
3217 | 3246 | ||
3218 | hmacs = kmalloc(optlen, GFP_KERNEL); | 3247 | hmacs= memdup_user(optval, optlen); |
3219 | if (!hmacs) | 3248 | if (IS_ERR(hmacs)) |
3220 | return -ENOMEM; | 3249 | return PTR_ERR(hmacs); |
3221 | |||
3222 | if (copy_from_user(hmacs, optval, optlen)) { | ||
3223 | err = -EFAULT; | ||
3224 | goto out; | ||
3225 | } | ||
3226 | 3250 | ||
3227 | idents = hmacs->shmac_num_idents; | 3251 | idents = hmacs->shmac_num_idents; |
3228 | if (idents == 0 || idents > SCTP_AUTH_NUM_HMACS || | 3252 | if (idents == 0 || idents > SCTP_AUTH_NUM_HMACS || |
@@ -3257,14 +3281,9 @@ static int sctp_setsockopt_auth_key(struct sock *sk, | |||
3257 | if (optlen <= sizeof(struct sctp_authkey)) | 3281 | if (optlen <= sizeof(struct sctp_authkey)) |
3258 | return -EINVAL; | 3282 | return -EINVAL; |
3259 | 3283 | ||
3260 | authkey = kmalloc(optlen, GFP_KERNEL); | 3284 | authkey= memdup_user(optval, optlen); |
3261 | if (!authkey) | 3285 | if (IS_ERR(authkey)) |
3262 | return -ENOMEM; | 3286 | return PTR_ERR(authkey); |
3263 | |||
3264 | if (copy_from_user(authkey, optval, optlen)) { | ||
3265 | ret = -EFAULT; | ||
3266 | goto out; | ||
3267 | } | ||
3268 | 3287 | ||
3269 | if (authkey->sca_keylength > optlen - sizeof(struct sctp_authkey)) { | 3288 | if (authkey->sca_keylength > optlen - sizeof(struct sctp_authkey)) { |
3270 | ret = -EINVAL; | 3289 | ret = -EINVAL; |
@@ -5283,6 +5302,55 @@ static int sctp_getsockopt_assoc_number(struct sock *sk, int len, | |||
5283 | return 0; | 5302 | return 0; |
5284 | } | 5303 | } |
5285 | 5304 | ||
5305 | /* | ||
5306 | * 8.2.6. Get the Current Identifiers of Associations | ||
5307 | * (SCTP_GET_ASSOC_ID_LIST) | ||
5308 | * | ||
5309 | * This option gets the current list of SCTP association identifiers of | ||
5310 | * the SCTP associations handled by a one-to-many style socket. | ||
5311 | */ | ||
5312 | static int sctp_getsockopt_assoc_ids(struct sock *sk, int len, | ||
5313 | char __user *optval, int __user *optlen) | ||
5314 | { | ||
5315 | struct sctp_sock *sp = sctp_sk(sk); | ||
5316 | struct sctp_association *asoc; | ||
5317 | struct sctp_assoc_ids *ids; | ||
5318 | u32 num = 0; | ||
5319 | |||
5320 | if (sctp_style(sk, TCP)) | ||
5321 | return -EOPNOTSUPP; | ||
5322 | |||
5323 | if (len < sizeof(struct sctp_assoc_ids)) | ||
5324 | return -EINVAL; | ||
5325 | |||
5326 | list_for_each_entry(asoc, &(sp->ep->asocs), asocs) { | ||
5327 | num++; | ||
5328 | } | ||
5329 | |||
5330 | if (len < sizeof(struct sctp_assoc_ids) + sizeof(sctp_assoc_t) * num) | ||
5331 | return -EINVAL; | ||
5332 | |||
5333 | len = sizeof(struct sctp_assoc_ids) + sizeof(sctp_assoc_t) * num; | ||
5334 | |||
5335 | ids = kmalloc(len, GFP_KERNEL); | ||
5336 | if (unlikely(!ids)) | ||
5337 | return -ENOMEM; | ||
5338 | |||
5339 | ids->gaids_number_of_ids = num; | ||
5340 | num = 0; | ||
5341 | list_for_each_entry(asoc, &(sp->ep->asocs), asocs) { | ||
5342 | ids->gaids_assoc_id[num++] = asoc->assoc_id; | ||
5343 | } | ||
5344 | |||
5345 | if (put_user(len, optlen) || copy_to_user(optval, ids, len)) { | ||
5346 | kfree(ids); | ||
5347 | return -EFAULT; | ||
5348 | } | ||
5349 | |||
5350 | kfree(ids); | ||
5351 | return 0; | ||
5352 | } | ||
5353 | |||
5286 | SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname, | 5354 | SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname, |
5287 | char __user *optval, int __user *optlen) | 5355 | char __user *optval, int __user *optlen) |
5288 | { | 5356 | { |
@@ -5415,6 +5483,9 @@ SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname, | |||
5415 | case SCTP_GET_ASSOC_NUMBER: | 5483 | case SCTP_GET_ASSOC_NUMBER: |
5416 | retval = sctp_getsockopt_assoc_number(sk, len, optval, optlen); | 5484 | retval = sctp_getsockopt_assoc_number(sk, len, optval, optlen); |
5417 | break; | 5485 | break; |
5486 | case SCTP_GET_ASSOC_ID_LIST: | ||
5487 | retval = sctp_getsockopt_assoc_ids(sk, len, optval, optlen); | ||
5488 | break; | ||
5418 | default: | 5489 | default: |
5419 | retval = -ENOPROTOOPT; | 5490 | retval = -ENOPROTOOPT; |
5420 | break; | 5491 | break; |