aboutsummaryrefslogtreecommitdiffstats
path: root/net/sctp/socket.c
diff options
context:
space:
mode:
authorSridhar Samudrala <sri@us.ibm.com>2006-07-21 17:49:25 -0400
committerDavid S. Miller <davem@davemloft.net>2006-07-21 17:49:25 -0400
commitdc022a9874d026c7d1635ae66d1afafc5f053731 (patch)
tree3a1feddee57eabd788311e2433e922b59036e903 /net/sctp/socket.c
parent9faa730f1cbb951e95cb18e71b0fe265014c2450 (diff)
[SCTP]: ADDIP: Don't use an address as source until it is ASCONF-ACKed
This implements Rules D1 and D4 of Sec 4.3 in the ADDIP draft. Signed-off-by: Sridhar Samudrala <sri@us.ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/sctp/socket.c')
-rw-r--r--net/sctp/socket.c72
1 files changed, 58 insertions, 14 deletions
diff --git a/net/sctp/socket.c b/net/sctp/socket.c
index 518c55ab610b..54722e622e6d 100644
--- a/net/sctp/socket.c
+++ b/net/sctp/socket.c
@@ -369,7 +369,7 @@ SCTP_STATIC int sctp_do_bind(struct sock *sk, union sctp_addr *addr, int len)
369 369
370 /* Use GFP_ATOMIC since BHs are disabled. */ 370 /* Use GFP_ATOMIC since BHs are disabled. */
371 addr->v4.sin_port = ntohs(addr->v4.sin_port); 371 addr->v4.sin_port = ntohs(addr->v4.sin_port);
372 ret = sctp_add_bind_addr(bp, addr, GFP_ATOMIC); 372 ret = sctp_add_bind_addr(bp, addr, 1, GFP_ATOMIC);
373 addr->v4.sin_port = htons(addr->v4.sin_port); 373 addr->v4.sin_port = htons(addr->v4.sin_port);
374 sctp_write_unlock(&ep->base.addr_lock); 374 sctp_write_unlock(&ep->base.addr_lock);
375 sctp_local_bh_enable(); 375 sctp_local_bh_enable();
@@ -491,6 +491,7 @@ static int sctp_send_asconf_add_ip(struct sock *sk,
491 struct sctp_chunk *chunk; 491 struct sctp_chunk *chunk;
492 struct sctp_sockaddr_entry *laddr; 492 struct sctp_sockaddr_entry *laddr;
493 union sctp_addr *addr; 493 union sctp_addr *addr;
494 union sctp_addr saveaddr;
494 void *addr_buf; 495 void *addr_buf;
495 struct sctp_af *af; 496 struct sctp_af *af;
496 struct list_head *pos; 497 struct list_head *pos;
@@ -558,14 +559,26 @@ static int sctp_send_asconf_add_ip(struct sock *sk,
558 } 559 }
559 560
560 retval = sctp_send_asconf(asoc, chunk); 561 retval = sctp_send_asconf(asoc, chunk);
562 if (retval)
563 goto out;
561 564
562 /* FIXME: After sending the add address ASCONF chunk, we 565 /* Add the new addresses to the bind address list with
563 * cannot append the address to the association's binding 566 * use_as_src set to 0.
564 * address list, because the new address may be used as the
565 * source of a message sent to the peer before the ASCONF
566 * chunk is received by the peer. So we should wait until
567 * ASCONF_ACK is received.
568 */ 567 */
568 sctp_local_bh_disable();
569 sctp_write_lock(&asoc->base.addr_lock);
570 addr_buf = addrs;
571 for (i = 0; i < addrcnt; i++) {
572 addr = (union sctp_addr *)addr_buf;
573 af = sctp_get_af_specific(addr->v4.sin_family);
574 memcpy(&saveaddr, addr, af->sockaddr_len);
575 saveaddr.v4.sin_port = ntohs(saveaddr.v4.sin_port);
576 retval = sctp_add_bind_addr(bp, &saveaddr, 0,
577 GFP_ATOMIC);
578 addr_buf += af->sockaddr_len;
579 }
580 sctp_write_unlock(&asoc->base.addr_lock);
581 sctp_local_bh_enable();
569 } 582 }
570 583
571out: 584out:
@@ -676,12 +689,15 @@ static int sctp_send_asconf_del_ip(struct sock *sk,
676 struct sctp_sock *sp; 689 struct sctp_sock *sp;
677 struct sctp_endpoint *ep; 690 struct sctp_endpoint *ep;
678 struct sctp_association *asoc; 691 struct sctp_association *asoc;
692 struct sctp_transport *transport;
679 struct sctp_bind_addr *bp; 693 struct sctp_bind_addr *bp;
680 struct sctp_chunk *chunk; 694 struct sctp_chunk *chunk;
681 union sctp_addr *laddr; 695 union sctp_addr *laddr;
696 union sctp_addr saveaddr;
682 void *addr_buf; 697 void *addr_buf;
683 struct sctp_af *af; 698 struct sctp_af *af;
684 struct list_head *pos; 699 struct list_head *pos, *pos1;
700 struct sctp_sockaddr_entry *saddr;
685 int i; 701 int i;
686 int retval = 0; 702 int retval = 0;
687 703
@@ -748,14 +764,42 @@ static int sctp_send_asconf_del_ip(struct sock *sk,
748 goto out; 764 goto out;
749 } 765 }
750 766
751 retval = sctp_send_asconf(asoc, chunk); 767 /* Reset use_as_src flag for the addresses in the bind address
768 * list that are to be deleted.
769 */
770 sctp_local_bh_disable();
771 sctp_write_lock(&asoc->base.addr_lock);
772 addr_buf = addrs;
773 for (i = 0; i < addrcnt; i++) {
774 laddr = (union sctp_addr *)addr_buf;
775 af = sctp_get_af_specific(laddr->v4.sin_family);
776 memcpy(&saveaddr, laddr, af->sockaddr_len);
777 saveaddr.v4.sin_port = ntohs(saveaddr.v4.sin_port);
778 list_for_each(pos1, &bp->address_list) {
779 saddr = list_entry(pos1,
780 struct sctp_sockaddr_entry,
781 list);
782 if (sctp_cmp_addr_exact(&saddr->a, &saveaddr))
783 saddr->use_as_src = 0;
784 }
785 addr_buf += af->sockaddr_len;
786 }
787 sctp_write_unlock(&asoc->base.addr_lock);
788 sctp_local_bh_enable();
752 789
753 /* FIXME: After sending the delete address ASCONF chunk, we 790 /* Update the route and saddr entries for all the transports
754 * cannot remove the addresses from the association's bind 791 * as some of the addresses in the bind address list are
755 * address list, because there maybe some packet send to 792 * about to be deleted and cannot be used as source addresses.
756 * the delete addresses, so we should wait until ASCONF_ACK
757 * packet is received.
758 */ 793 */
794 list_for_each(pos1, &asoc->peer.transport_addr_list) {
795 transport = list_entry(pos1, struct sctp_transport,
796 transports);
797 dst_release(transport->dst);
798 sctp_transport_route(transport, NULL,
799 sctp_sk(asoc->base.sk));
800 }
801
802 retval = sctp_send_asconf(asoc, chunk);
759 } 803 }
760out: 804out:
761 return retval; 805 return retval;