Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 64995
b: refs/heads/master
c: 559cf71
h: refs/heads/master
i:
  64993: 884a58b
  64991: 996eb09
v: v3
  • Loading branch information
Vlad Yasevich authored and David S. Miller committed Sep 16, 2007
1 parent 298e410 commit 0af58f8
Show file tree
Hide file tree
Showing 9 changed files with 107 additions and 164 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: 293035479942400a7fe8e4f72465d4e4e466b91a
refs/heads/master: 559cf710b07c5e2cfa3fb8d8f4a1320fd84c53f9
7 changes: 3 additions & 4 deletions trunk/include/net/sctp/structs.h
Original file line number Diff line number Diff line change
Expand Up @@ -1155,7 +1155,9 @@ int sctp_bind_addr_copy(struct sctp_bind_addr *dest,
int flags);
int sctp_add_bind_addr(struct sctp_bind_addr *, union sctp_addr *,
__u8 use_as_src, gfp_t gfp);
int sctp_del_bind_addr(struct sctp_bind_addr *, union sctp_addr *);
int sctp_del_bind_addr(struct sctp_bind_addr *, union sctp_addr *,
void (*rcu_call)(struct rcu_head *,
void (*func)(struct rcu_head *)));
int sctp_bind_addr_match(struct sctp_bind_addr *, const union sctp_addr *,
struct sctp_sock *);
union sctp_addr *sctp_find_unmatch_addr(struct sctp_bind_addr *bp,
Expand Down Expand Up @@ -1226,9 +1228,6 @@ struct sctp_ep_common {
* bind_addr.address_list is our set of local IP addresses.
*/
struct sctp_bind_addr bind_addr;

/* Protection during address list comparisons. */
rwlock_t addr_lock;
};


Expand Down
14 changes: 2 additions & 12 deletions trunk/net/sctp/associola.c
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,6 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a

/* Initialize the bind addr area. */
sctp_bind_addr_init(&asoc->base.bind_addr, ep->base.bind_addr.port);
rwlock_init(&asoc->base.addr_lock);

asoc->state = SCTP_STATE_CLOSED;

Expand Down Expand Up @@ -937,8 +936,6 @@ struct sctp_transport *sctp_assoc_is_match(struct sctp_association *asoc,
{
struct sctp_transport *transport;

sctp_read_lock(&asoc->base.addr_lock);

if ((htons(asoc->base.bind_addr.port) == laddr->v4.sin_port) &&
(htons(asoc->peer.port) == paddr->v4.sin_port)) {
transport = sctp_assoc_lookup_paddr(asoc, paddr);
Expand All @@ -952,7 +949,6 @@ struct sctp_transport *sctp_assoc_is_match(struct sctp_association *asoc,
transport = NULL;

out:
sctp_read_unlock(&asoc->base.addr_lock);
return transport;
}

Expand Down Expand Up @@ -1376,19 +1372,13 @@ int sctp_assoc_set_bind_addr_from_cookie(struct sctp_association *asoc,
int sctp_assoc_lookup_laddr(struct sctp_association *asoc,
const union sctp_addr *laddr)
{
int found;
int found = 0;

sctp_read_lock(&asoc->base.addr_lock);
if ((asoc->base.bind_addr.port == ntohs(laddr->v4.sin_port)) &&
sctp_bind_addr_match(&asoc->base.bind_addr, laddr,
sctp_sk(asoc->base.sk))) {
sctp_sk(asoc->base.sk)))
found = 1;
goto out;
}

found = 0;
out:
sctp_read_unlock(&asoc->base.addr_lock);
return found;
}

Expand Down
68 changes: 45 additions & 23 deletions trunk/net/sctp/bind_addr.c
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,11 @@ int sctp_add_bind_addr(struct sctp_bind_addr *bp, union sctp_addr *new,

INIT_LIST_HEAD(&addr->list);
INIT_RCU_HEAD(&addr->rcu);
list_add_tail(&addr->list, &bp->address_list);

/* We always hold a socket lock when calling this function,
* and that acts as a writer synchronizing lock.
*/
list_add_tail_rcu(&addr->list, &bp->address_list);
SCTP_DBG_OBJCNT_INC(addr);

return 0;
Expand All @@ -176,23 +180,35 @@ int sctp_add_bind_addr(struct sctp_bind_addr *bp, union sctp_addr *new,
/* Delete an address from the bind address list in the SCTP_bind_addr
* structure.
*/
int sctp_del_bind_addr(struct sctp_bind_addr *bp, union sctp_addr *del_addr)
int sctp_del_bind_addr(struct sctp_bind_addr *bp, union sctp_addr *del_addr,
void (*rcu_call)(struct rcu_head *head,
void (*func)(struct rcu_head *head)))
{
struct list_head *pos, *temp;
struct sctp_sockaddr_entry *addr;
struct sctp_sockaddr_entry *addr, *temp;

list_for_each_safe(pos, temp, &bp->address_list) {
addr = list_entry(pos, struct sctp_sockaddr_entry, list);
/* We hold the socket lock when calling this function,
* and that acts as a writer synchronizing lock.
*/
list_for_each_entry_safe(addr, temp, &bp->address_list, list) {
if (sctp_cmp_addr_exact(&addr->a, del_addr)) {
/* Found the exact match. */
list_del(pos);
kfree(addr);
SCTP_DBG_OBJCNT_DEC(addr);

return 0;
addr->valid = 0;
list_del_rcu(&addr->list);
break;
}
}

/* Call the rcu callback provided in the args. This function is
* called by both BH packet processing and user side socket option
* processing, but it works on different lists in those 2 contexts.
* Each context provides it's own callback, whether call_rcu_bh()
* or call_rcu(), to make sure that we wait for an appropriate time.
*/
if (addr && !addr->valid) {
rcu_call(&addr->rcu, sctp_local_addr_free);
SCTP_DBG_OBJCNT_DEC(addr);
}

return -EINVAL;
}

Expand Down Expand Up @@ -302,15 +318,20 @@ int sctp_bind_addr_match(struct sctp_bind_addr *bp,
struct sctp_sock *opt)
{
struct sctp_sockaddr_entry *laddr;
struct list_head *pos;

list_for_each(pos, &bp->address_list) {
laddr = list_entry(pos, struct sctp_sockaddr_entry, list);
if (opt->pf->cmp_addr(&laddr->a, addr, opt))
return 1;
int match = 0;

rcu_read_lock();
list_for_each_entry_rcu(laddr, &bp->address_list, list) {
if (!laddr->valid)
continue;
if (opt->pf->cmp_addr(&laddr->a, addr, opt)) {
match = 1;
break;
}
}
rcu_read_unlock();

return 0;
return match;
}

/* Find the first address in the bind address list that is not present in
Expand All @@ -325,18 +346,19 @@ union sctp_addr *sctp_find_unmatch_addr(struct sctp_bind_addr *bp,
union sctp_addr *addr;
void *addr_buf;
struct sctp_af *af;
struct list_head *pos;
int i;

list_for_each(pos, &bp->address_list) {
laddr = list_entry(pos, struct sctp_sockaddr_entry, list);

/* This is only called sctp_send_asconf_del_ip() and we hold
* the socket lock in that code patch, so that address list
* can't change.
*/
list_for_each_entry(laddr, &bp->address_list, list) {
addr_buf = (union sctp_addr *)addrs;
for (i = 0; i < addrcnt; i++) {
addr = (union sctp_addr *)addr_buf;
af = sctp_get_af_specific(addr->v4.sin_family);
if (!af)
return NULL;
break;

if (opt->pf->cmp_addr(&laddr->a, addr, opt))
break;
Expand Down
27 changes: 7 additions & 20 deletions trunk/net/sctp/endpointola.c
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,6 @@ static struct sctp_endpoint *sctp_endpoint_init(struct sctp_endpoint *ep,

/* Initialize the bind addr area */
sctp_bind_addr_init(&ep->base.bind_addr, 0);
rwlock_init(&ep->base.addr_lock);

/* Remember who we are attached to. */
ep->base.sk = sk;
Expand Down Expand Up @@ -225,21 +224,14 @@ void sctp_endpoint_put(struct sctp_endpoint *ep)
struct sctp_endpoint *sctp_endpoint_is_match(struct sctp_endpoint *ep,
const union sctp_addr *laddr)
{
struct sctp_endpoint *retval;
struct sctp_endpoint *retval = NULL;

sctp_read_lock(&ep->base.addr_lock);
if (htons(ep->base.bind_addr.port) == laddr->v4.sin_port) {
if (sctp_bind_addr_match(&ep->base.bind_addr, laddr,
sctp_sk(ep->base.sk))) {
sctp_sk(ep->base.sk)))
retval = ep;
goto out;
}
}

retval = NULL;

out:
sctp_read_unlock(&ep->base.addr_lock);
return retval;
}

Expand All @@ -261,9 +253,7 @@ static struct sctp_association *__sctp_endpoint_lookup_assoc(
list_for_each(pos, &ep->asocs) {
asoc = list_entry(pos, struct sctp_association, asocs);
if (rport == asoc->peer.port) {
sctp_read_lock(&asoc->base.addr_lock);
*transport = sctp_assoc_lookup_paddr(asoc, paddr);
sctp_read_unlock(&asoc->base.addr_lock);

if (*transport)
return asoc;
Expand Down Expand Up @@ -295,20 +285,17 @@ struct sctp_association *sctp_endpoint_lookup_assoc(
int sctp_endpoint_is_peeled_off(struct sctp_endpoint *ep,
const union sctp_addr *paddr)
{
struct list_head *pos;
struct sctp_sockaddr_entry *addr;
struct sctp_bind_addr *bp;

sctp_read_lock(&ep->base.addr_lock);
bp = &ep->base.bind_addr;
list_for_each(pos, &bp->address_list) {
addr = list_entry(pos, struct sctp_sockaddr_entry, list);
if (sctp_has_association(&addr->a, paddr)) {
sctp_read_unlock(&ep->base.addr_lock);
/* This function is called with the socket lock held,
* so the address_list can not change.
*/
list_for_each_entry(addr, &bp->address_list, list) {
if (sctp_has_association(&addr->a, paddr))
return 1;
}
}
sctp_read_unlock(&ep->base.addr_lock);

return 0;
}
Expand Down
12 changes: 5 additions & 7 deletions trunk/net/sctp/ipv6.c
Original file line number Diff line number Diff line change
Expand Up @@ -302,9 +302,7 @@ static void sctp_v6_get_saddr(struct sctp_association *asoc,
union sctp_addr *saddr)
{
struct sctp_bind_addr *bp;
rwlock_t *addr_lock;
struct sctp_sockaddr_entry *laddr;
struct list_head *pos;
sctp_scope_t scope;
union sctp_addr *baddr = NULL;
__u8 matchlen = 0;
Expand All @@ -324,14 +322,14 @@ static void sctp_v6_get_saddr(struct sctp_association *asoc,
scope = sctp_scope(daddr);

bp = &asoc->base.bind_addr;
addr_lock = &asoc->base.addr_lock;

/* Go through the bind address list and find the best source address
* that matches the scope of the destination address.
*/
sctp_read_lock(addr_lock);
list_for_each(pos, &bp->address_list) {
laddr = list_entry(pos, struct sctp_sockaddr_entry, list);
rcu_read_lock();
list_for_each_entry_rcu(laddr, &bp->address_list, list) {
if (!laddr->valid)
continue;
if ((laddr->use_as_src) &&
(laddr->a.sa.sa_family == AF_INET6) &&
(scope <= sctp_scope(&laddr->a))) {
Expand All @@ -353,7 +351,7 @@ static void sctp_v6_get_saddr(struct sctp_association *asoc,
__FUNCTION__, asoc, NIP6(daddr->v6.sin6_addr));
}

sctp_read_unlock(addr_lock);
rcu_read_unlock();
}

/* Make a copy of all potential local addresses. */
Expand Down
25 changes: 10 additions & 15 deletions trunk/net/sctp/protocol.c
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ int sctp_copy_local_addr_list(struct sctp_bind_addr *bp, sctp_scope_t scope,
(copy_flags & SCTP_ADDR6_ALLOWED) &&
(copy_flags & SCTP_ADDR6_PEERSUPP)))) {
error = sctp_add_bind_addr(bp, &addr->a, 1,
GFP_ATOMIC);
GFP_ATOMIC);
if (error)
goto end_copy;
}
Expand Down Expand Up @@ -428,9 +428,7 @@ static struct dst_entry *sctp_v4_get_dst(struct sctp_association *asoc,
struct rtable *rt;
struct flowi fl;
struct sctp_bind_addr *bp;
rwlock_t *addr_lock;
struct sctp_sockaddr_entry *laddr;
struct list_head *pos;
struct dst_entry *dst = NULL;
union sctp_addr dst_saddr;

Expand Down Expand Up @@ -459,23 +457,20 @@ static struct dst_entry *sctp_v4_get_dst(struct sctp_association *asoc,
goto out;

bp = &asoc->base.bind_addr;
addr_lock = &asoc->base.addr_lock;

if (dst) {
/* Walk through the bind address list and look for a bind
* address that matches the source address of the returned dst.
*/
sctp_read_lock(addr_lock);
list_for_each(pos, &bp->address_list) {
laddr = list_entry(pos, struct sctp_sockaddr_entry,
list);
if (!laddr->use_as_src)
rcu_read_lock();
list_for_each_entry_rcu(laddr, &bp->address_list, list) {
if (!laddr->valid || !laddr->use_as_src)
continue;
sctp_v4_dst_saddr(&dst_saddr, dst, htons(bp->port));
if (sctp_v4_cmp_addr(&dst_saddr, &laddr->a))
goto out_unlock;
}
sctp_read_unlock(addr_lock);
rcu_read_unlock();

/* None of the bound addresses match the source address of the
* dst. So release it.
Expand All @@ -487,10 +482,10 @@ static struct dst_entry *sctp_v4_get_dst(struct sctp_association *asoc,
/* Walk through the bind address list and try to get a dst that
* matches a bind address as the source address.
*/
sctp_read_lock(addr_lock);
list_for_each(pos, &bp->address_list) {
laddr = list_entry(pos, struct sctp_sockaddr_entry, list);

rcu_read_lock();
list_for_each_entry_rcu(laddr, &bp->address_list, list) {
if (!laddr->valid)
continue;
if ((laddr->use_as_src) &&
(AF_INET == laddr->a.sa.sa_family)) {
fl.fl4_src = laddr->a.v4.sin_addr.s_addr;
Expand All @@ -502,7 +497,7 @@ static struct dst_entry *sctp_v4_get_dst(struct sctp_association *asoc,
}

out_unlock:
sctp_read_unlock(addr_lock);
rcu_read_unlock();
out:
if (dst)
SCTP_DEBUG_PRINTK("rt_dst:%u.%u.%u.%u, rt_src:%u.%u.%u.%u\n",
Expand Down
18 changes: 6 additions & 12 deletions trunk/net/sctp/sm_make_chunk.c
Original file line number Diff line number Diff line change
Expand Up @@ -1531,7 +1531,7 @@ struct sctp_association *sctp_unpack_cookie(
/* Also, add the destination address. */
if (list_empty(&retval->base.bind_addr.address_list)) {
sctp_add_bind_addr(&retval->base.bind_addr, &chunk->dest, 1,
GFP_ATOMIC);
GFP_ATOMIC);
}

retval->next_tsn = retval->c.initial_tsn;
Expand Down Expand Up @@ -2613,22 +2613,16 @@ static int sctp_asconf_param_success(struct sctp_association *asoc,

switch (asconf_param->param_hdr.type) {
case SCTP_PARAM_ADD_IP:
sctp_local_bh_disable();
sctp_write_lock(&asoc->base.addr_lock);
list_for_each(pos, &bp->address_list) {
saddr = list_entry(pos, struct sctp_sockaddr_entry, list);
/* This is always done in BH context with a socket lock
* held, so the list can not change.
*/
list_for_each_entry(saddr, &bp->address_list, list) {
if (sctp_cmp_addr_exact(&saddr->a, &addr))
saddr->use_as_src = 1;
}
sctp_write_unlock(&asoc->base.addr_lock);
sctp_local_bh_enable();
break;
case SCTP_PARAM_DEL_IP:
sctp_local_bh_disable();
sctp_write_lock(&asoc->base.addr_lock);
retval = sctp_del_bind_addr(bp, &addr);
sctp_write_unlock(&asoc->base.addr_lock);
sctp_local_bh_enable();
retval = sctp_del_bind_addr(bp, &addr, call_rcu_bh);
list_for_each(pos, &asoc->peer.transport_addr_list) {
transport = list_entry(pos, struct sctp_transport,
transports);
Expand Down
Loading

0 comments on commit 0af58f8

Please sign in to comment.