Commit d8367696 authored by Jon Grimm's avatar Jon Grimm

[SCTP] Last of the v4/v6 partioning (for now)

Mostly code on the bind path, splitting out to pf and af family
specific functions.   Minor code cleanups/fixes mixed in.  
parent d09fc925
...@@ -123,8 +123,8 @@ extern sctp_protocol_t sctp_proto; ...@@ -123,8 +123,8 @@ extern sctp_protocol_t sctp_proto;
extern struct sock *sctp_get_ctl_sock(void); extern struct sock *sctp_get_ctl_sock(void);
extern int sctp_copy_local_addr_list(sctp_protocol_t *, sctp_bind_addr_t *, extern int sctp_copy_local_addr_list(sctp_protocol_t *, sctp_bind_addr_t *,
sctp_scope_t, int priority, int flags); sctp_scope_t, int priority, int flags);
extern sctp_pf_t *sctp_get_pf_specific(int family); extern struct sctp_pf *sctp_get_pf_specific(sa_family_t family);
extern void sctp_set_pf_specific(int family, sctp_pf_t *); extern int sctp_register_pf(struct sctp_pf *, sa_family_t);
/* /*
* sctp_socket.c * sctp_socket.c
......
...@@ -234,7 +234,7 @@ struct SCTP_protocol { ...@@ -234,7 +234,7 @@ struct SCTP_protocol {
* Pointers to address related SCTP functions. * Pointers to address related SCTP functions.
* (i.e. things that depend on the address family.) * (i.e. things that depend on the address family.)
*/ */
typedef struct sctp_func { struct sctp_af {
int (*queue_xmit) (struct sk_buff *skb); int (*queue_xmit) (struct sk_buff *skb);
int (*setsockopt) (struct sock *sk, int (*setsockopt) (struct sock *sk,
int level, int level,
...@@ -259,27 +259,34 @@ typedef struct sctp_func { ...@@ -259,27 +259,34 @@ typedef struct sctp_func {
void (*from_skb) (union sctp_addr *, void (*from_skb) (union sctp_addr *,
struct sk_buff *skb, struct sk_buff *skb,
int saddr); int saddr);
void (*from_sk) (union sctp_addr *,
struct sock *sk);
void (*to_sk) (union sctp_addr *,
struct sock *sk);
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 *); int (*is_any) (const union sctp_addr *);
int (*available) (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;
struct list_head list; struct list_head list;
} sctp_func_t; };
sctp_func_t *sctp_get_af_specific(sa_family_t); struct sctp_af *sctp_get_af_specific(sa_family_t);
int sctp_register_af(struct sctp_af *);
/* Protocol family functions. */ /* Protocol family functions. */
typedef struct sctp_pf { 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 *, int (*cmp_addr) (const union sctp_addr *,
const union sctp_addr *, const union sctp_addr *,
struct sctp_opt *); struct sctp_opt *);
struct sctp_func *af; int (*bind_verify) (struct sctp_opt *, union sctp_addr *);
struct sctp_af *af;
} sctp_pf_t; } sctp_pf_t;
/* SCTP Socket type: UDP or TCP style. */ /* SCTP Socket type: UDP or TCP style. */
...@@ -623,7 +630,7 @@ struct SCTP_transport { ...@@ -623,7 +630,7 @@ struct SCTP_transport {
union sctp_addr ipaddr; union sctp_addr ipaddr;
/* These are the functions we call to handle LLP stuff. */ /* These are the functions we call to handle LLP stuff. */
sctp_func_t *af_specific; struct sctp_af *af_specific;
/* Which association do we belong to? */ /* Which association do we belong to? */
sctp_association_t *asoc; sctp_association_t *asoc;
......
...@@ -24,3 +24,4 @@ EXPORT_SYMBOL(inet6_bind); ...@@ -24,3 +24,4 @@ EXPORT_SYMBOL(inet6_bind);
EXPORT_SYMBOL(inet6_getname); EXPORT_SYMBOL(inet6_getname);
EXPORT_SYMBOL(inet6_ioctl); EXPORT_SYMBOL(inet6_ioctl);
EXPORT_SYMBOL(ipv6_get_saddr); EXPORT_SYMBOL(ipv6_get_saddr);
EXPORT_SYMBOL(ipv6_chk_addr);
...@@ -642,7 +642,7 @@ __u16 __sctp_association_get_next_ssn(sctp_association_t *asoc, __u16 sid) ...@@ -642,7 +642,7 @@ __u16 __sctp_association_get_next_ssn(sctp_association_t *asoc, __u16 sid)
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)
{ {
struct sctp_func *af; struct sctp_af *af;
af = sctp_get_af_specific(ss1->sa.sa_family); af = sctp_get_af_specific(ss1->sa.sa_family);
if (!af) if (!af)
......
...@@ -327,7 +327,7 @@ static int sctp_copy_one_addr(sctp_bind_addr_t *dest, union sctp_addr *addr, ...@@ -327,7 +327,7 @@ static int sctp_copy_one_addr(sctp_bind_addr_t *dest, union sctp_addr *addr,
/* Is this a wildcard address? */ /* Is this a wildcard address? */
int sctp_is_any(const union sctp_addr *addr) int sctp_is_any(const union sctp_addr *addr)
{ {
struct sctp_func *af = sctp_get_af_specific(addr->sa.sa_family); struct sctp_af *af = sctp_get_af_specific(addr->sa.sa_family);
if (!af) if (!af)
return 0; return 0;
return af->is_any(addr); return af->is_any(addr);
...@@ -362,7 +362,7 @@ int sctp_in_scope(const union sctp_addr *addr, sctp_scope_t scope) ...@@ -362,7 +362,7 @@ int sctp_in_scope(const union sctp_addr *addr, sctp_scope_t scope)
/* What is the scope of 'addr'? */ /* What is the scope of 'addr'? */
sctp_scope_t sctp_scope(const union sctp_addr *addr) sctp_scope_t sctp_scope(const union sctp_addr *addr)
{ {
struct sctp_func *af; struct sctp_af *af;
af = sctp_get_af_specific(addr->sa.sa_family); af = sctp_get_af_specific(addr->sa.sa_family);
if (!af) if (!af)
......
...@@ -96,7 +96,7 @@ int sctp_rcv(struct sk_buff *skb) ...@@ -96,7 +96,7 @@ int sctp_rcv(struct sk_buff *skb)
struct sctphdr *sh; struct sctphdr *sh;
union sctp_addr src; union sctp_addr src;
union sctp_addr dest; union sctp_addr dest;
struct sctp_func *af; struct sctp_af *af;
int ret = 0; int ret = 0;
if (skb->pkt_type!=PACKET_HOST) if (skb->pkt_type!=PACKET_HOST)
......
...@@ -140,8 +140,8 @@ static inline int sctp_v6_xmit(struct sk_buff *skb) ...@@ -140,8 +140,8 @@ static inline int sctp_v6_xmit(struct sk_buff *skb)
* to disallow loopback when the scoping rules have * to disallow loopback when the scoping rules have
* not bound loopback to the endpoint. * not bound loopback to the endpoint.
*/ */
if (sctp_ipv6_addr_type(&saddr) & IPV6_ADDR_LOOPBACK) { if (ipv6_addr_type(&saddr) & IPV6_ADDR_LOOPBACK) {
if (!(sctp_ipv6_addr_type(&np->daddr) & if (!(ipv6_addr_type(&np->daddr) &
IPV6_ADDR_LOOPBACK)) { IPV6_ADDR_LOOPBACK)) {
ipv6_addr_copy(&saddr, &np->daddr); ipv6_addr_copy(&saddr, &np->daddr);
} }
...@@ -176,7 +176,7 @@ struct dst_entry *sctp_v6_get_dst(union sctp_addr *daddr, ...@@ -176,7 +176,7 @@ 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 = { struct flowi fl = {
.nl_u = { .ip6_u = { .daddr = &daddr->v6.sin6_addr, } } }; .nl_u = { .ip6_u = { .daddr = &daddr->v6.sin6_addr, } } };
...@@ -261,6 +261,20 @@ static void sctp_v6_from_skb(union sctp_addr *addr,struct sk_buff *skb, ...@@ -261,6 +261,20 @@ 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);
} }
/* Initialize an sctp_addr from a socket. */
static void sctp_v6_from_sk(union sctp_addr *addr, struct sock *sk)
{
addr->v6.sin6_family = AF_INET6;
addr->v6.sin6_port = inet_sk(sk)->num;
addr->v6.sin6_addr = inet6_sk(sk)->rcv_saddr;
}
/* Initialize sk->rcv_saddr from sctp_addr. */
static void sctp_v6_to_sk(union sctp_addr *addr, struct sock *sk)
{
inet6_sk(sk)->rcv_saddr = addr->v6.sin6_addr;
}
/* Initialize a sctp_addr from a dst_entry. */ /* Initialize a sctp_addr from a dst_entry. */
static void sctp_v6_dst_saddr(union sctp_addr *addr, struct dst_entry *dst) static void sctp_v6_dst_saddr(union sctp_addr *addr, struct dst_entry *dst)
{ {
...@@ -270,15 +284,15 @@ static void sctp_v6_dst_saddr(union sctp_addr *addr, struct dst_entry *dst) ...@@ -270,15 +284,15 @@ static void sctp_v6_dst_saddr(union sctp_addr *addr, struct dst_entry *dst)
} }
/* Compare addresses exactly. Well.. almost exactly; ignore scope_id /* Compare addresses exactly. Well.. almost exactly; ignore scope_id
* for now. FIXME. * for now. FIXME: v4-mapped-v6.
*/ */
static int sctp_v6_cmp_addr(const union sctp_addr *addr1, static int sctp_v6_cmp_addr(const union sctp_addr *addr1,
const union sctp_addr *addr2) const union sctp_addr *addr2)
{ {
int match; int match;
if (addr1->sa.sa_family != addr2->sa.sa_family) if (addr1->sa.sa_family != addr2->sa.sa_family)
return 0; return 0;
match = !ipv6_addr_cmp((struct in6_addr *)&addr1->v6.sin6_addr, match = !ipv6_addr_cmp((struct in6_addr *)&addr1->v6.sin6_addr,
(struct in6_addr *)&addr2->v6.sin6_addr); (struct in6_addr *)&addr2->v6.sin6_addr);
return match; return match;
...@@ -300,6 +314,22 @@ static int sctp_v6_is_any(const union sctp_addr *addr) ...@@ -300,6 +314,22 @@ static int sctp_v6_is_any(const union sctp_addr *addr)
return IPV6_ADDR_ANY == type; return IPV6_ADDR_ANY == type;
} }
/* Should this be available for binding? */
static int sctp_v6_available(const union sctp_addr *addr)
{
int type;
struct in6_addr *in6 = (struct in6_addr *)&addr->v6.sin6_addr;
type = ipv6_addr_type(in6);
if (IPV6_ADDR_ANY == type)
return 1;
if (!(type & IPV6_ADDR_UNICAST))
return 0;
return ipv6_chk_addr(in6, NULL);
}
/* 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.
* *
...@@ -309,7 +339,7 @@ static int sctp_v6_is_any(const union sctp_addr *addr) ...@@ -309,7 +339,7 @@ static int sctp_v6_is_any(const union sctp_addr *addr)
*/ */
static int sctp_v6_addr_valid(union sctp_addr *addr) static int sctp_v6_addr_valid(union sctp_addr *addr)
{ {
int ret = sctp_ipv6_addr_type(&addr->v6.sin6_addr); int ret = ipv6_addr_type(&addr->v6.sin6_addr);
/* FIXME: v4-mapped-v6 address support. */ /* FIXME: v4-mapped-v6 address support. */
...@@ -442,14 +472,14 @@ static int sctp_inet6_af_supported(sa_family_t family) ...@@ -442,14 +472,14 @@ static int sctp_inet6_af_supported(sa_family_t family)
/* Address matching with wildcards allowed. This extra level /* Address matching with wildcards allowed. This extra level
* of indirection lets us choose whether a PF_INET6 should * of indirection lets us choose whether a PF_INET6 should
* disallow any v4 addresses if we so choose. * disallow any v4 addresses if we so choose.
*/ */
static int sctp_inet6_cmp_addr(const union sctp_addr *addr1, static int sctp_inet6_cmp_addr(const union sctp_addr *addr1,
const union sctp_addr *addr2, const union sctp_addr *addr2,
struct sctp_opt *opt) struct sctp_opt *opt)
{ {
struct sctp_func *af1, *af2; struct sctp_af *af1, *af2;
af1 = sctp_get_af_specific(addr1->sa.sa_family); af1 = sctp_get_af_specific(addr1->sa.sa_family);
af2 = sctp_get_af_specific(addr2->sa.sa_family); af2 = sctp_get_af_specific(addr2->sa.sa_family);
...@@ -461,11 +491,25 @@ static int sctp_inet6_cmp_addr(const union sctp_addr *addr1, ...@@ -461,11 +491,25 @@ static int sctp_inet6_cmp_addr(const union sctp_addr *addr1,
if (addr1->sa.sa_family != addr2->sa.sa_family) if (addr1->sa.sa_family != addr2->sa.sa_family)
return 0; return 0;
return af1->cmp_addr(addr1, addr2); return af1->cmp_addr(addr1, addr2);
} }
/* Verify that the provided sockaddr looks bindable. Common verification,
* has already been taken care of.
*/
static int sctp_inet6_bind_verify(struct sctp_opt *opt, union sctp_addr *addr)
{
struct sctp_af *af;
/* ASSERT: address family has already been verified. */
if (addr->sa.sa_family != AF_INET6) {
af = sctp_get_af_specific(addr->sa.sa_family);
} else
af = opt->pf->af;
return af->available(addr);
}
static struct proto_ops inet6_seqpacket_ops = { static struct proto_ops inet6_seqpacket_ops = {
.family = PF_INET6, .family = PF_INET6,
...@@ -501,29 +545,33 @@ static struct inet6_protocol sctpv6_protocol = { ...@@ -501,29 +545,33 @@ static struct inet6_protocol sctpv6_protocol = {
.err_handler = sctp_v6_err, .err_handler = sctp_v6_err,
}; };
static sctp_func_t sctp_ipv6_specific = { static struct sctp_af sctp_ipv6_specific = {
.queue_xmit = sctp_v6_xmit, .queue_xmit = sctp_v6_xmit,
.setsockopt = ipv6_setsockopt, .setsockopt = ipv6_setsockopt,
.getsockopt = ipv6_getsockopt, .getsockopt = ipv6_getsockopt,
.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,
.from_sk = sctp_v6_from_sk,
.to_sk = sctp_v6_to_sk,
.dst_saddr = sctp_v6_dst_saddr, .dst_saddr = sctp_v6_dst_saddr,
.cmp_addr = sctp_v6_cmp_addr, .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, .is_any = sctp_v6_is_any,
.available = sctp_v6_available,
.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,
}; };
static sctp_pf_t sctp_pf_inet6_specific = { static struct sctp_pf 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, .cmp_addr = sctp_inet6_cmp_addr,
.bind_verify = sctp_inet6_bind_verify,
.af = &sctp_ipv6_specific, .af = &sctp_ipv6_specific,
}; };
...@@ -538,11 +586,10 @@ int sctp_v6_init(void) ...@@ -538,11 +586,10 @@ int sctp_v6_init(void)
inet6_register_protosw(&sctpv6_protosw); inet6_register_protosw(&sctpv6_protosw);
/* Register the SCTP specfic PF_INET6 functions. */ /* Register the SCTP specfic PF_INET6 functions. */
sctp_set_pf_specific(PF_INET6, &sctp_pf_inet6_specific); sctp_register_pf(&sctp_pf_inet6_specific, PF_INET6);
/* Fill in address family info. */ /* Register the SCTP specfic AF_INET6 functions. */
INIT_LIST_HEAD(&sctp_ipv6_specific.list); sctp_register_af(&sctp_ipv6_specific);
list_add_tail(&sctp_ipv6_specific.list, &sctp_proto.address_families);
return 0; return 0;
} }
......
...@@ -67,8 +67,10 @@ struct sctp_mib sctp_statistics[NR_CPUS * 2]; ...@@ -67,8 +67,10 @@ struct sctp_mib sctp_statistics[NR_CPUS * 2];
*/ */
static struct socket *sctp_ctl_socket; static struct socket *sctp_ctl_socket;
static sctp_pf_t *sctp_pf_inet6_specific; static struct sctp_pf *sctp_pf_inet6_specific;
static sctp_pf_t *sctp_pf_inet_specific; static struct sctp_pf *sctp_pf_inet_specific;
static struct sctp_af *sctp_af_v4_specific;
static struct sctp_af *sctp_af_v6_specific;
extern struct net_proto_family inet_family_ops; extern struct net_proto_family inet_family_ops;
...@@ -140,12 +142,12 @@ static void __sctp_get_local_addr_list(sctp_protocol_t *proto) ...@@ -140,12 +142,12 @@ static void __sctp_get_local_addr_list(sctp_protocol_t *proto)
{ {
struct net_device *dev; struct net_device *dev;
struct list_head *pos; struct list_head *pos;
struct sctp_func *af; struct sctp_af *af;
read_lock(&dev_base_lock); read_lock(&dev_base_lock);
for (dev = dev_base; dev; dev = dev->next) { for (dev = dev_base; dev; dev = dev->next) {
list_for_each(pos, &proto->address_families) { list_for_each(pos, &proto->address_families) {
af = list_entry(pos, sctp_func_t, list); af = list_entry(pos, struct sctp_af, list);
af->copy_addrlist(&proto->local_addr_list, dev); af->copy_addrlist(&proto->local_addr_list, dev);
} }
} }
...@@ -251,7 +253,6 @@ struct dst_entry *sctp_v4_get_dst(union sctp_addr *daddr, ...@@ -251,7 +253,6 @@ struct dst_entry *sctp_v4_get_dst(union sctp_addr *daddr,
return &rt->u.dst; return &rt->u.dst;
} }
/* Initialize a sctp_addr from in incoming skb. */ /* Initialize a sctp_addr from in incoming skb. */
static void sctp_v4_from_skb(union sctp_addr *addr, struct sk_buff *skb, static void sctp_v4_from_skb(union sctp_addr *addr, struct sk_buff *skb,
int is_saddr) int is_saddr)
...@@ -274,6 +275,21 @@ static void sctp_v4_from_skb(union sctp_addr *addr, struct sk_buff *skb, ...@@ -274,6 +275,21 @@ 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));
} }
/* Initialize an sctp_addr from a socket. */
static void sctp_v4_from_sk(union sctp_addr *addr, struct sock *sk)
{
addr->v4.sin_family = AF_INET;
addr->v4.sin_port = inet_sk(sk)->num;
addr->v4.sin_addr.s_addr = inet_sk(sk)->rcv_saddr;
}
/* Initialize sk->rcv_saddr from sctp_addr. */
static void sctp_v4_to_sk(union sctp_addr *addr, struct sock *sk)
{
inet_sk(sk)->rcv_saddr = addr->v4.sin_addr.s_addr;
}
/* Initialize a sctp_addr from a dst_entry. */ /* Initialize a sctp_addr from a dst_entry. */
static void sctp_v4_dst_saddr(union sctp_addr *saddr, struct dst_entry *dst) static void sctp_v4_dst_saddr(union sctp_addr *saddr, struct dst_entry *dst)
{ {
...@@ -311,7 +327,7 @@ static int sctp_v4_is_any(const union sctp_addr *addr) ...@@ -311,7 +327,7 @@ static int sctp_v4_is_any(const union sctp_addr *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 binding.
* *
* Output: * Output:
* Return 0 - If the address is a non-unicast or an illegal address. * Return 0 - If the address is a non-unicast or an illegal address.
...@@ -326,6 +342,18 @@ static int sctp_v4_addr_valid(union sctp_addr *addr) ...@@ -326,6 +342,18 @@ static int sctp_v4_addr_valid(union sctp_addr *addr)
return 1; return 1;
} }
/* Should this be available for binding? */
static int sctp_v4_available(const union sctp_addr *addr)
{
int ret = inet_addr_type(addr->v4.sin_addr.s_addr);
/* FIXME: ip_nonlocal_bind sysctl support. */
if (addr->v4.sin_addr.s_addr != INADDR_ANY && ret != RTN_LOCAL)
return 0;
return 1;
}
/* 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>.
...@@ -405,29 +433,42 @@ int sctp_ctl_sock_init(void) ...@@ -405,29 +433,42 @@ int sctp_ctl_sock_init(void)
return 0; return 0;
} }
/* Register address family specific functions. */
int sctp_register_af(struct sctp_af *af)
{
switch (af->sa_family) {
case AF_INET:
if (sctp_af_v4_specific)
return 0;
sctp_af_v4_specific = sctp_af_v4_specific = af;
break;
case AF_INET6:
if (sctp_af_v6_specific)
return 0;
sctp_af_v6_specific = sctp_af_v6_specific = af;
break;
default:
return 0;
}
INIT_LIST_HEAD(&af->list);
list_add_tail(&af->list, &sctp_proto.address_families);
return 1;
}
/* Get the table of functions for manipulating a particular address /* Get the table of functions for manipulating a particular address
* family. * family.
*/ */
sctp_func_t *sctp_get_af_specific(sa_family_t family) struct sctp_af *sctp_get_af_specific(sa_family_t family)
{ {
struct list_head *pos; switch (family) {
sctp_protocol_t *proto = sctp_get_protocol(); case AF_INET:
struct sctp_func *retval, *af; return sctp_af_v4_specific;
case AF_INET6:
retval = NULL; return sctp_af_v6_specific;
default:
/* Cycle through all AF specific functions looking for a return NULL;
* match.
*/
list_for_each(pos, &proto->address_families) {
af = list_entry(pos, sctp_func_t, list);
if (family == af->sa_family) {
retval = af;
break;
}
} }
return retval;
} }
/* Common code to initialize a AF_INET msg_name. */ /* Common code to initialize a AF_INET msg_name. */
...@@ -495,18 +536,25 @@ static int sctp_inet_cmp_addr(const union sctp_addr *addr1, ...@@ -495,18 +536,25 @@ static int sctp_inet_cmp_addr(const union sctp_addr *addr1,
return 0; return 0;
} }
/* Verify that provided sockaddr looks bindable. Common verification has
* already been taken care of.
*/
static int sctp_inet_bind_verify(struct sctp_opt *opt, union sctp_addr *addr)
{
return sctp_v4_available(addr);
}
struct sctp_func sctp_ipv4_specific; struct sctp_af sctp_ipv4_specific;
static sctp_pf_t sctp_pf_inet = { static struct sctp_pf 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, .cmp_addr = sctp_inet_cmp_addr,
.bind_verify = sctp_inet_bind_verify,
.af = &sctp_ipv4_specific, .af = &sctp_ipv4_specific,
}; };
/* Registration for netdev events. */ /* Registration for netdev events. */
struct notifier_block sctp_netdev_notifier = { struct notifier_block sctp_netdev_notifier = {
.notifier_call = sctp_netdev_event, .notifier_call = sctp_netdev_event,
...@@ -551,25 +599,28 @@ static struct inet_protocol sctp_protocol = { ...@@ -551,25 +599,28 @@ static struct inet_protocol sctp_protocol = {
}; };
/* IPv4 address related functions. */ /* IPv4 address related functions. */
struct sctp_func sctp_ipv4_specific = { struct sctp_af sctp_ipv4_specific = {
.queue_xmit = ip_queue_xmit, .queue_xmit = ip_queue_xmit,
.setsockopt = ip_setsockopt, .setsockopt = ip_setsockopt,
.getsockopt = ip_getsockopt, .getsockopt = ip_getsockopt,
.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,
.from_sk = sctp_v4_from_sk,
.to_sk = sctp_v4_to_sk,
.dst_saddr = sctp_v4_dst_saddr, .dst_saddr = sctp_v4_dst_saddr,
.cmp_addr = sctp_v4_cmp_addr, .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, .is_any = sctp_v4_is_any,
.available = sctp_v4_available,
.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),
.sa_family = AF_INET, .sa_family = AF_INET,
}; };
sctp_pf_t *sctp_get_pf_specific(int family) { struct sctp_pf *sctp_get_pf_specific(sa_family_t family) {
switch (family) { switch (family) {
case PF_INET: case PF_INET:
...@@ -581,20 +632,24 @@ sctp_pf_t *sctp_get_pf_specific(int family) { ...@@ -581,20 +632,24 @@ sctp_pf_t *sctp_get_pf_specific(int family) {
} }
} }
/* Set the PF specific function table. */ /* Register the PF specific function table. */
void sctp_set_pf_specific(int family, sctp_pf_t *pf) int sctp_register_pf(struct sctp_pf *pf, sa_family_t family)
{ {
switch (family) { switch (family) {
case PF_INET: case PF_INET:
if (sctp_pf_inet_specific)
return 0;
sctp_pf_inet_specific = pf; sctp_pf_inet_specific = pf;
break; break;
case PF_INET6: case PF_INET6:
if (sctp_pf_inet6_specific)
return 0;
sctp_pf_inet6_specific = pf; sctp_pf_inet6_specific = pf;
break; break;
default: default:
BUG(); return 0;
break;
} }
return 1;
} }
/* Initialize the universe into something sensible. */ /* Initialize the universe into something sensible. */
...@@ -617,7 +672,7 @@ int sctp_init(void) ...@@ -617,7 +672,7 @@ int sctp_init(void)
sctp_dbg_objcnt_init(); sctp_dbg_objcnt_init();
/* Initialize the SCTP specific PF functions. */ /* Initialize the SCTP specific PF functions. */
sctp_set_pf_specific(PF_INET, &sctp_pf_inet); sctp_register_pf(&sctp_pf_inet, PF_INET);
/* /*
* 14. Suggested SCTP Protocol Parameter Values * 14. Suggested SCTP Protocol Parameter Values
*/ */
...@@ -709,8 +764,7 @@ int sctp_init(void) ...@@ -709,8 +764,7 @@ int sctp_init(void)
sctp_sysctl_register(); sctp_sysctl_register();
INIT_LIST_HEAD(&sctp_proto.address_families); INIT_LIST_HEAD(&sctp_proto.address_families);
INIT_LIST_HEAD(&sctp_ipv4_specific.list); sctp_register_af(&sctp_ipv4_specific);
list_add_tail(&sctp_ipv4_specific.list, &sctp_proto.address_families);
status = sctp_v6_init(); status = sctp_v6_init();
if (status) if (status)
......
...@@ -87,12 +87,7 @@ static int sctp_wait_for_sndbuf(sctp_association_t *asoc, long *timeo_p, ...@@ -87,12 +87,7 @@ static int sctp_wait_for_sndbuf(sctp_association_t *asoc, long *timeo_p,
int msg_len); int msg_len);
static int sctp_wait_for_packet(struct sock * sk, int *err, long *timeo_p); static int sctp_wait_for_packet(struct sock * sk, int *err, long *timeo_p);
static int sctp_wait_for_connect(sctp_association_t *asoc, long *timeo_p); static int sctp_wait_for_connect(sctp_association_t *asoc, long *timeo_p);
static inline void sctp_sk_addr_set(struct sock *, static inline int sctp_verify_addr(struct sock *, union sctp_addr *, int);
const union sctp_addr *newaddr,
union sctp_addr *saveaddr);
static inline void sctp_sk_addr_restore(struct sock *,
const union sctp_addr *);
static inline int sctp_verify_addr(struct sock *, struct sockaddr *, int);
static int sctp_bindx_add(struct sock *, struct sockaddr_storage *, int); static int sctp_bindx_add(struct sock *, struct sockaddr_storage *, int);
static int sctp_bindx_rem(struct sock *, struct sockaddr_storage *, int); static int sctp_bindx_rem(struct sock *, struct sockaddr_storage *, int);
static int sctp_do_bind(struct sock *, union sctp_addr *, int); static int sctp_do_bind(struct sock *, union sctp_addr *, int);
...@@ -133,101 +128,75 @@ int sctp_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len) ...@@ -133,101 +128,75 @@ int sctp_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len)
return retval; return retval;
} }
static long sctp_get_port_local(struct sock *, unsigned short); static long sctp_get_port_local(struct sock *, union sctp_addr *);
/* Bind a local address either to an endpoint or to an association. */ /* Verify this is a valid sockaddr. */
SCTP_STATIC int sctp_do_bind(struct sock *sk, union sctp_addr *newaddr, static struct sctp_af *sctp_sockaddr_af(struct sctp_opt *opt,
int addr_len) union sctp_addr *addr, int len)
{ {
sctp_opt_t *sp = sctp_sk(sk); struct sctp_af *af;
sctp_endpoint_t *ep = sp->ep;
sctp_bind_addr_t *bp = &ep->base.bind_addr;
unsigned short sa_family = newaddr->sa.sa_family;
union sctp_addr tmpaddr, saveaddr;
unsigned short *snum;
int ret = 0;
SCTP_DEBUG_PRINTK("sctp_do_bind(sk: %p, newaddr: %p, addr_len: %d)\n", /* Check minimum size. */
sk, newaddr, addr_len); if (len < sizeof (struct sockaddr))
return NULL;
/* FIXME: This function needs to handle v4-mapped-on-v6
* addresses!
*/
if (PF_INET == sk->family) {
if (sa_family != AF_INET)
return -EINVAL;
}
/* Make a local copy of the new address. */ /* Does this PF support this AF? */
tmpaddr = *newaddr; if (!opt->pf->af_supported(addr->sa.sa_family))
return NULL;
switch (sa_family) { /* If we get this far, af is valid. */
case AF_INET: af = sctp_get_af_specific(addr->sa.sa_family);
if (addr_len < sizeof(struct sockaddr_in))
return -EINVAL;
ret = inet_addr_type(newaddr->v4.sin_addr.s_addr); if (len < af->sockaddr_len)
return NULL;
/* FIXME: return af;
* Should we allow apps to bind to non-local addresses by }
* checking the IP sysctl parameter "ip_nonlocal_bind"?
*/
if (newaddr->v4.sin_addr.s_addr != INADDR_ANY &&
ret != RTN_LOCAL)
return -EADDRNOTAVAIL;
tmpaddr.v4.sin_port = htons(tmpaddr.v4.sin_port);
snum = &tmpaddr.v4.sin_port;
break;
case AF_INET6: /* Bind a local address either to an endpoint or to an association. */
SCTP_V6( SCTP_STATIC int sctp_do_bind(struct sock *sk, union sctp_addr *addr, int len)
/* FIXME: Hui, please verify this. Looking at {
* the ipv6 code I see a SIN6_LEN_RFC2133 check. sctp_opt_t *sp = sctp_sk(sk);
* I'm guessing that scope_id is a newer addition. sctp_endpoint_t *ep = sp->ep;
*/ sctp_bind_addr_t *bp = &ep->base.bind_addr;
if (addr_len < sizeof(struct sockaddr_in6)) struct sctp_af *af;
return -EINVAL; unsigned short snum;
int ret = 0;
/* FIXME - The support for IPv6 multiple types SCTP_DEBUG_PRINTK("sctp_do_bind(sk: %p, newaddr: %p, len: %d)\n",
* of addresses need to be added later. sk, addr, len);
*/
ret = sctp_ipv6_addr_type(&newaddr->v6.sin6_addr);
tmpaddr.v6.sin6_port = htons(tmpaddr.v6.sin6_port);
snum = &tmpaddr.v6.sin6_port;
break;
)
default: /* Common sockaddr verification. */
af = sctp_sockaddr_af(sp, addr, len);
if (!af)
return -EINVAL; return -EINVAL;
};
/* PF specific bind() address verification. */
if (!sp->pf->bind_verify(sp, addr))
return -EADDRNOTAVAIL;
snum= ntohs(addr->v4.sin_port);
SCTP_DEBUG_PRINTK("sctp_do_bind: port: %d, new port: %d\n", SCTP_DEBUG_PRINTK("sctp_do_bind: port: %d, new port: %d\n",
bp->port, *snum); bp->port, snum);
/* We must either be unbound, or bind to the same port. */ /* We must either be unbound, or bind to the same port. */
if (bp->port && (*snum != bp->port)) { if (bp->port && (snum != bp->port)) {
SCTP_DEBUG_PRINTK("sctp_do_bind:" SCTP_DEBUG_PRINTK("sctp_do_bind:"
" New port %d does not match existing port " " New port %d does not match existing port "
"%d.\n", *snum, bp->port); "%d.\n", snum, bp->port);
return -EINVAL; return -EINVAL;
} }
if (*snum && *snum < PROT_SOCK && !capable(CAP_NET_BIND_SERVICE)) if (snum && snum < PROT_SOCK && !capable(CAP_NET_BIND_SERVICE))
return -EACCES; return -EACCES;
/* FIXME - Make socket understand that there might be multiple bind
* addresses and there will be multiple source addresses involved in
* routing and failover decisions.
*/
sctp_sk_addr_set(sk, &tmpaddr, &saveaddr);
/* Make sure we are allowed to bind here. /* Make sure we are allowed to bind here.
* The function sctp_get_port_local() does duplicate address * The function sctp_get_port_local() does duplicate address
* detection. * detection.
*/ */
if ((ret = sctp_get_port_local(sk, *snum))) { if ((ret = sctp_get_port_local(sk, addr))) {
sctp_sk_addr_restore(sk, &saveaddr);
if (ret == (long) sk) { if (ret == (long) sk) {
/* This endpoint has a conflicting address. */ /* This endpoint has a conflicting address. */
return -EINVAL; return -EINVAL;
...@@ -237,25 +206,32 @@ SCTP_STATIC int sctp_do_bind(struct sock *sk, union sctp_addr *newaddr, ...@@ -237,25 +206,32 @@ SCTP_STATIC int sctp_do_bind(struct sock *sk, union sctp_addr *newaddr,
} }
/* Refresh ephemeral port. */ /* Refresh ephemeral port. */
if (!*snum) if (!snum)
*snum = inet_sk(sk)->num; snum = inet_sk(sk)->num;
/* The getsockname() API depends on 'sport' being set. */
inet_sk(sk)->sport = htons(inet_sk(sk)->num);
/* Add the address to the bind address list. */ /* Add the address to the bind address list. */
sctp_local_bh_disable(); sctp_local_bh_disable();
sctp_write_lock(&ep->base.addr_lock); sctp_write_lock(&ep->base.addr_lock);
/* Use GFP_ATOMIC since BHs are disabled. */ /* Use GFP_ATOMIC since BHs are disabled. */
if ((ret = sctp_add_bind_addr(bp, &tmpaddr, GFP_ATOMIC))) { addr->v4.sin_port = ntohs(addr->v4.sin_port);
sctp_sk_addr_restore(sk, &saveaddr); ret = sctp_add_bind_addr(bp, addr, GFP_ATOMIC);
} else if (!bp->port) { addr->v4.sin_port = htons(addr->v4.sin_port);
bp->port = *snum; if (!ret && !bp->port)
} bp->port = snum;
sctp_write_unlock(&ep->base.addr_lock); sctp_write_unlock(&ep->base.addr_lock);
sctp_local_bh_enable(); sctp_local_bh_enable();
/* Copy back into socket for getsockname() use. */
if (!ret) {
inet_sk(sk)->sport = htons(inet_sk(sk)->num);
af->to_sk(addr, sk);
}
return ret; return ret;
} }
...@@ -778,7 +754,7 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk, ...@@ -778,7 +754,7 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
* For a peeled-off socket, msg_name is ignored. * For a peeled-off socket, msg_name is ignored.
*/ */
if ((SCTP_SOCKET_UDP_HIGH_BANDWIDTH != sp->type) && msg->msg_name) { if ((SCTP_SOCKET_UDP_HIGH_BANDWIDTH != sp->type) && msg->msg_name) {
err = sctp_verify_addr(sk, (struct sockaddr *)msg->msg_name, err = sctp_verify_addr(sk, (union sctp_addr *)msg->msg_name,
msg->msg_namelen); msg->msg_namelen);
if (err) if (err)
return err; return err;
...@@ -1355,13 +1331,10 @@ static inline int sctp_setsockopt_set_peer_addr_params(struct sock *sk, ...@@ -1355,13 +1331,10 @@ static inline int sctp_setsockopt_set_peer_addr_params(struct sock *sk,
* optlen - the size of the buffer. * optlen - the size of the buffer.
*/ */
SCTP_STATIC int sctp_setsockopt(struct sock *sk, int level, int optname, SCTP_STATIC int sctp_setsockopt(struct sock *sk, int level, int optname,
char *optval, int optlen) char *optval, int optlen)
{ {
int retval = 0; int retval = 0;
char *tmp; char *tmp;
sctp_protocol_t *proto = sctp_get_protocol();
struct list_head *pos;
sctp_func_t *af;
SCTP_DEBUG_PRINTK("sctp_setsockopt(sk: %p... optname: %d)\n", SCTP_DEBUG_PRINTK("sctp_setsockopt(sk: %p... optname: %d)\n",
sk, optname); sk, optname);
...@@ -1373,14 +1346,9 @@ SCTP_STATIC int sctp_setsockopt(struct sock *sk, int level, int optname, ...@@ -1373,14 +1346,9 @@ SCTP_STATIC int sctp_setsockopt(struct sock *sk, int level, int optname,
* are at all well-founded. * are at all well-founded.
*/ */
if (level != SOL_SCTP) { if (level != SOL_SCTP) {
list_for_each(pos, &proto->address_families) { struct sctp_af *af = sctp_sk(sk)->pf->af;
af = list_entry(pos, sctp_func_t, list); retval = af->setsockopt(sk, level, optname, optval, optlen);
goto out_nounlock;
retval = af->setsockopt(sk, level, optname, optval,
optlen);
if (retval < 0)
goto out_nounlock;
}
} }
sctp_lock_sock(sk); sctp_lock_sock(sk);
...@@ -1484,7 +1452,7 @@ SCTP_STATIC int sctp_connect(struct sock *sk, struct sockaddr *uaddr, ...@@ -1484,7 +1452,7 @@ SCTP_STATIC int sctp_connect(struct sock *sk, struct sockaddr *uaddr,
goto out_unlock; goto out_unlock;
} }
err = sctp_verify_addr(sk, uaddr, addr_len); err = sctp_verify_addr(sk, (union sctp_addr *)uaddr, addr_len);
if (err) if (err)
goto out_unlock; goto out_unlock;
...@@ -1942,9 +1910,6 @@ SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname, ...@@ -1942,9 +1910,6 @@ SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname,
char *optval, int *optlen) char *optval, int *optlen)
{ {
int retval = 0; int retval = 0;
sctp_protocol_t *proto = sctp_get_protocol();
sctp_func_t *af;
struct list_head *pos;
int len; int len;
SCTP_DEBUG_PRINTK("sctp_getsockopt(sk: %p, ...)\n", sk); SCTP_DEBUG_PRINTK("sctp_getsockopt(sk: %p, ...)\n", sk);
...@@ -1956,13 +1921,10 @@ SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname, ...@@ -1956,13 +1921,10 @@ SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname,
* are at all well-founded. * are at all well-founded.
*/ */
if (level != SOL_SCTP) { if (level != SOL_SCTP) {
list_for_each(pos, &proto->address_families) { struct sctp_af *af = sctp_sk(sk)->pf->af;
af = list_entry(pos, sctp_func_t, list);
retval = af->getsockopt(sk, level, optname, retval = af->getsockopt(sk, level, optname, optval, optlen);
optval, optlen); return retval;
if (retval < 0)
return retval;
}
} }
if (get_user(len, optlen)) if (get_user(len, optlen))
...@@ -2030,12 +1992,17 @@ static void sctp_unhash(struct sock *sk) ...@@ -2030,12 +1992,17 @@ static void sctp_unhash(struct sock *sk)
*/ */
static sctp_bind_bucket_t *sctp_bucket_create(sctp_bind_hashbucket_t *head, static sctp_bind_bucket_t *sctp_bucket_create(sctp_bind_hashbucket_t *head,
unsigned short snum); unsigned short snum);
static long sctp_get_port_local(struct sock *sk, unsigned short snum) static long sctp_get_port_local(struct sock *sk, union sctp_addr *addr)
{ {
sctp_bind_hashbucket_t *head; /* hash list */ sctp_bind_hashbucket_t *head; /* hash list */
sctp_bind_bucket_t *pp; /* hash list port iterator */ sctp_bind_bucket_t *pp; /* hash list port iterator */
sctp_protocol_t *sctp = sctp_get_protocol(); sctp_protocol_t *sctp = sctp_get_protocol();
unsigned short snum;
int ret; int ret;
/* NOTE: Remember to put this back to net order. */
addr->v4.sin_port = ntohs(addr->v4.sin_port);
snum = addr->v4.sin_port;
SCTP_DEBUG_PRINTK("sctp_get_port() begins, snum=%d\n", snum); SCTP_DEBUG_PRINTK("sctp_get_port() begins, snum=%d\n", snum);
...@@ -2101,6 +2068,7 @@ static long sctp_get_port_local(struct sock *sk, unsigned short snum) ...@@ -2101,6 +2068,7 @@ static long sctp_get_port_local(struct sock *sk, unsigned short snum)
} }
} }
if (pp != NULL && pp->sk != NULL) { if (pp != NULL && pp->sk != NULL) {
/* We had a port hash table hit - there is an /* We had a port hash table hit - there is an
* available port (pp != NULL) and it is being * available port (pp != NULL) and it is being
...@@ -2108,7 +2076,6 @@ static long sctp_get_port_local(struct sock *sk, unsigned short snum) ...@@ -2108,7 +2076,6 @@ static long sctp_get_port_local(struct sock *sk, unsigned short snum)
* socket is going to be sk2. * socket is going to be sk2.
*/ */
int sk_reuse = sk->reuse; int sk_reuse = sk->reuse;
union sctp_addr tmpaddr;
struct sock *sk2 = pp->sk; struct sock *sk2 = pp->sk;
SCTP_DEBUG_PRINTK("sctp_get_port() found a " SCTP_DEBUG_PRINTK("sctp_get_port() found a "
...@@ -2116,27 +2083,6 @@ static long sctp_get_port_local(struct sock *sk, unsigned short snum) ...@@ -2116,27 +2083,6 @@ static long sctp_get_port_local(struct sock *sk, unsigned short snum)
if (pp->fastreuse != 0 && sk->reuse != 0) if (pp->fastreuse != 0 && sk->reuse != 0)
goto success; goto success;
/* FIXME - multiple addresses need to be supported
* later.
*/
switch (sk->family) {
case PF_INET:
tmpaddr.v4.sin_family = AF_INET;
tmpaddr.v4.sin_port = snum;
tmpaddr.v4.sin_addr.s_addr = inet_sk(sk)->rcv_saddr;
break;
case PF_INET6:
SCTP_V6(tmpaddr.v6.sin6_family = AF_INET6;
tmpaddr.v6.sin6_port = snum;
tmpaddr.v6.sin6_addr = inet6_sk(sk)->rcv_saddr;
)
break;
default:
break;
};
/* Run through the list of sockets bound to the port /* Run through the list of sockets bound to the port
* (pp->port) [via the pointers bind_next and * (pp->port) [via the pointers bind_next and
* bind_pprev in the struct sock *sk2 (pp->sk)]. On each one, * bind_pprev in the struct sock *sk2 (pp->sk)]. On each one,
...@@ -2154,8 +2100,7 @@ static long sctp_get_port_local(struct sock *sk, unsigned short snum) ...@@ -2154,8 +2100,7 @@ static long sctp_get_port_local(struct sock *sk, unsigned short snum)
if (sk_reuse && sk2->reuse) if (sk_reuse && sk2->reuse)
continue; continue;
if (sctp_bind_addr_match(&ep2->base.bind_addr, if (sctp_bind_addr_match(&ep2->base.bind_addr, addr,
&tmpaddr,
sctp_sk(sk))) sctp_sk(sk)))
goto found; goto found;
} }
...@@ -2207,12 +2152,25 @@ static long sctp_get_port_local(struct sock *sk, unsigned short snum) ...@@ -2207,12 +2152,25 @@ static long sctp_get_port_local(struct sock *sk, unsigned short snum)
sctp_local_bh_enable(); sctp_local_bh_enable();
SCTP_DEBUG_PRINTK("sctp_get_port() ends, ret=%d\n", ret); SCTP_DEBUG_PRINTK("sctp_get_port() ends, ret=%d\n", ret);
addr->v4.sin_port = htons(addr->v4.sin_port);
return ret; return ret;
} }
/* Assign a 'snum' port to the socket. If snum == 0, an ephemeral
* port is requested.
*/
static int sctp_get_port(struct sock *sk, unsigned short snum) static int sctp_get_port(struct sock *sk, unsigned short snum)
{ {
long ret = sctp_get_port_local(sk, snum); long ret;
union sctp_addr addr;
struct sctp_af *af = sctp_sk(sk)->pf->af;
/* Set up a dummy address struct from the sk. */
af->from_sk(&addr, sk);
addr.v4.sin_port = htons(snum);
/* Note: sk->num gets filled in if ephemeral port request. */
ret = sctp_get_port_local(sk, &addr);
return (ret ? 1 : 0); return (ret ? 1 : 0);
} }
...@@ -2413,7 +2371,7 @@ void sctp_put_port(struct sock *sk) ...@@ -2413,7 +2371,7 @@ void sctp_put_port(struct sock *sk)
static int sctp_autobind(struct sock *sk) static int sctp_autobind(struct sock *sk)
{ {
union sctp_addr autoaddr; union sctp_addr autoaddr;
struct sctp_func *af; struct sctp_af *af;
unsigned short port; unsigned short port;
/* Initialize a local sockaddr structure to INADDR_ANY. */ /* Initialize a local sockaddr structure to INADDR_ANY. */
...@@ -2537,58 +2495,6 @@ SCTP_STATIC int sctp_msghdr_parse(const struct msghdr *msg, ...@@ -2537,58 +2495,6 @@ SCTP_STATIC int sctp_msghdr_parse(const struct msghdr *msg,
return 0; return 0;
} }
/* Setup sk->rcv_saddr before calling get_port(). */
static inline void sctp_sk_addr_set(struct sock *sk,
const union sctp_addr *newaddr,
union sctp_addr *saveaddr)
{
struct inet_opt *inet = inet_sk(sk);
saveaddr->sa.sa_family = newaddr->sa.sa_family;
switch (newaddr->sa.sa_family) {
case AF_INET:
saveaddr->v4.sin_addr.s_addr = inet->rcv_saddr;
inet->rcv_saddr = inet->saddr = newaddr->v4.sin_addr.s_addr;
break;
case AF_INET6:
SCTP_V6({
struct ipv6_pinfo *np = inet6_sk(sk);
saveaddr->v6.sin6_addr = np->rcv_saddr;
np->rcv_saddr = np->saddr = newaddr->v6.sin6_addr;
break;
})
default:
break;
};
}
/* Restore sk->rcv_saddr after failing get_port(). */
static inline void sctp_sk_addr_restore(struct sock *sk, const union sctp_addr *addr)
{
struct inet_opt *inet = inet_sk(sk);
switch (addr->sa.sa_family) {
case AF_INET:
inet->rcv_saddr = inet->saddr = addr->v4.sin_addr.s_addr;
break;
case AF_INET6:
SCTP_V6({
struct ipv6_pinfo *np = inet6_sk(sk);
np->rcv_saddr = np->saddr = addr->v6.sin6_addr;
break;
})
default:
break;
};
}
/* /*
* Wait for a packet.. * Wait for a packet..
* Note: This function is the same function as in core/datagram.c * Note: This function is the same function as in core/datagram.c
...@@ -2711,27 +2617,15 @@ static struct sk_buff *sctp_skb_recv_datagram(struct sock *sk, int flags, int no ...@@ -2711,27 +2617,15 @@ static struct sk_buff *sctp_skb_recv_datagram(struct sock *sk, int flags, int no
} }
/* Verify that this is a valid address. */ /* Verify that this is a valid address. */
static int sctp_verify_addr(struct sock *sk, struct sockaddr *addr, int len) static int sctp_verify_addr(struct sock *sk, union sctp_addr *addr, int len)
{ {
struct sctp_func *af; struct sctp_af *af;
/* Check minimum size. */
if (len < sizeof (struct sockaddr))
return -EINVAL;
/* Do we support this address family in general? */ /* Verify basic sockaddr. */
af = sctp_get_af_specific(addr->sa_family); af = sctp_sockaddr_af(sctp_sk(sk), addr, len);
if (!af) if (!af)
return -EINVAL; return -EINVAL;
/* Does this PF support this AF? */
if (!sctp_sk(sk)->pf->af_supported(addr->sa_family))
return -EINVAL;
/* Verify the minimum for this AF sockaddr. */
if (len < af->sockaddr_len)
return -EINVAL;
/* Is this a valid SCTP address? */ /* Is this a valid SCTP address? */
if (!af->addr_valid((union sctp_addr *)addr)) if (!af->addr_valid((union sctp_addr *)addr))
return -EINVAL; return -EINVAL;
......
...@@ -207,7 +207,7 @@ void sctp_transport_route(sctp_transport_t *transport, union sctp_addr *saddr, ...@@ -207,7 +207,7 @@ void sctp_transport_route(sctp_transport_t *transport, union sctp_addr *saddr,
struct sctp_opt *opt) struct sctp_opt *opt)
{ {
sctp_association_t *asoc = transport->asoc; sctp_association_t *asoc = transport->asoc;
struct sctp_func *af = transport->af_specific; struct sctp_af *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;
......
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