Commit d09fc925 authored by Sridhar Samudrala's avatar Sridhar Samudrala

Merge dyn9-47-18-140.beaverton.ibm.com:/home/sridhar/BK/sctp-2.5

into dyn9-47-18-140.beaverton.ibm.com:/home/sridhar/BK/lksctp-2.5.47
parents 5a5ba3a0 2520f0dc
...@@ -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.
*/ */
...@@ -92,7 +92,7 @@ sctp_association_t *sctp_association_new(const sctp_endpoint_t *ep, ...@@ -92,7 +92,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;
...@@ -368,43 +368,29 @@ sctp_transport_t *sctp_assoc_add_peer(sctp_association_t *asoc, ...@@ -368,43 +368,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.
...@@ -648,62 +634,6 @@ __u16 __sctp_association_get_next_ssn(sctp_association_t *asoc, __u16 sid) ...@@ -648,62 +634,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.
* *
...@@ -712,38 +642,13 @@ int sctp_cmp_addr(const union sctp_addr *ss1, const union sctp_addr *ss2) ...@@ -712,38 +642,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.
...@@ -858,7 +763,8 @@ sctp_transport_t *sctp_assoc_is_match(sctp_association_t *asoc, ...@@ -858,7 +763,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;
...@@ -901,7 +807,7 @@ static void sctp_assoc_bh_rcv(sctp_association_t *asoc) ...@@ -901,7 +807,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);
......
...@@ -2151,12 +2151,13 @@ static long sctp_get_port_local(struct sock *sk, unsigned short snum) ...@@ -2151,12 +2151,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