Commit f72c208b authored by David S. Miller's avatar David S. Miller

Merge http://linux-lksctp.bkbits.net/lksctp-2.5

into nuts.ninka.net:/disk1/davem/BK/net-2.5
parents f3e971e4 4a542137
/* SCTP kernel reference Implementation
* (C) Copyright IBM Corp. 2001, 2003
* Copyright (c) 1999-2000 Cisco, Inc.
* Copyright (c) 1999-2001 Motorola, Inc.
* Copyright (c) 2001-2002 International Business Machines, Corp.
* Copyright (c) 2001 Intel Corp.
* Copyright (c) 2001 Nokia, Inc.
* Copyright (c) 2001 La Monte H.P. Yarroll
......@@ -42,6 +42,8 @@
* randall@sctp.chicago.il.us
* kmorneau@cisco.com
* qxie1@email.mot.com
* Sridhar Samudrala <sri@us.ibm.com>
* Kevin Gao <kevin.gao@intel.com>
*
* Any bugs reported given to us we will try to fix... any fixes shared will
* be incorporated into the next SCTP release.
......@@ -507,6 +509,11 @@ typedef struct sctp_cwr_chunk {
* The ASCONF Parameter Response is used in the ASCONF-ACK to
* report status of ASCONF processing.
*/
typedef struct sctp_addip_param {
sctp_paramhdr_t param_hdr;
__u32 crr_id;
}sctp_addip_param_t __attribute__((packed));
typedef struct sctp_addiphdr {
__u32 serial;
__u8 params[0];
......
/* SCTP kernel reference Implementation
* (C) Copyright IBM Corp. 2001, 2003
* Copyright (c) 1999-2000 Cisco, Inc.
* Copyright (c) 1999-2001 Motorola, Inc.
* Copyright (c) 2001-2003 International Business Machines, Corp.
* Copyright (c) 2001-2003 Intel Corp.
*
* This file is part of the SCTP kernel reference Implementation
......@@ -40,6 +40,7 @@
* Sridhar Samudrala <sri@us.ibm.com>
* Ardelle Fan <ardelle.fan@intel.com>
* Ryan Layer <rmlayer@us.ibm.com>
* Kevin Gao <kevin.gao@intel.com>
*
* Any bugs reported given to us we will try to fix... any fixes shared will
* be incorporated into the next SCTP release.
......@@ -145,6 +146,7 @@ int sctp_primitive_SHUTDOWN(struct sctp_association *, void *arg);
int sctp_primitive_ABORT(struct sctp_association *, void *arg);
int sctp_primitive_SEND(struct sctp_association *, void *arg);
int sctp_primitive_REQUESTHEARTBEAT(struct sctp_association *, void *arg);
int sctp_primitive_ASCONF(struct sctp_association *, void *arg);
/*
* sctp/crc32c.c
......@@ -404,6 +406,12 @@ static inline struct list_head *sctp_list_dequeue(struct list_head *list)
return result;
}
/* Tests if the list has one and only one entry. */
static inline int sctp_list_single_entry(struct list_head *head)
{
return ((head->next != head) && (head->next == head->prev));
}
/* Calculate the size (in bytes) occupied by the data of an iovec. */
static inline size_t get_user_iov_size(struct iovec *iov, int iovlen)
{
......@@ -525,6 +533,19 @@ static inline int ipver2af(__u8 ipver)
};
}
/* Convert from an address parameter type to an address family. */
static inline int param_type2af(__u16 type)
{
switch (type) {
case SCTP_PARAM_IPV4_ADDRESS:
return AF_INET;
case SCTP_PARAM_IPV6_ADDRESS:
return AF_INET6;
default:
return 0;
};
}
/* Perform some sanity checks. */
static inline int sctp_sanity_check(void)
{
......
/* SCTP kernel reference Implementation
* (C) Copyright IBM Corp. 2001, 2003
* Copyright (c) 1999-2000 Cisco, Inc.
* Copyright (c) 1999-2001 Motorola, Inc.
* Copyright (c) 2001 Intel Corp.
* Copyright (c) 2001-2002 International Business Machines Corp.
*
* This file is part of the SCTP kernel reference Implementation
*
......@@ -41,6 +41,7 @@
* Sridhar Samudrala <sri@us.ibm.com>
* Daisy Chang <daisyc@us.ibm.com>
* Ardelle Fan <ardelle.fan@intel.com>
* Kevin Gao <kevin.gao@intel.com>
*
* Any bugs reported given to us we will try to fix... any fixes shared will
* be incorporated into the next SCTP release.
......@@ -268,6 +269,9 @@ struct sctp_chunk *sctp_process_asconf(struct sctp_association *asoc,
struct sctp_chunk *asconf,
int vparam_len);
struct sctp_chunk *sctp_make_asconf_set_prim(struct sctp_association *asoc,
union sctp_addr *addr);
void sctp_chunk_assign_tsn(struct sctp_chunk *);
void sctp_chunk_assign_ssn(struct sctp_chunk *);
......@@ -330,12 +334,6 @@ void sctp_send_stale_cookie_err(const struct sctp_endpoint *ep,
__u32 sctp_generate_tag(const struct sctp_endpoint *);
__u32 sctp_generate_tsn(const struct sctp_endpoint *);
/* 4th level prototypes */
void sctp_param2sockaddr(union sctp_addr *addr, union sctp_addr_param *,
__u16 port, int iif);
int sctp_addr2sockaddr(const union sctp_params, union sctp_addr *);
int sockaddr2sctp_addr(const union sctp_addr *, union sctp_addr_param *);
/* Extern declarations for major data structures. */
const sctp_sm_table_entry_t *sctp_chunk_event_lookup(sctp_cid_t, sctp_state_t);
extern const sctp_sm_table_entry_t
......
/* SCTP kernel reference Implementation
* (C) Copyright IBM Corp. 2001, 2003
* Copyright (c) 1999-2000 Cisco, Inc.
* Copyright (c) 1999-2001 Motorola, Inc.
* Copyright (c) 2001 Intel Corp.
* Copyright (c) 2001-2003 International Business Machines Corp.
*
* This file is part of the SCTP kernel reference Implementation
*
......@@ -45,6 +45,7 @@
* Ardelle Fan <ardelle.fan@intel.com>
* Ryan Layer <rmlayer@us.ibm.com>
* Anup Pemmaiah <pemmaiah@cc.usu.edu>
* Kevin Gao <kevin.gao@intel.com>
*
* Any bugs reported given to us we will try to fix... any fixes shared will
* be incorporated into the next SCTP release.
......@@ -217,86 +218,6 @@ extern struct sctp_globals {
#define sctp_local_addr_list (sctp_globals.local_addr_list)
#define sctp_local_addr_lock (sctp_globals.local_addr_lock)
/*
* Pointers to address related SCTP functions.
* (i.e. things that depend on the address family.)
*/
struct sctp_af {
int (*sctp_xmit) (struct sk_buff *skb,
struct sctp_transport *,
int ipfragok);
int (*setsockopt) (struct sock *sk,
int level,
int optname,
char *optval,
int optlen);
int (*getsockopt) (struct sock *sk,
int level,
int optname,
char *optval,
int *optlen);
struct dst_entry *(*get_dst) (struct sctp_association *asoc,
union sctp_addr *daddr,
union sctp_addr *saddr);
void (*get_saddr) (struct sctp_association *asoc,
struct dst_entry *dst,
union sctp_addr *daddr,
union sctp_addr *saddr);
void (*copy_addrlist) (struct list_head *,
struct net_device *);
void (*dst_saddr) (union sctp_addr *saddr,
struct dst_entry *dst,
unsigned short port);
int (*cmp_addr) (const union sctp_addr *addr1,
const union sctp_addr *addr2);
void (*addr_copy) (union sctp_addr *dst,
union sctp_addr *src);
void (*from_skb) (union sctp_addr *,
struct sk_buff *skb,
int saddr);
void (*from_sk) (union sctp_addr *,
struct sock *sk);
void (*to_sk_saddr) (union sctp_addr *,
struct sock *sk);
void (*to_sk_daddr) (union sctp_addr *,
struct sock *sk);
int (*addr_valid) (union sctp_addr *,
struct sctp_opt *);
sctp_scope_t (*scope) (union sctp_addr *);
void (*inaddr_any) (union sctp_addr *, unsigned short);
int (*is_any) (const union sctp_addr *);
int (*available) (union sctp_addr *,
struct sctp_opt *);
int (*skb_iif) (const struct sk_buff *sk);
int (*is_ce) (const struct sk_buff *sk);
void (*seq_dump_addr)(struct seq_file *seq,
union sctp_addr *addr);
__u16 net_header_len;
int sockaddr_len;
sa_family_t sa_family;
struct list_head list;
};
struct sctp_af *sctp_get_af_specific(sa_family_t);
int sctp_register_af(struct sctp_af *);
/* Protocol family functions. */
struct sctp_pf {
void (*event_msgname)(struct sctp_ulpevent *, char *, int *);
void (*skb_msgname) (struct sk_buff *, char *, int *);
int (*af_supported) (sa_family_t, struct sctp_opt *);
int (*cmp_addr) (const union sctp_addr *,
const union sctp_addr *,
struct sctp_opt *);
int (*bind_verify) (struct sctp_opt *, union sctp_addr *);
int (*send_verify) (struct sctp_opt *, union sctp_addr *);
int (*supported_addrs)(const struct sctp_opt *, __u16 *);
struct sock *(*create_accept_sk) (struct sock *sk,
struct sctp_association *asoc);
void (*addr_v4map) (struct sctp_opt *, union sctp_addr *);
struct sctp_af *af;
};
/* SCTP Socket type: UDP or TCP style. */
typedef enum {
SCTP_SOCKET_UDP = 0,
......@@ -488,6 +409,92 @@ static inline __u16 sctp_ssn_next(struct sctp_stream *stream, __u16 id)
return stream->ssn[id]++;
}
/*
* Pointers to address related SCTP functions.
* (i.e. things that depend on the address family.)
*/
struct sctp_af {
int (*sctp_xmit) (struct sk_buff *skb,
struct sctp_transport *,
int ipfragok);
int (*setsockopt) (struct sock *sk,
int level,
int optname,
char *optval,
int optlen);
int (*getsockopt) (struct sock *sk,
int level,
int optname,
char *optval,
int *optlen);
struct dst_entry *(*get_dst) (struct sctp_association *asoc,
union sctp_addr *daddr,
union sctp_addr *saddr);
void (*get_saddr) (struct sctp_association *asoc,
struct dst_entry *dst,
union sctp_addr *daddr,
union sctp_addr *saddr);
void (*copy_addrlist) (struct list_head *,
struct net_device *);
void (*dst_saddr) (union sctp_addr *saddr,
struct dst_entry *dst,
unsigned short port);
int (*cmp_addr) (const union sctp_addr *addr1,
const union sctp_addr *addr2);
void (*addr_copy) (union sctp_addr *dst,
union sctp_addr *src);
void (*from_skb) (union sctp_addr *,
struct sk_buff *skb,
int saddr);
void (*from_sk) (union sctp_addr *,
struct sock *sk);
void (*to_sk_saddr) (union sctp_addr *,
struct sock *sk);
void (*to_sk_daddr) (union sctp_addr *,
struct sock *sk);
void (*from_addr_param) (union sctp_addr *,
union sctp_addr_param *,
__u16 port, int iif);
int (*to_addr_param) (const union sctp_addr *,
union sctp_addr_param *);
int (*addr_valid) (union sctp_addr *,
struct sctp_opt *);
sctp_scope_t (*scope) (union sctp_addr *);
void (*inaddr_any) (union sctp_addr *, unsigned short);
int (*is_any) (const union sctp_addr *);
int (*available) (union sctp_addr *,
struct sctp_opt *);
int (*skb_iif) (const struct sk_buff *sk);
int (*is_ce) (const struct sk_buff *sk);
void (*seq_dump_addr)(struct seq_file *seq,
union sctp_addr *addr);
__u16 net_header_len;
int sockaddr_len;
sa_family_t sa_family;
struct list_head list;
};
struct sctp_af *sctp_get_af_specific(sa_family_t);
int sctp_register_af(struct sctp_af *);
/* Protocol family functions. */
struct sctp_pf {
void (*event_msgname)(struct sctp_ulpevent *, char *, int *);
void (*skb_msgname) (struct sk_buff *, char *, int *);
int (*af_supported) (sa_family_t, struct sctp_opt *);
int (*cmp_addr) (const union sctp_addr *,
const union sctp_addr *,
struct sctp_opt *);
int (*bind_verify) (struct sctp_opt *, union sctp_addr *);
int (*send_verify) (struct sctp_opt *, union sctp_addr *);
int (*supported_addrs)(const struct sctp_opt *, __u16 *);
struct sock *(*create_accept_sk) (struct sock *sk,
struct sctp_association *asoc);
void (*addr_v4map) (struct sctp_opt *, union sctp_addr *);
struct sctp_af *af;
};
/* Structure to track chunk fragments that have been acked, but peer
* fragments of the same message have not.
*/
......@@ -1688,6 +1695,8 @@ struct sctp_transport *sctp_assoc_choose_shutdown_transport(
void sctp_assoc_update_retran_path(struct sctp_association *);
struct sctp_transport *sctp_assoc_lookup_paddr(const struct sctp_association *,
const union sctp_addr *);
int sctp_assoc_lookup_laddr(struct sctp_association *asoc,
const union sctp_addr *laddr);
struct sctp_transport *sctp_assoc_add_peer(struct sctp_association *,
const union sctp_addr *address,
const int gfp);
......
......@@ -551,13 +551,15 @@ struct sctp_status {
};
/*
* 8.3, 8.5 get all peer/local addresses on a socket
* This parameter struct is for getsockopt
* 8.3, 8.5 get all peer/local addresses in an association.
* This parameter struct is used by SCTP_GET_PEER_ADDRS and
* SCTP_GET_LOCAL_ADDRS socket options used internally to implement
* sctp_getpaddrs() and sctp_getladdrs() API.
*/
struct sctp_getaddrs {
sctp_assoc_t assoc_id;
int addr_num;
struct sockaddr_storage *addrs;
struct sockaddr *addrs;
};
/* These are bit fields for msghdr->msg_flags. See section 5.1. */
......
/* SCTP kernel reference Implementation
* (C) Copyright IBM Corp. 2001, 2003
* Copyright (c) 1999-2000 Cisco, Inc.
* Copyright (c) 1999-2001 Motorola, Inc.
* Copyright (c) 2001-2003 International Business Machines Corp.
* Copyright (c) 2001 Intel Corp.
* Copyright (c) 2001 La Monte H.P. Yarroll
*
......@@ -42,6 +42,7 @@
* Sridhar Samudrala <sri@us.ibm.com>
* Daisy Chang <daisyc@us.ibm.com>
* Ryan Layer <rmlayer@us.ibm.com>
* Kevin Gao <kevin.gao@intel.com>
*
* Any bugs reported given to us we will try to fix... any fixes shared will
* be incorporated into the next SCTP release.
......@@ -1155,3 +1156,23 @@ int sctp_assoc_set_bind_addr_from_cookie(struct sctp_association *asoc,
return sctp_raw_to_bind_addrs(&asoc->base.bind_addr, raw, var_size3,
asoc->ep->base.bind_addr.port, gfp);
}
/* Lookup laddr in the bind address list of an association. */
int sctp_assoc_lookup_laddr(struct sctp_association *asoc,
const union sctp_addr *laddr)
{
int found;
sctp_read_lock(&asoc->base.addr_lock);
if ((asoc->base.bind_addr.port == ntohs(laddr->v4.sin_port)) &&
sctp_bind_addr_match(&asoc->base.bind_addr, laddr,
sctp_sk(asoc->base.sk))) {
found = 1;
goto out;
}
found = 0;
out:
sctp_read_unlock(&asoc->base.addr_lock);
return found;
}
/* SCTP kernel reference Implementation
* (C) Copyright IBM Corp. 2001, 2003
* Copyright (c) Cisco 1999,2000
* Copyright (c) Motorola 1999,2000,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.
......@@ -223,6 +223,8 @@ union sctp_params sctp_bind_addrs_to_raw(const struct sctp_bind_addr *bp,
int len;
struct sctp_sockaddr_entry *addr;
struct list_head *pos;
struct sctp_af *af;
addrparms_len = 0;
len = 0;
......@@ -247,7 +249,8 @@ union sctp_params sctp_bind_addrs_to_raw(const struct sctp_bind_addr *bp,
list_for_each(pos, &bp->address_list) {
addr = list_entry(pos, struct sctp_sockaddr_entry, list);
len = sockaddr2sctp_addr(&addr->a, &rawaddr);
af = sctp_get_af_specific(addr->a.v4.sin_family);
len = af->to_addr_param(&addr->a, &rawaddr);
memcpy(addrparms.v, &rawaddr, len);
addrparms.v += len;
addrparms_len += len;
......@@ -270,34 +273,31 @@ int sctp_raw_to_bind_addrs(struct sctp_bind_addr *bp, __u8 *raw_addr_list,
union sctp_addr addr;
int retval = 0;
int len;
struct sctp_af *af;
/* Convert the raw address to standard address format */
while (addrs_len) {
param = (struct sctp_paramhdr *)raw_addr_list;
rawaddr = (union sctp_addr_param *)raw_addr_list;
switch (param->type) {
case SCTP_PARAM_IPV4_ADDRESS:
case SCTP_PARAM_IPV6_ADDRESS:
sctp_param2sockaddr(&addr, rawaddr, port, 0);
retval = sctp_add_bind_addr(bp, &addr, gfp);
if (retval) {
/* Can't finish building the list, clean up. */
sctp_bind_addr_clean(bp);
break;;
}
len = ntohs(param->length);
addrs_len -= len;
raw_addr_list += len;
break;
default:
/* Corrupted raw addr list! */
af = sctp_get_af_specific(param_type2af(param->type));
if (unlikely(!af)) {
retval = -EINVAL;
sctp_bind_addr_clean(bp);
break;
}
if (retval)
break;
af->from_addr_param(&addr, rawaddr, port, 0);
retval = sctp_add_bind_addr(bp, &addr, gfp);
if (retval) {
/* Can't finish building the list, clean up. */
sctp_bind_addr_clean(bp);
break;;
}
len = ntohs(param->length);
addrs_len -= len;
raw_addr_list += len;
}
return retval;
......
......@@ -768,6 +768,7 @@ static struct sctp_association *__sctp_rcv_init_lookup(struct sk_buff *skb,
union sctp_params params;
sctp_init_chunk_t *init;
struct sctp_transport *transport;
struct sctp_af *af;
ch = (sctp_chunkhdr_t *) skb->data;
......@@ -802,11 +803,12 @@ static struct sctp_association *__sctp_rcv_init_lookup(struct sk_buff *skb,
sctp_walk_params(params, init, init_hdr.params) {
/* Note: Ignoring hostname addresses. */
if ((SCTP_PARAM_IPV4_ADDRESS != params.p->type) &&
(SCTP_PARAM_IPV6_ADDRESS != params.p->type))
af = sctp_get_af_specific(param_type2af(params.p->type));
if (!af)
continue;
sctp_param2sockaddr(paddr, params.addr, ntohs(sh->source), 0);
af->from_addr_param(paddr, params.addr, ntohs(sh->source), 0);
asoc = __sctp_lookup_association(laddr, paddr, &transport);
if (asoc)
return asoc;
......
......@@ -399,6 +399,33 @@ static void sctp_v6_to_sk_daddr(union sctp_addr *addr, struct sock *sk)
}
}
/* Initialize a sctp_addr from an address parameter. */
static void sctp_v6_from_addr_param(union sctp_addr *addr,
union sctp_addr_param *param,
__u16 port, int iif)
{
addr->v6.sin6_family = AF_INET6;
addr->v6.sin6_port = port;
addr->v6.sin6_flowinfo = 0; /* BUG */
ipv6_addr_copy(&addr->v6.sin6_addr, &param->v6.addr);
addr->v6.sin6_scope_id = iif;
}
/* Initialize an address parameter from a sctp_addr and return the length
* of the address parameter.
*/
static int sctp_v6_to_addr_param(const union sctp_addr *addr,
union sctp_addr_param *param)
{
int length = sizeof(sctp_ipv6addr_param_t);
param->v6.param_hdr.type = SCTP_PARAM_IPV6_ADDRESS;
param->v6.param_hdr.length = ntohs(length);
ipv6_addr_copy(&param->v6.addr, &addr->v6.sin6_addr);
return length;
}
/* Initialize a sctp_addr from a dst_entry. */
static void sctp_v6_dst_saddr(union sctp_addr *addr, struct dst_entry *dst,
unsigned short port)
......@@ -903,6 +930,8 @@ static struct sctp_af sctp_ipv6_specific = {
.from_sk = sctp_v6_from_sk,
.to_sk_saddr = sctp_v6_to_sk_saddr,
.to_sk_daddr = sctp_v6_to_sk_daddr,
.from_addr_param = sctp_v6_from_addr_param,
.to_addr_param = sctp_v6_to_addr_param,
.dst_saddr = sctp_v6_dst_saddr,
.cmp_addr = sctp_v6_cmp_addr,
.scope = sctp_v6_scope,
......
......@@ -39,6 +39,7 @@
* Narasimha Budihal <narasimha@refcode.org>
* Karl Knutson <karl@athena.chicago.il.us>
* Ardelle Fan <ardelle.fan@intel.com>
* Kevin Gao <kevin.gao@intel.com>
*
* Any bugs reported given to us we will try to fix... any fixes shared will
* be incorporated into the next SCTP release.
......@@ -203,3 +204,16 @@ DECLARE_PRIMITIVE(SEND);
*/
DECLARE_PRIMITIVE(REQUESTHEARTBEAT);
/* ADDIP
* 3.1.1 Address Configuration Change Chunk (ASCONF)
*
* This chunk is used to communicate to the remote endpoint one of the
* configuration change requests that MUST be acknowledged. The
* information carried in the ASCONF Chunk uses the form of a
* Type-Length-Value (TLV), as described in "3.2.1 Optional/
* Variable-length Parameter Format" in RFC2960 [5], forall variable
* parameters.
*/
DECLARE_PRIMITIVE(ASCONF);
......@@ -295,6 +295,31 @@ static void sctp_v4_to_sk_daddr(union sctp_addr *addr, struct sock *sk)
inet_sk(sk)->daddr = addr->v4.sin_addr.s_addr;
}
/* Initialize a sctp_addr from an address parameter. */
static void sctp_v4_from_addr_param(union sctp_addr *addr,
union sctp_addr_param *param,
__u16 port, int iif)
{
addr->v4.sin_family = AF_INET;
addr->v4.sin_port = port;
addr->v4.sin_addr.s_addr = param->v4.addr.s_addr;
}
/* Initialize an address parameter from a sctp_addr and return the length
* of the address parameter.
*/
static int sctp_v4_to_addr_param(const union sctp_addr *addr,
union sctp_addr_param *param)
{
int length = sizeof(sctp_ipv4addr_param_t);
param->v4.param_hdr.type = SCTP_PARAM_IPV4_ADDRESS;
param->v4.param_hdr.length = ntohs(length);
param->v4.addr.s_addr = addr->v4.sin_addr.s_addr;
return length;
}
/* Initialize a sctp_addr from a dst_entry. */
static void sctp_v4_dst_saddr(union sctp_addr *saddr, struct dst_entry *dst,
unsigned short port)
......@@ -862,6 +887,8 @@ struct sctp_af sctp_ipv4_specific = {
.from_sk = sctp_v4_from_sk,
.to_sk_saddr = sctp_v4_to_sk_saddr,
.to_sk_daddr = sctp_v4_to_sk_daddr,
.from_addr_param= sctp_v4_from_addr_param,
.to_addr_param = sctp_v4_to_addr_param,
.dst_saddr = sctp_v4_dst_saddr,
.cmp_addr = sctp_v4_cmp_addr,
.addr_valid = sctp_v4_addr_valid,
......
/* SCTP kernel reference Implementation
* Copyright (C) IBM Corp. 2001, 2003
* Copyright (c) 1999-2000 Cisco, Inc.
* Copyright (c) 1999-2001 Motorola, Inc.
* Copyright (c) 2001-2002 Intel Corp.
* Copyright (c) 2001-2002 International Business Machines Corp.
*
* This file is part of the SCTP kernel reference Implementation
*
......@@ -48,6 +48,7 @@
* Sridhar Samudrala <sri@us.ibm.com>
* Daisy Chang <daisyc@us.ibm.com>
* Ardelle Fan <ardelle.fan@intel.com>
* Kevin Gao <kevin.gao@intel.com>
*
* Any bugs reported given to us we will try to fix... any fixes shared will
* be incorporated into the next SCTP release.
......@@ -1213,6 +1214,7 @@ struct sctp_association *sctp_make_temp_asoc(const struct sctp_endpoint *ep,
struct sctp_association *asoc;
struct sk_buff *skb;
sctp_scope_t scope;
struct sctp_af *af;
/* Create the bare association. */
scope = sctp_scope(sctp_source(chunk));
......@@ -1222,29 +1224,10 @@ struct sctp_association *sctp_make_temp_asoc(const struct sctp_endpoint *ep,
asoc->temp = 1;
skb = chunk->skb;
/* Create an entry for the source address of the packet. */
/* FIXME: Use the af specific helpers. */
switch (skb->nh.iph->version) {
case 4:
asoc->c.peer_addr.v4.sin_family = AF_INET;
asoc->c.peer_addr.v4.sin_port = ntohs(chunk->sctp_hdr->source);
asoc->c.peer_addr.v4.sin_addr.s_addr = skb->nh.iph->saddr;
break;
case 6:
asoc->c.peer_addr.v6.sin6_family = AF_INET6;
asoc->c.peer_addr.v6.sin6_port
= ntohs(chunk->sctp_hdr->source);
asoc->c.peer_addr.v6.sin6_flowinfo = 0; /* BUG BUG BUG */
asoc->c.peer_addr.v6.sin6_addr = skb->nh.ipv6h->saddr;
asoc->c.peer_addr.v6.sin6_scope_id =
((struct inet6_skb_parm *)skb->cb)->iif;
break;
default:
/* Yikes! I never heard of this kind of address. */
af = sctp_get_af_specific(ipver2af(skb->nh.iph->version));
if (unlikely(!af))
goto fail;
};
af->from_skb(&asoc->c.peer_addr, skb, 1);
nodata:
return asoc;
......@@ -1830,11 +1813,14 @@ int sctp_process_init(struct sctp_association *asoc, sctp_cid_t cid,
* stream sequence number shall be set to 0.
*/
/* Allocate storage for the negotiated streams. */
asoc->ssnmap = sctp_ssnmap_new(asoc->peer.i.num_outbound_streams,
asoc->c.sinit_num_ostreams, gfp);
if (!asoc->ssnmap)
goto nomem_ssnmap;
/* Allocate storage for the negotiated streams if it is not a temporary * association.
*/
if (!asoc->temp) {
asoc->ssnmap = sctp_ssnmap_new(asoc->c.sinit_max_instreams,
asoc->c.sinit_num_ostreams, gfp);
if (!asoc->ssnmap)
goto nomem_ssnmap;
}
/* ADDIP Section 4.1 ASCONF Chunk Procedures
*
......@@ -1882,6 +1868,7 @@ int sctp_process_param(struct sctp_association *asoc, union sctp_params param,
int retval = 1;
sctp_scope_t scope;
time_t stale;
struct sctp_af *af;
/* We maintain all INIT parameters in network byte order all the
* time. This allows us to not worry about whether the parameters
......@@ -1893,7 +1880,8 @@ int sctp_process_param(struct sctp_association *asoc, union sctp_params param,
break;
/* Fall through. */
case SCTP_PARAM_IPV4_ADDRESS:
sctp_param2sockaddr(&addr, param.addr, asoc->peer.port, 0);
af = sctp_get_af_specific(param_type2af(param.p->type));
af->from_addr_param(&addr, param.addr, asoc->peer.port, 0);
scope = sctp_scope(peer_addr);
if (sctp_in_scope(&addr, scope))
if (!sctp_assoc_add_peer(asoc, &addr, gfp))
......@@ -2005,90 +1993,6 @@ __u32 sctp_generate_tsn(const struct sctp_endpoint *ep)
return retval;
}
/********************************************************************
* 4th Level Abstractions
********************************************************************/
/* Convert from an SCTP IP parameter to a union sctp_addr. */
void sctp_param2sockaddr(union sctp_addr *addr, union sctp_addr_param *param,
__u16 port, int iif)
{
switch(param->v4.param_hdr.type) {
case SCTP_PARAM_IPV4_ADDRESS:
addr->v4.sin_family = AF_INET;
addr->v4.sin_port = port;
addr->v4.sin_addr.s_addr = param->v4.addr.s_addr;
break;
case SCTP_PARAM_IPV6_ADDRESS:
addr->v6.sin6_family = AF_INET6;
addr->v6.sin6_port = port;
addr->v6.sin6_flowinfo = 0; /* BUG */
addr->v6.sin6_addr = param->v6.addr;
addr->v6.sin6_scope_id = iif;
break;
default:
SCTP_DEBUG_PRINTK("Illegal address type %d\n",
ntohs(param->v4.param_hdr.type));
break;
};
}
/* Convert an IP address in an SCTP param into a sockaddr_in. */
/* Returns true if a valid conversion was possible. */
int sctp_addr2sockaddr(union sctp_params p, union sctp_addr *sa)
{
switch (p.p->type) {
case SCTP_PARAM_IPV4_ADDRESS:
sa->v4.sin_addr = *((struct in_addr *)&p.v4->addr);
sa->v4.sin_family = AF_INET;
break;
case SCTP_PARAM_IPV6_ADDRESS:
*((struct in6_addr *)&sa->v4.sin_addr)
= p.v6->addr;
sa->v4.sin_family = AF_INET6;
break;
default:
return 0;
};
return 1;
}
/* Convert a sockaddr_in to an IP address in an SCTP param.
* Returns len if a valid conversion was possible.
*/
int sockaddr2sctp_addr(const union sctp_addr *sa, union sctp_addr_param *p)
{
int len = 0;
switch (sa->v4.sin_family) {
case AF_INET:
p->v4.param_hdr.type = SCTP_PARAM_IPV4_ADDRESS;
p->v4.param_hdr.length = ntohs(sizeof(sctp_ipv4addr_param_t));
len = sizeof(sctp_ipv4addr_param_t);
p->v4.addr.s_addr = sa->v4.sin_addr.s_addr;
break;
case AF_INET6:
p->v6.param_hdr.type = SCTP_PARAM_IPV6_ADDRESS;
p->v6.param_hdr.length = ntohs(sizeof(sctp_ipv6addr_param_t));
len = sizeof(sctp_ipv6addr_param_t);
p->v6.addr = *(&sa->v6.sin6_addr);
break;
default:
printk(KERN_WARNING "sockaddr2sctp_addr: Illegal family %d.\n",
sa->v4.sin_family);
return 0;
};
return len;
}
/*
* ADDIP 3.1.1 Address Configuration Change Chunk (ASCONF)
* 0 1 2 3
......@@ -2119,8 +2023,9 @@ struct sctp_chunk *sctp_make_asconf(struct sctp_association *asoc,
int length = sizeof(asconf) + vparam_len;
union sctp_params addrparam;
int addrlen;
struct sctp_af *af = sctp_get_af_specific(addr->v4.sin_family);
addrlen = sockaddr2sctp_addr(addr, (union sctp_addr_param *)&addrparam);
addrlen = af->to_addr_param(addr, (union sctp_addr_param *)&addrparam);
if (!addrlen)
return NULL;
length += addrlen;
......@@ -2135,7 +2040,51 @@ struct sctp_chunk *sctp_make_asconf(struct sctp_association *asoc,
retval->subh.addip_hdr =
sctp_addto_chunk(retval, sizeof(asconf), &asconf);
retval->param_hdr.v =
sctp_addto_chunk(retval, addrlen, &addr);
sctp_addto_chunk(retval, addrlen, &addrparam);
return retval;
}
/* ADDIP
* 3.2.4 Set Primary IP Address
* 0 1 2 3
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Type =0xC004 | Length = Variable |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | ASCONF-Request Correlation ID |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Address Parameter |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*
* Create an ASCONF chunk with Set Primary IP address parameter.
*/
struct sctp_chunk *sctp_make_asconf_set_prim(struct sctp_association *asoc,
union sctp_addr *addr)
{
sctp_addip_param_t param;
struct sctp_chunk *retval;
int len = sizeof(param);
union sctp_params addrparam;
int addrlen;
struct sctp_af *af = sctp_get_af_specific(addr->v4.sin_family);
addrlen = af->to_addr_param(addr, (union sctp_addr_param *)&addrparam);
if (!addrlen)
return NULL;
len += addrlen;
/* Create the chunk and make asconf header. */
retval = sctp_make_asconf(asoc, addr, len);
if (!retval)
return NULL;
param.param_hdr.type = SCTP_PARAM_SET_PRIMARY;
param.param_hdr.length = htons(len);
param.crr_id = 0;
sctp_addto_chunk(retval, sizeof(param), &param);
sctp_addto_chunk(retval, addrlen, &addrparam);
return retval;
}
......
......@@ -929,6 +929,7 @@ static int sctp_sf_send_restart_abort(union sctp_addr *ssa,
struct sctp_errhdr *errhdr;
struct sctp_endpoint *ep;
char buffer[sizeof(struct sctp_errhdr)+sizeof(union sctp_addr_param)];
struct sctp_af *af = sctp_get_af_specific(ssa->v4.sin_family);
/* Build the error on the stack. We are way to malloc crazy
* throughout the code today.
......@@ -937,7 +938,7 @@ static int sctp_sf_send_restart_abort(union sctp_addr *ssa,
addrparm = (union sctp_addr_param *)errhdr->variable;
/* Copy into a parm format. */
len = sockaddr2sctp_addr(ssa, addrparm);
len = af->to_addr_param(ssa, addrparm);
len += sizeof(sctp_errhdr_t);
errhdr->cause = SCTP_ERROR_RESTART;
......
/* Copyright (c) 1999-2000 Cisco, Inc.
/* SCTP kernel reference Implementation
* (C) Copyright IBM Corp. 2001, 2003
* Copyright (c) 1999-2000 Cisco, Inc.
* Copyright (c) 1999-2001 Motorola, Inc.
* Copyright (c) 2001-2003 International Business Machines, Corp.
* Copyright (c) 2001-2003 Intel Corp.
* Copyright (c) 2001-2002 Nokia, Inc.
* Copyright (c) 2001 La Monte H.P. Yarroll
......@@ -50,6 +51,7 @@
* Ardelle Fan <ardelle.fan@intel.com>
* Ryan Layer <rmlayer@us.ibm.com>
* Anup Pemmaiah <pemmaiah@cc.usu.edu>
* Kevin Gao <kevin.gao@intel.com>
*
* Any bugs reported given to us we will try to fix... any fixes shared will
* be incorporated into the next SCTP release.
......@@ -93,8 +95,8 @@ static int sctp_wait_for_connect(struct sctp_association *, long *timeo_p);
static int sctp_wait_for_accept(struct sock *sk, long timeo);
static void sctp_wait_for_close(struct sock *sk, long timeo);
static inline int sctp_verify_addr(struct sock *, union sctp_addr *, 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_add(struct sock *, struct sockaddr *, int);
static int sctp_bindx_rem(struct sock *, struct sockaddr *, int);
static int sctp_do_bind(struct sock *, union sctp_addr *, int);
static int sctp_autobind(struct sock *sk);
static void sctp_sock_migrate(struct sock *, struct sock *,
......@@ -170,10 +172,7 @@ struct sctp_transport *sctp_addr_id2transport(struct sock *sk,
* sd - the socket descriptor returned by socket().
* addr - the address structure (struct sockaddr_in or struct
* sockaddr_in6 [RFC 2553]),
* addrlen - the size of the address structure.
*
* The caller should use struct sockaddr_storage described in RFC 2553
* to represent addr for portability reason.
* addr_len - the size of the address structure.
*/
int sctp_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len)
{
......@@ -298,112 +297,6 @@ SCTP_STATIC int sctp_do_bind(struct sock *sk, union sctp_addr *addr, int len)
return ret;
}
/* API 8.1 sctp_bindx()
*
* The syntax of sctp_bindx() is,
*
* ret = sctp_bindx(int sd,
* struct sockaddr_storage *addrs,
* int addrcnt,
* int flags);
*
* If sd is an IPv4 socket, the addresses passed must be IPv4 addresses.
* If the sd is an IPv6 socket, the addresses passed can either be IPv4
* or IPv6 addresses.
*
* A single address may be specified as INADDR_ANY or IPV6_ADDR_ANY, see
* section 3.1.2 for this usage.
*
* addrs is a pointer to an array of one or more socket addresses. Each
* address is contained in a struct sockaddr_storage, so each address is
* fixed length. The caller specifies the number of addresses in the
* array with addrcnt.
*
* On success, sctp_bindx() returns 0. On failure, sctp_bindx() returns -1,
* and sets errno to the appropriate error code. [ Editor's note: need
* to fill in all error code? ]
*
* For SCTP, the port given in each socket address must be the same, or
* sctp_bindx() will fail, setting errno to EINVAL .
*
* The flags parameter is formed from the bitwise OR of zero or
* more of the following currently defined flags:
*
* SCTP_BINDX_ADD_ADDR
* SCTP_BINDX_REM_ADDR
*
* SCTP_BIND_ADD_ADDR directs SCTP to add the given addresses to the
* association, and SCTP_BIND_REM_ADDR directs SCTP to remove the given
* addresses from the association. The two flags are mutually exclusive;
* if both are given, sctp_bindx() will fail with EINVAL. A caller may not
* remove all addresses from an association; sctp_bindx() will reject such
* an attempt with EINVAL.
*
* An application can use sctp_bindx(SCTP_BINDX_ADD_ADDR) to associate
* additional addresses with an endpoint after calling bind(). Or use
* sctp_bindx(SCTP_BINDX_REM_ADDR) to remove some addresses a listening
* socket is associated with so that no new association accepted will be
* associated with those addresses.
*
* SCTP_BIND_ADD_ADDR is defined as 0, so that it becomes the default
* behavior for sctp_bindx() when no flags are given.
*
* Adding and removing addresses from a connected association is optional
* functionality. Implementations that do not support this functionality
* should return EOPNOTSUPP.
*
* NOTE: This could be integrated into sctp_setsockopt_bindx(),
* but keeping it this way makes it easier if sometime sys_bindx is
* added.
*/
/* Unprotected by locks. Call only with socket lock sk->sk_lock held! See
* sctp_bindx() for a lock-protected call.
*/
static int __sctp_bindx(struct sock *sk, struct sockaddr_storage *addrs,
int addrcnt, int flags)
{
int retval = 0;
SCTP_DEBUG_PRINTK("__sctp_bindx(sk: %p, addrs: %p, addrcnt: %d, "
"flags: %s)\n", sk, addrs, addrcnt,
(SCTP_BINDX_ADD_ADDR == flags) ? "ADD" :
((SCTP_BINDX_REM_ADDR == flags) ? "REM" : "BOGUS"));
switch (flags) {
case SCTP_BINDX_ADD_ADDR:
retval = sctp_bindx_add(sk, addrs, addrcnt);
break;
case SCTP_BINDX_REM_ADDR:
retval = sctp_bindx_rem(sk, addrs, addrcnt);
break;
default:
retval = -EINVAL;
break;
};
return retval;
}
/* BINDX with locks.
*
* NOTE: Currently unused at all ...
*/
int sctp_bindx(struct sock *sk, struct sockaddr_storage *addrs, int addrcnt,
int flags)
{
int retval;
sctp_lock_sock(sk);
retval = __sctp_bindx(sk, addrs, addrcnt, flags);
sctp_release_sock(sk);
return retval;
}
/* Add a list of addresses as bind addresses to local endpoint or
* association.
*
......@@ -414,41 +307,39 @@ int sctp_bindx(struct sock *sk, struct sockaddr_storage *addrs, int addrcnt,
* If any of them fails, then the operation will be reversed and the
* ones that were added will be removed.
*
* Only __sctp_bindx() is supposed to call this function.
* Only sctp_setsockopt_bindx() is supposed to call this function.
*/
int sctp_bindx_add(struct sock *sk, struct sockaddr_storage *addrs, int addrcnt)
int sctp_bindx_add(struct sock *sk, struct sockaddr *addrs, int addrcnt)
{
int cnt;
int retval = 0;
int addr_len;
void *addr_buf;
struct sockaddr *sa_addr;
struct sctp_af *af;
SCTP_DEBUG_PRINTK("sctp_bindx_add (sk: %p, addrs: %p, addrcnt: %d)\n",
sk, addrs, addrcnt);
addr_buf = addrs;
for (cnt = 0; cnt < addrcnt; cnt++) {
/* The list may contain either IPv4 or IPv6 address;
* determine the address length for walking thru the list.
*/
switch (((struct sockaddr *)&addrs[cnt])->sa_family) {
case AF_INET:
addr_len = sizeof(struct sockaddr_in);
break;
case AF_INET6:
addr_len = sizeof(struct sockaddr_in6);
break;
default:
sa_addr = (struct sockaddr *)addr_buf;
af = sctp_get_af_specific(sa_addr->sa_family);
if (!af) {
retval = -EINVAL;
goto err_bindx_add;
};
}
retval = sctp_do_bind(sk, (union sctp_addr *)&addrs[cnt],
addr_len);
retval = sctp_do_bind(sk, (union sctp_addr *)sa_addr,
af->sockaddr_len);
addr_buf += af->sockaddr_len;
err_bindx_add:
if (retval < 0) {
/* Failed. Cleanup the ones that has been added */
/* Failed. Cleanup the ones that have been added */
if (cnt > 0)
sctp_bindx_rem(sk, addrs, cnt);
return retval;
......@@ -471,9 +362,9 @@ int sctp_bindx_add(struct sock *sk, struct sockaddr_storage *addrs, int addrcnt)
* At least one address has to be left; if only one address is
* available, the operation will return -EBUSY.
*
* Only __sctp_bindx() is supposed to call this function.
* Only sctp_setsockopt_bindx() is supposed to call this function.
*/
int sctp_bindx_rem(struct sock *sk, struct sockaddr_storage *addrs, int addrcnt)
int sctp_bindx_rem(struct sock *sk, struct sockaddr *addrs, int addrcnt)
{
struct sctp_opt *sp = sctp_sk(sk);
struct sctp_endpoint *ep = sp->ep;
......@@ -481,50 +372,41 @@ int sctp_bindx_rem(struct sock *sk, struct sockaddr_storage *addrs, int addrcnt)
struct sctp_bind_addr *bp = &ep->base.bind_addr;
int retval = 0;
union sctp_addr saveaddr;
void *addr_buf;
struct sockaddr *sa_addr;
struct sctp_af *af;
SCTP_DEBUG_PRINTK("sctp_bindx_rem (sk: %p, addrs: %p, addrcnt: %d)\n",
sk, addrs, addrcnt);
addr_buf = addrs;
for (cnt = 0; cnt < addrcnt; cnt++) {
/* If there is only one bind address, there is nothing more
* to be removed (we need at least one address here).
/* If the bind address list is empty or if there is only one
* bind address, there is nothing more to be removed (we need
* at least one address here).
*/
if (list_empty(&bp->address_list)) {
if (list_empty(&bp->address_list) ||
(sctp_list_single_entry(&bp->address_list))) {
retval = -EBUSY;
goto err_bindx_rem;
}
/* The list may contain either IPv4 or IPv6 address;
* determine the address length for walking thru the list.
* determine the address length to copy the address to
* saveaddr.
*/
switch (((struct sockaddr *)&addrs[cnt])->sa_family) {
case AF_INET:
saveaddr = *((union sctp_addr *)
&addrs[cnt]);
saveaddr.v4.sin_port = ntohs(saveaddr.v4.sin_port);
/* Verify the port. */
if (saveaddr.v4.sin_port != bp->port) {
retval = -EINVAL;
goto err_bindx_rem;
}
break;
case AF_INET6:
saveaddr = *((union sctp_addr *)
&addrs[cnt]);
saveaddr.v6.sin6_port =
ntohs(saveaddr.v6.sin6_port);
/* verify the port */
if (saveaddr.v6.sin6_port != bp->port) {
retval = -EINVAL;
goto err_bindx_rem;
}
break;
default:
sa_addr = (struct sockaddr *)addr_buf;
af = sctp_get_af_specific(sa_addr->sa_family);
if (!af) {
retval = -EINVAL;
goto err_bindx_rem;
};
}
memcpy(&saveaddr, sa_addr, af->sockaddr_len);
saveaddr.v4.sin_port = ntohs(saveaddr.v4.sin_port);
if (saveaddr.v4.sin_port != bp->port) {
retval = -EINVAL;
goto err_bindx_rem;
}
/* FIXME - There is probably a need to check if sk->sk_saddr and
* sk->sk_rcv_addr are currently set to one of the addresses to
......@@ -541,6 +423,7 @@ int sctp_bindx_rem(struct sock *sk, struct sockaddr_storage *addrs, int addrcnt)
sctp_write_unlock(&ep->base.addr_lock);
sctp_local_bh_enable();
addr_buf += af->sockaddr_len;
err_bindx_rem:
if (retval < 0) {
/* Failed. Add the ones that has been removed back */
......@@ -553,18 +436,62 @@ int sctp_bindx_rem(struct sock *sk, struct sockaddr_storage *addrs, int addrcnt)
return retval;
}
/* Helper for tunneling sys_bindx() requests through sctp_setsockopt()
/* Helper for tunneling sctp_bindx() requests through sctp_setsockopt()
*
* API 8.1
* int sctp_bindx(int sd, struct sockaddr *addrs, int addrcnt,
* int flags);
*
* If sd is an IPv4 socket, the addresses passed must be IPv4 addresses.
* If the sd is an IPv6 socket, the addresses passed can either be IPv4
* or IPv6 addresses.
*
* A single address may be specified as INADDR_ANY or IN6ADDR_ANY, see
* Section 3.1.2 for this usage.
*
* addrs is a pointer to an array of one or more socket addresses. Each
* address is contained in its appropriate structure (i.e. struct
* sockaddr_in or struct sockaddr_in6) the family of the address type
* must be used to distengish the address length (note that this
* representation is termed a "packed array" of addresses). The caller
* specifies the number of addresses in the array with addrcnt.
*
* On success, sctp_bindx() returns 0. On failure, sctp_bindx() returns
* -1, and sets errno to the appropriate error code.
*
* For SCTP, the port given in each socket address must be the same, or
* sctp_bindx() will fail, setting errno to EINVAL.
*
* The flags parameter is formed from the bitwise OR of zero or more of
* the following currently defined flags:
*
* SCTP_BINDX_ADD_ADDR
*
* SCTP_BINDX_REM_ADDR
*
* SCTP_BINDX_ADD_ADDR directs SCTP to add the given addresses to the
* association, and SCTP_BINDX_REM_ADDR directs SCTP to remove the given
* addresses from the association. The two flags are mutually exclusive;
* if both are given, sctp_bindx() will fail with EINVAL. A caller may
* not remove all addresses from an association; sctp_bindx() will
* reject such an attempt with EINVAL.
*
* An application can use sctp_bindx(SCTP_BINDX_ADD_ADDR) to associate
* additional addresses with an endpoint after calling bind(). Or use
* sctp_bindx(SCTP_BINDX_REM_ADDR) to remove some addresses a listening
* socket is associated with so that no new association accepted will be
* associated with those addresses. If the endpoint supports dynamic
* address a SCTP_BINDX_REM_ADDR or SCTP_BINDX_ADD_ADDR may cause a
* endpoint to send the appropriate message to the peer to change the
* peers address lists.
*
* Adding and removing addresses from a connected association is
* optional functionality. Implementations that do not support this
* functionality should return EOPNOTSUPP.
*
* Basically do nothing but copying the addresses from user to kernel
* land and invoking sctp_bindx on the sk. This is used for tunneling
* the sctp_bindx() [sys_bindx()] request through sctp_setsockopt()
* from userspace.
*
* Note I don't use move_addr_to_kernel(): the reason is we would be
* iterating over an array of struct sockaddr_storage passing always
* what we know is a good size (sizeof (struct sock...)), so it is
* pointless. Instead check the whole area for read access and copy
* it.
* land and invoking either sctp_bindx_add() or sctp_bindx_rem() on the sk.
* This is used for tunneling the sctp_bindx() request through sctp_setsockopt() * from userspace.
*
* We don't use copy_from_user() for optimization: we first do the
* sanity checks (buffer size -fast- and access check-healthy
......@@ -584,38 +511,70 @@ int sctp_bindx_rem(struct sock *sk, struct sockaddr_storage *addrs, int addrcnt)
*
* Returns 0 if ok, <0 errno code on error.
*/
SCTP_STATIC int sctp_setsockopt_bindx(struct sock* sk,
struct sockaddr_storage *addrs,
int addrssize, int op)
SCTP_STATIC int sctp_setsockopt_bindx(struct sock* sk, struct sockaddr *addrs,
int addrs_size, int op)
{
struct sockaddr_storage *kaddrs;
struct sockaddr *kaddrs;
int err;
size_t addrcnt;
int addrcnt = 0;
int walk_size = 0;
struct sockaddr *sa_addr;
void *addr_buf;
struct sctp_af *af;
SCTP_DEBUG_PRINTK("sctp_do_setsocktopt_bindx: sk %p addrs %p"
" addrssize %d opt %d\n", sk, addrs, addrssize, op);
SCTP_DEBUG_PRINTK("sctp_setsocktopt_bindx: sk %p addrs %p"
" addrs_size %d opt %d\n", sk, addrs, addrs_size, op);
/* Do we have an integer number of structs sockaddr_storage? */
if (unlikely(addrssize <= 0 ||
addrssize % sizeof(struct sockaddr_storage) != 0))
if (unlikely(addrs_size <= 0))
return -EINVAL;
/* Check the user passed a healthy pointer. */
if (unlikely(!access_ok(VERIFY_READ, addrs, addrssize)))
if (unlikely(!access_ok(VERIFY_READ, addrs, addrs_size)))
return -EFAULT;
/* Alloc space for the address array in kernel memory. */
kaddrs = (struct sockaddr_storage *) kmalloc(addrssize, GFP_KERNEL);
kaddrs = (struct sockaddr *)kmalloc(addrs_size, GFP_KERNEL);
if (unlikely(!kaddrs))
return -ENOMEM;
if (copy_from_user(kaddrs, addrs, addrssize)) {
if (__copy_from_user(kaddrs, addrs, addrs_size)) {
kfree(kaddrs);
return -EFAULT;
}
addrcnt = addrssize / sizeof(struct sockaddr_storage);
err = __sctp_bindx(sk, kaddrs, addrcnt, op); /* Do the work. */
/* Walk through the addrs buffer and count the number of addresses. */
addr_buf = kaddrs;
while (walk_size < addrs_size) {
sa_addr = (struct sockaddr *)addr_buf;
af = sctp_get_af_specific(sa_addr->sa_family);
/* If the address family is not supported or if this address
* causes the address buffer to overflow return EINVAL.
*/
if (!af || (walk_size + af->sockaddr_len) > addrs_size) {
kfree(kaddrs);
return -EINVAL;
}
addrcnt++;
addr_buf += af->sockaddr_len;
walk_size += af->sockaddr_len;
}
/* Do the work. */
switch (op) {
case SCTP_BINDX_ADD_ADDR:
err = sctp_bindx_add(sk, kaddrs, addrcnt);
break;
case SCTP_BINDX_REM_ADDR:
err = sctp_bindx_rem(sk, kaddrs, addrcnt);
break;
default:
err = -EINVAL;
break;
};
kfree(kaddrs);
return err;
......@@ -1476,7 +1435,7 @@ static int sctp_setsockopt_initmsg(struct sock *sk, char *optval, int optlen)
}
/*
* 7.1.14 Set default send parameters (SET_DEFAULT_SEND_PARAM)
* 7.1.14 Set default send parameters (SCTP_DEFAULT_SEND_PARAM)
*
* Applications that wish to use the sendto() system call may wish to
* specify a default set of parameters that would normally be supplied
......@@ -1522,7 +1481,7 @@ static int sctp_setsockopt_default_send_param(struct sock *sk,
return 0;
}
/* 7.1.10 Set Peer Primary Address (SCTP_PRIMARY_ADDR)
/* 7.1.10 Set Primary Address (SCTP_PRIMARY_ADDR)
*
* Requests that the local SCTP stack use the enclosed peer address as
* the association primary. The enclosed address must be one of the
......@@ -1727,6 +1686,62 @@ static int sctp_setsockopt_maxseg(struct sock *sk, char *optval, int optlen)
return 0;
}
/*
* 7.1.9 Set Peer Primary Address (SCTP_SET_PEER_PRIMARY_ADDR)
*
* Requests that the peer mark the enclosed address as the association
* primary. The enclosed address must be one of the association's
* locally bound addresses. The following structure is used to make a
* set primary request:
*/
static int sctp_setsockopt_peer_primary_addr(struct sock *sk, char *optval,
int optlen)
{
struct sctp_opt *sp;
struct sctp_endpoint *ep;
struct sctp_association *asoc = NULL;
struct sctp_setpeerprim prim;
struct sctp_chunk *chunk;
int err;
sp = sctp_sk(sk);
ep = sp->ep;
if (optlen != sizeof(struct sctp_setpeerprim))
return -EINVAL;
if (copy_from_user(&prim, optval, optlen))
return -EFAULT;
asoc = sctp_id2assoc(sk, prim.sspp_assoc_id);
if (!asoc)
return -EINVAL;
if (!sctp_state(asoc, ESTABLISHED))
return -ENOTCONN;
if (!sctp_assoc_lookup_laddr(asoc, (union sctp_addr *)&prim.sspp_addr))
return -EADDRNOTAVAIL;
/* Create an ASCONF chunk with SET_PRIMARY parameter */
chunk = sctp_make_asconf_set_prim(asoc,
(union sctp_addr *)&prim.sspp_addr);
if (!chunk)
return -ENOMEM;
err = sctp_primitive_ASCONF(asoc, chunk);
if (err) {
sctp_chunk_free(chunk);
return err;
}
SCTP_DEBUG_PRINTK("We set peer primary addr primitively.\n");
return 0;
}
/* API 6.2 setsockopt(), getsockopt()
*
* Applications use setsockopt() and getsockopt() to set or retrieve
......@@ -1771,16 +1786,14 @@ SCTP_STATIC int sctp_setsockopt(struct sock *sk, int level, int optname,
switch (optname) {
case SCTP_SOCKOPT_BINDX_ADD:
/* 'optlen' is the size of the addresses buffer. */
retval = sctp_setsockopt_bindx(sk, (struct sockaddr_storage *)
optval, optlen,
SCTP_BINDX_ADD_ADDR);
retval = sctp_setsockopt_bindx(sk, (struct sockaddr *)optval,
optlen, SCTP_BINDX_ADD_ADDR);
break;
case SCTP_SOCKOPT_BINDX_REM:
/* 'optlen' is the size of the addresses buffer. */
retval = sctp_setsockopt_bindx(sk, (struct sockaddr_storage *)
optval, optlen,
SCTP_BINDX_REM_ADDR);
retval = sctp_setsockopt_bindx(sk, (struct sockaddr *)optval,
optlen, SCTP_BINDX_REM_ADDR);
break;
case SCTP_DISABLE_FRAGMENTS:
......@@ -1809,6 +1822,9 @@ SCTP_STATIC int sctp_setsockopt(struct sock *sk, int level, int optname,
case SCTP_PRIMARY_ADDR:
retval = sctp_setsockopt_primary_addr(sk, optval, optlen);
break;
case SCTP_SET_PEER_PRIMARY_ADDR:
retval = sctp_setsockopt_peer_primary_addr(sk, optval, optlen);
break;
case SCTP_NODELAY:
retval = sctp_setsockopt_nodelay(sk, optval, optlen);
break;
......@@ -2056,9 +2072,8 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk)
return -ESOCKTNOSUPPORT;
}
/* FIXME: The next draft (04) of the SCTP Sockets Extensions
* should include a socket option for manipulating these
* message parameters (and a few others).
/* Initialize default send parameters. These parameters can be
* modified with the SCTP_DEFAULT_SEND_PARAM socket option.
*/
sp->default_stream = 0;
sp->default_ppid = 0;
......@@ -2077,7 +2092,6 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk)
/* Initialize default RTO related parameters. These parameters can
* be modified for with the SCTP_RTOINFO socket option.
* FIXME: These are not used yet.
*/
sp->rtoinfo.srto_initial = (sctp_rto_initial / HZ) * 1000;
sp->rtoinfo.srto_max = (sctp_rto_max / HZ) * 1000;
......@@ -2093,15 +2107,10 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk)
sp->assocparams.sasoc_cookie_life = (sctp_valid_cookie_life / HZ)
* 1000;
/* Initialize default event subscriptions.
* the struct sock is initialized to zero, so only
* enable the events needed. By default, UDP-style
* sockets enable io and association change notifications.
/* Initialize default event subscriptions. By default, all the
* options are off.
*/
if (sctp_style(sk, UDP)) {
sp->subscribe.sctp_data_io_event = 1;
sp->subscribe.sctp_association_event = 1;
}
memset(&sp->subscribe, 0, sizeof(struct sctp_event_subscribe));
/* Default Peer Address Parameters. These defaults can
* be modified via SCTP_PEER_ADDR_PARAMS
......@@ -2552,7 +2561,7 @@ static int sctp_getsockopt_initmsg(struct sock *sk, int len, char *optval, int *
}
static int sctp_getsockopt_peer_addrs_num(struct sock *sk, int len,
char *optval, int *optlen)
char *optval, int *optlen)
{
sctp_assoc_t id;
struct sctp_association *asoc;
......@@ -2565,9 +2574,7 @@ static int sctp_getsockopt_peer_addrs_num(struct sock *sk, int len,
if (copy_from_user(&id, optval, sizeof(sctp_assoc_t)))
return -EFAULT;
/*
* For UDP-style sockets, id specifies the association to query.
*/
/* For UDP-style sockets, id specifies the association to query. */
asoc = sctp_id2assoc(sk, id);
if (!asoc)
return -EINVAL;
......@@ -2582,16 +2589,17 @@ static int sctp_getsockopt_peer_addrs_num(struct sock *sk, int len,
}
static int sctp_getsockopt_peer_addrs(struct sock *sk, int len,
char *optval, int *optlen)
char *optval, int *optlen)
{
struct sctp_association *asoc;
struct list_head *pos;
int cnt = 0;
struct sctp_getaddrs getaddrs;
struct sctp_transport *from;
struct sockaddr_storage *to;
void *to;
union sctp_addr temp;
struct sctp_opt *sp = sctp_sk(sk);
int addrlen;
if (len != sizeof(struct sctp_getaddrs))
return -EINVAL;
......@@ -2600,21 +2608,21 @@ static int sctp_getsockopt_peer_addrs(struct sock *sk, int len,
return -EFAULT;
if (getaddrs.addr_num <= 0) return -EINVAL;
/*
* For UDP-style sockets, id specifies the association to query.
*/
/* For UDP-style sockets, id specifies the association to query. */
asoc = sctp_id2assoc(sk, getaddrs.assoc_id);
if (!asoc)
return -EINVAL;
to = getaddrs.addrs;
to = (void *)getaddrs.addrs;
list_for_each(pos, &asoc->peer.transport_addr_list) {
from = list_entry(pos, struct sctp_transport, transports);
memcpy(&temp, &from->ipaddr, sizeof(temp));
sctp_get_pf_specific(sk->sk_family)->addr_v4map(sp, &temp);
if (copy_to_user(to, &temp, sizeof(temp)))
addrlen = sctp_get_af_specific(sk->sk_family)->sockaddr_len;
if (copy_to_user(to, &temp, addrlen))
return -EFAULT;
to ++;
to += addrlen ;
cnt ++;
if (cnt >= getaddrs.addr_num) break;
}
......@@ -2673,9 +2681,10 @@ static int sctp_getsockopt_local_addrs(struct sock *sk, int len,
int cnt = 0;
struct sctp_getaddrs getaddrs;
struct sctp_sockaddr_entry *from;
struct sockaddr_storage *to;
void *to;
union sctp_addr temp;
struct sctp_opt *sp = sctp_sk(sk);
int addrlen;
if (len != sizeof(struct sctp_getaddrs))
return -EINVAL;
......@@ -2699,16 +2708,17 @@ static int sctp_getsockopt_local_addrs(struct sock *sk, int len,
bp = &asoc->base.bind_addr;
}
to = getaddrs.addrs;
to = (void *)getaddrs.addrs;
list_for_each(pos, &bp->address_list) {
from = list_entry(pos,
struct sctp_sockaddr_entry,
list);
memcpy(&temp, &from->a, sizeof(temp));
sctp_get_pf_specific(sk->sk_family)->addr_v4map(sp, &temp);
if (copy_to_user(to, &temp, sizeof(temp)))
addrlen = sctp_get_af_specific(temp.sa.sa_family)->sockaddr_len;
if (copy_to_user(to, &temp, addrlen))
return -EFAULT;
to ++;
to += addrlen;
cnt ++;
if (cnt >= getaddrs.addr_num) break;
}
......@@ -2759,7 +2769,7 @@ static int sctp_getsockopt_primary_addr(struct sock *sk, int len,
/*
*
* 7.1.14 Set default send parameters (SET_DEFAULT_SEND_PARAM)
* 7.1.14 Set default send parameters (SCTP_DEFAULT_SEND_PARAM)
*
* Applications that wish to use the sendto() system call may wish to
* specify a default set of parameters that would normally be supplied
......@@ -3331,9 +3341,19 @@ SCTP_STATIC int sctp_seqpacket_listen(struct sock *sk, int backlog)
if (!sctp_style(sk, UDP))
return -EINVAL;
/* If backlog is zero, disable listening. */
if (!backlog) {
if (sctp_sstate(sk, CLOSED))
return 0;
sctp_unhash_endpoint(ep);
sk->sk_state = SCTP_SS_CLOSED;
}
/* Return if we are already listening. */
if (sctp_sstate(sk, LISTENING))
return 0;
/*
* If a bind() or sctp_bindx() is not called prior to a listen()
* call that allows new associations to be accepted, the system
......@@ -3364,6 +3384,15 @@ SCTP_STATIC int sctp_stream_listen(struct sock *sk, int backlog)
struct sctp_opt *sp = sctp_sk(sk);
struct sctp_endpoint *ep = sp->ep;
/* If backlog is zero, disable listening. */
if (!backlog) {
if (sctp_sstate(sk, CLOSED))
return 0;
sctp_unhash_endpoint(ep);
sk->sk_state = SCTP_SS_CLOSED;
}
if (sctp_sstate(sk, LISTENING))
return 0;
......
......@@ -214,7 +214,7 @@ static int sctp_sysctl_jiffies_ms(ctl_table *table, int __user *name, int nlen,
if (olen != sizeof (int))
return -EINVAL;
}
if (put_user((*(int *)(table->data) / HZ) * 1000,
if (put_user((*(int *)(table->data) * 1000) / HZ,
(int *)oldval) ||
(oldlenp && put_user(sizeof (int), oldlenp)))
return -EFAULT;
......@@ -228,7 +228,7 @@ static int sctp_sysctl_jiffies_ms(ctl_table *table, int __user *name, int nlen,
if (get_user(new, (int *)newval))
return -EFAULT;
*(int *)(table->data) = (new * HZ) * 1000;
*(int *)(table->data) = (new * HZ) / 1000;
}
return 1;
}
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