aboutsummaryrefslogtreecommitdiffstats
path: root/net/sctp/socket.c
diff options
context:
space:
mode:
authorMichio Honda <micchie@sfc.wide.ad.jp>2011-04-26 07:19:36 -0400
committerDavid S. Miller <davem@davemloft.net>2011-06-02 05:04:53 -0400
commit8a07eb0a50aebc8c95478d49c28c7f8419a26cef (patch)
treea98ab91189d1dd0781d7768c0b0d395c1919d571 /net/sctp/socket.c
parent7dc04d712203eecdc1435a4cd135935c4a297be5 (diff)
sctp: Add ASCONF operation on the single-homed host
In this case, the SCTP association transmits an ASCONF packet including addition of the new IP address and deletion of the old address. This patch implements this functionality. In this case, the ASCONF chunk is added to the beginning of the queue, because the other chunks cannot be transmitted in this state. Signed-off-by: Michio Honda <micchie@sfc.wide.ad.jp> Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org> Acked-by: Wei Yongjun <yjwei@cn.fujitsu.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/sctp/socket.c')
-rw-r--r--net/sctp/socket.c56
1 files changed, 50 insertions, 6 deletions
diff --git a/net/sctp/socket.c b/net/sctp/socket.c
index cc06198dc444..e7e1b142875c 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: