Commit f8dfb3b0 authored by Jon Grimm's avatar Jon Grimm

[SCTP] Addr family cleanup part 2. (jgrimm)

Splitting out yet more code.  New af and pf specific functions. 
parent d9a91e70
......@@ -2,7 +2,7 @@
* Copyright (c) 1999-2000 Cisco, Inc.
* Copyright (c) 1999-2001 Motorola, Inc.
* Copyright (c) 2001 Intel Corp.
* Copyright (c) 2001 International Business Machines Corp.
* Copyright (c) 2001-2002 International Business Machines Corp.
*
* This file is part of the SCTP kernel reference Implementation
*
......@@ -257,6 +257,8 @@ typedef struct sctp_func {
void (*from_skb) (union sctp_addr *,
struct sk_buff *skb,
int saddr);
int (*addr_valid) (union sctp_addr *);
sctp_scope_t (*scope) (union sctp_addr *);
__u16 net_header_len;
int sockaddr_len;
sa_family_t sa_family;
......@@ -269,6 +271,7 @@ sctp_func_t *sctp_get_af_specific(sa_family_t);
typedef struct sctp_pf {
void (*event_msgname)(sctp_ulpevent_t *, char *, int *);
void (*skb_msgname)(struct sk_buff *, char *, int *);
int (*af_supported)(sa_family_t);
} sctp_pf_t;
/* SCTP Socket type: UDP or TCP style. */
......@@ -505,7 +508,7 @@ void *sctp_addto_chunk(sctp_chunk_t *chunk, int len, const void *data);
int sctp_user_addto_chunk(sctp_chunk_t *chunk, int len, struct iovec *data);
sctp_chunk_t *sctp_chunkify(struct sk_buff *, const sctp_association_t *,
struct sock *);
void sctp_init_addrs(sctp_chunk_t *chunk);
void sctp_init_addrs(sctp_chunk_t *, union sctp_addr *, union sctp_addr *);
const union sctp_addr *sctp_source(const sctp_chunk_t *chunk);
/* This is a structure for holding either an IPv6 or an IPv4 address. */
......
/* SCTP kernel reference Implementation
* Copyright (c) Cisco 1999,2000
* Copyright (c) Motorola 1999,2000,2001
* Copyright (c) International Business Machines Corp., 2001
* Copyright (c) International Business Machines Corp., 2001,2002
* Copyright (c) La Monte H.P. Yarroll 2001
*
* This file is part of the SCTP kernel reference implementation.
......@@ -422,110 +422,11 @@ int sctp_in_scope(const union sctp_addr *addr, sctp_scope_t scope)
/* What is the scope of 'addr'? */
sctp_scope_t sctp_scope(const union sctp_addr *addr)
{
sctp_scope_t retval = SCTP_SCOPE_GLOBAL;
struct sctp_func *af;
switch (addr->sa.sa_family) {
case AF_INET:
/* We are checking the loopback, private and other address
* scopes as defined in RFC 1918.
* The IPv4 scoping is based on the draft for SCTP IPv4
* scoping <draft-stewart-tsvwg-sctp-ipv4-00.txt>.
* The set of SCTP address scope hopefully can cover both
* types of addresses.
*/
/* Should IPv4 scoping be a sysctl configurable option
* so users can turn it off (default on) for certain
* unconventional networking environments?
*/
/* Check for unusable SCTP addresses. */
if (IS_IPV4_UNUSABLE_ADDRESS(&addr->v4.sin_addr.s_addr)) {
retval = SCTP_SCOPE_UNUSABLE;
} else if (LOOPBACK(addr->v4.sin_addr.s_addr)) {
retval = SCTP_SCOPE_LOOPBACK;
} else if (IS_IPV4_LINK_ADDRESS(&addr->v4.sin_addr.s_addr)) {
retval = SCTP_SCOPE_LINK;
} else if (IS_IPV4_PRIVATE_ADDRESS(&addr->v4.sin_addr.s_addr)) {
retval = SCTP_SCOPE_PRIVATE;
} else {
retval = SCTP_SCOPE_GLOBAL;
}
break;
case AF_INET6:
{
SCTP_V6(
int v6scope;
v6scope = ipv6_addr_scope((struct in6_addr *)
&addr->v6.sin6_addr);
/* The IPv6 scope is really a set of bit
* fields. See IFA_* in <net/if_inet6.h>.
* Mapping them to the generic SCTP scope
* set is an attempt to have code
* consistencies with the IPv4 scoping.
*/
switch (v6scope) {
case IFA_HOST:
retval = SCTP_SCOPE_LOOPBACK;
break;
case IFA_LINK:
retval = SCTP_SCOPE_LINK;
break;
case IFA_SITE:
retval = SCTP_SCOPE_PRIVATE;
break;
default:
retval = SCTP_SCOPE_GLOBAL;
break;
};
);
break;
}
default:
retval = SCTP_SCOPE_GLOBAL;
break;
};
af = sctp_get_af_specific(addr->sa.sa_family);
if (!af)
return SCTP_SCOPE_UNUSABLE;
return retval;
}
/* This function checks if the address is a valid address to be used for
* SCTP.
*
* Output:
* Return 0 - If the address is a non-unicast or an illegal address.
* Return 1 - If the address is a unicast.
*/
int sctp_addr_is_valid(const union sctp_addr *addr)
{
unsigned short sa_family = addr->sa.sa_family;
switch (sa_family) {
case AF_INET:
/* Is this a non-unicast address or a unusable SCTP address? */
if (IS_IPV4_UNUSABLE_ADDRESS(&addr->v4.sin_addr.s_addr))
return 0;
break;
case AF_INET6:
SCTP_V6(
{
int ret = sctp_ipv6_addr_type(&addr->v6.sin6_addr);
/* Is this a non-unicast address */
if (!(ret & IPV6_ADDR_UNICAST))
return 0;
break;
});
default:
return 0;
};
return 1;
return af->scope((union sctp_addr *)addr);
}
......@@ -132,7 +132,7 @@ int sctp_rcv(struct sk_buff *skb)
* IP broadcast addresses cannot be used in an SCTP transport
* address."
*/
if (!sctp_addr_is_valid(&src) || !sctp_addr_is_valid(&dest))
if (!af->addr_valid(&src) || !af->addr_valid(&dest))
goto discard_it;
asoc = __sctp_rcv_lookup(skb, &src, &dest, &transport);
......@@ -172,7 +172,7 @@ int sctp_rcv(struct sk_buff *skb)
chunk->sctp_hdr = sh;
/* Set the source and destination addresses of the incoming chunk. */
sctp_init_addrs(chunk);
sctp_init_addrs(chunk, &src, &dest);
/* Remember where we came from. */
chunk->transport = transport;
......
......@@ -262,13 +262,62 @@ static void sctp_v6_from_skb(union sctp_addr *addr,struct sk_buff *skb,
}
/* Check if the dst entry's source addr matches the given source addr. */
int sctp_v6_cmp_saddr(struct dst_entry *dst, union sctp_addr *saddr)
static int sctp_v6_cmp_saddr(struct dst_entry *dst, union sctp_addr *saddr)
{
struct rt6_info *rt = (struct rt6_info *)dst;
return ipv6_addr_cmp(&rt->rt6i_src.addr, &saddr->v6.sin6_addr);
}
/* This function checks if the address is a valid address to be used for
* SCTP.
*
* Output:
* Return 0 - If the address is a non-unicast or an illegal address.
* Return 1 - If the address is a unicast.
*/
static int sctp_v6_addr_valid(union sctp_addr *addr)
{
int ret = sctp_ipv6_addr_type(&addr->v6.sin6_addr);
/* FIXME: v4-mapped-v6 address support. */
/* Is this a non-unicast address */
if (!(ret & IPV6_ADDR_UNICAST))
return 0;
return 1;
}
/* What is the scope of 'addr'? */
static sctp_scope_t sctp_v6_scope(union sctp_addr *addr)
{
int v6scope;
sctp_scope_t retval;
/* The IPv6 scope is really a set of bit fields.
* See IFA_* in <net/if_inet6.h>. Map to a generic SCTP scope.
*/
v6scope = ipv6_addr_scope(&addr->v6.sin6_addr);
switch (v6scope) {
case IFA_HOST:
retval = SCTP_SCOPE_LOOPBACK;
break;
case IFA_LINK:
retval = SCTP_SCOPE_LINK;
break;
case IFA_SITE:
retval = SCTP_SCOPE_PRIVATE;
break;
default:
retval = SCTP_SCOPE_GLOBAL;
break;
};
return retval;
}
/* Initialize a PF_INET6 socket msg_name. */
static void sctp_inet6_msgname(char *msgname, int *addr_len)
{
......@@ -344,6 +393,23 @@ static void sctp_inet6_skb_msgname(struct sk_buff *skb, char *msgname,
}
}
/* Do we support this AF? */
static int sctp_inet6_af_supported(sa_family_t family)
{
/* FIXME: v4-mapped-v6 addresses. The I-D is still waffling
* on what to do with sockaddr formats for PF_INET6 sockets.
* For now assume we'll support both.
*/
switch (family) {
case AF_INET6:
case AF_INET:
return 1;
default:
return 0;
}
}
static struct proto_ops inet6_seqpacket_ops = {
.family = PF_INET6,
.release = inet6_release,
......@@ -386,6 +452,8 @@ static sctp_func_t sctp_ipv6_specific = {
.copy_addrlist = sctp_v6_copy_addrlist,
.from_skb = sctp_v6_from_skb,
.cmp_saddr = sctp_v6_cmp_saddr,
.scope = sctp_v6_scope,
.addr_valid = sctp_v6_addr_valid,
.net_header_len = sizeof(struct ipv6hdr),
.sockaddr_len = sizeof(struct sockaddr_in6),
.sa_family = AF_INET6,
......@@ -394,6 +462,7 @@ static sctp_func_t sctp_ipv6_specific = {
static sctp_pf_t sctp_pf_inet6_specific = {
.event_msgname = sctp_inet6_event_msgname,
.skb_msgname = sctp_inet6_skb_msgname,
.af_supported = sctp_inet6_af_supported,
};
/* Initialize IPv6 support and register with inet6 stack. */
......
......@@ -283,6 +283,51 @@ int sctp_v4_cmp_saddr(struct dst_entry *dst, union sctp_addr *saddr)
return (rt->rt_src == saddr->v4.sin_addr.s_addr);
}
/* This function checks if the address is a valid address to be used for
* SCTP.
*
* Output:
* Return 0 - If the address is a non-unicast or an illegal address.
* Return 1 - If the address is a unicast.
*/
static int sctp_v4_addr_valid(union sctp_addr *addr)
{
/* Is this a non-unicast address or a unusable SCTP address? */
if (IS_IPV4_UNUSABLE_ADDRESS(&addr->v4.sin_addr.s_addr))
return 0;
return 1;
}
/* Checking the loopback, private and other address scopes as defined in
* RFC 1918. The IPv4 scoping is based on the draft for SCTP IPv4
* scoping <draft-stewart-tsvwg-sctp-ipv4-00.txt>.
*/
static sctp_scope_t sctp_v4_scope(union sctp_addr *addr)
{
sctp_scope_t retval;
/* Should IPv4 scoping be a sysctl configurable option
* so users can turn it off (default on) for certain
* unconventional networking environments?
*/
/* Check for unusable SCTP addresses. */
if (IS_IPV4_UNUSABLE_ADDRESS(&addr->v4.sin_addr.s_addr)) {
retval = SCTP_SCOPE_UNUSABLE;
} else if (LOOPBACK(addr->v4.sin_addr.s_addr)) {
retval = SCTP_SCOPE_LOOPBACK;
} else if (IS_IPV4_LINK_ADDRESS(&addr->v4.sin_addr.s_addr)) {
retval = SCTP_SCOPE_LINK;
} else if (IS_IPV4_PRIVATE_ADDRESS(&addr->v4.sin_addr.s_addr)) {
retval = SCTP_SCOPE_PRIVATE;
} else {
retval = SCTP_SCOPE_GLOBAL;
}
return retval;
}
/* Event handler for inet device events.
* Basically, whenever there is an event, we re-build our local address list.
*/
......@@ -374,13 +419,13 @@ static void sctp_inet_event_msgname(sctp_ulpevent_t *event, char *msgname, int *
}
/* Initialize and copy out a msgname from an inbound skb. */
static void sctp_inet_skb_msgname(struct sk_buff *skb, char *msgname, int *addr_len)
static void sctp_inet_skb_msgname(struct sk_buff *skb, char *msgname, int *len)
{
struct sctphdr *sh;
struct sockaddr_in *sin;
if (msgname) {
sctp_inet_msgname(msgname, addr_len);
sctp_inet_msgname(msgname, len);
sin = (struct sockaddr_in *)msgname;
sh = (struct sctphdr *)skb->h.raw;
sin->sin_port = sh->source;
......@@ -388,9 +433,17 @@ static void sctp_inet_skb_msgname(struct sk_buff *skb, char *msgname, int *addr_
}
}
/* Do we support this AF? */
static int sctp_inet_af_supported(sa_family_t family)
{
/* PF_INET only supports AF_INET addresses. */
return (AF_INET == family);
}
static sctp_pf_t sctp_pf_inet = {
.event_msgname = sctp_inet_event_msgname,
.skb_msgname = sctp_inet_skb_msgname,
.af_supported = sctp_inet_af_supported,
};
......@@ -446,6 +499,8 @@ struct sctp_func sctp_ipv4_specific = {
.copy_addrlist = sctp_v4_copy_addrlist,
.from_skb = sctp_v4_from_skb,
.cmp_saddr = sctp_v4_cmp_saddr,
.addr_valid = sctp_v4_addr_valid,
.scope = sctp_v4_scope,
.net_header_len = sizeof(struct iphdr),
.sockaddr_len = sizeof(struct sockaddr_in),
.sa_family = AF_INET,
......
......@@ -1031,47 +1031,11 @@ sctp_chunk_t *sctp_chunkify(struct sk_buff *skb, const sctp_association_t *asoc,
}
/* Set chunk->source and dest based on the IP header in chunk->skb. */
void sctp_init_addrs(sctp_chunk_t *chunk)
void sctp_init_addrs(sctp_chunk_t *chunk, union sctp_addr *src,
union sctp_addr *dest)
{
union sctp_addr *source, *dest;
struct sk_buff *skb;
struct sctphdr *sh;
struct iphdr *ih4;
struct ipv6hdr *ih6;
source = &chunk->source;
dest = &chunk->dest;
skb = chunk->skb;
ih4 = skb->nh.iph;
ih6 = skb->nh.ipv6h;
sh = chunk->sctp_hdr;
switch (ih4->version) {
case 4:
source->v4.sin_family = AF_INET;
source->v4.sin_port = ntohs(sh->source);
source->v4.sin_addr.s_addr = ih4->saddr;
dest->v4.sin_family = AF_INET;
dest->v4.sin_port = ntohs(sh->dest);
dest->v4.sin_addr.s_addr = ih4->daddr;
break;
case 6:
SCTP_V6(
source->v6.sin6_family = AF_INET6;
source->v6.sin6_port = ntohs(sh->source);
source->v6.sin6_addr = ih6->saddr;
dest->v6.sin6_family = AF_INET6;
dest->v6.sin6_port = ntohs(sh->dest);
dest->v6.sin6_addr = ih6->daddr;
/* FIXME: What do we do with scope, etc. ? */
break;
)
default:
/* This is a bogus address type, just bail. */
break;
};
memcpy(&chunk->source, src, sizeof(union sctp_addr));
memcpy(&chunk->dest, dest, sizeof(union sctp_addr));
}
/* Extract the source address from a chunk. */
......
......@@ -2691,35 +2691,30 @@ static struct sk_buff *sctp_skb_recv_datagram(struct sock *sk, int flags, int no
return NULL;
}
static inline int sctp_verify_addr(struct sock *sk, struct sockaddr *addr, int addrlen)
/* Verify that this is a valid address. */
static int sctp_verify_addr(struct sock *sk, struct sockaddr *addr, int len)
{
union sctp_addr *sa;
struct sctp_func *af;
if (addrlen < sizeof (struct sockaddr))
/* Check minimum size. */
if (len < sizeof (struct sockaddr))
return -EINVAL;
sa = (union sctp_addr *)addr;
switch (sa->sa.sa_family) {
case AF_INET:
if (addrlen < sizeof(struct sockaddr_in))
/* Do we support this address family in general? */
af = sctp_get_af_specific(addr->sa_family);
if (!af)
return -EINVAL;
break;
case AF_INET6:
if (PF_INET == sk->family)
return -EINVAL;
SCTP_V6(
if (addrlen < sizeof(struct sockaddr_in6))
/* Does this PF support this AF? */
if (!sctp_sk(sk)->pf->af_supported(addr->sa_family))
return -EINVAL;
break;
);
default:
/* Verify the minimum for this AF sockaddr. */
if (len < af->sockaddr_len)
return -EINVAL;
};
/* Disallow any illegal addresses to be used as destinations. */
if (!sctp_addr_is_valid(sa))
/* Is this a valid SCTP address? */
if (!af->addr_valid((union sctp_addr *)addr))
return -EINVAL;
return 0;
......
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