Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 247000
b: refs/heads/master
c: 9914ae3
h: refs/heads/master
v: v3
  • Loading branch information
Vlad Yasevich authored and David S. Miller committed Apr 27, 2011
1 parent ac88488 commit 3019e3d
Show file tree
Hide file tree
Showing 6 changed files with 113 additions and 128 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: 625034113bd45c71fb9e329f52f25fef9e6993a3
refs/heads/master: 9914ae3ca770389a3bec3114d0a07532a7f235dd
14 changes: 6 additions & 8 deletions trunk/include/net/sctp/structs.h
Original file line number Diff line number Diff line change
Expand Up @@ -566,17 +566,15 @@ struct sctp_af {
int __user *optlen);
struct dst_entry *(*get_dst) (struct sctp_association *asoc,
union sctp_addr *daddr,
union sctp_addr *saddr);
union sctp_addr *saddr,
struct flowi *fl,
struct sock *sk);
void (*get_saddr) (struct sctp_sock *sk,
struct sctp_association *asoc,
struct dst_entry *dst,
struct sctp_transport *t,
union sctp_addr *daddr,
union sctp_addr *saddr);
struct flowi *fl);
void (*copy_addrlist) (struct list_head *,
struct net_device *);
void (*dst_saddr) (union sctp_addr *saddr,
struct dst_entry *dst,
__be16 port);
int (*cmp_addr) (const union sctp_addr *addr1,
const union sctp_addr *addr2);
void (*addr_copy) (union sctp_addr *dst,
Expand Down Expand Up @@ -1061,7 +1059,7 @@ void sctp_transport_set_owner(struct sctp_transport *,
struct sctp_association *);
void sctp_transport_route(struct sctp_transport *, union sctp_addr *,
struct sctp_sock *);
void sctp_transport_pmtu(struct sctp_transport *);
void sctp_transport_pmtu(struct sctp_transport *, struct sock *sk);
void sctp_transport_free(struct sctp_transport *);
void sctp_transport_reset_timers(struct sctp_transport *);
void sctp_transport_hold(struct sctp_transport *);
Expand Down
161 changes: 73 additions & 88 deletions trunk/net/sctp/ipv6.c
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,10 @@

static inline int sctp_v6_addr_match_len(union sctp_addr *s1,
union sctp_addr *s2);
static void sctp_v6_to_addr(union sctp_addr *addr, struct in6_addr *saddr,
__be16 port);
static int sctp_v6_cmp_addr(const union sctp_addr *addr1,
const union sctp_addr *addr2);

/* Event handler for inet6 address addition/deletion events.
* The sctp_local_addr_list needs to be protocted by a spin lock since
Expand Down Expand Up @@ -245,73 +249,99 @@ static int sctp_v6_xmit(struct sk_buff *skb, struct sctp_transport *transport)
*/
static struct dst_entry *sctp_v6_get_dst(struct sctp_association *asoc,
union sctp_addr *daddr,
union sctp_addr *saddr)
union sctp_addr *saddr,
struct flowi *fl,
struct sock *sk)
{
struct dst_entry *dst = NULL;
struct flowi6 fl6;
struct flowi6 *fl6 = &fl->u.ip6;
struct sctp_bind_addr *bp;
struct sctp_sockaddr_entry *laddr;
union sctp_addr *baddr = NULL;
union sctp_addr dst_saddr;
__u8 matchlen = 0;
__u8 bmatchlen;
sctp_scope_t scope;
int err = 0;

memset(&fl6, 0, sizeof(fl6));
ipv6_addr_copy(&fl6.daddr, &daddr->v6.sin6_addr);
memset(fl6, 0, sizeof(struct flowi6));
ipv6_addr_copy(&fl6->daddr, &daddr->v6.sin6_addr);
if (ipv6_addr_type(&daddr->v6.sin6_addr) & IPV6_ADDR_LINKLOCAL)
fl6.flowi6_oif = daddr->v6.sin6_scope_id;
fl6->flowi6_oif = daddr->v6.sin6_scope_id;


SCTP_DEBUG_PRINTK("%s: DST=%pI6 ", __func__, &fl6.daddr);
SCTP_DEBUG_PRINTK("%s: DST=%pI6 ", __func__, &fl6->daddr);

if (saddr) {
ipv6_addr_copy(&fl6.saddr, &saddr->v6.sin6_addr);
SCTP_DEBUG_PRINTK("SRC=%pI6 - ", &fl6.saddr);
ipv6_addr_copy(&fl6->saddr, &saddr->v6.sin6_addr);
SCTP_DEBUG_PRINTK("SRC=%pI6 - ", &fl6->saddr);
}

dst = ip6_route_output(&init_net, NULL, &fl6);
err = ip6_dst_lookup(sk, &dst, fl6);
if (!asoc || saddr)
goto out;

if (dst->error) {
dst_release(dst);
dst = NULL;
bp = &asoc->base.bind_addr;
scope = sctp_scope(daddr);
/* Walk through the bind address list and try to get a dst that
* matches a bind address as the source address.
bp = &asoc->base.bind_addr;
scope = sctp_scope(daddr);
/* ip6_dst_lookup has filled in the fl6->saddr for us. Check
* to see if we can use it.
*/
if (!err) {
/* Walk through the bind address list and look for a bind
* address that matches the source address of the returned dst.
*/
sctp_v6_to_addr(&dst_saddr, &fl6->saddr, htons(bp->port));
rcu_read_lock();
list_for_each_entry_rcu(laddr, &bp->address_list, list) {
if (!laddr->valid)
if (!laddr->valid || (laddr->state != SCTP_ADDR_SRC))
continue;
if ((laddr->state == SCTP_ADDR_SRC) &&
(laddr->a.sa.sa_family == AF_INET6) &&
(scope <= sctp_scope(&laddr->a))) {
bmatchlen = sctp_v6_addr_match_len(daddr,
&laddr->a);
if (!baddr || (matchlen < bmatchlen)) {
baddr = &laddr->a;
matchlen = bmatchlen;
}

/* Do not compare against v4 addrs */
if ((laddr->a.sa.sa_family == AF_INET6) &&
(sctp_v6_cmp_addr(&dst_saddr, &laddr->a))) {
rcu_read_unlock();
goto out;
}
}
rcu_read_unlock();
if (baddr) {
ipv6_addr_copy(&fl6.saddr, &baddr->v6.sin6_addr);
dst = ip6_route_output(&init_net, NULL, &fl6);
/* None of the bound addresses match the source address of the
* dst. So release it.
*/
dst_release(dst);
dst = NULL;
}

/* Walk through the bind address list and try to get the
* best source address for a given destination.
*/
rcu_read_lock();
list_for_each_entry_rcu(laddr, &bp->address_list, list) {
if (!laddr->valid && laddr->state != SCTP_ADDR_SRC)
continue;
if ((laddr->a.sa.sa_family == AF_INET6) &&
(scope <= sctp_scope(&laddr->a))) {
bmatchlen = sctp_v6_addr_match_len(daddr, &laddr->a);
if (!baddr || (matchlen < bmatchlen)) {
baddr = &laddr->a;
matchlen = bmatchlen;
}
}
}
rcu_read_unlock();
if (baddr) {
ipv6_addr_copy(&fl6->saddr, &baddr->v6.sin6_addr);
err = ip6_dst_lookup(sk, &dst, fl6);
}

out:
if (!dst->error) {
if (!err) {
struct rt6_info *rt;
rt = (struct rt6_info *)dst;
SCTP_DEBUG_PRINTK("rt6_dst:%pI6 rt6_src:%pI6\n",
&rt->rt6i_dst.addr, &rt->rt6i_src.addr);
&rt->rt6i_dst.addr, &fl6->saddr);
return dst;
}
SCTP_DEBUG_PRINTK("NO ROUTE\n");
dst_release(dst);
return NULL;
}

Expand All @@ -328,64 +358,21 @@ static inline int sctp_v6_addr_match_len(union sctp_addr *s1,
* and asoc's bind address list.
*/
static void sctp_v6_get_saddr(struct sctp_sock *sk,
struct sctp_association *asoc,
struct dst_entry *dst,
struct sctp_transport *t,
union sctp_addr *daddr,
union sctp_addr *saddr)
struct flowi *fl)
{
struct sctp_bind_addr *bp;
struct sctp_sockaddr_entry *laddr;
sctp_scope_t scope;
union sctp_addr *baddr = NULL;
__u8 matchlen = 0;
__u8 bmatchlen;
struct flowi6 *fl6 = &fl->u.ip6;
union sctp_addr *saddr = &t->saddr;

SCTP_DEBUG_PRINTK("%s: asoc:%p dst:%p daddr:%pI6 ",
__func__, asoc, dst, &daddr->v6.sin6_addr);

if (!asoc) {
ipv6_dev_get_saddr(sock_net(sctp_opt2sk(sk)),
dst ? ip6_dst_idev(dst)->dev : NULL,
&daddr->v6.sin6_addr,
inet6_sk(&sk->inet.sk)->srcprefs,
&saddr->v6.sin6_addr);
SCTP_DEBUG_PRINTK("saddr from ipv6_get_saddr: %pI6\n",
&saddr->v6.sin6_addr);
return;
}

scope = sctp_scope(daddr);
__func__, t->asoc, t->dst, &daddr->v6.sin6_addr);

bp = &asoc->base.bind_addr;

/* Go through the bind address list and find the best source address
* that matches the scope of the destination address.
*/
rcu_read_lock();
list_for_each_entry_rcu(laddr, &bp->address_list, list) {
if (!laddr->valid)
continue;
if ((laddr->state == SCTP_ADDR_SRC) &&
(laddr->a.sa.sa_family == AF_INET6) &&
(scope <= sctp_scope(&laddr->a))) {
bmatchlen = sctp_v6_addr_match_len(daddr, &laddr->a);
if (!baddr || (matchlen < bmatchlen)) {
baddr = &laddr->a;
matchlen = bmatchlen;
}
}
}

if (baddr) {
memcpy(saddr, baddr, sizeof(union sctp_addr));
SCTP_DEBUG_PRINTK("saddr: %pI6\n", &saddr->v6.sin6_addr);
} else {
pr_err("%s: asoc:%p Could not find a valid source "
"address for the dest:%pI6\n",
__func__, asoc, &daddr->v6.sin6_addr);
if (t->dst) {
saddr->v6.sin6_family = AF_INET6;
ipv6_addr_copy(&saddr->v6.sin6_addr, &fl6->saddr);
}

rcu_read_unlock();
}

/* Make a copy of all potential local addresses. */
Expand Down Expand Up @@ -507,14 +494,13 @@ static int sctp_v6_to_addr_param(const union sctp_addr *addr,
return length;
}

/* Initialize a sctp_addr from a dst_entry. */
static void sctp_v6_dst_saddr(union sctp_addr *addr, struct dst_entry *dst,
/* Initialize a sctp_addr from struct in6_addr. */
static void sctp_v6_to_addr(union sctp_addr *addr, struct in6_addr *saddr,
__be16 port)
{
struct rt6_info *rt = (struct rt6_info *)dst;
addr->sa.sa_family = AF_INET6;
addr->v6.sin6_port = port;
ipv6_addr_copy(&addr->v6.sin6_addr, &rt->rt6i_src.addr);
ipv6_addr_copy(&addr->v6.sin6_addr, saddr);
}

/* Compare addresses exactly.
Expand Down Expand Up @@ -1001,7 +987,6 @@ static struct sctp_af sctp_af_inet6 = {
.to_sk_daddr = sctp_v6_to_sk_daddr,
.from_addr_param = sctp_v6_from_addr_param,
.to_addr_param = sctp_v6_to_addr_param,
.dst_saddr = sctp_v6_dst_saddr,
.cmp_addr = sctp_v6_cmp_addr,
.scope = sctp_v6_scope,
.addr_valid = sctp_v6_addr_valid,
Expand Down
47 changes: 22 additions & 25 deletions trunk/net/sctp/protocol.c
Original file line number Diff line number Diff line change
Expand Up @@ -465,33 +465,35 @@ static sctp_scope_t sctp_v4_scope(union sctp_addr *addr)
*/
static struct dst_entry *sctp_v4_get_dst(struct sctp_association *asoc,
union sctp_addr *daddr,
union sctp_addr *saddr)
union sctp_addr *saddr,
struct flowi *fl,
struct sock *sk)
{
struct rtable *rt;
struct flowi4 fl4;
struct flowi4 *fl4 = &fl->u.ip4;
struct sctp_bind_addr *bp;
struct sctp_sockaddr_entry *laddr;
struct dst_entry *dst = NULL;
union sctp_addr dst_saddr;

memset(&fl4, 0x0, sizeof(struct flowi4));
fl4.daddr = daddr->v4.sin_addr.s_addr;
fl4.fl4_dport = daddr->v4.sin_port;
fl4.flowi4_proto = IPPROTO_SCTP;
memset(fl4, 0x0, sizeof(struct flowi4));
fl4->daddr = daddr->v4.sin_addr.s_addr;
fl4->fl4_dport = daddr->v4.sin_port;
fl4->flowi4_proto = IPPROTO_SCTP;
if (asoc) {
fl4.flowi4_tos = RT_CONN_FLAGS(asoc->base.sk);
fl4.flowi4_oif = asoc->base.sk->sk_bound_dev_if;
fl4.fl4_sport = htons(asoc->base.bind_addr.port);
fl4->flowi4_tos = RT_CONN_FLAGS(asoc->base.sk);
fl4->flowi4_oif = asoc->base.sk->sk_bound_dev_if;
fl4->fl4_sport = htons(asoc->base.bind_addr.port);
}
if (saddr) {
fl4.saddr = saddr->v4.sin_addr.s_addr;
fl4.fl4_sport = saddr->v4.sin_port;
fl4->saddr = saddr->v4.sin_addr.s_addr;
fl4->fl4_sport = saddr->v4.sin_port;
}

SCTP_DEBUG_PRINTK("%s: DST:%pI4, SRC:%pI4 - ",
__func__, &fl4.daddr, &fl4.saddr);
__func__, &fl4->daddr, &fl4->saddr);

rt = ip_route_output_key(&init_net, &fl4);
rt = ip_route_output_key(&init_net, fl4);
if (!IS_ERR(rt))
dst = &rt->dst;

Expand Down Expand Up @@ -533,9 +535,9 @@ static struct dst_entry *sctp_v4_get_dst(struct sctp_association *asoc,
continue;
if ((laddr->state == SCTP_ADDR_SRC) &&
(AF_INET == laddr->a.sa.sa_family)) {
fl4.saddr = laddr->a.v4.sin_addr.s_addr;
fl4.fl4_sport = laddr->a.v4.sin_port;
rt = ip_route_output_key(&init_net, &fl4);
fl4->saddr = laddr->a.v4.sin_addr.s_addr;
fl4->fl4_sport = laddr->a.v4.sin_port;
rt = ip_route_output_key(&init_net, fl4);
if (!IS_ERR(rt)) {
dst = &rt->dst;
goto out_unlock;
Expand All @@ -559,19 +561,15 @@ static struct dst_entry *sctp_v4_get_dst(struct sctp_association *asoc,
* to cache it separately and hence this is an empty routine.
*/
static void sctp_v4_get_saddr(struct sctp_sock *sk,
struct sctp_association *asoc,
struct dst_entry *dst,
struct sctp_transport *t,
union sctp_addr *daddr,
union sctp_addr *saddr)
struct flowi *fl)
{
struct rtable *rt = (struct rtable *)dst;

if (!asoc)
return;
union sctp_addr *saddr = &t->saddr;
struct rtable *rt = (struct rtable *)t->dst;

if (rt) {
saddr->v4.sin_family = AF_INET;
saddr->v4.sin_port = htons(asoc->base.bind_addr.port);
saddr->v4.sin_addr.s_addr = rt->rt_src;
}
}
Expand Down Expand Up @@ -950,7 +948,6 @@ static struct sctp_af sctp_af_inet = {
.to_sk_daddr = sctp_v4_to_sk_daddr,
.from_addr_param = sctp_v4_from_addr_param,
.to_addr_param = sctp_v4_to_addr_param,
.dst_saddr = sctp_v4_dst_saddr,
.cmp_addr = sctp_v4_cmp_addr,
.addr_valid = sctp_v4_addr_valid,
.inaddr_any = sctp_v4_inaddr_any,
Expand Down
2 changes: 1 addition & 1 deletion trunk/net/sctp/socket.c
Original file line number Diff line number Diff line change
Expand Up @@ -2287,7 +2287,7 @@ static int sctp_apply_peer_addr_params(struct sctp_paddrparams *params,
trans->param_flags =
(trans->param_flags & ~SPP_PMTUD) | pmtud_change;
if (update) {
sctp_transport_pmtu(trans);
sctp_transport_pmtu(trans, sctp_opt2sk(sp));
sctp_assoc_sync_pmtu(asoc);
}
} else if (asoc) {
Expand Down
Loading

0 comments on commit 3019e3d

Please sign in to comment.