diff options
author | Sridhar Samudrala <sri@us.ibm.com> | 2006-07-21 17:49:25 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2006-07-21 17:49:25 -0400 |
commit | dc022a9874d026c7d1635ae66d1afafc5f053731 (patch) | |
tree | 3a1feddee57eabd788311e2433e922b59036e903 | |
parent | 9faa730f1cbb951e95cb18e71b0fe265014c2450 (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>
-rw-r--r-- | include/net/sctp/structs.h | 7 | ||||
-rw-r--r-- | net/sctp/bind_addr.c | 8 | ||||
-rw-r--r-- | net/sctp/ipv6.c | 3 | ||||
-rw-r--r-- | net/sctp/protocol.c | 7 | ||||
-rw-r--r-- | net/sctp/sm_make_chunk.c | 10 | ||||
-rw-r--r-- | net/sctp/socket.c | 72 |
6 files changed, 80 insertions, 27 deletions
diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h index 268f2e19ccbb..e5aa7ff1f5b5 100644 --- a/include/net/sctp/structs.h +++ b/include/net/sctp/structs.h | |||
@@ -731,13 +731,10 @@ void sctp_init_addrs(struct sctp_chunk *, union sctp_addr *, | |||
731 | const union sctp_addr *sctp_source(const struct sctp_chunk *chunk); | 731 | const union sctp_addr *sctp_source(const struct sctp_chunk *chunk); |
732 | 732 | ||
733 | /* This is a structure for holding either an IPv6 or an IPv4 address. */ | 733 | /* This is a structure for holding either an IPv6 or an IPv4 address. */ |
734 | /* sin_family -- AF_INET or AF_INET6 | ||
735 | * sin_port -- ordinary port number | ||
736 | * sin_addr -- cast to either (struct in_addr) or (struct in6_addr) | ||
737 | */ | ||
738 | struct sctp_sockaddr_entry { | 734 | struct sctp_sockaddr_entry { |
739 | struct list_head list; | 735 | struct list_head list; |
740 | union sctp_addr a; | 736 | union sctp_addr a; |
737 | __u8 use_as_src; | ||
741 | }; | 738 | }; |
742 | 739 | ||
743 | typedef struct sctp_chunk *(sctp_packet_phandler_t)(struct sctp_association *); | 740 | typedef struct sctp_chunk *(sctp_packet_phandler_t)(struct sctp_association *); |
@@ -1142,7 +1139,7 @@ int sctp_bind_addr_copy(struct sctp_bind_addr *dest, | |||
1142 | sctp_scope_t scope, gfp_t gfp, | 1139 | sctp_scope_t scope, gfp_t gfp, |
1143 | int flags); | 1140 | int flags); |
1144 | int sctp_add_bind_addr(struct sctp_bind_addr *, union sctp_addr *, | 1141 | int sctp_add_bind_addr(struct sctp_bind_addr *, union sctp_addr *, |
1145 | gfp_t gfp); | 1142 | __u8 use_as_src, gfp_t gfp); |
1146 | int sctp_del_bind_addr(struct sctp_bind_addr *, union sctp_addr *); | 1143 | int sctp_del_bind_addr(struct sctp_bind_addr *, union sctp_addr *); |
1147 | int sctp_bind_addr_match(struct sctp_bind_addr *, const union sctp_addr *, | 1144 | int sctp_bind_addr_match(struct sctp_bind_addr *, const union sctp_addr *, |
1148 | struct sctp_sock *); | 1145 | struct sctp_sock *); |
diff --git a/net/sctp/bind_addr.c b/net/sctp/bind_addr.c index 2b962627f631..2b9c12a170e5 100644 --- a/net/sctp/bind_addr.c +++ b/net/sctp/bind_addr.c | |||
@@ -146,7 +146,7 @@ void sctp_bind_addr_free(struct sctp_bind_addr *bp) | |||
146 | 146 | ||
147 | /* Add an address to the bind address list in the SCTP_bind_addr structure. */ | 147 | /* Add an address to the bind address list in the SCTP_bind_addr structure. */ |
148 | int sctp_add_bind_addr(struct sctp_bind_addr *bp, union sctp_addr *new, | 148 | int sctp_add_bind_addr(struct sctp_bind_addr *bp, union sctp_addr *new, |
149 | gfp_t gfp) | 149 | __u8 use_as_src, gfp_t gfp) |
150 | { | 150 | { |
151 | struct sctp_sockaddr_entry *addr; | 151 | struct sctp_sockaddr_entry *addr; |
152 | 152 | ||
@@ -163,6 +163,8 @@ int sctp_add_bind_addr(struct sctp_bind_addr *bp, union sctp_addr *new, | |||
163 | if (!addr->a.v4.sin_port) | 163 | if (!addr->a.v4.sin_port) |
164 | addr->a.v4.sin_port = bp->port; | 164 | addr->a.v4.sin_port = bp->port; |
165 | 165 | ||
166 | addr->use_as_src = use_as_src; | ||
167 | |||
166 | INIT_LIST_HEAD(&addr->list); | 168 | INIT_LIST_HEAD(&addr->list); |
167 | list_add_tail(&addr->list, &bp->address_list); | 169 | list_add_tail(&addr->list, &bp->address_list); |
168 | SCTP_DBG_OBJCNT_INC(addr); | 170 | SCTP_DBG_OBJCNT_INC(addr); |
@@ -274,7 +276,7 @@ int sctp_raw_to_bind_addrs(struct sctp_bind_addr *bp, __u8 *raw_addr_list, | |||
274 | } | 276 | } |
275 | 277 | ||
276 | af->from_addr_param(&addr, rawaddr, port, 0); | 278 | af->from_addr_param(&addr, rawaddr, port, 0); |
277 | retval = sctp_add_bind_addr(bp, &addr, gfp); | 279 | retval = sctp_add_bind_addr(bp, &addr, 1, gfp); |
278 | if (retval) { | 280 | if (retval) { |
279 | /* Can't finish building the list, clean up. */ | 281 | /* Can't finish building the list, clean up. */ |
280 | sctp_bind_addr_clean(bp); | 282 | sctp_bind_addr_clean(bp); |
@@ -367,7 +369,7 @@ static int sctp_copy_one_addr(struct sctp_bind_addr *dest, | |||
367 | (((AF_INET6 == addr->sa.sa_family) && | 369 | (((AF_INET6 == addr->sa.sa_family) && |
368 | (flags & SCTP_ADDR6_ALLOWED) && | 370 | (flags & SCTP_ADDR6_ALLOWED) && |
369 | (flags & SCTP_ADDR6_PEERSUPP)))) | 371 | (flags & SCTP_ADDR6_PEERSUPP)))) |
370 | error = sctp_add_bind_addr(dest, addr, gfp); | 372 | error = sctp_add_bind_addr(dest, addr, 1, gfp); |
371 | } | 373 | } |
372 | 374 | ||
373 | return error; | 375 | return error; |
diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c index 8ef08070c8b6..99c0cefc04e0 100644 --- a/net/sctp/ipv6.c +++ b/net/sctp/ipv6.c | |||
@@ -290,7 +290,8 @@ static void sctp_v6_get_saddr(struct sctp_association *asoc, | |||
290 | sctp_read_lock(addr_lock); | 290 | sctp_read_lock(addr_lock); |
291 | list_for_each(pos, &bp->address_list) { | 291 | list_for_each(pos, &bp->address_list) { |
292 | laddr = list_entry(pos, struct sctp_sockaddr_entry, list); | 292 | laddr = list_entry(pos, struct sctp_sockaddr_entry, list); |
293 | if ((laddr->a.sa.sa_family == AF_INET6) && | 293 | if ((laddr->use_as_src) && |
294 | (laddr->a.sa.sa_family == AF_INET6) && | ||
294 | (scope <= sctp_scope(&laddr->a))) { | 295 | (scope <= sctp_scope(&laddr->a))) { |
295 | bmatchlen = sctp_v6_addr_match_len(daddr, &laddr->a); | 296 | bmatchlen = sctp_v6_addr_match_len(daddr, &laddr->a); |
296 | if (!baddr || (matchlen < bmatchlen)) { | 297 | if (!baddr || (matchlen < bmatchlen)) { |
diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index 816c033d7886..1ab03a27a76e 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c | |||
@@ -240,7 +240,7 @@ int sctp_copy_local_addr_list(struct sctp_bind_addr *bp, sctp_scope_t scope, | |||
240 | (((AF_INET6 == addr->a.sa.sa_family) && | 240 | (((AF_INET6 == addr->a.sa.sa_family) && |
241 | (copy_flags & SCTP_ADDR6_ALLOWED) && | 241 | (copy_flags & SCTP_ADDR6_ALLOWED) && |
242 | (copy_flags & SCTP_ADDR6_PEERSUPP)))) { | 242 | (copy_flags & SCTP_ADDR6_PEERSUPP)))) { |
243 | error = sctp_add_bind_addr(bp, &addr->a, | 243 | error = sctp_add_bind_addr(bp, &addr->a, 1, |
244 | GFP_ATOMIC); | 244 | GFP_ATOMIC); |
245 | if (error) | 245 | if (error) |
246 | goto end_copy; | 246 | goto end_copy; |
@@ -486,6 +486,8 @@ static struct dst_entry *sctp_v4_get_dst(struct sctp_association *asoc, | |||
486 | list_for_each(pos, &bp->address_list) { | 486 | list_for_each(pos, &bp->address_list) { |
487 | laddr = list_entry(pos, struct sctp_sockaddr_entry, | 487 | laddr = list_entry(pos, struct sctp_sockaddr_entry, |
488 | list); | 488 | list); |
489 | if (!laddr->use_as_src) | ||
490 | continue; | ||
489 | sctp_v4_dst_saddr(&dst_saddr, dst, bp->port); | 491 | sctp_v4_dst_saddr(&dst_saddr, dst, bp->port); |
490 | if (sctp_v4_cmp_addr(&dst_saddr, &laddr->a)) | 492 | if (sctp_v4_cmp_addr(&dst_saddr, &laddr->a)) |
491 | goto out_unlock; | 493 | goto out_unlock; |
@@ -506,7 +508,8 @@ static struct dst_entry *sctp_v4_get_dst(struct sctp_association *asoc, | |||
506 | list_for_each(pos, &bp->address_list) { | 508 | list_for_each(pos, &bp->address_list) { |
507 | laddr = list_entry(pos, struct sctp_sockaddr_entry, list); | 509 | laddr = list_entry(pos, struct sctp_sockaddr_entry, list); |
508 | 510 | ||
509 | if (AF_INET == laddr->a.sa.sa_family) { | 511 | if ((laddr->use_as_src) && |
512 | (AF_INET == laddr->a.sa.sa_family)) { | ||
510 | fl.fl4_src = laddr->a.v4.sin_addr.s_addr; | 513 | fl.fl4_src = laddr->a.v4.sin_addr.s_addr; |
511 | if (!ip_route_output_key(&rt, &fl)) { | 514 | if (!ip_route_output_key(&rt, &fl)) { |
512 | dst = &rt->u.dst; | 515 | dst = &rt->u.dst; |
diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c index 8134e8b1cdca..4f11f5858209 100644 --- a/net/sctp/sm_make_chunk.c +++ b/net/sctp/sm_make_chunk.c | |||
@@ -1493,7 +1493,7 @@ no_hmac: | |||
1493 | 1493 | ||
1494 | /* Also, add the destination address. */ | 1494 | /* Also, add the destination address. */ |
1495 | if (list_empty(&retval->base.bind_addr.address_list)) { | 1495 | if (list_empty(&retval->base.bind_addr.address_list)) { |
1496 | sctp_add_bind_addr(&retval->base.bind_addr, &chunk->dest, | 1496 | sctp_add_bind_addr(&retval->base.bind_addr, &chunk->dest, 1, |
1497 | GFP_ATOMIC); | 1497 | GFP_ATOMIC); |
1498 | } | 1498 | } |
1499 | 1499 | ||
@@ -2565,6 +2565,7 @@ static int sctp_asconf_param_success(struct sctp_association *asoc, | |||
2565 | union sctp_addr_param *addr_param; | 2565 | union sctp_addr_param *addr_param; |
2566 | struct list_head *pos; | 2566 | struct list_head *pos; |
2567 | struct sctp_transport *transport; | 2567 | struct sctp_transport *transport; |
2568 | struct sctp_sockaddr_entry *saddr; | ||
2568 | int retval = 0; | 2569 | int retval = 0; |
2569 | 2570 | ||
2570 | addr_param = (union sctp_addr_param *) | 2571 | addr_param = (union sctp_addr_param *) |
@@ -2578,7 +2579,11 @@ static int sctp_asconf_param_success(struct sctp_association *asoc, | |||
2578 | case SCTP_PARAM_ADD_IP: | 2579 | case SCTP_PARAM_ADD_IP: |
2579 | sctp_local_bh_disable(); | 2580 | sctp_local_bh_disable(); |
2580 | sctp_write_lock(&asoc->base.addr_lock); | 2581 | sctp_write_lock(&asoc->base.addr_lock); |
2581 | retval = sctp_add_bind_addr(bp, &addr, GFP_ATOMIC); | 2582 | list_for_each(pos, &bp->address_list) { |
2583 | saddr = list_entry(pos, struct sctp_sockaddr_entry, list); | ||
2584 | if (sctp_cmp_addr_exact(&saddr->a, &addr)) | ||
2585 | saddr->use_as_src = 1; | ||
2586 | } | ||
2582 | sctp_write_unlock(&asoc->base.addr_lock); | 2587 | sctp_write_unlock(&asoc->base.addr_lock); |
2583 | sctp_local_bh_enable(); | 2588 | sctp_local_bh_enable(); |
2584 | break; | 2589 | break; |
@@ -2591,6 +2596,7 @@ static int sctp_asconf_param_success(struct sctp_association *asoc, | |||
2591 | list_for_each(pos, &asoc->peer.transport_addr_list) { | 2596 | list_for_each(pos, &asoc->peer.transport_addr_list) { |
2592 | transport = list_entry(pos, struct sctp_transport, | 2597 | transport = list_entry(pos, struct sctp_transport, |
2593 | transports); | 2598 | transports); |
2599 | dst_release(transport->dst); | ||
2594 | sctp_transport_route(transport, NULL, | 2600 | sctp_transport_route(transport, NULL, |
2595 | sctp_sk(asoc->base.sk)); | 2601 | sctp_sk(asoc->base.sk)); |
2596 | } | 2602 | } |
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 | ||
571 | out: | 584 | out: |
@@ -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 | } |
760 | out: | 804 | out: |
761 | return retval; | 805 | return retval; |