aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/net/sctp/structs.h2
-rw-r--r--net/sctp/associola.c6
-rw-r--r--net/sctp/outqueue.c13
-rw-r--r--net/sctp/protocol.c4
-rw-r--r--net/sctp/sm_make_chunk.c27
-rw-r--r--net/sctp/socket.c56
6 files changed, 101 insertions, 7 deletions
diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h
index cd8c929e6b0..31d7ea2e1d2 100644
--- a/include/net/sctp/structs.h
+++ b/include/net/sctp/structs.h
@@ -1913,6 +1913,8 @@ struct sctp_association {
1913 * after reaching 4294967295. 1913 * after reaching 4294967295.
1914 */ 1914 */
1915 __u32 addip_serial; 1915 __u32 addip_serial;
1916 union sctp_addr *asconf_addr_del_pending;
1917 int src_out_of_asoc_ok;
1916 1918
1917 /* SCTP AUTH: list of the endpoint shared keys. These 1919 /* SCTP AUTH: list of the endpoint shared keys. These
1918 * keys are provided out of band by the user applicaton 1920 * keys are provided out of band by the user applicaton
diff --git a/net/sctp/associola.c b/net/sctp/associola.c
index 4a62888f2e4..dc16b90ddb6 100644
--- a/net/sctp/associola.c
+++ b/net/sctp/associola.c
@@ -280,6 +280,8 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a
280 asoc->peer.asconf_capable = 0; 280 asoc->peer.asconf_capable = 0;
281 if (sctp_addip_noauth) 281 if (sctp_addip_noauth)
282 asoc->peer.asconf_capable = 1; 282 asoc->peer.asconf_capable = 1;
283 asoc->asconf_addr_del_pending = NULL;
284 asoc->src_out_of_asoc_ok = 0;
283 285
284 /* Create an input queue. */ 286 /* Create an input queue. */
285 sctp_inq_init(&asoc->base.inqueue); 287 sctp_inq_init(&asoc->base.inqueue);
@@ -446,6 +448,10 @@ void sctp_association_free(struct sctp_association *asoc)
446 448
447 sctp_asconf_queue_teardown(asoc); 449 sctp_asconf_queue_teardown(asoc);
448 450
451 /* Free pending address space being deleted */
452 if (asoc->asconf_addr_del_pending != NULL)
453 kfree(asoc->asconf_addr_del_pending);
454
449 /* AUTH - Free the endpoint shared keys */ 455 /* AUTH - Free the endpoint shared keys */
450 sctp_auth_destroy_keys(&asoc->endpoint_shared_keys); 456 sctp_auth_destroy_keys(&asoc->endpoint_shared_keys);
451 457
diff --git a/net/sctp/outqueue.c b/net/sctp/outqueue.c
index 1c88c8911dc..edc753297a4 100644
--- a/net/sctp/outqueue.c
+++ b/net/sctp/outqueue.c
@@ -754,6 +754,16 @@ static int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)
754 */ 754 */
755 755
756 list_for_each_entry_safe(chunk, tmp, &q->control_chunk_list, list) { 756 list_for_each_entry_safe(chunk, tmp, &q->control_chunk_list, list) {
757 /* RFC 5061, 5.3
758 * F1) This means that until such time as the ASCONF
759 * containing the add is acknowledged, the sender MUST
760 * NOT use the new IP address as a source for ANY SCTP
761 * packet except on carrying an ASCONF Chunk.
762 */
763 if (asoc->src_out_of_asoc_ok &&
764 chunk->chunk_hdr->type != SCTP_CID_ASCONF)
765 continue;
766
757 list_del_init(&chunk->list); 767 list_del_init(&chunk->list);
758 768
759 /* Pick the right transport to use. */ 769 /* Pick the right transport to use. */
@@ -881,6 +891,9 @@ static int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)
881 } 891 }
882 } 892 }
883 893
894 if (q->asoc->src_out_of_asoc_ok)
895 goto sctp_flush_out;
896
884 /* Is it OK to send data chunks? */ 897 /* Is it OK to send data chunks? */
885 switch (asoc->state) { 898 switch (asoc->state) {
886 case SCTP_STATE_COOKIE_ECHOED: 899 case SCTP_STATE_COOKIE_ECHOED:
diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c
index 013c6136c54..af0a6b0fc9b 100644
--- a/net/sctp/protocol.c
+++ b/net/sctp/protocol.c
@@ -503,7 +503,9 @@ static void sctp_v4_get_dst(struct sctp_transport *t, union sctp_addr *saddr,
503 sctp_v4_dst_saddr(&dst_saddr, fl4, htons(bp->port)); 503 sctp_v4_dst_saddr(&dst_saddr, fl4, htons(bp->port));
504 rcu_read_lock(); 504 rcu_read_lock();
505 list_for_each_entry_rcu(laddr, &bp->address_list, list) { 505 list_for_each_entry_rcu(laddr, &bp->address_list, list) {
506 if (!laddr->valid || (laddr->state != SCTP_ADDR_SRC)) 506 if (!laddr->valid || (laddr->state == SCTP_ADDR_DEL) ||
507 (laddr->state != SCTP_ADDR_SRC &&
508 !asoc->src_out_of_asoc_ok))
507 continue; 509 continue;
508 if (sctp_v4_cmp_addr(&dst_saddr, &laddr->a)) 510 if (sctp_v4_cmp_addr(&dst_saddr, &laddr->a))
509 goto out_unlock; 511 goto out_unlock;
diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c
index 37406039820..3363d378825 100644
--- a/net/sctp/sm_make_chunk.c
+++ b/net/sctp/sm_make_chunk.c
@@ -2768,6 +2768,7 @@ struct sctp_chunk *sctp_make_asconf_update_ip(struct sctp_association *asoc,
2768 int addr_param_len = 0; 2768 int addr_param_len = 0;
2769 int totallen = 0; 2769 int totallen = 0;
2770 int i; 2770 int i;
2771 int del_pickup = 0;
2771 2772
2772 /* Get total length of all the address parameters. */ 2773 /* Get total length of all the address parameters. */
2773 addr_buf = addrs; 2774 addr_buf = addrs;
@@ -2780,6 +2781,13 @@ struct sctp_chunk *sctp_make_asconf_update_ip(struct sctp_association *asoc,
2780 totallen += addr_param_len; 2781 totallen += addr_param_len;
2781 2782
2782 addr_buf += af->sockaddr_len; 2783 addr_buf += af->sockaddr_len;
2784 if (asoc->asconf_addr_del_pending && !del_pickup) {
2785 /* reuse the parameter length from the same scope one */
2786 totallen += paramlen;
2787 totallen += addr_param_len;
2788 del_pickup = 1;
2789 SCTP_DEBUG_PRINTK("mkasconf_update_ip: picked same-scope del_pending addr, totallen for all addresses is %d\n", totallen);
2790 }
2783 } 2791 }
2784 2792
2785 /* Create an asconf chunk with the required length. */ 2793 /* Create an asconf chunk with the required length. */
@@ -2802,6 +2810,17 @@ struct sctp_chunk *sctp_make_asconf_update_ip(struct sctp_association *asoc,
2802 2810
2803 addr_buf += af->sockaddr_len; 2811 addr_buf += af->sockaddr_len;
2804 } 2812 }
2813 if (flags == SCTP_PARAM_ADD_IP && del_pickup) {
2814 addr = asoc->asconf_addr_del_pending;
2815 af = sctp_get_af_specific(addr->v4.sin_family);
2816 addr_param_len = af->to_addr_param(addr, &addr_param);
2817 param.param_hdr.type = SCTP_PARAM_DEL_IP;
2818 param.param_hdr.length = htons(paramlen + addr_param_len);
2819 param.crr_id = i;
2820
2821 sctp_addto_chunk(retval, paramlen, &param);
2822 sctp_addto_chunk(retval, addr_param_len, &addr_param);
2823 }
2805 return retval; 2824 return retval;
2806} 2825}
2807 2826
@@ -3224,6 +3243,11 @@ static void sctp_asconf_param_success(struct sctp_association *asoc,
3224 case SCTP_PARAM_DEL_IP: 3243 case SCTP_PARAM_DEL_IP:
3225 local_bh_disable(); 3244 local_bh_disable();
3226 sctp_del_bind_addr(bp, &addr); 3245 sctp_del_bind_addr(bp, &addr);
3246 if (asoc->asconf_addr_del_pending != NULL &&
3247 sctp_cmp_addr_exact(asoc->asconf_addr_del_pending, &addr)) {
3248 kfree(asoc->asconf_addr_del_pending);
3249 asoc->asconf_addr_del_pending = NULL;
3250 }
3227 local_bh_enable(); 3251 local_bh_enable();
3228 list_for_each_entry(transport, &asoc->peer.transport_addr_list, 3252 list_for_each_entry(transport, &asoc->peer.transport_addr_list,
3229 transports) { 3253 transports) {
@@ -3381,6 +3405,9 @@ int sctp_process_asconf_ack(struct sctp_association *asoc,
3381 asconf_len -= length; 3405 asconf_len -= length;
3382 } 3406 }
3383 3407
3408 if (no_err && asoc->src_out_of_asoc_ok)
3409 asoc->src_out_of_asoc_ok = 0;
3410
3384 /* Free the cached last sent asconf chunk. */ 3411 /* Free the cached last sent asconf chunk. */
3385 list_del_init(&asconf->transmitted_list); 3412 list_del_init(&asconf->transmitted_list);
3386 sctp_chunk_free(asconf); 3413 sctp_chunk_free(asconf);
diff --git a/net/sctp/socket.c b/net/sctp/socket.c
index cc06198dc44..e7e1b142875 100644
--- a/net/sctp/socket.c
+++ b/net/sctp/socket.c
@@ -583,10 +583,6 @@ static int sctp_send_asconf_add_ip(struct sock *sk,
583 goto out; 583 goto out;
584 } 584 }
585 585
586 retval = sctp_send_asconf(asoc, chunk);
587 if (retval)
588 goto out;
589
590 /* Add the new addresses to the bind address list with 586 /* Add the new addresses to the bind address list with
591 * use_as_src set to 0. 587 * use_as_src set to 0.
592 */ 588 */
@@ -599,6 +595,23 @@ static int sctp_send_asconf_add_ip(struct sock *sk,
599 SCTP_ADDR_NEW, GFP_ATOMIC); 595 SCTP_ADDR_NEW, GFP_ATOMIC);
600 addr_buf += af->sockaddr_len; 596 addr_buf += af->sockaddr_len;
601 } 597 }
598 if (asoc->src_out_of_asoc_ok) {
599 struct sctp_transport *trans;
600
601 list_for_each_entry(trans,
602 &asoc->peer.transport_addr_list, transports) {
603 /* Clear the source and route cache */
604 dst_release(trans->dst);
605 trans->cwnd = min(4*asoc->pathmtu, max_t(__u32,
606 2*asoc->pathmtu, 4380));
607 trans->ssthresh = asoc->peer.i.a_rwnd;
608 trans->rto = asoc->rto_initial;
609 trans->rtt = trans->srtt = trans->rttvar = 0;
610 sctp_transport_route(trans, NULL,
611 sctp_sk(asoc->base.sk));
612 }
613 }
614 retval = sctp_send_asconf(asoc, chunk);
602 } 615 }
603 616
604out: 617out:
@@ -715,7 +728,9 @@ static int sctp_send_asconf_del_ip(struct sock *sk,
715 struct sctp_sockaddr_entry *saddr; 728 struct sctp_sockaddr_entry *saddr;
716 int i; 729 int i;
717 int retval = 0; 730 int retval = 0;
731 int stored = 0;
718 732
733 chunk = NULL;
719 if (!sctp_addip_enable) 734 if (!sctp_addip_enable)
720 return retval; 735 return retval;
721 736
@@ -766,8 +781,33 @@ static int sctp_send_asconf_del_ip(struct sock *sk,
766 bp = &asoc->base.bind_addr; 781 bp = &asoc->base.bind_addr;
767 laddr = sctp_find_unmatch_addr(bp, (union sctp_addr *)addrs, 782 laddr = sctp_find_unmatch_addr(bp, (union sctp_addr *)addrs,
768 addrcnt, sp); 783 addrcnt, sp);
769 if (!laddr) 784 if ((laddr == NULL) && (addrcnt == 1)) {
770 continue; 785 if (asoc->asconf_addr_del_pending)
786 continue;
787 asoc->asconf_addr_del_pending =
788 kzalloc(sizeof(union sctp_addr), GFP_ATOMIC);
789 asoc->asconf_addr_del_pending->sa.sa_family =
790 addrs->sa_family;
791 asoc->asconf_addr_del_pending->v4.sin_port =
792 htons(bp->port);
793 if (addrs->sa_family == AF_INET) {
794 struct sockaddr_in *sin;
795
796 sin = (struct sockaddr_in *)addrs;
797 asoc->asconf_addr_del_pending->v4.sin_addr.s_addr = sin->sin_addr.s_addr;
798 } else if (addrs->sa_family == AF_INET6) {
799 struct sockaddr_in6 *sin6;
800
801 sin6 = (struct sockaddr_in6 *)addrs;
802 ipv6_addr_copy(&asoc->asconf_addr_del_pending->v6.sin6_addr, &sin6->sin6_addr);
803 }
804 SCTP_DEBUG_PRINTK_IPADDR("send_asconf_del_ip: keep the last address asoc: %p ",
805 " at %p\n", asoc, asoc->asconf_addr_del_pending,
806 asoc->asconf_addr_del_pending);
807 asoc->src_out_of_asoc_ok = 1;
808 stored = 1;
809 goto skip_mkasconf;
810 }
771 811
772 /* We do not need RCU protection throughout this loop 812 /* We do not need RCU protection throughout this loop
773 * because this is done under a socket lock from the 813 * because this is done under a socket lock from the
@@ -780,6 +820,7 @@ static int sctp_send_asconf_del_ip(struct sock *sk,
780 goto out; 820 goto out;
781 } 821 }
782 822
823skip_mkasconf:
783 /* Reset use_as_src flag for the addresses in the bind address 824 /* Reset use_as_src flag for the addresses in the bind address
784 * list that are to be deleted. 825 * list that are to be deleted.
785 */ 826 */
@@ -805,6 +846,9 @@ static int sctp_send_asconf_del_ip(struct sock *sk,
805 sctp_sk(asoc->base.sk)); 846 sctp_sk(asoc->base.sk));
806 } 847 }
807 848
849 if (stored)
850 /* We don't need to transmit ASCONF */
851 continue;
808 retval = sctp_send_asconf(asoc, chunk); 852 retval = sctp_send_asconf(asoc, chunk);
809 } 853 }
810out: 854out: