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 /* SCTP kernel reference Implementation
* (C) Copyright IBM Corp. 2001, 2003
* Copyright (c) 1999-2000 Cisco, Inc. * Copyright (c) 1999-2000 Cisco, Inc.
* Copyright (c) 1999-2001 Motorola, Inc. * Copyright (c) 1999-2001 Motorola, Inc.
* Copyright (c) 2001-2002 International Business Machines, Corp.
* Copyright (c) 2001 Intel Corp. * Copyright (c) 2001 Intel Corp.
* Copyright (c) 2001 Nokia, Inc. * Copyright (c) 2001 Nokia, Inc.
* Copyright (c) 2001 La Monte H.P. Yarroll * Copyright (c) 2001 La Monte H.P. Yarroll
...@@ -42,6 +42,8 @@ ...@@ -42,6 +42,8 @@
* randall@sctp.chicago.il.us * randall@sctp.chicago.il.us
* kmorneau@cisco.com * kmorneau@cisco.com
* qxie1@email.mot.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 * Any bugs reported given to us we will try to fix... any fixes shared will
* be incorporated into the next SCTP release. * be incorporated into the next SCTP release.
...@@ -507,6 +509,11 @@ typedef struct sctp_cwr_chunk { ...@@ -507,6 +509,11 @@ typedef struct sctp_cwr_chunk {
* The ASCONF Parameter Response is used in the ASCONF-ACK to * The ASCONF Parameter Response is used in the ASCONF-ACK to
* report status of ASCONF processing. * 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 { typedef struct sctp_addiphdr {
__u32 serial; __u32 serial;
__u8 params[0]; __u8 params[0];
......
/* SCTP kernel reference Implementation /* SCTP kernel reference Implementation
* (C) Copyright IBM Corp. 2001, 2003
* Copyright (c) 1999-2000 Cisco, Inc. * Copyright (c) 1999-2000 Cisco, Inc.
* Copyright (c) 1999-2001 Motorola, Inc. * Copyright (c) 1999-2001 Motorola, Inc.
* Copyright (c) 2001-2003 International Business Machines, Corp.
* Copyright (c) 2001-2003 Intel Corp. * Copyright (c) 2001-2003 Intel Corp.
* *
* This file is part of the SCTP kernel reference Implementation * This file is part of the SCTP kernel reference Implementation
...@@ -40,6 +40,7 @@ ...@@ -40,6 +40,7 @@
* Sridhar Samudrala <sri@us.ibm.com> * Sridhar Samudrala <sri@us.ibm.com>
* Ardelle Fan <ardelle.fan@intel.com> * Ardelle Fan <ardelle.fan@intel.com>
* Ryan Layer <rmlayer@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 * Any bugs reported given to us we will try to fix... any fixes shared will
* be incorporated into the next SCTP release. * be incorporated into the next SCTP release.
...@@ -145,6 +146,7 @@ int sctp_primitive_SHUTDOWN(struct sctp_association *, void *arg); ...@@ -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_ABORT(struct sctp_association *, void *arg);
int sctp_primitive_SEND(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_REQUESTHEARTBEAT(struct sctp_association *, void *arg);
int sctp_primitive_ASCONF(struct sctp_association *, void *arg);
/* /*
* sctp/crc32c.c * sctp/crc32c.c
...@@ -404,6 +406,12 @@ static inline struct list_head *sctp_list_dequeue(struct list_head *list) ...@@ -404,6 +406,12 @@ static inline struct list_head *sctp_list_dequeue(struct list_head *list)
return result; 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. */ /* 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) static inline size_t get_user_iov_size(struct iovec *iov, int iovlen)
{ {
...@@ -525,6 +533,19 @@ static inline int ipver2af(__u8 ipver) ...@@ -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. */ /* Perform some sanity checks. */
static inline int sctp_sanity_check(void) static inline int sctp_sanity_check(void)
{ {
......
/* SCTP kernel reference Implementation /* SCTP kernel reference Implementation
* (C) Copyright IBM Corp. 2001, 2003
* Copyright (c) 1999-2000 Cisco, Inc. * Copyright (c) 1999-2000 Cisco, Inc.
* Copyright (c) 1999-2001 Motorola, Inc. * Copyright (c) 1999-2001 Motorola, Inc.
* Copyright (c) 2001 Intel Corp. * Copyright (c) 2001 Intel Corp.
* Copyright (c) 2001-2002 International Business Machines Corp.
* *
* This file is part of the SCTP kernel reference Implementation * This file is part of the SCTP kernel reference Implementation
* *
...@@ -41,6 +41,7 @@ ...@@ -41,6 +41,7 @@
* Sridhar Samudrala <sri@us.ibm.com> * Sridhar Samudrala <sri@us.ibm.com>
* Daisy Chang <daisyc@us.ibm.com> * Daisy Chang <daisyc@us.ibm.com>
* Ardelle Fan <ardelle.fan@intel.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 * Any bugs reported given to us we will try to fix... any fixes shared will
* be incorporated into the next SCTP release. * be incorporated into the next SCTP release.
...@@ -268,6 +269,9 @@ struct sctp_chunk *sctp_process_asconf(struct sctp_association *asoc, ...@@ -268,6 +269,9 @@ struct sctp_chunk *sctp_process_asconf(struct sctp_association *asoc,
struct sctp_chunk *asconf, struct sctp_chunk *asconf,
int vparam_len); 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_tsn(struct sctp_chunk *);
void sctp_chunk_assign_ssn(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, ...@@ -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_tag(const struct sctp_endpoint *);
__u32 sctp_generate_tsn(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. */ /* Extern declarations for major data structures. */
const sctp_sm_table_entry_t *sctp_chunk_event_lookup(sctp_cid_t, sctp_state_t); const sctp_sm_table_entry_t *sctp_chunk_event_lookup(sctp_cid_t, sctp_state_t);
extern const sctp_sm_table_entry_t extern const sctp_sm_table_entry_t
......
/* SCTP kernel reference Implementation /* SCTP kernel reference Implementation
* (C) Copyright IBM Corp. 2001, 2003
* Copyright (c) 1999-2000 Cisco, Inc. * Copyright (c) 1999-2000 Cisco, Inc.
* Copyright (c) 1999-2001 Motorola, Inc. * Copyright (c) 1999-2001 Motorola, Inc.
* Copyright (c) 2001 Intel Corp. * Copyright (c) 2001 Intel Corp.
* Copyright (c) 2001-2003 International Business Machines Corp.
* *
* This file is part of the SCTP kernel reference Implementation * This file is part of the SCTP kernel reference Implementation
* *
...@@ -45,6 +45,7 @@ ...@@ -45,6 +45,7 @@
* Ardelle Fan <ardelle.fan@intel.com> * Ardelle Fan <ardelle.fan@intel.com>
* Ryan Layer <rmlayer@us.ibm.com> * Ryan Layer <rmlayer@us.ibm.com>
* Anup Pemmaiah <pemmaiah@cc.usu.edu> * 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 * Any bugs reported given to us we will try to fix... any fixes shared will
* be incorporated into the next SCTP release. * be incorporated into the next SCTP release.
...@@ -217,86 +218,6 @@ extern struct sctp_globals { ...@@ -217,86 +218,6 @@ extern struct sctp_globals {
#define sctp_local_addr_list (sctp_globals.local_addr_list) #define sctp_local_addr_list (sctp_globals.local_addr_list)
#define sctp_local_addr_lock (sctp_globals.local_addr_lock) #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. */ /* SCTP Socket type: UDP or TCP style. */
typedef enum { typedef enum {
SCTP_SOCKET_UDP = 0, SCTP_SOCKET_UDP = 0,
...@@ -488,6 +409,92 @@ static inline __u16 sctp_ssn_next(struct sctp_stream *stream, __u16 id) ...@@ -488,6 +409,92 @@ static inline __u16 sctp_ssn_next(struct sctp_stream *stream, __u16 id)
return stream->ssn[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 /* Structure to track chunk fragments that have been acked, but peer
* fragments of the same message have not. * fragments of the same message have not.
*/ */
...@@ -1688,6 +1695,8 @@ struct sctp_transport *sctp_assoc_choose_shutdown_transport( ...@@ -1688,6 +1695,8 @@ struct sctp_transport *sctp_assoc_choose_shutdown_transport(
void sctp_assoc_update_retran_path(struct sctp_association *); void sctp_assoc_update_retran_path(struct sctp_association *);
struct sctp_transport *sctp_assoc_lookup_paddr(const struct sctp_association *, struct sctp_transport *sctp_assoc_lookup_paddr(const struct sctp_association *,
const union sctp_addr *); 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 *, struct sctp_transport *sctp_assoc_add_peer(struct sctp_association *,
const union sctp_addr *address, const union sctp_addr *address,
const int gfp); const int gfp);
......
...@@ -551,13 +551,15 @@ struct sctp_status { ...@@ -551,13 +551,15 @@ struct sctp_status {
}; };
/* /*
* 8.3, 8.5 get all peer/local addresses on a socket * 8.3, 8.5 get all peer/local addresses in an association.
* This parameter struct is for getsockopt * 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 { struct sctp_getaddrs {
sctp_assoc_t assoc_id; sctp_assoc_t assoc_id;
int addr_num; int addr_num;
struct sockaddr_storage *addrs; struct sockaddr *addrs;
}; };
/* These are bit fields for msghdr->msg_flags. See section 5.1. */ /* These are bit fields for msghdr->msg_flags. See section 5.1. */
......
/* SCTP kernel reference Implementation /* SCTP kernel reference Implementation
* (C) Copyright IBM Corp. 2001, 2003
* Copyright (c) 1999-2000 Cisco, Inc. * Copyright (c) 1999-2000 Cisco, Inc.
* Copyright (c) 1999-2001 Motorola, Inc. * Copyright (c) 1999-2001 Motorola, Inc.
* Copyright (c) 2001-2003 International Business Machines Corp.
* Copyright (c) 2001 Intel Corp. * Copyright (c) 2001 Intel Corp.
* Copyright (c) 2001 La Monte H.P. Yarroll * Copyright (c) 2001 La Monte H.P. Yarroll
* *
...@@ -42,6 +42,7 @@ ...@@ -42,6 +42,7 @@
* Sridhar Samudrala <sri@us.ibm.com> * Sridhar Samudrala <sri@us.ibm.com>
* Daisy Chang <daisyc@us.ibm.com> * Daisy Chang <daisyc@us.ibm.com>
* Ryan Layer <rmlayer@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 * Any bugs reported given to us we will try to fix... any fixes shared will
* be incorporated into the next SCTP release. * be incorporated into the next SCTP release.
...@@ -1155,3 +1156,23 @@ int sctp_assoc_set_bind_addr_from_cookie(struct sctp_association *asoc, ...@@ -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, return sctp_raw_to_bind_addrs(&asoc->base.bind_addr, raw, var_size3,
asoc->ep->base.bind_addr.port, gfp); 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 /* SCTP kernel reference Implementation
* (C) Copyright IBM Corp. 2001, 2003
* Copyright (c) Cisco 1999,2000 * Copyright (c) Cisco 1999,2000
* Copyright (c) Motorola 1999,2000,2001 * Copyright (c) Motorola 1999,2000,2001
* Copyright (c) International Business Machines Corp., 2001,2002
* Copyright (c) La Monte H.P. Yarroll 2001 * Copyright (c) La Monte H.P. Yarroll 2001
* *
* This file is part of the SCTP kernel reference implementation. * 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, ...@@ -223,6 +223,8 @@ union sctp_params sctp_bind_addrs_to_raw(const struct sctp_bind_addr *bp,
int len; int len;
struct sctp_sockaddr_entry *addr; struct sctp_sockaddr_entry *addr;
struct list_head *pos; struct list_head *pos;
struct sctp_af *af;
addrparms_len = 0; addrparms_len = 0;
len = 0; len = 0;
...@@ -247,7 +249,8 @@ union sctp_params sctp_bind_addrs_to_raw(const struct sctp_bind_addr *bp, ...@@ -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) { list_for_each(pos, &bp->address_list) {
addr = list_entry(pos, struct sctp_sockaddr_entry, 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); memcpy(addrparms.v, &rawaddr, len);
addrparms.v += len; addrparms.v += len;
addrparms_len += len; addrparms_len += len;
...@@ -270,34 +273,31 @@ int sctp_raw_to_bind_addrs(struct sctp_bind_addr *bp, __u8 *raw_addr_list, ...@@ -270,34 +273,31 @@ int sctp_raw_to_bind_addrs(struct sctp_bind_addr *bp, __u8 *raw_addr_list,
union sctp_addr addr; union sctp_addr addr;
int retval = 0; int retval = 0;
int len; int len;
struct sctp_af *af;
/* Convert the raw address to standard address format */ /* Convert the raw address to standard address format */
while (addrs_len) { while (addrs_len) {
param = (struct sctp_paramhdr *)raw_addr_list; param = (struct sctp_paramhdr *)raw_addr_list;
rawaddr = (union sctp_addr_param *)raw_addr_list; rawaddr = (union sctp_addr_param *)raw_addr_list;
switch (param->type) { af = sctp_get_af_specific(param_type2af(param->type));
case SCTP_PARAM_IPV4_ADDRESS: if (unlikely(!af)) {
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! */
retval = -EINVAL; retval = -EINVAL;
sctp_bind_addr_clean(bp); sctp_bind_addr_clean(bp);
break; 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; return retval;
......
...@@ -768,6 +768,7 @@ static struct sctp_association *__sctp_rcv_init_lookup(struct sk_buff *skb, ...@@ -768,6 +768,7 @@ static struct sctp_association *__sctp_rcv_init_lookup(struct sk_buff *skb,
union sctp_params params; union sctp_params params;
sctp_init_chunk_t *init; sctp_init_chunk_t *init;
struct sctp_transport *transport; struct sctp_transport *transport;
struct sctp_af *af;
ch = (sctp_chunkhdr_t *) skb->data; ch = (sctp_chunkhdr_t *) skb->data;
...@@ -802,11 +803,12 @@ static struct sctp_association *__sctp_rcv_init_lookup(struct sk_buff *skb, ...@@ -802,11 +803,12 @@ static struct sctp_association *__sctp_rcv_init_lookup(struct sk_buff *skb,
sctp_walk_params(params, init, init_hdr.params) { sctp_walk_params(params, init, init_hdr.params) {
/* Note: Ignoring hostname addresses. */ /* Note: Ignoring hostname addresses. */
if ((SCTP_PARAM_IPV4_ADDRESS != params.p->type) && af = sctp_get_af_specific(param_type2af(params.p->type));
(SCTP_PARAM_IPV6_ADDRESS != params.p->type)) if (!af)
continue; 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); asoc = __sctp_lookup_association(laddr, paddr, &transport);
if (asoc) if (asoc)
return asoc; return asoc;
......
...@@ -399,6 +399,33 @@ static void sctp_v6_to_sk_daddr(union sctp_addr *addr, struct sock *sk) ...@@ -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. */ /* 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,
unsigned short port) unsigned short port)
...@@ -903,6 +930,8 @@ static struct sctp_af sctp_ipv6_specific = { ...@@ -903,6 +930,8 @@ static struct sctp_af sctp_ipv6_specific = {
.from_sk = sctp_v6_from_sk, .from_sk = sctp_v6_from_sk,
.to_sk_saddr = sctp_v6_to_sk_saddr, .to_sk_saddr = sctp_v6_to_sk_saddr,
.to_sk_daddr = sctp_v6_to_sk_daddr, .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, .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,
......
...@@ -39,6 +39,7 @@ ...@@ -39,6 +39,7 @@
* Narasimha Budihal <narasimha@refcode.org> * Narasimha Budihal <narasimha@refcode.org>
* Karl Knutson <karl@athena.chicago.il.us> * Karl Knutson <karl@athena.chicago.il.us>
* Ardelle Fan <ardelle.fan@intel.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 * Any bugs reported given to us we will try to fix... any fixes shared will
* be incorporated into the next SCTP release. * be incorporated into the next SCTP release.
...@@ -203,3 +204,16 @@ DECLARE_PRIMITIVE(SEND); ...@@ -203,3 +204,16 @@ DECLARE_PRIMITIVE(SEND);
*/ */
DECLARE_PRIMITIVE(REQUESTHEARTBEAT); 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) ...@@ -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; 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. */ /* 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,
unsigned short port) unsigned short port)
...@@ -862,6 +887,8 @@ struct sctp_af sctp_ipv4_specific = { ...@@ -862,6 +887,8 @@ struct sctp_af sctp_ipv4_specific = {
.from_sk = sctp_v4_from_sk, .from_sk = sctp_v4_from_sk,
.to_sk_saddr = sctp_v4_to_sk_saddr, .to_sk_saddr = sctp_v4_to_sk_saddr,
.to_sk_daddr = sctp_v4_to_sk_daddr, .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, .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,
......
/* SCTP kernel reference Implementation /* SCTP kernel reference Implementation
* Copyright (C) IBM Corp. 2001, 2003
* Copyright (c) 1999-2000 Cisco, Inc. * Copyright (c) 1999-2000 Cisco, Inc.
* Copyright (c) 1999-2001 Motorola, Inc. * Copyright (c) 1999-2001 Motorola, Inc.
* Copyright (c) 2001-2002 Intel Corp. * Copyright (c) 2001-2002 Intel Corp.
* Copyright (c) 2001-2002 International Business Machines Corp.
* *
* This file is part of the SCTP kernel reference Implementation * This file is part of the SCTP kernel reference Implementation
* *
...@@ -48,6 +48,7 @@ ...@@ -48,6 +48,7 @@
* Sridhar Samudrala <sri@us.ibm.com> * Sridhar Samudrala <sri@us.ibm.com>
* Daisy Chang <daisyc@us.ibm.com> * Daisy Chang <daisyc@us.ibm.com>
* Ardelle Fan <ardelle.fan@intel.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 * Any bugs reported given to us we will try to fix... any fixes shared will
* be incorporated into the next SCTP release. * be incorporated into the next SCTP release.
...@@ -1213,6 +1214,7 @@ struct sctp_association *sctp_make_temp_asoc(const struct sctp_endpoint *ep, ...@@ -1213,6 +1214,7 @@ struct sctp_association *sctp_make_temp_asoc(const struct sctp_endpoint *ep,
struct sctp_association *asoc; struct sctp_association *asoc;
struct sk_buff *skb; struct sk_buff *skb;
sctp_scope_t scope; sctp_scope_t scope;
struct sctp_af *af;
/* Create the bare association. */ /* Create the bare association. */
scope = sctp_scope(sctp_source(chunk)); scope = sctp_scope(sctp_source(chunk));
...@@ -1222,29 +1224,10 @@ struct sctp_association *sctp_make_temp_asoc(const struct sctp_endpoint *ep, ...@@ -1222,29 +1224,10 @@ struct sctp_association *sctp_make_temp_asoc(const struct sctp_endpoint *ep,
asoc->temp = 1; asoc->temp = 1;
skb = chunk->skb; skb = chunk->skb;
/* Create an entry for the source address of the packet. */ /* Create an entry for the source address of the packet. */
/* FIXME: Use the af specific helpers. */ af = sctp_get_af_specific(ipver2af(skb->nh.iph->version));
switch (skb->nh.iph->version) { if (unlikely(!af))
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. */
goto fail; goto fail;
}; af->from_skb(&asoc->c.peer_addr, skb, 1);
nodata: nodata:
return asoc; return asoc;
...@@ -1830,11 +1813,14 @@ int sctp_process_init(struct sctp_association *asoc, sctp_cid_t cid, ...@@ -1830,11 +1813,14 @@ int sctp_process_init(struct sctp_association *asoc, sctp_cid_t cid,
* stream sequence number shall be set to 0. * stream sequence number shall be set to 0.
*/ */
/* Allocate storage for the negotiated streams. */ /* Allocate storage for the negotiated streams if it is not a temporary * association.
asoc->ssnmap = sctp_ssnmap_new(asoc->peer.i.num_outbound_streams, */
asoc->c.sinit_num_ostreams, gfp); if (!asoc->temp) {
if (!asoc->ssnmap) asoc->ssnmap = sctp_ssnmap_new(asoc->c.sinit_max_instreams,
goto nomem_ssnmap; asoc->c.sinit_num_ostreams, gfp);
if (!asoc->ssnmap)
goto nomem_ssnmap;
}
/* ADDIP Section 4.1 ASCONF Chunk Procedures /* ADDIP Section 4.1 ASCONF Chunk Procedures
* *
...@@ -1882,6 +1868,7 @@ int sctp_process_param(struct sctp_association *asoc, union sctp_params param, ...@@ -1882,6 +1868,7 @@ int sctp_process_param(struct sctp_association *asoc, union sctp_params param,
int retval = 1; int retval = 1;
sctp_scope_t scope; sctp_scope_t scope;
time_t stale; time_t stale;
struct sctp_af *af;
/* We maintain all INIT parameters in network byte order all the /* We maintain all INIT parameters in network byte order all the
* time. This allows us to not worry about whether the parameters * 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, ...@@ -1893,7 +1880,8 @@ int sctp_process_param(struct sctp_association *asoc, union sctp_params param,
break; break;
/* Fall through. */ /* Fall through. */
case SCTP_PARAM_IPV4_ADDRESS: 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); scope = sctp_scope(peer_addr);
if (sctp_in_scope(&addr, scope)) if (sctp_in_scope(&addr, scope))
if (!sctp_assoc_add_peer(asoc, &addr, gfp)) if (!sctp_assoc_add_peer(asoc, &addr, gfp))
...@@ -2005,90 +1993,6 @@ __u32 sctp_generate_tsn(const struct sctp_endpoint *ep) ...@@ -2005,90 +1993,6 @@ __u32 sctp_generate_tsn(const struct sctp_endpoint *ep)
return retval; 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) * ADDIP 3.1.1 Address Configuration Change Chunk (ASCONF)
* 0 1 2 3 * 0 1 2 3
...@@ -2119,8 +2023,9 @@ struct sctp_chunk *sctp_make_asconf(struct sctp_association *asoc, ...@@ -2119,8 +2023,9 @@ struct sctp_chunk *sctp_make_asconf(struct sctp_association *asoc,
int length = sizeof(asconf) + vparam_len; int length = sizeof(asconf) + vparam_len;
union sctp_params addrparam; union sctp_params addrparam;
int addrlen; 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) if (!addrlen)
return NULL; return NULL;
length += addrlen; length += addrlen;
...@@ -2135,7 +2040,51 @@ struct sctp_chunk *sctp_make_asconf(struct sctp_association *asoc, ...@@ -2135,7 +2040,51 @@ struct sctp_chunk *sctp_make_asconf(struct sctp_association *asoc,
retval->subh.addip_hdr = retval->subh.addip_hdr =
sctp_addto_chunk(retval, sizeof(asconf), &asconf); sctp_addto_chunk(retval, sizeof(asconf), &asconf);
retval->param_hdr.v = 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; return retval;
} }
......
...@@ -929,6 +929,7 @@ static int sctp_sf_send_restart_abort(union sctp_addr *ssa, ...@@ -929,6 +929,7 @@ static int sctp_sf_send_restart_abort(union sctp_addr *ssa,
struct sctp_errhdr *errhdr; struct sctp_errhdr *errhdr;
struct sctp_endpoint *ep; struct sctp_endpoint *ep;
char buffer[sizeof(struct sctp_errhdr)+sizeof(union sctp_addr_param)]; 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 /* Build the error on the stack. We are way to malloc crazy
* throughout the code today. * throughout the code today.
...@@ -937,7 +938,7 @@ static int sctp_sf_send_restart_abort(union sctp_addr *ssa, ...@@ -937,7 +938,7 @@ static int sctp_sf_send_restart_abort(union sctp_addr *ssa,
addrparm = (union sctp_addr_param *)errhdr->variable; addrparm = (union sctp_addr_param *)errhdr->variable;
/* Copy into a parm format. */ /* Copy into a parm format. */
len = sockaddr2sctp_addr(ssa, addrparm); len = af->to_addr_param(ssa, addrparm);
len += sizeof(sctp_errhdr_t); len += sizeof(sctp_errhdr_t);
errhdr->cause = SCTP_ERROR_RESTART; 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) 1999-2001 Motorola, Inc.
* Copyright (c) 2001-2003 International Business Machines, Corp.
* Copyright (c) 2001-2003 Intel Corp. * Copyright (c) 2001-2003 Intel Corp.
* Copyright (c) 2001-2002 Nokia, Inc. * Copyright (c) 2001-2002 Nokia, Inc.
* Copyright (c) 2001 La Monte H.P. Yarroll * Copyright (c) 2001 La Monte H.P. Yarroll
...@@ -50,6 +51,7 @@ ...@@ -50,6 +51,7 @@
* Ardelle Fan <ardelle.fan@intel.com> * Ardelle Fan <ardelle.fan@intel.com>
* Ryan Layer <rmlayer@us.ibm.com> * Ryan Layer <rmlayer@us.ibm.com>
* Anup Pemmaiah <pemmaiah@cc.usu.edu> * 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 * Any bugs reported given to us we will try to fix... any fixes shared will
* be incorporated into the next SCTP release. * be incorporated into the next SCTP release.
...@@ -93,8 +95,8 @@ static int sctp_wait_for_connect(struct sctp_association *, long *timeo_p); ...@@ -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 int sctp_wait_for_accept(struct sock *sk, long timeo);
static void sctp_wait_for_close(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 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_add(struct sock *, struct sockaddr *, int);
static int sctp_bindx_rem(struct sock *, struct sockaddr_storage *, 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_do_bind(struct sock *, union sctp_addr *, int);
static int sctp_autobind(struct sock *sk); static int sctp_autobind(struct sock *sk);
static void sctp_sock_migrate(struct sock *, struct sock *, static void sctp_sock_migrate(struct sock *, struct sock *,
...@@ -170,10 +172,7 @@ struct sctp_transport *sctp_addr_id2transport(struct sock *sk, ...@@ -170,10 +172,7 @@ struct sctp_transport *sctp_addr_id2transport(struct sock *sk,
* sd - the socket descriptor returned by socket(). * sd - the socket descriptor returned by socket().
* addr - the address structure (struct sockaddr_in or struct * addr - the address structure (struct sockaddr_in or struct
* sockaddr_in6 [RFC 2553]), * sockaddr_in6 [RFC 2553]),
* addrlen - the size of the address structure. * addr_len - the size of the address structure.
*
* The caller should use struct sockaddr_storage described in RFC 2553
* to represent addr for portability reason.
*/ */
int sctp_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len) 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) ...@@ -298,112 +297,6 @@ SCTP_STATIC int sctp_do_bind(struct sock *sk, union sctp_addr *addr, int len)
return ret; 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 /* Add a list of addresses as bind addresses to local endpoint or
* association. * association.
* *
...@@ -414,41 +307,39 @@ int sctp_bindx(struct sock *sk, struct sockaddr_storage *addrs, int addrcnt, ...@@ -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 * If any of them fails, then the operation will be reversed and the
* ones that were added will be removed. * 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 cnt;
int retval = 0; 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", SCTP_DEBUG_PRINTK("sctp_bindx_add (sk: %p, addrs: %p, addrcnt: %d)\n",
sk, addrs, addrcnt); sk, addrs, addrcnt);
addr_buf = addrs;
for (cnt = 0; cnt < addrcnt; cnt++) { for (cnt = 0; cnt < addrcnt; cnt++) {
/* The list may contain either IPv4 or IPv6 address; /* The list may contain either IPv4 or IPv6 address;
* determine the address length for walking thru the list. * determine the address length for walking thru the list.
*/ */
switch (((struct sockaddr *)&addrs[cnt])->sa_family) { sa_addr = (struct sockaddr *)addr_buf;
case AF_INET: af = sctp_get_af_specific(sa_addr->sa_family);
addr_len = sizeof(struct sockaddr_in); if (!af) {
break;
case AF_INET6:
addr_len = sizeof(struct sockaddr_in6);
break;
default:
retval = -EINVAL; retval = -EINVAL;
goto err_bindx_add; goto err_bindx_add;
}; }
retval = sctp_do_bind(sk, (union sctp_addr *)&addrs[cnt], retval = sctp_do_bind(sk, (union sctp_addr *)sa_addr,
addr_len); af->sockaddr_len);
addr_buf += af->sockaddr_len;
err_bindx_add: err_bindx_add:
if (retval < 0) { if (retval < 0) {
/* Failed. Cleanup the ones that has been added */ /* Failed. Cleanup the ones that have been added */
if (cnt > 0) if (cnt > 0)
sctp_bindx_rem(sk, addrs, cnt); sctp_bindx_rem(sk, addrs, cnt);
return retval; return retval;
...@@ -471,9 +362,9 @@ int sctp_bindx_add(struct sock *sk, struct sockaddr_storage *addrs, int addrcnt) ...@@ -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 * At least one address has to be left; if only one address is
* available, the operation will return -EBUSY. * 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_opt *sp = sctp_sk(sk);
struct sctp_endpoint *ep = sp->ep; struct sctp_endpoint *ep = sp->ep;
...@@ -481,50 +372,41 @@ int sctp_bindx_rem(struct sock *sk, struct sockaddr_storage *addrs, int addrcnt) ...@@ -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; struct sctp_bind_addr *bp = &ep->base.bind_addr;
int retval = 0; int retval = 0;
union sctp_addr saveaddr; 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", SCTP_DEBUG_PRINTK("sctp_bindx_rem (sk: %p, addrs: %p, addrcnt: %d)\n",
sk, addrs, addrcnt); sk, addrs, addrcnt);
addr_buf = addrs;
for (cnt = 0; cnt < addrcnt; cnt++) { for (cnt = 0; cnt < addrcnt; cnt++) {
/* If there is only one bind address, there is nothing more /* If the bind address list is empty or if there is only one
* to be removed (we need at least one address here). * 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; retval = -EBUSY;
goto err_bindx_rem; goto err_bindx_rem;
} }
/* The list may contain either IPv4 or IPv6 address; /* 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) { sa_addr = (struct sockaddr *)addr_buf;
case AF_INET: af = sctp_get_af_specific(sa_addr->sa_family);
saveaddr = *((union sctp_addr *) if (!af) {
&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:
retval = -EINVAL; retval = -EINVAL;
goto err_bindx_rem; 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 /* 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 * 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) ...@@ -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_write_unlock(&ep->base.addr_lock);
sctp_local_bh_enable(); sctp_local_bh_enable();
addr_buf += af->sockaddr_len;
err_bindx_rem: err_bindx_rem:
if (retval < 0) { if (retval < 0) {
/* Failed. Add the ones that has been removed back */ /* 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) ...@@ -553,18 +436,62 @@ int sctp_bindx_rem(struct sock *sk, struct sockaddr_storage *addrs, int addrcnt)
return retval; 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 * Basically do nothing but copying the addresses from user to kernel
* land and invoking sctp_bindx on the sk. This is used for tunneling * land and invoking either sctp_bindx_add() or sctp_bindx_rem() on the sk.
* the sctp_bindx() [sys_bindx()] request through sctp_setsockopt() * This is used for tunneling the sctp_bindx() request through sctp_setsockopt() * from userspace.
* 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.
* *
* We don't use copy_from_user() for optimization: we first do the * We don't use copy_from_user() for optimization: we first do the
* sanity checks (buffer size -fast- and access check-healthy * 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) ...@@ -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. * Returns 0 if ok, <0 errno code on error.
*/ */
SCTP_STATIC int sctp_setsockopt_bindx(struct sock* sk, SCTP_STATIC int sctp_setsockopt_bindx(struct sock* sk, struct sockaddr *addrs,
struct sockaddr_storage *addrs, int addrs_size, int op)
int addrssize, int op)
{ {
struct sockaddr_storage *kaddrs; struct sockaddr *kaddrs;
int err; 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" SCTP_DEBUG_PRINTK("sctp_setsocktopt_bindx: sk %p addrs %p"
" addrssize %d opt %d\n", sk, addrs, addrssize, op); " addrs_size %d opt %d\n", sk, addrs, addrs_size, op);
/* Do we have an integer number of structs sockaddr_storage? */ if (unlikely(addrs_size <= 0))
if (unlikely(addrssize <= 0 ||
addrssize % sizeof(struct sockaddr_storage) != 0))
return -EINVAL; return -EINVAL;
/* Check the user passed a healthy pointer. */ /* 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; return -EFAULT;
/* Alloc space for the address array in kernel memory. */ /* 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)) if (unlikely(!kaddrs))
return -ENOMEM; return -ENOMEM;
if (copy_from_user(kaddrs, addrs, addrssize)) { if (__copy_from_user(kaddrs, addrs, addrs_size)) {
kfree(kaddrs); kfree(kaddrs);
return -EFAULT; return -EFAULT;
} }
addrcnt = addrssize / sizeof(struct sockaddr_storage); /* Walk through the addrs buffer and count the number of addresses. */
err = __sctp_bindx(sk, kaddrs, addrcnt, op); /* Do the work. */ 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); kfree(kaddrs);
return err; return err;
...@@ -1476,7 +1435,7 @@ static int sctp_setsockopt_initmsg(struct sock *sk, char *optval, int optlen) ...@@ -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 * Applications that wish to use the sendto() system call may wish to
* specify a default set of parameters that would normally be supplied * 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, ...@@ -1522,7 +1481,7 @@ static int sctp_setsockopt_default_send_param(struct sock *sk,
return 0; 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 * Requests that the local SCTP stack use the enclosed peer address as
* the association primary. The enclosed address must be one of the * 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) ...@@ -1727,6 +1686,62 @@ static int sctp_setsockopt_maxseg(struct sock *sk, char *optval, int optlen)
return 0; 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() /* API 6.2 setsockopt(), getsockopt()
* *
* Applications use setsockopt() and getsockopt() to set or retrieve * 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, ...@@ -1771,16 +1786,14 @@ SCTP_STATIC int sctp_setsockopt(struct sock *sk, int level, int optname,
switch (optname) { switch (optname) {
case SCTP_SOCKOPT_BINDX_ADD: case SCTP_SOCKOPT_BINDX_ADD:
/* 'optlen' is the size of the addresses buffer. */ /* 'optlen' is the size of the addresses buffer. */
retval = sctp_setsockopt_bindx(sk, (struct sockaddr_storage *) retval = sctp_setsockopt_bindx(sk, (struct sockaddr *)optval,
optval, optlen, optlen, SCTP_BINDX_ADD_ADDR);
SCTP_BINDX_ADD_ADDR);
break; break;
case SCTP_SOCKOPT_BINDX_REM: case SCTP_SOCKOPT_BINDX_REM:
/* 'optlen' is the size of the addresses buffer. */ /* 'optlen' is the size of the addresses buffer. */
retval = sctp_setsockopt_bindx(sk, (struct sockaddr_storage *) retval = sctp_setsockopt_bindx(sk, (struct sockaddr *)optval,
optval, optlen, optlen, SCTP_BINDX_REM_ADDR);
SCTP_BINDX_REM_ADDR);
break; break;
case SCTP_DISABLE_FRAGMENTS: case SCTP_DISABLE_FRAGMENTS:
...@@ -1809,6 +1822,9 @@ SCTP_STATIC int sctp_setsockopt(struct sock *sk, int level, int optname, ...@@ -1809,6 +1822,9 @@ SCTP_STATIC int sctp_setsockopt(struct sock *sk, int level, int optname,
case SCTP_PRIMARY_ADDR: case SCTP_PRIMARY_ADDR:
retval = sctp_setsockopt_primary_addr(sk, optval, optlen); retval = sctp_setsockopt_primary_addr(sk, optval, optlen);
break; break;
case SCTP_SET_PEER_PRIMARY_ADDR:
retval = sctp_setsockopt_peer_primary_addr(sk, optval, optlen);
break;
case SCTP_NODELAY: case SCTP_NODELAY:
retval = sctp_setsockopt_nodelay(sk, optval, optlen); retval = sctp_setsockopt_nodelay(sk, optval, optlen);
break; break;
...@@ -2056,9 +2072,8 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk) ...@@ -2056,9 +2072,8 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk)
return -ESOCKTNOSUPPORT; return -ESOCKTNOSUPPORT;
} }
/* FIXME: The next draft (04) of the SCTP Sockets Extensions /* Initialize default send parameters. These parameters can be
* should include a socket option for manipulating these * modified with the SCTP_DEFAULT_SEND_PARAM socket option.
* message parameters (and a few others).
*/ */
sp->default_stream = 0; sp->default_stream = 0;
sp->default_ppid = 0; sp->default_ppid = 0;
...@@ -2077,7 +2092,6 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk) ...@@ -2077,7 +2092,6 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk)
/* Initialize default RTO related parameters. These parameters can /* Initialize default RTO related parameters. These parameters can
* be modified for with the SCTP_RTOINFO socket option. * 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_initial = (sctp_rto_initial / HZ) * 1000;
sp->rtoinfo.srto_max = (sctp_rto_max / HZ) * 1000; sp->rtoinfo.srto_max = (sctp_rto_max / HZ) * 1000;
...@@ -2093,15 +2107,10 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk) ...@@ -2093,15 +2107,10 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk)
sp->assocparams.sasoc_cookie_life = (sctp_valid_cookie_life / HZ) sp->assocparams.sasoc_cookie_life = (sctp_valid_cookie_life / HZ)
* 1000; * 1000;
/* Initialize default event subscriptions. /* Initialize default event subscriptions. By default, all the
* the struct sock is initialized to zero, so only * options are off.
* enable the events needed. By default, UDP-style
* sockets enable io and association change notifications.
*/ */
if (sctp_style(sk, UDP)) { memset(&sp->subscribe, 0, sizeof(struct sctp_event_subscribe));
sp->subscribe.sctp_data_io_event = 1;
sp->subscribe.sctp_association_event = 1;
}
/* Default Peer Address Parameters. These defaults can /* Default Peer Address Parameters. These defaults can
* be modified via SCTP_PEER_ADDR_PARAMS * be modified via SCTP_PEER_ADDR_PARAMS
...@@ -2552,7 +2561,7 @@ static int sctp_getsockopt_initmsg(struct sock *sk, int len, char *optval, int * ...@@ -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, static int sctp_getsockopt_peer_addrs_num(struct sock *sk, int len,
char *optval, int *optlen) char *optval, int *optlen)
{ {
sctp_assoc_t id; sctp_assoc_t id;
struct sctp_association *asoc; struct sctp_association *asoc;
...@@ -2565,9 +2574,7 @@ static int sctp_getsockopt_peer_addrs_num(struct sock *sk, int len, ...@@ -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))) if (copy_from_user(&id, optval, sizeof(sctp_assoc_t)))
return -EFAULT; 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); asoc = sctp_id2assoc(sk, id);
if (!asoc) if (!asoc)
return -EINVAL; return -EINVAL;
...@@ -2582,16 +2589,17 @@ static int sctp_getsockopt_peer_addrs_num(struct sock *sk, int len, ...@@ -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, static int sctp_getsockopt_peer_addrs(struct sock *sk, int len,
char *optval, int *optlen) char *optval, int *optlen)
{ {
struct sctp_association *asoc; struct sctp_association *asoc;
struct list_head *pos; struct list_head *pos;
int cnt = 0; int cnt = 0;
struct sctp_getaddrs getaddrs; struct sctp_getaddrs getaddrs;
struct sctp_transport *from; struct sctp_transport *from;
struct sockaddr_storage *to; void *to;
union sctp_addr temp; union sctp_addr temp;
struct sctp_opt *sp = sctp_sk(sk); struct sctp_opt *sp = sctp_sk(sk);
int addrlen;
if (len != sizeof(struct sctp_getaddrs)) if (len != sizeof(struct sctp_getaddrs))
return -EINVAL; return -EINVAL;
...@@ -2600,21 +2608,21 @@ static int sctp_getsockopt_peer_addrs(struct sock *sk, int len, ...@@ -2600,21 +2608,21 @@ static int sctp_getsockopt_peer_addrs(struct sock *sk, int len,
return -EFAULT; return -EFAULT;
if (getaddrs.addr_num <= 0) return -EINVAL; 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); asoc = sctp_id2assoc(sk, getaddrs.assoc_id);
if (!asoc) if (!asoc)
return -EINVAL; return -EINVAL;
to = getaddrs.addrs; to = (void *)getaddrs.addrs;
list_for_each(pos, &asoc->peer.transport_addr_list) { list_for_each(pos, &asoc->peer.transport_addr_list) {
from = list_entry(pos, struct sctp_transport, transports); from = list_entry(pos, struct sctp_transport, transports);
memcpy(&temp, &from->ipaddr, sizeof(temp)); memcpy(&temp, &from->ipaddr, sizeof(temp));
sctp_get_pf_specific(sk->sk_family)->addr_v4map(sp, &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; return -EFAULT;
to ++; to += addrlen ;
cnt ++; cnt ++;
if (cnt >= getaddrs.addr_num) break; if (cnt >= getaddrs.addr_num) break;
} }
...@@ -2673,9 +2681,10 @@ static int sctp_getsockopt_local_addrs(struct sock *sk, int len, ...@@ -2673,9 +2681,10 @@ static int sctp_getsockopt_local_addrs(struct sock *sk, int len,
int cnt = 0; int cnt = 0;
struct sctp_getaddrs getaddrs; struct sctp_getaddrs getaddrs;
struct sctp_sockaddr_entry *from; struct sctp_sockaddr_entry *from;
struct sockaddr_storage *to; void *to;
union sctp_addr temp; union sctp_addr temp;
struct sctp_opt *sp = sctp_sk(sk); struct sctp_opt *sp = sctp_sk(sk);
int addrlen;
if (len != sizeof(struct sctp_getaddrs)) if (len != sizeof(struct sctp_getaddrs))
return -EINVAL; return -EINVAL;
...@@ -2699,16 +2708,17 @@ static int sctp_getsockopt_local_addrs(struct sock *sk, int len, ...@@ -2699,16 +2708,17 @@ static int sctp_getsockopt_local_addrs(struct sock *sk, int len,
bp = &asoc->base.bind_addr; bp = &asoc->base.bind_addr;
} }
to = getaddrs.addrs; to = (void *)getaddrs.addrs;
list_for_each(pos, &bp->address_list) { list_for_each(pos, &bp->address_list) {
from = list_entry(pos, from = list_entry(pos,
struct sctp_sockaddr_entry, struct sctp_sockaddr_entry,
list); list);
memcpy(&temp, &from->a, sizeof(temp)); memcpy(&temp, &from->a, sizeof(temp));
sctp_get_pf_specific(sk->sk_family)->addr_v4map(sp, &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; return -EFAULT;
to ++; to += addrlen;
cnt ++; cnt ++;
if (cnt >= getaddrs.addr_num) break; if (cnt >= getaddrs.addr_num) break;
} }
...@@ -2759,7 +2769,7 @@ static int sctp_getsockopt_primary_addr(struct sock *sk, int len, ...@@ -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 * Applications that wish to use the sendto() system call may wish to
* specify a default set of parameters that would normally be supplied * 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) ...@@ -3331,9 +3341,19 @@ SCTP_STATIC int sctp_seqpacket_listen(struct sock *sk, int backlog)
if (!sctp_style(sk, UDP)) if (!sctp_style(sk, UDP))
return -EINVAL; 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)) if (sctp_sstate(sk, LISTENING))
return 0; return 0;
/* /*
* If a bind() or sctp_bindx() is not called prior to a listen() * If a bind() or sctp_bindx() is not called prior to a listen()
* call that allows new associations to be accepted, the system * 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) ...@@ -3364,6 +3384,15 @@ SCTP_STATIC int sctp_stream_listen(struct sock *sk, int backlog)
struct sctp_opt *sp = sctp_sk(sk); struct sctp_opt *sp = sctp_sk(sk);
struct sctp_endpoint *ep = sp->ep; 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)) if (sctp_sstate(sk, LISTENING))
return 0; return 0;
......
...@@ -214,7 +214,7 @@ static int sctp_sysctl_jiffies_ms(ctl_table *table, int __user *name, int nlen, ...@@ -214,7 +214,7 @@ static int sctp_sysctl_jiffies_ms(ctl_table *table, int __user *name, int nlen,
if (olen != sizeof (int)) if (olen != sizeof (int))
return -EINVAL; return -EINVAL;
} }
if (put_user((*(int *)(table->data) / HZ) * 1000, if (put_user((*(int *)(table->data) * 1000) / HZ,
(int *)oldval) || (int *)oldval) ||
(oldlenp && put_user(sizeof (int), oldlenp))) (oldlenp && put_user(sizeof (int), oldlenp)))
return -EFAULT; return -EFAULT;
...@@ -228,7 +228,7 @@ static int sctp_sysctl_jiffies_ms(ctl_table *table, int __user *name, int nlen, ...@@ -228,7 +228,7 @@ static int sctp_sysctl_jiffies_ms(ctl_table *table, int __user *name, int nlen,
if (get_user(new, (int *)newval)) if (get_user(new, (int *)newval))
return -EFAULT; return -EFAULT;
*(int *)(table->data) = (new * HZ) * 1000; *(int *)(table->data) = (new * HZ) / 1000;
} }
return 1; 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