Commit c5124639 authored by Jon Grimm's avatar Jon Grimm

[SCTP] PF_INET6 sockets should accept v4 addresses into association.

Yet more address split out, but with the sideeffect that PF_INET6 
sockets can accept v4 addresses.   Another sideeffect is that this 
fixes an issue with the destination lookup code to deal with wildcards,
as the previous code was not considering the wildcard a match and
consequently doing a second lookup.  
parent 7851956a
...@@ -250,8 +250,10 @@ typedef struct sctp_func { ...@@ -250,8 +250,10 @@ typedef struct sctp_func {
union sctp_addr *saddr); union sctp_addr *saddr);
void (*copy_addrlist) (struct list_head *, void (*copy_addrlist) (struct list_head *,
struct net_device *); struct net_device *);
int (*cmp_saddr) (struct dst_entry *dst, void (*dst_saddr) (union sctp_addr *saddr,
union sctp_addr *saddr); struct dst_entry *dst);
int (*cmp_addr) (const union sctp_addr *addr1,
const union sctp_addr *addr2);
void (*addr_copy) (union sctp_addr *dst, void (*addr_copy) (union sctp_addr *dst,
union sctp_addr *src); union sctp_addr *src);
void (*from_skb) (union sctp_addr *, void (*from_skb) (union sctp_addr *,
...@@ -260,6 +262,7 @@ typedef struct sctp_func { ...@@ -260,6 +262,7 @@ typedef struct sctp_func {
int (*addr_valid) (union sctp_addr *); int (*addr_valid) (union sctp_addr *);
sctp_scope_t (*scope) (union sctp_addr *); sctp_scope_t (*scope) (union sctp_addr *);
void (*inaddr_any) (union sctp_addr *, unsigned short); void (*inaddr_any) (union sctp_addr *, unsigned short);
int (*is_any) (const union sctp_addr *);
__u16 net_header_len; __u16 net_header_len;
int sockaddr_len; int sockaddr_len;
sa_family_t sa_family; sa_family_t sa_family;
...@@ -273,6 +276,9 @@ typedef struct sctp_pf { ...@@ -273,6 +276,9 @@ typedef struct sctp_pf {
void (*event_msgname)(sctp_ulpevent_t *, char *, int *); void (*event_msgname)(sctp_ulpevent_t *, char *, int *);
void (*skb_msgname)(struct sk_buff *, char *, int *); void (*skb_msgname)(struct sk_buff *, char *, int *);
int (*af_supported)(sa_family_t); int (*af_supported)(sa_family_t);
int (*cmp_addr) (const union sctp_addr *,
const union sctp_addr *,
struct sctp_opt *);
struct sctp_func *af; struct sctp_func *af;
} sctp_pf_t; } sctp_pf_t;
...@@ -758,7 +764,8 @@ extern sctp_transport_t *sctp_transport_new(const union sctp_addr *, int); ...@@ -758,7 +764,8 @@ extern sctp_transport_t *sctp_transport_new(const union sctp_addr *, int);
extern sctp_transport_t *sctp_transport_init(sctp_transport_t *, extern sctp_transport_t *sctp_transport_init(sctp_transport_t *,
const union sctp_addr *, int); const union sctp_addr *, int);
extern void sctp_transport_set_owner(sctp_transport_t *, sctp_association_t *); extern void sctp_transport_set_owner(sctp_transport_t *, sctp_association_t *);
extern void sctp_transport_route(sctp_transport_t *, union sctp_addr *); extern void sctp_transport_route(sctp_transport_t *, union sctp_addr *,
struct sctp_opt *);
extern void sctp_transport_free(sctp_transport_t *); extern void sctp_transport_free(sctp_transport_t *);
extern void sctp_transport_destroy(sctp_transport_t *); extern void sctp_transport_destroy(sctp_transport_t *);
extern void sctp_transport_reset_timers(sctp_transport_t *); extern void sctp_transport_reset_timers(sctp_transport_t *);
...@@ -908,7 +915,8 @@ int sctp_bind_addr_copy(sctp_bind_addr_t *dest, const sctp_bind_addr_t *src, ...@@ -908,7 +915,8 @@ int sctp_bind_addr_copy(sctp_bind_addr_t *dest, const sctp_bind_addr_t *src,
int sctp_add_bind_addr(sctp_bind_addr_t *, union sctp_addr *, int sctp_add_bind_addr(sctp_bind_addr_t *, union sctp_addr *,
int priority); int priority);
int sctp_del_bind_addr(sctp_bind_addr_t *, union sctp_addr *); int sctp_del_bind_addr(sctp_bind_addr_t *, union sctp_addr *);
int sctp_bind_addr_has_addr(sctp_bind_addr_t *, const union sctp_addr *); int sctp_bind_addr_match(sctp_bind_addr_t *, const union sctp_addr *,
struct sctp_opt *);
union sctp_params sctp_bind_addrs_to_raw(const sctp_bind_addr_t *bp, union sctp_params sctp_bind_addrs_to_raw(const sctp_bind_addr_t *bp,
int *addrs_len, int *addrs_len,
int priority); int priority);
...@@ -1565,14 +1573,11 @@ __u32 __sctp_association_get_next_tsn(sctp_association_t *); ...@@ -1565,14 +1573,11 @@ __u32 __sctp_association_get_next_tsn(sctp_association_t *);
__u32 __sctp_association_get_tsn_block(sctp_association_t *, int); __u32 __sctp_association_get_tsn_block(sctp_association_t *, int);
__u16 __sctp_association_get_next_ssn(sctp_association_t *, __u16 sid); __u16 __sctp_association_get_next_ssn(sctp_association_t *, __u16 sid);
int sctp_cmp_addr(const union sctp_addr *ss1,
const union sctp_addr *ss2);
int sctp_cmp_addr_exact(const union sctp_addr *ss1, int sctp_cmp_addr_exact(const union sctp_addr *ss1,
const union sctp_addr *ss2); const union sctp_addr *ss2);
sctp_chunk_t *sctp_get_ecne_prepend(sctp_association_t *asoc); sctp_chunk_t *sctp_get_ecne_prepend(sctp_association_t *asoc);
sctp_chunk_t *sctp_get_no_prepend(sctp_association_t *asoc); sctp_chunk_t *sctp_get_no_prepend(sctp_association_t *asoc);
/* A convenience structure to parse out SCTP specific CMSGs. */ /* A convenience structure to parse out SCTP specific CMSGs. */
typedef struct sctp_cmsgs { typedef struct sctp_cmsgs {
struct sctp_initmsg *init; struct sctp_initmsg *init;
......
...@@ -4,36 +4,36 @@ ...@@ -4,36 +4,36 @@
* Copyright (c) 2001-2002 International Business Machines Corp. * Copyright (c) 2001-2002 International Business Machines Corp.
* Copyright (c) 2001 Intel Corp. * Copyright (c) 2001 Intel Corp.
* Copyright (c) 2001 La Monte H.P. Yarroll * Copyright (c) 2001 La Monte H.P. Yarroll
* *
* This file is part of the SCTP kernel reference Implementation * This file is part of the SCTP kernel reference Implementation
* *
* This module provides the abstraction for an SCTP association. * This module provides the abstraction for an SCTP association.
* *
* The SCTP reference implementation is free software; * The SCTP reference implementation is free software;
* you can redistribute it and/or modify it under the terms of * you can redistribute it and/or modify it under the terms of
* the GNU General Public License as published by * the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option) * the Free Software Foundation; either version 2, or (at your option)
* any later version. * any later version.
* *
* The SCTP reference implementation is distributed in the hope that it * The SCTP reference implementation is distributed in the hope that it
* will be useful, but WITHOUT ANY WARRANTY; without even the implied * will be useful, but WITHOUT ANY WARRANTY; without even the implied
* ************************ * ************************
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details. * See the GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with GNU CC; see the file COPYING. If not, write to * along with GNU CC; see the file COPYING. If not, write to
* the Free Software Foundation, 59 Temple Place - Suite 330, * the Free Software Foundation, 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA. * Boston, MA 02111-1307, USA.
* *
* Please send any bug reports or fixes you make to the * Please send any bug reports or fixes you make to the
* email address(es): * email address(es):
* lksctp developers <lksctp-developers@lists.sourceforge.net> * lksctp developers <lksctp-developers@lists.sourceforge.net>
* *
* Or submit a bug report through the following website: * Or submit a bug report through the following website:
* http://www.sf.net/projects/lksctp * http://www.sf.net/projects/lksctp
* *
* Written or modified by: * Written or modified by:
* La Monte H.P. Yarroll <piggy@acm.org> * La Monte H.P. Yarroll <piggy@acm.org>
* Karl Knutson <karl@athena.chicago.il.us> * Karl Knutson <karl@athena.chicago.il.us>
* Jon Grimm <jgrimm@us.ibm.com> * Jon Grimm <jgrimm@us.ibm.com>
...@@ -41,7 +41,7 @@ ...@@ -41,7 +41,7 @@
* Hui Huang <hui.huang@nokia.com> * Hui Huang <hui.huang@nokia.com>
* Sridhar Samudrala <sri@us.ibm.com> * Sridhar Samudrala <sri@us.ibm.com>
* Daisy Chang <daisyc@us.ibm.com> * Daisy Chang <daisyc@us.ibm.com>
* *
* Any bugs reported given to us we will try to fix... any fixes shared will * Any bugs reported given to us we will try to fix... any fixes shared will
* be incorporated into the next SCTP release. * be incorporated into the next SCTP release.
*/ */
...@@ -93,7 +93,7 @@ sctp_association_t *sctp_association_new(const sctp_endpoint_t *ep, ...@@ -93,7 +93,7 @@ sctp_association_t *sctp_association_new(const sctp_endpoint_t *ep,
sctp_association_t *sctp_association_init(sctp_association_t *asoc, sctp_association_t *sctp_association_init(sctp_association_t *asoc,
const sctp_endpoint_t *ep, const sctp_endpoint_t *ep,
const struct sock *sk, const struct sock *sk,
sctp_scope_t scope, sctp_scope_t scope,
int priority) int priority)
{ {
sctp_opt_t *sp; sctp_opt_t *sp;
...@@ -369,43 +369,29 @@ sctp_transport_t *sctp_assoc_add_peer(sctp_association_t *asoc, ...@@ -369,43 +369,29 @@ sctp_transport_t *sctp_assoc_add_peer(sctp_association_t *asoc,
{ {
sctp_transport_t *peer; sctp_transport_t *peer;
sctp_opt_t *sp; sctp_opt_t *sp;
const __u16 *port; unsigned short port;
switch (addr->sa.sa_family) {
case AF_INET:
port = &addr->v4.sin_port;
break;
case AF_INET6:
SCTP_V6(
port = &addr->v6.sin6_port;
break;
);
default: /* AF_INET and AF_INET6 share common port field. */
return NULL; port = addr->v4.sin_port;
};
/* Set the port if it has not been set yet. */ /* Set the port if it has not been set yet. */
if (0 == asoc->peer.port) { if (0 == asoc->peer.port) {
asoc->peer.port = *port; asoc->peer.port = port;
} }
SCTP_ASSERT(*port == asoc->peer.port, ":Invalid port\n", return NULL);
/* Check to see if this is a duplicate. */ /* Check to see if this is a duplicate. */
peer = sctp_assoc_lookup_paddr(asoc, addr); peer = sctp_assoc_lookup_paddr(asoc, addr);
if (peer) if (peer)
return peer; return peer;
peer = sctp_transport_new(addr, priority); peer = sctp_transport_new(addr, priority);
if (NULL == peer) if (!peer)
return NULL; return NULL;
sctp_transport_set_owner(peer, asoc); sctp_transport_set_owner(peer, asoc);
/* Cache a route for the transport. */ /* Cache a route for the transport. */
sctp_transport_route(peer, NULL); sctp_transport_route(peer, NULL, sctp_sk(asoc->base.sk));
/* If this is the first transport addr on this association, /* If this is the first transport addr on this association,
* initialize the association PMTU to the peer's PMTU. * initialize the association PMTU to the peer's PMTU.
...@@ -649,62 +635,6 @@ __u16 __sctp_association_get_next_ssn(sctp_association_t *asoc, __u16 sid) ...@@ -649,62 +635,6 @@ __u16 __sctp_association_get_next_ssn(sctp_association_t *asoc, __u16 sid)
return asoc->ssn[sid]++; return asoc->ssn[sid]++;
} }
/* Compare two addresses to see if they match. Wildcard addresses
* always match within their address family.
*
* FIXME: We do not match address scopes correctly.
*/
int sctp_cmp_addr(const union sctp_addr *ss1, const union sctp_addr *ss2)
{
int len;
const void *base1;
const void *base2;
if (ss1->sa.sa_family != ss2->sa.sa_family)
return 0;
if (ss1->v4.sin_port != ss2->v4.sin_port)
return 0;
switch (ss1->sa.sa_family) {
case AF_INET:
if (INADDR_ANY == ss1->v4.sin_addr.s_addr ||
INADDR_ANY == ss2->v4.sin_addr.s_addr)
goto match;
len = sizeof(struct in_addr);
base1 = &ss1->v4.sin_addr;
base2 = &ss2->v4.sin_addr;
break;
case AF_INET6:
SCTP_V6(
if (IPV6_ADDR_ANY ==
sctp_ipv6_addr_type(&ss1->v6.sin6_addr))
goto match;
if (IPV6_ADDR_ANY ==
sctp_ipv6_addr_type(&ss2->v6.sin6_addr))
goto match;
len = sizeof(struct in6_addr);
base1 = &ss1->v6.sin6_addr;
base2 = &ss2->v6.sin6_addr;
break;
)
default:
printk(KERN_WARNING
"WARNING, bogus socket address family %d\n",
ss1->sa.sa_family);
return 0;
};
return (0 == memcmp(base1, base2, len));
match:
return 1;
}
/* Compare two addresses to see if they match. Wildcard addresses /* Compare two addresses to see if they match. Wildcard addresses
* only match themselves. * only match themselves.
* *
...@@ -713,38 +643,13 @@ int sctp_cmp_addr(const union sctp_addr *ss1, const union sctp_addr *ss2) ...@@ -713,38 +643,13 @@ int sctp_cmp_addr(const union sctp_addr *ss1, const union sctp_addr *ss2)
int sctp_cmp_addr_exact(const union sctp_addr *ss1, int sctp_cmp_addr_exact(const union sctp_addr *ss1,
const union sctp_addr *ss2) const union sctp_addr *ss2)
{ {
int len; struct sctp_func *af;
const void *base1;
const void *base2;
if (ss1->sa.sa_family != ss2->sa.sa_family)
return 0;
if (ss1->v4.sin_port != ss2->v4.sin_port)
return 0;
switch (ss1->sa.sa_family) { af = sctp_get_af_specific(ss1->sa.sa_family);
case AF_INET: if (!af)
len = sizeof(struct in_addr);
base1 = &ss1->v4.sin_addr;
base2 = &ss2->v4.sin_addr;
break;
case AF_INET6:
SCTP_V6(
len = sizeof(struct in6_addr);
base1 = &ss1->v6.sin6_addr;
base2 = &ss2->v6.sin6_addr;
break;
)
default:
printk(KERN_WARNING
"WARNING, bogus socket address family %d\n",
ss1->sa.sa_family);
return 0; return 0;
};
return (0 == memcmp(base1, base2, len)); return af->cmp_addr(ss1, ss2);
} }
/* Return an ecne chunk to get prepended to a packet. /* Return an ecne chunk to get prepended to a packet.
...@@ -859,7 +764,8 @@ sctp_transport_t *sctp_assoc_is_match(sctp_association_t *asoc, ...@@ -859,7 +764,8 @@ sctp_transport_t *sctp_assoc_is_match(sctp_association_t *asoc,
if (!transport) if (!transport)
goto out; goto out;
if (sctp_bind_addr_has_addr(&asoc->base.bind_addr, laddr)) if (sctp_bind_addr_match(&asoc->base.bind_addr, laddr,
sctp_sk(asoc->base.sk)))
goto out; goto out;
} }
transport = NULL; transport = NULL;
...@@ -902,7 +808,7 @@ static void sctp_assoc_bh_rcv(sctp_association_t *asoc) ...@@ -902,7 +808,7 @@ static void sctp_assoc_bh_rcv(sctp_association_t *asoc)
error = sctp_do_sm(SCTP_EVENT_T_CHUNK, SCTP_ST_CHUNK(subtype), error = sctp_do_sm(SCTP_EVENT_T_CHUNK, SCTP_ST_CHUNK(subtype),
state, ep, asoc, chunk, GFP_ATOMIC); state, ep, asoc, chunk, GFP_ATOMIC);
/* Check to see if the association is freed in response to /* Check to see if the association is freed in response to
* the incoming chunk. If so, get out of the while loop. * the incoming chunk. If so, get out of the while loop.
*/ */
if (!sctp_id2assoc(sk, associd)) if (!sctp_id2assoc(sk, associd))
......
...@@ -282,15 +282,16 @@ int sctp_raw_to_bind_addrs(sctp_bind_addr_t *bp, __u8 *raw_addr_list, ...@@ -282,15 +282,16 @@ int sctp_raw_to_bind_addrs(sctp_bind_addr_t *bp, __u8 *raw_addr_list,
* 2nd Level Abstractions * 2nd Level Abstractions
********************************************************************/ ********************************************************************/
/* Does this contain a specified address? */ /* Does this contain a specified address? Allow wildcarding. */
int sctp_bind_addr_has_addr(sctp_bind_addr_t *bp, const union sctp_addr *addr) int sctp_bind_addr_match(sctp_bind_addr_t *bp, const union sctp_addr *addr,
struct sctp_opt *opt)
{ {
struct sockaddr_storage_list *laddr; struct sockaddr_storage_list *laddr;
struct list_head *pos; struct list_head *pos;
list_for_each(pos, &bp->address_list) { list_for_each(pos, &bp->address_list) {
laddr = list_entry(pos, struct sockaddr_storage_list, list); laddr = list_entry(pos, struct sockaddr_storage_list, list);
if (sctp_cmp_addr(&laddr->a, addr)) if (opt->pf->cmp_addr(&laddr->a, addr, opt))
return 1; return 1;
} }
...@@ -323,30 +324,13 @@ static int sctp_copy_one_addr(sctp_bind_addr_t *dest, union sctp_addr *addr, ...@@ -323,30 +324,13 @@ static int sctp_copy_one_addr(sctp_bind_addr_t *dest, union sctp_addr *addr,
return error; return error;
} }
/* Is addr one of the wildcards? */ /* Is this a wildcard address? */
int sctp_is_any(const union sctp_addr *addr) int sctp_is_any(const union sctp_addr *addr)
{ {
int retval = 0; struct sctp_func *af = sctp_get_af_specific(addr->sa.sa_family);
if (!af)
switch (addr->sa.sa_family) { return 0;
case AF_INET: return af->is_any(addr);
if (INADDR_ANY == addr->v4.sin_addr.s_addr)
retval = 1;
break;
case AF_INET6:
SCTP_V6(
if (IPV6_ADDR_ANY ==
sctp_ipv6_addr_type(&addr->v6.sin6_addr))
retval = 1;
);
break;
default:
break;
};
return retval;
} }
/* Is 'addr' valid for 'scope'? */ /* Is 'addr' valid for 'scope'? */
...@@ -354,63 +338,19 @@ int sctp_in_scope(const union sctp_addr *addr, sctp_scope_t scope) ...@@ -354,63 +338,19 @@ int sctp_in_scope(const union sctp_addr *addr, sctp_scope_t scope)
{ {
sctp_scope_t addr_scope = sctp_scope(addr); sctp_scope_t addr_scope = sctp_scope(addr);
switch (addr->sa.sa_family) { /* The unusable SCTP addresses will not be considered with
case AF_INET: * any defined scopes.
/* According to the SCTP IPv4 address scoping document - */
* <draft-stewart-tsvwg-sctp-ipv4-00.txt>, the scope has if (SCTP_SCOPE_UNUSABLE == addr_scope)
* a heirarchy of 5 levels:
* Level 0 - unusable SCTP addresses
* Level 1 - loopback address
* Level 2 - link-local addresses
* Level 3 - private addresses.
* Level 4 - global addresses
* For INIT and INIT-ACK address list, let L be the level of
* of requested destination address, sender and receiver
* SHOULD include all of its addresses with level greater
* than or equal to L.
*/
/* The unusable SCTP addresses will not be considered with
* any defined scopes.
*/
if (SCTP_SCOPE_UNUSABLE == addr_scope)
return 0;
/* Note that we are assuming that the scoping are the same
* for both IPv4 addresses and IPv6 addresses, i.e., if the
* scope is link local, both IPv4 link local addresses and
* IPv6 link local addresses would be treated as in the
* scope. There is no filtering for IPv4 vs. IPv6 addresses
* based on scoping alone.
*/
if (addr_scope <= scope)
return 1;
break;
case AF_INET6:
/* FIXME:
* This is almost certainly wrong since scopes have an
* heirarchy. I don't know what RFC to look at.
* There may be some guidance in the SCTP implementors
* guide (an Internet Draft as of October 2001).
*
* Further verification on the correctness of the IPv6
* scoping is needed. According to the IPv6 scoping draft,
* the link local and site local address may require
* further scoping.
*
* Is the heirachy of the IPv6 scoping the same as what's
* defined for IPv4?
* If the same heirarchy indeed applies to both famiies,
* this function can be simplified with one set of code.
* (see the comments for IPv4 above)
*/
if (addr_scope <= scope)
return 1;
break;
default:
return 0; return 0;
}; /*
* For INIT and INIT-ACK address list, let L be the level of
* of requested destination address, sender and receiver
* SHOULD include all of its addresses with level greater
* than or equal to L.
*/
if (addr_scope <= scope)
return 1;
return 0; return 0;
} }
......
...@@ -243,7 +243,8 @@ sctp_endpoint_t *sctp_endpoint_is_match(sctp_endpoint_t *ep, ...@@ -243,7 +243,8 @@ sctp_endpoint_t *sctp_endpoint_is_match(sctp_endpoint_t *ep,
sctp_read_lock(&ep->base.addr_lock); sctp_read_lock(&ep->base.addr_lock);
if (ep->base.bind_addr.port == laddr->v4.sin_port) { if (ep->base.bind_addr.port == laddr->v4.sin_port) {
if (sctp_bind_addr_has_addr(&ep->base.bind_addr, laddr)) { if (sctp_bind_addr_match(&ep->base.bind_addr, laddr,
sctp_sk(ep->base.sk))) {
retval = ep; retval = ep;
goto out; goto out;
} }
......
...@@ -176,8 +176,8 @@ struct dst_entry *sctp_v6_get_dst(union sctp_addr *daddr, ...@@ -176,8 +176,8 @@ struct dst_entry *sctp_v6_get_dst(union sctp_addr *daddr,
union sctp_addr *saddr) union sctp_addr *saddr)
{ {
struct dst_entry *dst; struct dst_entry *dst;
struct flowi fl = { .nl_u = { .ip6_u = { .daddr = &daddr->v6.sin6_addr, struct flowi fl = {
} } }; .nl_u = { .ip6_u = { .daddr = &daddr->v6.sin6_addr, } } };
SCTP_DEBUG_PRINTK("%s: DST=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ", SCTP_DEBUG_PRINTK("%s: DST=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ",
...@@ -261,22 +261,45 @@ static void sctp_v6_from_skb(union sctp_addr *addr,struct sk_buff *skb, ...@@ -261,22 +261,45 @@ static void sctp_v6_from_skb(union sctp_addr *addr,struct sk_buff *skb,
ipv6_addr_copy(&addr->v6.sin6_addr, from); ipv6_addr_copy(&addr->v6.sin6_addr, from);
} }
/* Check if the dst entry's source addr matches the given source addr. */ /* Initialize a sctp_addr from a dst_entry. */
static int sctp_v6_cmp_saddr(struct dst_entry *dst, union sctp_addr *saddr) static void sctp_v6_dst_saddr(union sctp_addr *addr, struct dst_entry *dst)
{ {
struct rt6_info *rt = (struct rt6_info *)dst; struct rt6_info *rt = (struct rt6_info *)dst;
addr->sa.sa_family = AF_INET6;
ipv6_addr_copy(&addr->v6.sin6_addr, &rt->rt6i_src.addr);
}
/* Compare addresses exactly. Well.. almost exactly; ignore scope_id
* for now. FIXME.
*/
static int sctp_v6_cmp_addr(const union sctp_addr *addr1,
const union sctp_addr *addr2)
{
int match;
if (addr1->sa.sa_family != addr2->sa.sa_family)
return 0;
match = !ipv6_addr_cmp((struct in6_addr *)&addr1->v6.sin6_addr,
(struct in6_addr *)&addr2->v6.sin6_addr);
return ipv6_addr_cmp(&rt->rt6i_src.addr, &saddr->v6.sin6_addr); return match;
} }
/* Initialize addr struct to INADDR_ANY. */ /* Initialize addr struct to INADDR_ANY. */
void sctp_v6_inaddr_any(union sctp_addr *addr, unsigned short port) static void sctp_v6_inaddr_any(union sctp_addr *addr, unsigned short port)
{ {
memset(addr, 0x00, sizeof(union sctp_addr)); memset(addr, 0x00, sizeof(union sctp_addr));
addr->v6.sin6_family = AF_INET6; addr->v6.sin6_family = AF_INET6;
addr->v6.sin6_port = port; addr->v6.sin6_port = port;
} }
/* Is this a wildcard address? */
static int sctp_v6_is_any(const union sctp_addr *addr)
{
int type;
type = ipv6_addr_type((struct in6_addr *)&addr->v6.sin6_addr);
return IPV6_ADDR_ANY == type;
}
/* This function checks if the address is a valid address to be used for /* This function checks if the address is a valid address to be used for
* SCTP. * SCTP.
* *
...@@ -417,6 +440,32 @@ static int sctp_inet6_af_supported(sa_family_t family) ...@@ -417,6 +440,32 @@ static int sctp_inet6_af_supported(sa_family_t family)
} }
} }
/* Address matching with wildcards allowed. This extra level
* of indirection lets us choose whether a PF_INET6 should
* disallow any v4 addresses if we so choose.
*/
static int sctp_inet6_cmp_addr(const union sctp_addr *addr1,
const union sctp_addr *addr2,
struct sctp_opt *opt)
{
struct sctp_func *af1, *af2;
af1 = sctp_get_af_specific(addr1->sa.sa_family);
af2 = sctp_get_af_specific(addr2->sa.sa_family);
if (!af1 || !af2)
return 0;
/* Today, wildcard AF_INET/AF_INET6. */
if (sctp_is_any(addr1) || sctp_is_any(addr2))
return 1;
if (addr1->sa.sa_family != addr2->sa.sa_family)
return 0;
return af1->cmp_addr(addr1, addr2);
}
static struct proto_ops inet6_seqpacket_ops = { static struct proto_ops inet6_seqpacket_ops = {
.family = PF_INET6, .family = PF_INET6,
...@@ -459,10 +508,12 @@ static sctp_func_t sctp_ipv6_specific = { ...@@ -459,10 +508,12 @@ static sctp_func_t sctp_ipv6_specific = {
.get_dst = sctp_v6_get_dst, .get_dst = sctp_v6_get_dst,
.copy_addrlist = sctp_v6_copy_addrlist, .copy_addrlist = sctp_v6_copy_addrlist,
.from_skb = sctp_v6_from_skb, .from_skb = sctp_v6_from_skb,
.cmp_saddr = sctp_v6_cmp_saddr, .dst_saddr = sctp_v6_dst_saddr,
.cmp_addr = sctp_v6_cmp_addr,
.scope = sctp_v6_scope, .scope = sctp_v6_scope,
.addr_valid = sctp_v6_addr_valid, .addr_valid = sctp_v6_addr_valid,
.inaddr_any = sctp_v6_inaddr_any, .inaddr_any = sctp_v6_inaddr_any,
.is_any = sctp_v6_is_any,
.net_header_len = sizeof(struct ipv6hdr), .net_header_len = sizeof(struct ipv6hdr),
.sockaddr_len = sizeof(struct sockaddr_in6), .sockaddr_len = sizeof(struct sockaddr_in6),
.sa_family = AF_INET6, .sa_family = AF_INET6,
...@@ -472,6 +523,7 @@ static sctp_pf_t sctp_pf_inet6_specific = { ...@@ -472,6 +523,7 @@ static sctp_pf_t sctp_pf_inet6_specific = {
.event_msgname = sctp_inet6_event_msgname, .event_msgname = sctp_inet6_event_msgname,
.skb_msgname = sctp_inet6_skb_msgname, .skb_msgname = sctp_inet6_skb_msgname,
.af_supported = sctp_inet6_af_supported, .af_supported = sctp_inet6_af_supported,
.cmp_addr = sctp_inet6_cmp_addr,
.af = &sctp_ipv6_specific, .af = &sctp_ipv6_specific,
}; };
......
...@@ -425,7 +425,7 @@ int sctp_packet_transmit(sctp_packet_t *packet) ...@@ -425,7 +425,7 @@ int sctp_packet_transmit(sctp_packet_t *packet)
dst = transport->dst; dst = transport->dst;
if (!dst || dst->obsolete) { if (!dst || dst->obsolete) {
sctp_transport_route(transport, NULL); sctp_transport_route(transport, NULL, sctp_sk(sk));
} }
nskb->dst = dst_clone(transport->dst); nskb->dst = dst_clone(transport->dst);
......
...@@ -227,12 +227,11 @@ struct dst_entry *sctp_v4_get_dst(union sctp_addr *daddr, ...@@ -227,12 +227,11 @@ struct dst_entry *sctp_v4_get_dst(union sctp_addr *daddr,
union sctp_addr *saddr) union sctp_addr *saddr)
{ {
struct rtable *rt; struct rtable *rt;
struct flowi fl = { struct flowi fl;
.nl_u = {
.ip4_u = { .daddr = memset(&fl, 0x0, sizeof(struct flowi));
daddr->v4.sin_addr.s_addr, }}, fl.fl4_dst = daddr->v4.sin_addr.s_addr;
.proto = IPPROTO_SCTP, fl.proto = IPPROTO_SCTP;
};
if (saddr) if (saddr)
fl.fl4_src = saddr->v4.sin_addr.s_addr; fl.fl4_src = saddr->v4.sin_addr.s_addr;
...@@ -275,22 +274,42 @@ static void sctp_v4_from_skb(union sctp_addr *addr, struct sk_buff *skb, ...@@ -275,22 +274,42 @@ static void sctp_v4_from_skb(union sctp_addr *addr, struct sk_buff *skb,
memcpy(&addr->v4.sin_addr.s_addr, from, sizeof(struct in_addr)); memcpy(&addr->v4.sin_addr.s_addr, from, sizeof(struct in_addr));
} }
/* Check if the dst entry's source addr matches the given source addr. */ /* Initialize a sctp_addr from a dst_entry. */
int sctp_v4_cmp_saddr(struct dst_entry *dst, union sctp_addr *saddr) static void sctp_v4_dst_saddr(union sctp_addr *saddr, struct dst_entry *dst)
{ {
struct rtable *rt = (struct rtable *)dst; struct rtable *rt = (struct rtable *)dst;
saddr->v4.sin_family = AF_INET;
saddr->v4.sin_addr.s_addr = rt->rt_src;
}
/* Compare two addresses exactly. */
static int sctp_v4_cmp_addr(const union sctp_addr *addr1,
const union sctp_addr *addr2)
{
if (addr1->sa.sa_family != addr2->sa.sa_family)
return 0;
if (addr1->v4.sin_port != addr2->v4.sin_port)
return 0;
if (addr1->v4.sin_addr.s_addr != addr2->v4.sin_addr.s_addr)
return 0;
return (rt->rt_src == saddr->v4.sin_addr.s_addr); return 1;
} }
/* Initialize addr struct to INADDR_ANY. */ /* Initialize addr struct to INADDR_ANY. */
void sctp_v4_inaddr_any(union sctp_addr *addr, unsigned short port) static void sctp_v4_inaddr_any(union sctp_addr *addr, unsigned short port)
{ {
addr->v4.sin_family = AF_INET; addr->v4.sin_family = AF_INET;
addr->v4.sin_addr.s_addr = INADDR_ANY; addr->v4.sin_addr.s_addr = INADDR_ANY;
addr->v4.sin_port = port; addr->v4.sin_port = port;
} }
/* Is this a wildcard address? */
static int sctp_v4_is_any(const union sctp_addr *addr)
{
return INADDR_ANY == addr->v4.sin_addr.s_addr;
}
/* This function checks if the address is a valid address to be used for /* This function checks if the address is a valid address to be used for
* SCTP. * SCTP.
* *
...@@ -310,6 +329,16 @@ static int sctp_v4_addr_valid(union sctp_addr *addr) ...@@ -310,6 +329,16 @@ static int sctp_v4_addr_valid(union sctp_addr *addr)
/* Checking the loopback, private and other address scopes as defined in /* Checking the loopback, private and other address scopes as defined in
* RFC 1918. The IPv4 scoping is based on the draft for SCTP IPv4 * RFC 1918. The IPv4 scoping is based on the draft for SCTP IPv4
* scoping <draft-stewart-tsvwg-sctp-ipv4-00.txt>. * scoping <draft-stewart-tsvwg-sctp-ipv4-00.txt>.
*
* Level 0 - unusable SCTP addresses
* Level 1 - loopback address
* Level 2 - link-local addresses
* Level 3 - private addresses.
* Level 4 - global addresses
* For INIT and INIT-ACK address list, let L be the level of
* of requested destination address, sender and receiver
* SHOULD include all of its addresses with level greater
* than or equal to L.
*/ */
static sctp_scope_t sctp_v4_scope(union sctp_addr *addr) static sctp_scope_t sctp_v4_scope(union sctp_addr *addr)
{ {
...@@ -413,7 +442,8 @@ static void sctp_inet_msgname(char *msgname, int *addr_len) ...@@ -413,7 +442,8 @@ static void sctp_inet_msgname(char *msgname, int *addr_len)
} }
/* Copy the primary address of the peer primary address as the msg_name. */ /* Copy the primary address of the peer primary address as the msg_name. */
static void sctp_inet_event_msgname(sctp_ulpevent_t *event, char *msgname, int *addr_len) static void sctp_inet_event_msgname(sctp_ulpevent_t *event, char *msgname,
int *addr_len)
{ {
struct sockaddr_in *sin, *sinfrom; struct sockaddr_in *sin, *sinfrom;
...@@ -448,12 +478,31 @@ static int sctp_inet_af_supported(sa_family_t family) ...@@ -448,12 +478,31 @@ static int sctp_inet_af_supported(sa_family_t family)
return (AF_INET == family); return (AF_INET == family);
} }
/* Address matching with wildcards allowed. */
static int sctp_inet_cmp_addr(const union sctp_addr *addr1,
const union sctp_addr *addr2,
struct sctp_opt *opt)
{
/* PF_INET only supports AF_INET addresses. */
if (addr1->sa.sa_family != addr2->sa.sa_family)
return 0;
if (INADDR_ANY == addr1->v4.sin_addr.s_addr ||
INADDR_ANY == addr2->v4.sin_addr.s_addr)
return 1;
if (addr1->v4.sin_addr.s_addr == addr2->v4.sin_addr.s_addr)
return 1;
return 0;
}
struct sctp_func sctp_ipv4_specific; struct sctp_func sctp_ipv4_specific;
static sctp_pf_t sctp_pf_inet = { static sctp_pf_t sctp_pf_inet = {
.event_msgname = sctp_inet_event_msgname, .event_msgname = sctp_inet_event_msgname,
.skb_msgname = sctp_inet_skb_msgname, .skb_msgname = sctp_inet_skb_msgname,
.af_supported = sctp_inet_af_supported, .af_supported = sctp_inet_af_supported,
.cmp_addr = sctp_inet_cmp_addr,
.af = &sctp_ipv4_specific, .af = &sctp_ipv4_specific,
}; };
...@@ -509,9 +558,11 @@ struct sctp_func sctp_ipv4_specific = { ...@@ -509,9 +558,11 @@ struct sctp_func sctp_ipv4_specific = {
.get_dst = sctp_v4_get_dst, .get_dst = sctp_v4_get_dst,
.copy_addrlist = sctp_v4_copy_addrlist, .copy_addrlist = sctp_v4_copy_addrlist,
.from_skb = sctp_v4_from_skb, .from_skb = sctp_v4_from_skb,
.cmp_saddr = sctp_v4_cmp_saddr, .dst_saddr = sctp_v4_dst_saddr,
.cmp_addr = sctp_v4_cmp_addr,
.addr_valid = sctp_v4_addr_valid, .addr_valid = sctp_v4_addr_valid,
.inaddr_any = sctp_v4_inaddr_any, .inaddr_any = sctp_v4_inaddr_any,
.is_any = sctp_v4_is_any,
.scope = sctp_v4_scope, .scope = sctp_v4_scope,
.net_header_len = sizeof(struct iphdr), .net_header_len = sizeof(struct iphdr),
.sockaddr_len = sizeof(struct sockaddr_in), .sockaddr_len = sizeof(struct sockaddr_in),
......
...@@ -4314,7 +4314,8 @@ sctp_packet_t *sctp_ootb_pkt_new(const sctp_association_t *asoc, ...@@ -4314,7 +4314,8 @@ sctp_packet_t *sctp_ootb_pkt_new(const sctp_association_t *asoc,
/* Cache a route for the transport with the chunk's destination as /* Cache a route for the transport with the chunk's destination as
* the source address. * the source address.
*/ */
sctp_transport_route(transport, (union sctp_addr *)&chunk->dest); sctp_transport_route(transport, (union sctp_addr *)&chunk->dest,
sctp_sk(sctp_get_ctl_sock()));
packet = sctp_packet_init(packet, transport, sport, dport); packet = sctp_packet_init(packet, transport, sport, dport);
packet = sctp_packet_config(packet, vtag, 0, NULL); packet = sctp_packet_config(packet, vtag, 0, NULL);
......
...@@ -2117,12 +2117,13 @@ static long sctp_get_port_local(struct sock *sk, unsigned short snum) ...@@ -2117,12 +2117,13 @@ static long sctp_get_port_local(struct sock *sk, unsigned short snum)
sctp_endpoint_t *ep2; sctp_endpoint_t *ep2;
ep2 = sctp_sk(sk2)->ep; ep2 = sctp_sk(sk2)->ep;
if (!sk_reuse || !sk2->reuse) { if (sk_reuse && sk2->reuse)
if (sctp_bind_addr_has_addr( continue;
&ep2->base.bind_addr, &tmpaddr)) {
goto found; if (sctp_bind_addr_match(&ep2->base.bind_addr,
} &tmpaddr,
} sctp_sk(sk)))
goto found;
} }
found: found:
......
...@@ -203,17 +203,18 @@ void sctp_transport_set_owner(sctp_transport_t *transport, ...@@ -203,17 +203,18 @@ void sctp_transport_set_owner(sctp_transport_t *transport,
/* Caches the dst entry for a transport's destination address and an optional /* Caches the dst entry for a transport's destination address and an optional
* souce address. * souce address.
*/ */
void sctp_transport_route(sctp_transport_t *transport, void sctp_transport_route(sctp_transport_t *transport, union sctp_addr *saddr,
union sctp_addr *saddr) struct sctp_opt *opt)
{ {
sctp_association_t *asoc = transport->asoc; sctp_association_t *asoc = transport->asoc;
sctp_func_t *af = transport->af_specific; struct sctp_func *af = transport->af_specific;
union sctp_addr *daddr = &transport->ipaddr; union sctp_addr *daddr = &transport->ipaddr;
sctp_bind_addr_t *bp; sctp_bind_addr_t *bp;
rwlock_t *addr_lock; rwlock_t *addr_lock;
struct sockaddr_storage_list *laddr; struct sockaddr_storage_list *laddr;
struct list_head *pos; struct list_head *pos;
struct dst_entry *dst; struct dst_entry *dst;
union sctp_addr dst_saddr;
dst = af->get_dst(daddr, saddr); dst = af->get_dst(daddr, saddr);
...@@ -239,7 +240,8 @@ void sctp_transport_route(sctp_transport_t *transport, ...@@ -239,7 +240,8 @@ void sctp_transport_route(sctp_transport_t *transport,
list_for_each(pos, &bp->address_list) { list_for_each(pos, &bp->address_list) {
laddr = list_entry(pos, struct sockaddr_storage_list, laddr = list_entry(pos, struct sockaddr_storage_list,
list); list);
if (af->cmp_saddr(dst, &laddr->a)) af->dst_saddr(&dst_saddr, dst);
if (opt->pf->cmp_addr(&dst_saddr, &laddr->a, opt))
goto out_unlock; goto out_unlock;
} }
sctp_read_unlock(addr_lock); sctp_read_unlock(addr_lock);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment