diff options
Diffstat (limited to 'net/sctp')
-rw-r--r-- | net/sctp/associola.c | 27 | ||||
-rw-r--r-- | net/sctp/bind_addr.c | 8 | ||||
-rw-r--r-- | net/sctp/endpointola.c | 11 | ||||
-rw-r--r-- | net/sctp/ipv6.c | 3 | ||||
-rw-r--r-- | net/sctp/outqueue.c | 9 | ||||
-rw-r--r-- | net/sctp/protocol.c | 7 | ||||
-rw-r--r-- | net/sctp/sm_make_chunk.c | 14 | ||||
-rw-r--r-- | net/sctp/sm_sideeffect.c | 12 | ||||
-rw-r--r-- | net/sctp/sm_statefuns.c | 8 | ||||
-rw-r--r-- | net/sctp/socket.c | 74 | ||||
-rw-r--r-- | net/sctp/transport.c | 9 |
11 files changed, 134 insertions, 48 deletions
diff --git a/net/sctp/associola.c b/net/sctp/associola.c index 9d05e13e92f6..27329ce9c311 100644 --- a/net/sctp/associola.c +++ b/net/sctp/associola.c | |||
@@ -441,7 +441,8 @@ void sctp_assoc_set_primary(struct sctp_association *asoc, | |||
441 | /* If the primary path is changing, assume that the | 441 | /* If the primary path is changing, assume that the |
442 | * user wants to use this new path. | 442 | * user wants to use this new path. |
443 | */ | 443 | */ |
444 | if (transport->state != SCTP_INACTIVE) | 444 | if ((transport->state == SCTP_ACTIVE) || |
445 | (transport->state == SCTP_UNKNOWN)) | ||
445 | asoc->peer.active_path = transport; | 446 | asoc->peer.active_path = transport; |
446 | 447 | ||
447 | /* | 448 | /* |
@@ -532,11 +533,11 @@ struct sctp_transport *sctp_assoc_add_peer(struct sctp_association *asoc, | |||
532 | port = addr->v4.sin_port; | 533 | port = addr->v4.sin_port; |
533 | 534 | ||
534 | SCTP_DEBUG_PRINTK_IPADDR("sctp_assoc_add_peer:association %p addr: ", | 535 | SCTP_DEBUG_PRINTK_IPADDR("sctp_assoc_add_peer:association %p addr: ", |
535 | " port: %d state:%s\n", | 536 | " port: %d state:%d\n", |
536 | asoc, | 537 | asoc, |
537 | addr, | 538 | addr, |
538 | addr->v4.sin_port, | 539 | addr->v4.sin_port, |
539 | peer_state == SCTP_UNKNOWN?"UNKNOWN":"ACTIVE"); | 540 | peer_state); |
540 | 541 | ||
541 | /* Set the port if it has not been set yet. */ | 542 | /* Set the port if it has not been set yet. */ |
542 | if (0 == asoc->peer.port) | 543 | if (0 == asoc->peer.port) |
@@ -545,9 +546,12 @@ struct sctp_transport *sctp_assoc_add_peer(struct sctp_association *asoc, | |||
545 | /* Check to see if this is a duplicate. */ | 546 | /* Check to see if this is a duplicate. */ |
546 | peer = sctp_assoc_lookup_paddr(asoc, addr); | 547 | peer = sctp_assoc_lookup_paddr(asoc, addr); |
547 | if (peer) { | 548 | if (peer) { |
548 | if (peer_state == SCTP_ACTIVE && | 549 | if (peer->state == SCTP_UNKNOWN) { |
549 | peer->state == SCTP_UNKNOWN) | 550 | if (peer_state == SCTP_ACTIVE) |
550 | peer->state = SCTP_ACTIVE; | 551 | peer->state = SCTP_ACTIVE; |
552 | if (peer_state == SCTP_UNCONFIRMED) | ||
553 | peer->state = SCTP_UNCONFIRMED; | ||
554 | } | ||
551 | return peer; | 555 | return peer; |
552 | } | 556 | } |
553 | 557 | ||
@@ -739,7 +743,8 @@ void sctp_assoc_control_transport(struct sctp_association *asoc, | |||
739 | list_for_each(pos, &asoc->peer.transport_addr_list) { | 743 | list_for_each(pos, &asoc->peer.transport_addr_list) { |
740 | t = list_entry(pos, struct sctp_transport, transports); | 744 | t = list_entry(pos, struct sctp_transport, transports); |
741 | 745 | ||
742 | if (t->state == SCTP_INACTIVE) | 746 | if ((t->state == SCTP_INACTIVE) || |
747 | (t->state == SCTP_UNCONFIRMED)) | ||
743 | continue; | 748 | continue; |
744 | if (!first || t->last_time_heard > first->last_time_heard) { | 749 | if (!first || t->last_time_heard > first->last_time_heard) { |
745 | second = first; | 750 | second = first; |
@@ -759,7 +764,8 @@ void sctp_assoc_control_transport(struct sctp_association *asoc, | |||
759 | * [If the primary is active but not most recent, bump the most | 764 | * [If the primary is active but not most recent, bump the most |
760 | * recently used transport.] | 765 | * recently used transport.] |
761 | */ | 766 | */ |
762 | if (asoc->peer.primary_path->state != SCTP_INACTIVE && | 767 | if (((asoc->peer.primary_path->state == SCTP_ACTIVE) || |
768 | (asoc->peer.primary_path->state == SCTP_UNKNOWN)) && | ||
763 | first != asoc->peer.primary_path) { | 769 | first != asoc->peer.primary_path) { |
764 | second = first; | 770 | second = first; |
765 | first = asoc->peer.primary_path; | 771 | first = asoc->peer.primary_path; |
@@ -1054,7 +1060,7 @@ void sctp_assoc_update(struct sctp_association *asoc, | |||
1054 | transports); | 1060 | transports); |
1055 | if (!sctp_assoc_lookup_paddr(asoc, &trans->ipaddr)) | 1061 | if (!sctp_assoc_lookup_paddr(asoc, &trans->ipaddr)) |
1056 | sctp_assoc_add_peer(asoc, &trans->ipaddr, | 1062 | sctp_assoc_add_peer(asoc, &trans->ipaddr, |
1057 | GFP_ATOMIC, SCTP_ACTIVE); | 1063 | GFP_ATOMIC, trans->state); |
1058 | } | 1064 | } |
1059 | 1065 | ||
1060 | asoc->ctsn_ack_point = asoc->next_tsn - 1; | 1066 | asoc->ctsn_ack_point = asoc->next_tsn - 1; |
@@ -1094,7 +1100,8 @@ void sctp_assoc_update_retran_path(struct sctp_association *asoc) | |||
1094 | 1100 | ||
1095 | /* Try to find an active transport. */ | 1101 | /* Try to find an active transport. */ |
1096 | 1102 | ||
1097 | if (t->state != SCTP_INACTIVE) { | 1103 | if ((t->state == SCTP_ACTIVE) || |
1104 | (t->state == SCTP_UNKNOWN)) { | ||
1098 | break; | 1105 | break; |
1099 | } else { | 1106 | } else { |
1100 | /* Keep track of the next transport in case | 1107 | /* Keep track of the next transport in case |
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/endpointola.c b/net/sctp/endpointola.c index 67bd53070ee0..ffda1d680529 100644 --- a/net/sctp/endpointola.c +++ b/net/sctp/endpointola.c | |||
@@ -158,6 +158,12 @@ void sctp_endpoint_add_asoc(struct sctp_endpoint *ep, | |||
158 | void sctp_endpoint_free(struct sctp_endpoint *ep) | 158 | void sctp_endpoint_free(struct sctp_endpoint *ep) |
159 | { | 159 | { |
160 | ep->base.dead = 1; | 160 | ep->base.dead = 1; |
161 | |||
162 | ep->base.sk->sk_state = SCTP_SS_CLOSED; | ||
163 | |||
164 | /* Unlink this endpoint, so we can't find it again! */ | ||
165 | sctp_unhash_endpoint(ep); | ||
166 | |||
161 | sctp_endpoint_put(ep); | 167 | sctp_endpoint_put(ep); |
162 | } | 168 | } |
163 | 169 | ||
@@ -166,11 +172,6 @@ static void sctp_endpoint_destroy(struct sctp_endpoint *ep) | |||
166 | { | 172 | { |
167 | SCTP_ASSERT(ep->base.dead, "Endpoint is not dead", return); | 173 | SCTP_ASSERT(ep->base.dead, "Endpoint is not dead", return); |
168 | 174 | ||
169 | ep->base.sk->sk_state = SCTP_SS_CLOSED; | ||
170 | |||
171 | /* Unlink this endpoint, so we can't find it again! */ | ||
172 | sctp_unhash_endpoint(ep); | ||
173 | |||
174 | /* Free up the HMAC transform. */ | 175 | /* Free up the HMAC transform. */ |
175 | sctp_crypto_free_tfm(sctp_sk(ep->base.sk)->hmac); | 176 | sctp_crypto_free_tfm(sctp_sk(ep->base.sk)->hmac); |
176 | 177 | ||
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/outqueue.c b/net/sctp/outqueue.c index e5faa351aaad..30b710c54e64 100644 --- a/net/sctp/outqueue.c +++ b/net/sctp/outqueue.c | |||
@@ -691,7 +691,8 @@ int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout) | |||
691 | 691 | ||
692 | if (!new_transport) { | 692 | if (!new_transport) { |
693 | new_transport = asoc->peer.active_path; | 693 | new_transport = asoc->peer.active_path; |
694 | } else if (new_transport->state == SCTP_INACTIVE) { | 694 | } else if ((new_transport->state == SCTP_INACTIVE) || |
695 | (new_transport->state == SCTP_UNCONFIRMED)) { | ||
695 | /* If the chunk is Heartbeat or Heartbeat Ack, | 696 | /* If the chunk is Heartbeat or Heartbeat Ack, |
696 | * send it to chunk->transport, even if it's | 697 | * send it to chunk->transport, even if it's |
697 | * inactive. | 698 | * inactive. |
@@ -848,7 +849,8 @@ int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout) | |||
848 | */ | 849 | */ |
849 | new_transport = chunk->transport; | 850 | new_transport = chunk->transport; |
850 | if (!new_transport || | 851 | if (!new_transport || |
851 | new_transport->state == SCTP_INACTIVE) | 852 | ((new_transport->state == SCTP_INACTIVE) || |
853 | (new_transport->state == SCTP_UNCONFIRMED))) | ||
852 | new_transport = asoc->peer.active_path; | 854 | new_transport = asoc->peer.active_path; |
853 | 855 | ||
854 | /* Change packets if necessary. */ | 856 | /* Change packets if necessary. */ |
@@ -1464,7 +1466,8 @@ static void sctp_check_transmitted(struct sctp_outq *q, | |||
1464 | /* Mark the destination transport address as | 1466 | /* Mark the destination transport address as |
1465 | * active if it is not so marked. | 1467 | * active if it is not so marked. |
1466 | */ | 1468 | */ |
1467 | if (transport->state == SCTP_INACTIVE) { | 1469 | if ((transport->state == SCTP_INACTIVE) || |
1470 | (transport->state == SCTP_UNCONFIRMED)) { | ||
1468 | sctp_assoc_control_transport( | 1471 | sctp_assoc_control_transport( |
1469 | transport->asoc, | 1472 | transport->asoc, |
1470 | transport, | 1473 | transport, |
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 2a8773691695..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 | ||
@@ -2017,7 +2017,7 @@ static int sctp_process_param(struct sctp_association *asoc, | |||
2017 | af->from_addr_param(&addr, param.addr, asoc->peer.port, 0); | 2017 | af->from_addr_param(&addr, param.addr, asoc->peer.port, 0); |
2018 | scope = sctp_scope(peer_addr); | 2018 | scope = sctp_scope(peer_addr); |
2019 | if (sctp_in_scope(&addr, scope)) | 2019 | if (sctp_in_scope(&addr, scope)) |
2020 | if (!sctp_assoc_add_peer(asoc, &addr, gfp, SCTP_ACTIVE)) | 2020 | if (!sctp_assoc_add_peer(asoc, &addr, gfp, SCTP_UNCONFIRMED)) |
2021 | return 0; | 2021 | return 0; |
2022 | break; | 2022 | break; |
2023 | 2023 | ||
@@ -2418,7 +2418,7 @@ static __u16 sctp_process_asconf_param(struct sctp_association *asoc, | |||
2418 | * Due to Resource Shortage'. | 2418 | * Due to Resource Shortage'. |
2419 | */ | 2419 | */ |
2420 | 2420 | ||
2421 | peer = sctp_assoc_add_peer(asoc, &addr, GFP_ATOMIC, SCTP_ACTIVE); | 2421 | peer = sctp_assoc_add_peer(asoc, &addr, GFP_ATOMIC, SCTP_UNCONFIRMED); |
2422 | if (!peer) | 2422 | if (!peer) |
2423 | return SCTP_ERROR_RSRC_LOW; | 2423 | return SCTP_ERROR_RSRC_LOW; |
2424 | 2424 | ||
@@ -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/sm_sideeffect.c b/net/sctp/sm_sideeffect.c index c5beb2ad7ef7..9c10bdec1afe 100644 --- a/net/sctp/sm_sideeffect.c +++ b/net/sctp/sm_sideeffect.c | |||
@@ -430,7 +430,11 @@ static void sctp_do_8_2_transport_strike(struct sctp_association *asoc, | |||
430 | /* The check for association's overall error counter exceeding the | 430 | /* The check for association's overall error counter exceeding the |
431 | * threshold is done in the state function. | 431 | * threshold is done in the state function. |
432 | */ | 432 | */ |
433 | asoc->overall_error_count++; | 433 | /* When probing UNCONFIRMED addresses, the association overall |
434 | * error count is NOT incremented | ||
435 | */ | ||
436 | if (transport->state != SCTP_UNCONFIRMED) | ||
437 | asoc->overall_error_count++; | ||
434 | 438 | ||
435 | if (transport->state != SCTP_INACTIVE && | 439 | if (transport->state != SCTP_INACTIVE && |
436 | (transport->error_count++ >= transport->pathmaxrxt)) { | 440 | (transport->error_count++ >= transport->pathmaxrxt)) { |
@@ -610,7 +614,7 @@ static void sctp_cmd_transport_on(sctp_cmd_seq_t *cmds, | |||
610 | /* Mark the destination transport address as active if it is not so | 614 | /* Mark the destination transport address as active if it is not so |
611 | * marked. | 615 | * marked. |
612 | */ | 616 | */ |
613 | if (t->state == SCTP_INACTIVE) | 617 | if ((t->state == SCTP_INACTIVE) || (t->state == SCTP_UNCONFIRMED)) |
614 | sctp_assoc_control_transport(asoc, t, SCTP_TRANSPORT_UP, | 618 | sctp_assoc_control_transport(asoc, t, SCTP_TRANSPORT_UP, |
615 | SCTP_HEARTBEAT_SUCCESS); | 619 | SCTP_HEARTBEAT_SUCCESS); |
616 | 620 | ||
@@ -620,6 +624,10 @@ static void sctp_cmd_transport_on(sctp_cmd_seq_t *cmds, | |||
620 | */ | 624 | */ |
621 | hbinfo = (sctp_sender_hb_info_t *) chunk->skb->data; | 625 | hbinfo = (sctp_sender_hb_info_t *) chunk->skb->data; |
622 | sctp_transport_update_rto(t, (jiffies - hbinfo->sent_at)); | 626 | sctp_transport_update_rto(t, (jiffies - hbinfo->sent_at)); |
627 | |||
628 | /* Update the heartbeat timer. */ | ||
629 | if (!mod_timer(&t->hb_timer, sctp_transport_timeout(t))) | ||
630 | sctp_transport_hold(t); | ||
623 | } | 631 | } |
624 | 632 | ||
625 | /* Helper function to do a transport reset at the expiry of the hearbeat | 633 | /* Helper function to do a transport reset at the expiry of the hearbeat |
diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index 9e58144f4851..ead3f1b0ea3d 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c | |||
@@ -846,6 +846,7 @@ static sctp_disposition_t sctp_sf_heartbeat(const struct sctp_endpoint *ep, | |||
846 | hbinfo.param_hdr.length = htons(sizeof(sctp_sender_hb_info_t)); | 846 | hbinfo.param_hdr.length = htons(sizeof(sctp_sender_hb_info_t)); |
847 | hbinfo.daddr = transport->ipaddr; | 847 | hbinfo.daddr = transport->ipaddr; |
848 | hbinfo.sent_at = jiffies; | 848 | hbinfo.sent_at = jiffies; |
849 | hbinfo.hb_nonce = transport->hb_nonce; | ||
849 | 850 | ||
850 | /* Send a heartbeat to our peer. */ | 851 | /* Send a heartbeat to our peer. */ |
851 | paylen = sizeof(sctp_sender_hb_info_t); | 852 | paylen = sizeof(sctp_sender_hb_info_t); |
@@ -1048,6 +1049,10 @@ sctp_disposition_t sctp_sf_backbeat_8_3(const struct sctp_endpoint *ep, | |||
1048 | return SCTP_DISPOSITION_DISCARD; | 1049 | return SCTP_DISPOSITION_DISCARD; |
1049 | } | 1050 | } |
1050 | 1051 | ||
1052 | /* Validate the 64-bit random nonce. */ | ||
1053 | if (hbinfo->hb_nonce != link->hb_nonce) | ||
1054 | return SCTP_DISPOSITION_DISCARD; | ||
1055 | |||
1051 | max_interval = link->hbinterval + link->rto; | 1056 | max_interval = link->hbinterval + link->rto; |
1052 | 1057 | ||
1053 | /* Check if the timestamp looks valid. */ | 1058 | /* Check if the timestamp looks valid. */ |
@@ -5278,7 +5283,6 @@ static int sctp_eat_data(const struct sctp_association *asoc, | |||
5278 | datalen -= sizeof(sctp_data_chunk_t); | 5283 | datalen -= sizeof(sctp_data_chunk_t); |
5279 | 5284 | ||
5280 | deliver = SCTP_CMD_CHUNK_ULP; | 5285 | deliver = SCTP_CMD_CHUNK_ULP; |
5281 | chunk->data_accepted = 1; | ||
5282 | 5286 | ||
5283 | /* Think about partial delivery. */ | 5287 | /* Think about partial delivery. */ |
5284 | if ((datalen >= asoc->rwnd) && (!asoc->ulpq.pd_mode)) { | 5288 | if ((datalen >= asoc->rwnd) && (!asoc->ulpq.pd_mode)) { |
@@ -5357,6 +5361,8 @@ static int sctp_eat_data(const struct sctp_association *asoc, | |||
5357 | if (SCTP_CMD_CHUNK_ULP == deliver) | 5361 | if (SCTP_CMD_CHUNK_ULP == deliver) |
5358 | sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_TSN, SCTP_U32(tsn)); | 5362 | sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_TSN, SCTP_U32(tsn)); |
5359 | 5363 | ||
5364 | chunk->data_accepted = 1; | ||
5365 | |||
5360 | /* Note: Some chunks may get overcounted (if we drop) or overcounted | 5366 | /* Note: Some chunks may get overcounted (if we drop) or overcounted |
5361 | * if we renege and the chunk arrives again. | 5367 | * if we renege and the chunk arrives again. |
5362 | */ | 5368 | */ |
diff --git a/net/sctp/socket.c b/net/sctp/socket.c index 0a2c71d0d8aa..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; |
@@ -4977,7 +5021,7 @@ static struct sctp_bind_bucket *sctp_bucket_create( | |||
4977 | /* Caller must hold hashbucket lock for this tb with local BH disabled */ | 5021 | /* Caller must hold hashbucket lock for this tb with local BH disabled */ |
4978 | static void sctp_bucket_destroy(struct sctp_bind_bucket *pp) | 5022 | static void sctp_bucket_destroy(struct sctp_bind_bucket *pp) |
4979 | { | 5023 | { |
4980 | if (hlist_empty(&pp->owner)) { | 5024 | if (pp && hlist_empty(&pp->owner)) { |
4981 | if (pp->next) | 5025 | if (pp->next) |
4982 | pp->next->pprev = pp->pprev; | 5026 | pp->next->pprev = pp->pprev; |
4983 | *(pp->pprev) = pp->next; | 5027 | *(pp->pprev) = pp->next; |
diff --git a/net/sctp/transport.c b/net/sctp/transport.c index 160f62ad1cc5..2763aa93de1a 100644 --- a/net/sctp/transport.c +++ b/net/sctp/transport.c | |||
@@ -49,6 +49,7 @@ | |||
49 | */ | 49 | */ |
50 | 50 | ||
51 | #include <linux/types.h> | 51 | #include <linux/types.h> |
52 | #include <linux/random.h> | ||
52 | #include <net/sctp/sctp.h> | 53 | #include <net/sctp/sctp.h> |
53 | #include <net/sctp/sm.h> | 54 | #include <net/sctp/sm.h> |
54 | 55 | ||
@@ -85,7 +86,6 @@ static struct sctp_transport *sctp_transport_init(struct sctp_transport *peer, | |||
85 | 86 | ||
86 | peer->init_sent_count = 0; | 87 | peer->init_sent_count = 0; |
87 | 88 | ||
88 | peer->state = SCTP_ACTIVE; | ||
89 | peer->param_flags = SPP_HB_DISABLE | | 89 | peer->param_flags = SPP_HB_DISABLE | |
90 | SPP_PMTUD_ENABLE | | 90 | SPP_PMTUD_ENABLE | |
91 | SPP_SACKDELAY_ENABLE; | 91 | SPP_SACKDELAY_ENABLE; |
@@ -109,6 +109,9 @@ static struct sctp_transport *sctp_transport_init(struct sctp_transport *peer, | |||
109 | peer->hb_timer.function = sctp_generate_heartbeat_event; | 109 | peer->hb_timer.function = sctp_generate_heartbeat_event; |
110 | peer->hb_timer.data = (unsigned long)peer; | 110 | peer->hb_timer.data = (unsigned long)peer; |
111 | 111 | ||
112 | /* Initialize the 64-bit random nonce sent with heartbeat. */ | ||
113 | get_random_bytes(&peer->hb_nonce, sizeof(peer->hb_nonce)); | ||
114 | |||
112 | atomic_set(&peer->refcnt, 1); | 115 | atomic_set(&peer->refcnt, 1); |
113 | peer->dead = 0; | 116 | peer->dead = 0; |
114 | 117 | ||
@@ -517,7 +520,9 @@ void sctp_transport_lower_cwnd(struct sctp_transport *transport, | |||
517 | unsigned long sctp_transport_timeout(struct sctp_transport *t) | 520 | unsigned long sctp_transport_timeout(struct sctp_transport *t) |
518 | { | 521 | { |
519 | unsigned long timeout; | 522 | unsigned long timeout; |
520 | timeout = t->hbinterval + t->rto + sctp_jitter(t->rto); | 523 | timeout = t->rto + sctp_jitter(t->rto); |
524 | if (t->state != SCTP_UNCONFIRMED) | ||
525 | timeout += t->hbinterval; | ||
521 | timeout += jiffies; | 526 | timeout += jiffies; |
522 | return timeout; | 527 | return timeout; |
523 | } | 528 | } |