aboutsummaryrefslogtreecommitdiffstats
path: root/net/sctp
diff options
context:
space:
mode:
Diffstat (limited to 'net/sctp')
-rw-r--r--net/sctp/associola.c37
-rw-r--r--net/sctp/outqueue.c6
-rw-r--r--net/sctp/sm_sideeffect.c33
-rw-r--r--net/sctp/socket.c101
-rw-r--r--net/sctp/sysctl.c9
-rw-r--r--net/sctp/transport.c4
6 files changed, 176 insertions, 14 deletions
diff --git a/net/sctp/associola.c b/net/sctp/associola.c
index 8cf348e62e74..ebaef3ed6065 100644
--- a/net/sctp/associola.c
+++ b/net/sctp/associola.c
@@ -124,6 +124,8 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a
124 * socket values. 124 * socket values.
125 */ 125 */
126 asoc->max_retrans = sp->assocparams.sasoc_asocmaxrxt; 126 asoc->max_retrans = sp->assocparams.sasoc_asocmaxrxt;
127 asoc->pf_retrans = sctp_pf_retrans;
128
127 asoc->rto_initial = msecs_to_jiffies(sp->rtoinfo.srto_initial); 129 asoc->rto_initial = msecs_to_jiffies(sp->rtoinfo.srto_initial);
128 asoc->rto_max = msecs_to_jiffies(sp->rtoinfo.srto_max); 130 asoc->rto_max = msecs_to_jiffies(sp->rtoinfo.srto_max);
129 asoc->rto_min = msecs_to_jiffies(sp->rtoinfo.srto_min); 131 asoc->rto_min = msecs_to_jiffies(sp->rtoinfo.srto_min);
@@ -686,6 +688,9 @@ struct sctp_transport *sctp_assoc_add_peer(struct sctp_association *asoc,
686 /* Set the path max_retrans. */ 688 /* Set the path max_retrans. */
687 peer->pathmaxrxt = asoc->pathmaxrxt; 689 peer->pathmaxrxt = asoc->pathmaxrxt;
688 690
691 /* And the partial failure retrnas threshold */
692 peer->pf_retrans = asoc->pf_retrans;
693
689 /* Initialize the peer's SACK delay timeout based on the 694 /* Initialize the peer's SACK delay timeout based on the
690 * association configured value. 695 * association configured value.
691 */ 696 */
@@ -841,6 +846,7 @@ void sctp_assoc_control_transport(struct sctp_association *asoc,
841 struct sctp_ulpevent *event; 846 struct sctp_ulpevent *event;
842 struct sockaddr_storage addr; 847 struct sockaddr_storage addr;
843 int spc_state = 0; 848 int spc_state = 0;
849 bool ulp_notify = true;
844 850
845 /* Record the transition on the transport. */ 851 /* Record the transition on the transport. */
846 switch (command) { 852 switch (command) {
@@ -854,6 +860,14 @@ void sctp_assoc_control_transport(struct sctp_association *asoc,
854 spc_state = SCTP_ADDR_CONFIRMED; 860 spc_state = SCTP_ADDR_CONFIRMED;
855 else 861 else
856 spc_state = SCTP_ADDR_AVAILABLE; 862 spc_state = SCTP_ADDR_AVAILABLE;
863 /* Don't inform ULP about transition from PF to
864 * active state and set cwnd to 1, see SCTP
865 * Quick failover draft section 5.1, point 5
866 */
867 if (transport->state == SCTP_PF) {
868 ulp_notify = false;
869 transport->cwnd = 1;
870 }
857 transport->state = SCTP_ACTIVE; 871 transport->state = SCTP_ACTIVE;
858 break; 872 break;
859 873
@@ -872,6 +886,11 @@ void sctp_assoc_control_transport(struct sctp_association *asoc,
872 spc_state = SCTP_ADDR_UNREACHABLE; 886 spc_state = SCTP_ADDR_UNREACHABLE;
873 break; 887 break;
874 888
889 case SCTP_TRANSPORT_PF:
890 transport->state = SCTP_PF;
891 ulp_notify = false;
892 break;
893
875 default: 894 default:
876 return; 895 return;
877 } 896 }
@@ -879,12 +898,15 @@ void sctp_assoc_control_transport(struct sctp_association *asoc,
879 /* Generate and send a SCTP_PEER_ADDR_CHANGE notification to the 898 /* Generate and send a SCTP_PEER_ADDR_CHANGE notification to the
880 * user. 899 * user.
881 */ 900 */
882 memset(&addr, 0, sizeof(struct sockaddr_storage)); 901 if (ulp_notify) {
883 memcpy(&addr, &transport->ipaddr, transport->af_specific->sockaddr_len); 902 memset(&addr, 0, sizeof(struct sockaddr_storage));
884 event = sctp_ulpevent_make_peer_addr_change(asoc, &addr, 903 memcpy(&addr, &transport->ipaddr,
885 0, spc_state, error, GFP_ATOMIC); 904 transport->af_specific->sockaddr_len);
886 if (event) 905 event = sctp_ulpevent_make_peer_addr_change(asoc, &addr,
887 sctp_ulpq_tail_event(&asoc->ulpq, event); 906 0, spc_state, error, GFP_ATOMIC);
907 if (event)
908 sctp_ulpq_tail_event(&asoc->ulpq, event);
909 }
888 910
889 /* Select new active and retran paths. */ 911 /* Select new active and retran paths. */
890 912
@@ -900,7 +922,8 @@ void sctp_assoc_control_transport(struct sctp_association *asoc,
900 transports) { 922 transports) {
901 923
902 if ((t->state == SCTP_INACTIVE) || 924 if ((t->state == SCTP_INACTIVE) ||
903 (t->state == SCTP_UNCONFIRMED)) 925 (t->state == SCTP_UNCONFIRMED) ||
926 (t->state == SCTP_PF))
904 continue; 927 continue;
905 if (!first || t->last_time_heard > first->last_time_heard) { 928 if (!first || t->last_time_heard > first->last_time_heard) {
906 second = first; 929 second = first;
diff --git a/net/sctp/outqueue.c b/net/sctp/outqueue.c
index a0fa19f5650c..e7aa177c9522 100644
--- a/net/sctp/outqueue.c
+++ b/net/sctp/outqueue.c
@@ -792,7 +792,8 @@ static int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)
792 if (!new_transport) 792 if (!new_transport)
793 new_transport = asoc->peer.active_path; 793 new_transport = asoc->peer.active_path;
794 } else if ((new_transport->state == SCTP_INACTIVE) || 794 } else if ((new_transport->state == SCTP_INACTIVE) ||
795 (new_transport->state == SCTP_UNCONFIRMED)) { 795 (new_transport->state == SCTP_UNCONFIRMED) ||
796 (new_transport->state == SCTP_PF)) {
796 /* If the chunk is Heartbeat or Heartbeat Ack, 797 /* If the chunk is Heartbeat or Heartbeat Ack,
797 * send it to chunk->transport, even if it's 798 * send it to chunk->transport, even if it's
798 * inactive. 799 * inactive.
@@ -987,7 +988,8 @@ static int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)
987 new_transport = chunk->transport; 988 new_transport = chunk->transport;
988 if (!new_transport || 989 if (!new_transport ||
989 ((new_transport->state == SCTP_INACTIVE) || 990 ((new_transport->state == SCTP_INACTIVE) ||
990 (new_transport->state == SCTP_UNCONFIRMED))) 991 (new_transport->state == SCTP_UNCONFIRMED) ||
992 (new_transport->state == SCTP_PF)))
991 new_transport = asoc->peer.active_path; 993 new_transport = asoc->peer.active_path;
992 if (new_transport->state == SCTP_UNCONFIRMED) 994 if (new_transport->state == SCTP_UNCONFIRMED)
993 continue; 995 continue;
diff --git a/net/sctp/sm_sideeffect.c b/net/sctp/sm_sideeffect.c
index 8716da1a8592..fe99628e1257 100644
--- a/net/sctp/sm_sideeffect.c
+++ b/net/sctp/sm_sideeffect.c
@@ -76,6 +76,8 @@ static int sctp_side_effects(sctp_event_t event_type, sctp_subtype_t subtype,
76 sctp_cmd_seq_t *commands, 76 sctp_cmd_seq_t *commands,
77 gfp_t gfp); 77 gfp_t gfp);
78 78
79static void sctp_cmd_hb_timer_update(sctp_cmd_seq_t *cmds,
80 struct sctp_transport *t);
79/******************************************************************** 81/********************************************************************
80 * Helper functions 82 * Helper functions
81 ********************************************************************/ 83 ********************************************************************/
@@ -470,7 +472,8 @@ sctp_timer_event_t *sctp_timer_events[SCTP_NUM_TIMEOUT_TYPES] = {
470 * notification SHOULD be sent to the upper layer. 472 * notification SHOULD be sent to the upper layer.
471 * 473 *
472 */ 474 */
473static void sctp_do_8_2_transport_strike(struct sctp_association *asoc, 475static void sctp_do_8_2_transport_strike(sctp_cmd_seq_t *commands,
476 struct sctp_association *asoc,
474 struct sctp_transport *transport, 477 struct sctp_transport *transport,
475 int is_hb) 478 int is_hb)
476{ 479{
@@ -495,6 +498,23 @@ static void sctp_do_8_2_transport_strike(struct sctp_association *asoc,
495 transport->error_count++; 498 transport->error_count++;
496 } 499 }
497 500
501 /* If the transport error count is greater than the pf_retrans
502 * threshold, and less than pathmaxrtx, then mark this transport
503 * as Partially Failed, ee SCTP Quick Failover Draft, secon 5.1,
504 * point 1
505 */
506 if ((transport->state != SCTP_PF) &&
507 (asoc->pf_retrans < transport->pathmaxrxt) &&
508 (transport->error_count > asoc->pf_retrans)) {
509
510 sctp_assoc_control_transport(asoc, transport,
511 SCTP_TRANSPORT_PF,
512 0);
513
514 /* Update the hb timer to resend a heartbeat every rto */
515 sctp_cmd_hb_timer_update(commands, transport);
516 }
517
498 if (transport->state != SCTP_INACTIVE && 518 if (transport->state != SCTP_INACTIVE &&
499 (transport->error_count > transport->pathmaxrxt)) { 519 (transport->error_count > transport->pathmaxrxt)) {
500 SCTP_DEBUG_PRINTK_IPADDR("transport_strike:association %p", 520 SCTP_DEBUG_PRINTK_IPADDR("transport_strike:association %p",
@@ -699,6 +719,10 @@ static void sctp_cmd_transport_on(sctp_cmd_seq_t *cmds,
699 SCTP_HEARTBEAT_SUCCESS); 719 SCTP_HEARTBEAT_SUCCESS);
700 } 720 }
701 721
722 if (t->state == SCTP_PF)
723 sctp_assoc_control_transport(asoc, t, SCTP_TRANSPORT_UP,
724 SCTP_HEARTBEAT_SUCCESS);
725
702 /* The receiver of the HEARTBEAT ACK should also perform an 726 /* The receiver of the HEARTBEAT ACK should also perform an
703 * RTT measurement for that destination transport address 727 * RTT measurement for that destination transport address
704 * using the time value carried in the HEARTBEAT ACK chunk. 728 * using the time value carried in the HEARTBEAT ACK chunk.
@@ -1565,8 +1589,8 @@ static int sctp_cmd_interpreter(sctp_event_t event_type,
1565 1589
1566 case SCTP_CMD_STRIKE: 1590 case SCTP_CMD_STRIKE:
1567 /* Mark one strike against a transport. */ 1591 /* Mark one strike against a transport. */
1568 sctp_do_8_2_transport_strike(asoc, cmd->obj.transport, 1592 sctp_do_8_2_transport_strike(commands, asoc,
1569 0); 1593 cmd->obj.transport, 0);
1570 break; 1594 break;
1571 1595
1572 case SCTP_CMD_TRANSPORT_IDLE: 1596 case SCTP_CMD_TRANSPORT_IDLE:
@@ -1576,7 +1600,8 @@ static int sctp_cmd_interpreter(sctp_event_t event_type,
1576 1600
1577 case SCTP_CMD_TRANSPORT_HB_SENT: 1601 case SCTP_CMD_TRANSPORT_HB_SENT:
1578 t = cmd->obj.transport; 1602 t = cmd->obj.transport;
1579 sctp_do_8_2_transport_strike(asoc, t, 1); 1603 sctp_do_8_2_transport_strike(commands, asoc,
1604 t, 1);
1580 t->hb_sent = 1; 1605 t->hb_sent = 1;
1581 break; 1606 break;
1582 1607
diff --git a/net/sctp/socket.c b/net/sctp/socket.c
index 5d488cdcf679..5e259817a7f3 100644
--- a/net/sctp/socket.c
+++ b/net/sctp/socket.c
@@ -3478,6 +3478,56 @@ static int sctp_setsockopt_auto_asconf(struct sock *sk, char __user *optval,
3478} 3478}
3479 3479
3480 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
3481/* API 6.2 setsockopt(), getsockopt() 3531/* API 6.2 setsockopt(), getsockopt()
3482 * 3532 *
3483 * Applications use setsockopt() and getsockopt() to set or retrieve 3533 * Applications use setsockopt() and getsockopt() to set or retrieve
@@ -3627,6 +3677,9 @@ SCTP_STATIC int sctp_setsockopt(struct sock *sk, int level, int optname,
3627 case SCTP_AUTO_ASCONF: 3677 case SCTP_AUTO_ASCONF:
3628 retval = sctp_setsockopt_auto_asconf(sk, optval, optlen); 3678 retval = sctp_setsockopt_auto_asconf(sk, optval, optlen);
3629 break; 3679 break;
3680 case SCTP_PEER_ADDR_THLDS:
3681 retval = sctp_setsockopt_paddr_thresholds(sk, optval, optlen);
3682 break;
3630 default: 3683 default:
3631 retval = -ENOPROTOOPT; 3684 retval = -ENOPROTOOPT;
3632 break; 3685 break;
@@ -5498,6 +5551,51 @@ static int sctp_getsockopt_assoc_ids(struct sock *sk, int len,
5498 return 0; 5551 return 0;
5499} 5552}
5500 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
5501SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname, 5599SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname,
5502 char __user *optval, int __user *optlen) 5600 char __user *optval, int __user *optlen)
5503{ 5601{
@@ -5636,6 +5734,9 @@ SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname,
5636 case SCTP_AUTO_ASCONF: 5734 case SCTP_AUTO_ASCONF:
5637 retval = sctp_getsockopt_auto_asconf(sk, len, optval, optlen); 5735 retval = sctp_getsockopt_auto_asconf(sk, len, optval, optlen);
5638 break; 5736 break;
5737 case SCTP_PEER_ADDR_THLDS:
5738 retval = sctp_getsockopt_paddr_thresholds(sk, optval, len, optlen);
5739 break;
5639 default: 5740 default:
5640 retval = -ENOPROTOOPT; 5741 retval = -ENOPROTOOPT;
5641 break; 5742 break;
diff --git a/net/sctp/sysctl.c b/net/sctp/sysctl.c
index e5fe639c89e7..2b2bfe933ff1 100644
--- a/net/sctp/sysctl.c
+++ b/net/sctp/sysctl.c
@@ -141,6 +141,15 @@ static ctl_table sctp_table[] = {
141 .extra2 = &int_max 141 .extra2 = &int_max
142 }, 142 },
143 { 143 {
144 .procname = "pf_retrans",
145 .data = &sctp_pf_retrans,
146 .maxlen = sizeof(int),
147 .mode = 0644,
148 .proc_handler = proc_dointvec_minmax,
149 .extra1 = &zero,
150 .extra2 = &int_max
151 },
152 {
144 .procname = "max_init_retransmits", 153 .procname = "max_init_retransmits",
145 .data = &sctp_max_retrans_init, 154 .data = &sctp_max_retrans_init,
146 .maxlen = sizeof(int), 155 .maxlen = sizeof(int),
diff --git a/net/sctp/transport.c b/net/sctp/transport.c
index a6b7ee9ce28a..d1c652ed2f3d 100644
--- a/net/sctp/transport.c
+++ b/net/sctp/transport.c
@@ -87,6 +87,7 @@ static struct sctp_transport *sctp_transport_init(struct sctp_transport *peer,
87 87
88 /* Initialize the default path max_retrans. */ 88 /* Initialize the default path max_retrans. */
89 peer->pathmaxrxt = sctp_max_retrans_path; 89 peer->pathmaxrxt = sctp_max_retrans_path;
90 peer->pf_retrans = sctp_pf_retrans;
90 91
91 INIT_LIST_HEAD(&peer->transmitted); 92 INIT_LIST_HEAD(&peer->transmitted);
92 INIT_LIST_HEAD(&peer->send_ready); 93 INIT_LIST_HEAD(&peer->send_ready);
@@ -595,7 +596,8 @@ unsigned long sctp_transport_timeout(struct sctp_transport *t)
595{ 596{
596 unsigned long timeout; 597 unsigned long timeout;
597 timeout = t->rto + sctp_jitter(t->rto); 598 timeout = t->rto + sctp_jitter(t->rto);
598 if (t->state != SCTP_UNCONFIRMED) 599 if ((t->state != SCTP_UNCONFIRMED) &&
600 (t->state != SCTP_PF))
599 timeout += t->hbinterval; 601 timeout += t->hbinterval;
600 timeout += jiffies; 602 timeout += jiffies;
601 return timeout; 603 return timeout;