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.c119
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
1944out_free: 1950out_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 }
1947out_unlock: 1955out_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 */
3488static 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 */
5561static 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
5493SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname, 5599SCTP_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;