diff options
Diffstat (limited to 'net/sctp/socket.c')
-rw-r--r-- | net/sctp/socket.c | 119 |
1 files changed, 114 insertions, 5 deletions
diff --git a/net/sctp/socket.c b/net/sctp/socket.c index b3b8a8d813eb..5e259817a7f3 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c | |||
@@ -1231,8 +1231,14 @@ out_free: | |||
1231 | SCTP_DEBUG_PRINTK("About to exit __sctp_connect() free asoc: %p" | 1231 | SCTP_DEBUG_PRINTK("About to exit __sctp_connect() free asoc: %p" |
1232 | " kaddrs: %p err: %d\n", | 1232 | " kaddrs: %p err: %d\n", |
1233 | asoc, kaddrs, err); | 1233 | asoc, kaddrs, err); |
1234 | if (asoc) | 1234 | if (asoc) { |
1235 | /* sctp_primitive_ASSOCIATE may have added this association | ||
1236 | * To the hash table, try to unhash it, just in case, its a noop | ||
1237 | * if it wasn't hashed so we're safe | ||
1238 | */ | ||
1239 | sctp_unhash_established(asoc); | ||
1235 | sctp_association_free(asoc); | 1240 | sctp_association_free(asoc); |
1241 | } | ||
1236 | return err; | 1242 | return err; |
1237 | } | 1243 | } |
1238 | 1244 | ||
@@ -1853,7 +1859,7 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk, | |||
1853 | } | 1859 | } |
1854 | 1860 | ||
1855 | if (asoc->pmtu_pending) | 1861 | if (asoc->pmtu_pending) |
1856 | sctp_assoc_pending_pmtu(asoc); | 1862 | sctp_assoc_pending_pmtu(sk, asoc); |
1857 | 1863 | ||
1858 | /* If fragmentation is disabled and the message length exceeds the | 1864 | /* If fragmentation is disabled and the message length exceeds the |
1859 | * association fragmentation point, return EMSGSIZE. The I-D | 1865 | * association fragmentation point, return EMSGSIZE. The I-D |
@@ -1942,8 +1948,10 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk, | |||
1942 | goto out_unlock; | 1948 | goto out_unlock; |
1943 | 1949 | ||
1944 | out_free: | 1950 | out_free: |
1945 | if (new_asoc) | 1951 | if (new_asoc) { |
1952 | sctp_unhash_established(asoc); | ||
1946 | sctp_association_free(asoc); | 1953 | sctp_association_free(asoc); |
1954 | } | ||
1947 | out_unlock: | 1955 | out_unlock: |
1948 | sctp_release_sock(sk); | 1956 | sctp_release_sock(sk); |
1949 | 1957 | ||
@@ -2365,7 +2373,7 @@ static int sctp_apply_peer_addr_params(struct sctp_paddrparams *params, | |||
2365 | if ((params->spp_flags & SPP_PMTUD_DISABLE) && params->spp_pathmtu) { | 2373 | if ((params->spp_flags & SPP_PMTUD_DISABLE) && params->spp_pathmtu) { |
2366 | if (trans) { | 2374 | if (trans) { |
2367 | trans->pathmtu = params->spp_pathmtu; | 2375 | trans->pathmtu = params->spp_pathmtu; |
2368 | sctp_assoc_sync_pmtu(asoc); | 2376 | sctp_assoc_sync_pmtu(sctp_opt2sk(sp), asoc); |
2369 | } else if (asoc) { | 2377 | } else if (asoc) { |
2370 | asoc->pathmtu = params->spp_pathmtu; | 2378 | asoc->pathmtu = params->spp_pathmtu; |
2371 | sctp_frag_point(asoc, params->spp_pathmtu); | 2379 | sctp_frag_point(asoc, params->spp_pathmtu); |
@@ -2382,7 +2390,7 @@ static int sctp_apply_peer_addr_params(struct sctp_paddrparams *params, | |||
2382 | (trans->param_flags & ~SPP_PMTUD) | pmtud_change; | 2390 | (trans->param_flags & ~SPP_PMTUD) | pmtud_change; |
2383 | if (update) { | 2391 | if (update) { |
2384 | sctp_transport_pmtu(trans, sctp_opt2sk(sp)); | 2392 | sctp_transport_pmtu(trans, sctp_opt2sk(sp)); |
2385 | sctp_assoc_sync_pmtu(asoc); | 2393 | sctp_assoc_sync_pmtu(sctp_opt2sk(sp), asoc); |
2386 | } | 2394 | } |
2387 | } else if (asoc) { | 2395 | } else if (asoc) { |
2388 | asoc->param_flags = | 2396 | asoc->param_flags = |
@@ -3470,6 +3478,56 @@ static int sctp_setsockopt_auto_asconf(struct sock *sk, char __user *optval, | |||
3470 | } | 3478 | } |
3471 | 3479 | ||
3472 | 3480 | ||
3481 | /* | ||
3482 | * SCTP_PEER_ADDR_THLDS | ||
3483 | * | ||
3484 | * This option allows us to alter the partially failed threshold for one or all | ||
3485 | * transports in an association. See Section 6.1 of: | ||
3486 | * http://www.ietf.org/id/draft-nishida-tsvwg-sctp-failover-05.txt | ||
3487 | */ | ||
3488 | static int sctp_setsockopt_paddr_thresholds(struct sock *sk, | ||
3489 | char __user *optval, | ||
3490 | unsigned int optlen) | ||
3491 | { | ||
3492 | struct sctp_paddrthlds val; | ||
3493 | struct sctp_transport *trans; | ||
3494 | struct sctp_association *asoc; | ||
3495 | |||
3496 | if (optlen < sizeof(struct sctp_paddrthlds)) | ||
3497 | return -EINVAL; | ||
3498 | if (copy_from_user(&val, (struct sctp_paddrthlds __user *)optval, | ||
3499 | sizeof(struct sctp_paddrthlds))) | ||
3500 | return -EFAULT; | ||
3501 | |||
3502 | |||
3503 | if (sctp_is_any(sk, (const union sctp_addr *)&val.spt_address)) { | ||
3504 | asoc = sctp_id2assoc(sk, val.spt_assoc_id); | ||
3505 | if (!asoc) | ||
3506 | return -ENOENT; | ||
3507 | list_for_each_entry(trans, &asoc->peer.transport_addr_list, | ||
3508 | transports) { | ||
3509 | if (val.spt_pathmaxrxt) | ||
3510 | trans->pathmaxrxt = val.spt_pathmaxrxt; | ||
3511 | trans->pf_retrans = val.spt_pathpfthld; | ||
3512 | } | ||
3513 | |||
3514 | if (val.spt_pathmaxrxt) | ||
3515 | asoc->pathmaxrxt = val.spt_pathmaxrxt; | ||
3516 | asoc->pf_retrans = val.spt_pathpfthld; | ||
3517 | } else { | ||
3518 | trans = sctp_addr_id2transport(sk, &val.spt_address, | ||
3519 | val.spt_assoc_id); | ||
3520 | if (!trans) | ||
3521 | return -ENOENT; | ||
3522 | |||
3523 | if (val.spt_pathmaxrxt) | ||
3524 | trans->pathmaxrxt = val.spt_pathmaxrxt; | ||
3525 | trans->pf_retrans = val.spt_pathpfthld; | ||
3526 | } | ||
3527 | |||
3528 | return 0; | ||
3529 | } | ||
3530 | |||
3473 | /* API 6.2 setsockopt(), getsockopt() | 3531 | /* API 6.2 setsockopt(), getsockopt() |
3474 | * | 3532 | * |
3475 | * Applications use setsockopt() and getsockopt() to set or retrieve | 3533 | * Applications use setsockopt() and getsockopt() to set or retrieve |
@@ -3619,6 +3677,9 @@ SCTP_STATIC int sctp_setsockopt(struct sock *sk, int level, int optname, | |||
3619 | case SCTP_AUTO_ASCONF: | 3677 | case SCTP_AUTO_ASCONF: |
3620 | retval = sctp_setsockopt_auto_asconf(sk, optval, optlen); | 3678 | retval = sctp_setsockopt_auto_asconf(sk, optval, optlen); |
3621 | break; | 3679 | break; |
3680 | case SCTP_PEER_ADDR_THLDS: | ||
3681 | retval = sctp_setsockopt_paddr_thresholds(sk, optval, optlen); | ||
3682 | break; | ||
3622 | default: | 3683 | default: |
3623 | retval = -ENOPROTOOPT; | 3684 | retval = -ENOPROTOOPT; |
3624 | break; | 3685 | break; |
@@ -5490,6 +5551,51 @@ static int sctp_getsockopt_assoc_ids(struct sock *sk, int len, | |||
5490 | return 0; | 5551 | return 0; |
5491 | } | 5552 | } |
5492 | 5553 | ||
5554 | /* | ||
5555 | * SCTP_PEER_ADDR_THLDS | ||
5556 | * | ||
5557 | * This option allows us to fetch the partially failed threshold for one or all | ||
5558 | * transports in an association. See Section 6.1 of: | ||
5559 | * http://www.ietf.org/id/draft-nishida-tsvwg-sctp-failover-05.txt | ||
5560 | */ | ||
5561 | static int sctp_getsockopt_paddr_thresholds(struct sock *sk, | ||
5562 | char __user *optval, | ||
5563 | int len, | ||
5564 | int __user *optlen) | ||
5565 | { | ||
5566 | struct sctp_paddrthlds val; | ||
5567 | struct sctp_transport *trans; | ||
5568 | struct sctp_association *asoc; | ||
5569 | |||
5570 | if (len < sizeof(struct sctp_paddrthlds)) | ||
5571 | return -EINVAL; | ||
5572 | len = sizeof(struct sctp_paddrthlds); | ||
5573 | if (copy_from_user(&val, (struct sctp_paddrthlds __user *)optval, len)) | ||
5574 | return -EFAULT; | ||
5575 | |||
5576 | if (sctp_is_any(sk, (const union sctp_addr *)&val.spt_address)) { | ||
5577 | asoc = sctp_id2assoc(sk, val.spt_assoc_id); | ||
5578 | if (!asoc) | ||
5579 | return -ENOENT; | ||
5580 | |||
5581 | val.spt_pathpfthld = asoc->pf_retrans; | ||
5582 | val.spt_pathmaxrxt = asoc->pathmaxrxt; | ||
5583 | } else { | ||
5584 | trans = sctp_addr_id2transport(sk, &val.spt_address, | ||
5585 | val.spt_assoc_id); | ||
5586 | if (!trans) | ||
5587 | return -ENOENT; | ||
5588 | |||
5589 | val.spt_pathmaxrxt = trans->pathmaxrxt; | ||
5590 | val.spt_pathpfthld = trans->pf_retrans; | ||
5591 | } | ||
5592 | |||
5593 | if (put_user(len, optlen) || copy_to_user(optval, &val, len)) | ||
5594 | return -EFAULT; | ||
5595 | |||
5596 | return 0; | ||
5597 | } | ||
5598 | |||
5493 | SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname, | 5599 | SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname, |
5494 | char __user *optval, int __user *optlen) | 5600 | char __user *optval, int __user *optlen) |
5495 | { | 5601 | { |
@@ -5628,6 +5734,9 @@ SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname, | |||
5628 | case SCTP_AUTO_ASCONF: | 5734 | case SCTP_AUTO_ASCONF: |
5629 | retval = sctp_getsockopt_auto_asconf(sk, len, optval, optlen); | 5735 | retval = sctp_getsockopt_auto_asconf(sk, len, optval, optlen); |
5630 | break; | 5736 | break; |
5737 | case SCTP_PEER_ADDR_THLDS: | ||
5738 | retval = sctp_getsockopt_paddr_thresholds(sk, optval, len, optlen); | ||
5739 | break; | ||
5631 | default: | 5740 | default: |
5632 | retval = -ENOPROTOOPT; | 5741 | retval = -ENOPROTOOPT; |
5633 | break; | 5742 | break; |