Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 255333
b: refs/heads/master
c: 8a07eb0
h: refs/heads/master
i:
  255331: f09e082
v: v3
  • Loading branch information
Michio Honda authored and David S. Miller committed Jun 2, 2011
1 parent e6089e1 commit 1879d83
Show file tree
Hide file tree
Showing 7 changed files with 102 additions and 8 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 7dc04d712203eecdc1435a4cd135935c4a297be5
refs/heads/master: 8a07eb0a50aebc8c95478d49c28c7f8419a26cef
2 changes: 2 additions & 0 deletions trunk/include/net/sctp/structs.h
Original file line number Diff line number Diff line change
Expand Up @@ -1913,6 +1913,8 @@ struct sctp_association {
* after reaching 4294967295.
*/
__u32 addip_serial;
union sctp_addr *asconf_addr_del_pending;
int src_out_of_asoc_ok;

/* SCTP AUTH: list of the endpoint shared keys. These
* keys are provided out of band by the user applicaton
Expand Down
6 changes: 6 additions & 0 deletions trunk/net/sctp/associola.c
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,8 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a
asoc->peer.asconf_capable = 0;
if (sctp_addip_noauth)
asoc->peer.asconf_capable = 1;
asoc->asconf_addr_del_pending = NULL;
asoc->src_out_of_asoc_ok = 0;

/* Create an input queue. */
sctp_inq_init(&asoc->base.inqueue);
Expand Down Expand Up @@ -446,6 +448,10 @@ void sctp_association_free(struct sctp_association *asoc)

sctp_asconf_queue_teardown(asoc);

/* Free pending address space being deleted */
if (asoc->asconf_addr_del_pending != NULL)
kfree(asoc->asconf_addr_del_pending);

/* AUTH - Free the endpoint shared keys */
sctp_auth_destroy_keys(&asoc->endpoint_shared_keys);

Expand Down
13 changes: 13 additions & 0 deletions trunk/net/sctp/outqueue.c
Original file line number Diff line number Diff line change
Expand Up @@ -754,6 +754,16 @@ static int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)
*/

list_for_each_entry_safe(chunk, tmp, &q->control_chunk_list, list) {
/* RFC 5061, 5.3
* F1) This means that until such time as the ASCONF
* containing the add is acknowledged, the sender MUST
* NOT use the new IP address as a source for ANY SCTP
* packet except on carrying an ASCONF Chunk.
*/
if (asoc->src_out_of_asoc_ok &&
chunk->chunk_hdr->type != SCTP_CID_ASCONF)
continue;

list_del_init(&chunk->list);

/* Pick the right transport to use. */
Expand Down Expand Up @@ -881,6 +891,9 @@ static int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)
}
}

if (q->asoc->src_out_of_asoc_ok)
goto sctp_flush_out;

/* Is it OK to send data chunks? */
switch (asoc->state) {
case SCTP_STATE_COOKIE_ECHOED:
Expand Down
4 changes: 3 additions & 1 deletion trunk/net/sctp/protocol.c
Original file line number Diff line number Diff line change
Expand Up @@ -503,7 +503,9 @@ static void sctp_v4_get_dst(struct sctp_transport *t, union sctp_addr *saddr,
sctp_v4_dst_saddr(&dst_saddr, fl4, htons(bp->port));
rcu_read_lock();
list_for_each_entry_rcu(laddr, &bp->address_list, list) {
if (!laddr->valid || (laddr->state != SCTP_ADDR_SRC))
if (!laddr->valid || (laddr->state == SCTP_ADDR_DEL) ||
(laddr->state != SCTP_ADDR_SRC &&
!asoc->src_out_of_asoc_ok))
continue;
if (sctp_v4_cmp_addr(&dst_saddr, &laddr->a))
goto out_unlock;
Expand Down
27 changes: 27 additions & 0 deletions trunk/net/sctp/sm_make_chunk.c
Original file line number Diff line number Diff line change
Expand Up @@ -2768,6 +2768,7 @@ struct sctp_chunk *sctp_make_asconf_update_ip(struct sctp_association *asoc,
int addr_param_len = 0;
int totallen = 0;
int i;
int del_pickup = 0;

/* Get total length of all the address parameters. */
addr_buf = addrs;
Expand All @@ -2780,6 +2781,13 @@ struct sctp_chunk *sctp_make_asconf_update_ip(struct sctp_association *asoc,
totallen += addr_param_len;

addr_buf += af->sockaddr_len;
if (asoc->asconf_addr_del_pending && !del_pickup) {
/* reuse the parameter length from the same scope one */
totallen += paramlen;
totallen += addr_param_len;
del_pickup = 1;
SCTP_DEBUG_PRINTK("mkasconf_update_ip: picked same-scope del_pending addr, totallen for all addresses is %d\n", totallen);
}
}

/* Create an asconf chunk with the required length. */
Expand All @@ -2802,6 +2810,17 @@ struct sctp_chunk *sctp_make_asconf_update_ip(struct sctp_association *asoc,

addr_buf += af->sockaddr_len;
}
if (flags == SCTP_PARAM_ADD_IP && del_pickup) {
addr = asoc->asconf_addr_del_pending;
af = sctp_get_af_specific(addr->v4.sin_family);
addr_param_len = af->to_addr_param(addr, &addr_param);
param.param_hdr.type = SCTP_PARAM_DEL_IP;
param.param_hdr.length = htons(paramlen + addr_param_len);
param.crr_id = i;

sctp_addto_chunk(retval, paramlen, &param);
sctp_addto_chunk(retval, addr_param_len, &addr_param);
}
return retval;
}

Expand Down Expand Up @@ -3224,6 +3243,11 @@ static void sctp_asconf_param_success(struct sctp_association *asoc,
case SCTP_PARAM_DEL_IP:
local_bh_disable();
sctp_del_bind_addr(bp, &addr);
if (asoc->asconf_addr_del_pending != NULL &&
sctp_cmp_addr_exact(asoc->asconf_addr_del_pending, &addr)) {
kfree(asoc->asconf_addr_del_pending);
asoc->asconf_addr_del_pending = NULL;
}
local_bh_enable();
list_for_each_entry(transport, &asoc->peer.transport_addr_list,
transports) {
Expand Down Expand Up @@ -3381,6 +3405,9 @@ int sctp_process_asconf_ack(struct sctp_association *asoc,
asconf_len -= length;
}

if (no_err && asoc->src_out_of_asoc_ok)
asoc->src_out_of_asoc_ok = 0;

/* Free the cached last sent asconf chunk. */
list_del_init(&asconf->transmitted_list);
sctp_chunk_free(asconf);
Expand Down
56 changes: 50 additions & 6 deletions trunk/net/sctp/socket.c
Original file line number Diff line number Diff line change
Expand Up @@ -583,10 +583,6 @@ static int sctp_send_asconf_add_ip(struct sock *sk,
goto out;
}

retval = sctp_send_asconf(asoc, chunk);
if (retval)
goto out;

/* Add the new addresses to the bind address list with
* use_as_src set to 0.
*/
Expand All @@ -599,6 +595,23 @@ static int sctp_send_asconf_add_ip(struct sock *sk,
SCTP_ADDR_NEW, GFP_ATOMIC);
addr_buf += af->sockaddr_len;
}
if (asoc->src_out_of_asoc_ok) {
struct sctp_transport *trans;

list_for_each_entry(trans,
&asoc->peer.transport_addr_list, transports) {
/* Clear the source and route cache */
dst_release(trans->dst);
trans->cwnd = min(4*asoc->pathmtu, max_t(__u32,
2*asoc->pathmtu, 4380));
trans->ssthresh = asoc->peer.i.a_rwnd;
trans->rto = asoc->rto_initial;
trans->rtt = trans->srtt = trans->rttvar = 0;
sctp_transport_route(trans, NULL,
sctp_sk(asoc->base.sk));
}
}
retval = sctp_send_asconf(asoc, chunk);
}

out:
Expand Down Expand Up @@ -715,7 +728,9 @@ static int sctp_send_asconf_del_ip(struct sock *sk,
struct sctp_sockaddr_entry *saddr;
int i;
int retval = 0;
int stored = 0;

chunk = NULL;
if (!sctp_addip_enable)
return retval;

Expand Down Expand Up @@ -766,8 +781,33 @@ static int sctp_send_asconf_del_ip(struct sock *sk,
bp = &asoc->base.bind_addr;
laddr = sctp_find_unmatch_addr(bp, (union sctp_addr *)addrs,
addrcnt, sp);
if (!laddr)
continue;
if ((laddr == NULL) && (addrcnt == 1)) {
if (asoc->asconf_addr_del_pending)
continue;
asoc->asconf_addr_del_pending =
kzalloc(sizeof(union sctp_addr), GFP_ATOMIC);
asoc->asconf_addr_del_pending->sa.sa_family =
addrs->sa_family;
asoc->asconf_addr_del_pending->v4.sin_port =
htons(bp->port);
if (addrs->sa_family == AF_INET) {
struct sockaddr_in *sin;

sin = (struct sockaddr_in *)addrs;
asoc->asconf_addr_del_pending->v4.sin_addr.s_addr = sin->sin_addr.s_addr;
} else if (addrs->sa_family == AF_INET6) {
struct sockaddr_in6 *sin6;

sin6 = (struct sockaddr_in6 *)addrs;
ipv6_addr_copy(&asoc->asconf_addr_del_pending->v6.sin6_addr, &sin6->sin6_addr);
}
SCTP_DEBUG_PRINTK_IPADDR("send_asconf_del_ip: keep the last address asoc: %p ",
" at %p\n", asoc, asoc->asconf_addr_del_pending,
asoc->asconf_addr_del_pending);
asoc->src_out_of_asoc_ok = 1;
stored = 1;
goto skip_mkasconf;
}

/* We do not need RCU protection throughout this loop
* because this is done under a socket lock from the
Expand All @@ -780,6 +820,7 @@ static int sctp_send_asconf_del_ip(struct sock *sk,
goto out;
}

skip_mkasconf:
/* Reset use_as_src flag for the addresses in the bind address
* list that are to be deleted.
*/
Expand All @@ -805,6 +846,9 @@ static int sctp_send_asconf_del_ip(struct sock *sk,
sctp_sk(asoc->base.sk));
}

if (stored)
/* We don't need to transmit ASCONF */
continue;
retval = sctp_send_asconf(asoc, chunk);
}
out:
Expand Down

0 comments on commit 1879d83

Please sign in to comment.