Commit 1ee0db3c authored by David S. Miller's avatar David S. Miller

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

into nuts.ninka.net:/home/davem/src/BK/sctp-2.5
parents afab4c80 ccdf98ff
......@@ -119,12 +119,10 @@
*/
/*
* sctp_protocol.c
* sctp/protocol.c
*/
extern struct sctp_protocol sctp_proto;
extern struct sock *sctp_get_ctl_sock(void);
extern int sctp_copy_local_addr_list(struct sctp_protocol *,
struct sctp_bind_addr *,
extern int sctp_copy_local_addr_list(struct sctp_bind_addr *,
sctp_scope_t, int gfp, int flags);
extern struct sctp_pf *sctp_get_pf_specific(sa_family_t family);
extern int sctp_register_pf(struct sctp_pf *, sa_family_t);
......@@ -275,6 +273,7 @@ extern atomic_t sctp_dbg_objcnt_assoc;
extern atomic_t sctp_dbg_objcnt_transport;
extern atomic_t sctp_dbg_objcnt_chunk;
extern atomic_t sctp_dbg_objcnt_bind_addr;
extern atomic_t sctp_dbg_objcnt_bind_bucket;
extern atomic_t sctp_dbg_objcnt_addr;
extern atomic_t sctp_dbg_objcnt_ssnmap;
extern atomic_t sctp_dbg_objcnt_datamsg;
......@@ -418,6 +417,10 @@ static inline __s32 sctp_jitter(__u32 rto)
static __u32 sctp_rand;
__s32 ret;
/* Avoid divide by zero. */
if (!rto)
rto = 1;
sctp_rand += jiffies;
sctp_rand ^= (sctp_rand << 12);
sctp_rand ^= (sctp_rand >> 20);
......@@ -448,7 +451,7 @@ static inline int sctp_frag_point(const struct sctp_opt *sp, int pmtu)
* there is room for a param header too.
*/
#define sctp_walk_params(pos, chunk, member)\
_sctp_walk_params((pos), (chunk), ntohs((chunk)->chunk_hdr.length), member)
_sctp_walk_params((pos), (chunk), WORD_ROUND(ntohs((chunk)->chunk_hdr.length)), member)
#define _sctp_walk_params(pos, chunk, end, member)\
for (pos.v = chunk->member;\
......@@ -456,6 +459,18 @@ for (pos.v = chunk->member;\
pos.v <= (void *)chunk + end - WORD_ROUND(ntohs(pos.p->length)); \
pos.v += WORD_ROUND(ntohs(pos.p->length)))
#define sctp_walk_errors(err, chunk_hdr)\
_sctp_walk_errors((err), (chunk_hdr), ntohs((chunk_hdr)->length))
#define _sctp_walk_errors(err, chunk_hdr, end)\
for (err = (sctp_errhdr_t *)((void *)chunk_hdr + \
sizeof(sctp_chunkhdr_t));\
(void *)err <= (void *)chunk_hdr + end - sizeof(sctp_errhdr_t) &&\
(void *)err <= (void *)chunk_hdr + end - \
WORD_ROUND(ntohs(err->length));\
err = (sctp_errhdr_t *)((void *)err + \
WORD_ROUND(ntohs(err->length))))
/* Round an int up to the next multiple of 4. */
#define WORD_ROUND(s) (((s)+3)&~3)
......@@ -491,12 +506,6 @@ void sctp_put_port(struct sock *sk);
/* Static inline functions. */
/* Return the SCTP protocol structure. */
static inline struct sctp_protocol *sctp_get_protocol(void)
{
return &sctp_proto;
}
/* Convert from an IP version number to an Address Family symbol. */
static inline int ipver2af(__u8 ipver)
{
......@@ -524,24 +533,21 @@ static inline int sctp_sanity_check(void)
/* This is the hash function for the SCTP port hash table. */
static inline int sctp_phashfn(__u16 lport)
{
struct sctp_protocol *sctp_proto = sctp_get_protocol();
return (lport & (sctp_proto->port_hashsize - 1));
return (lport & (sctp_port_hashsize - 1));
}
/* This is the hash function for the endpoint hash table. */
static inline int sctp_ep_hashfn(__u16 lport)
{
struct sctp_protocol *sctp_proto = sctp_get_protocol();
return (lport & (sctp_proto->ep_hashsize - 1));
return (lport & (sctp_ep_hashsize - 1));
}
/* This is the hash function for the association hash table. */
static inline int sctp_assoc_hashfn(__u16 lport, __u16 rport)
{
struct sctp_protocol *sctp_proto = sctp_get_protocol();
int h = (lport << 16) + rport;
h ^= h>>8;
return (h & (sctp_proto->assoc_hashsize - 1));
return (h & (sctp_assoc_hashsize - 1));
}
/* This is the hash function for the association hash table. This is
......@@ -550,10 +556,9 @@ static inline int sctp_assoc_hashfn(__u16 lport, __u16 rport)
*/
static inline int sctp_vtag_hashfn(__u16 lport, __u16 rport, __u32 vtag)
{
struct sctp_protocol *sctp_proto = sctp_get_protocol();
int h = (lport << 16) + rport;
h ^= vtag;
return (h & (sctp_proto->assoc_hashsize-1));
return (h & (sctp_assoc_hashsize-1));
}
/* WARNING: Do not change the layout of the members in sctp_sock! */
......
......@@ -71,7 +71,7 @@ union sctp_addr {
};
/* Forward declarations for data structures. */
struct sctp_protocol;
struct sctp_globals;
struct sctp_endpoint;
struct sctp_association;
struct sctp_transport;
......@@ -92,28 +92,28 @@ struct sctp_ssnmap;
/* Structures useful for managing bind/connect. */
typedef struct sctp_bind_bucket {
struct sctp_bind_bucket {
unsigned short port;
unsigned short fastreuse;
struct sctp_bind_bucket *next;
struct sctp_bind_bucket **pprev;
struct sock *sk;
} sctp_bind_bucket_t;
};
typedef struct sctp_bind_hashbucket {
struct sctp_bind_hashbucket {
spinlock_t lock;
struct sctp_bind_bucket *chain;
} sctp_bind_hashbucket_t;
};
/* Used for hashing all associations. */
typedef struct sctp_hashbucket {
struct sctp_hashbucket {
rwlock_t lock;
struct sctp_ep_common *chain;
} sctp_hashbucket_t __attribute__((__aligned__(8)));
} __attribute__((__aligned__(8)));
/* The SCTP protocol structure. */
struct sctp_protocol {
/* The SCTP globals structure. */
extern struct sctp_globals {
/* RFC2960 Section 14. Suggested SCTP Protocol Parameter Values
*
* The following protocol parameters are RECOMMENDED:
......@@ -167,17 +167,17 @@ struct sctp_protocol {
/* This is the hash of all endpoints. */
int ep_hashsize;
sctp_hashbucket_t *ep_hashbucket;
struct sctp_hashbucket *ep_hashbucket;
/* This is the hash of all associations. */
int assoc_hashsize;
sctp_hashbucket_t *assoc_hashbucket;
struct sctp_hashbucket *assoc_hashbucket;
/* This is the sctp port control hash. */
int port_hashsize;
int port_rover;
spinlock_t port_alloc_lock; /* Protects port_rover. */
sctp_bind_hashbucket_t *port_hashtable;
struct sctp_bind_hashbucket *port_hashtable;
/* This is the global local address list.
* We actively maintain this complete list of interfaces on
......@@ -187,8 +187,33 @@ struct sctp_protocol {
*/
struct list_head local_addr_list;
spinlock_t local_addr_lock;
};
} sctp_globals;
#define sctp_rto_initial (sctp_globals.rto_initial)
#define sctp_rto_min (sctp_globals.rto_min)
#define sctp_rto_max (sctp_globals.rto_max)
#define sctp_rto_alpha (sctp_globals.rto_alpha)
#define sctp_rto_beta (sctp_globals.rto_beta)
#define sctp_max_burst (sctp_globals.max_burst)
#define sctp_valid_cookie_life (sctp_globals.valid_cookie_life)
#define sctp_cookie_preserve_enable (sctp_globals.cookie_preserve_enable)
#define sctp_max_retrans_association (sctp_globals.max_retrans_association)
#define sctp_max_retrans_path (sctp_globals.max_retrans_path)
#define sctp_max_retrans_init (sctp_globals.max_retrans_init)
#define sctp_hb_interval (sctp_globals.hb_interval)
#define sctp_max_instreams (sctp_globals.max_instreams)
#define sctp_max_outstreams (sctp_globals.max_outstreams)
#define sctp_address_families (sctp_globals.address_families)
#define sctp_ep_hashsize (sctp_globals.ep_hashsize)
#define sctp_ep_hashbucket (sctp_globals.ep_hashbucket)
#define sctp_assoc_hashsize (sctp_globals.assoc_hashsize)
#define sctp_assoc_hashbucket (sctp_globals.assoc_hashbucket)
#define sctp_port_hashsize (sctp_globals.port_hashsize)
#define sctp_port_rover (sctp_globals.port_rover)
#define sctp_port_alloc_lock (sctp_globals.port_alloc_lock)
#define sctp_port_hashtable (sctp_globals.port_hashtable)
#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.
......@@ -240,6 +265,8 @@ struct sctp_af {
int (*available) (const union sctp_addr *);
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;
......@@ -289,6 +316,10 @@ struct sctp_opt {
/* Various Socket Options. */
__u16 default_stream;
__u32 default_ppid;
__u16 default_flags;
__u32 default_context;
__u32 default_timetolive;
struct sctp_initmsg initmsg;
struct sctp_rtoinfo rtoinfo;
struct sctp_paddrparams paddrparam;
......@@ -1492,13 +1523,12 @@ struct sctp_association {
*/
int counters[SCTP_NUMBER_COUNTERS];
struct {
__u16 stream;
__u16 flags;
__u32 ppid;
__u32 context;
__u32 timetolive;
} defaults;
/* Default send parameters. */
__u16 default_stream;
__u16 default_flags;
__u32 default_ppid;
__u32 default_context;
__u32 default_timetolive;
/* This tracks outbound ssn for a given stream. */
struct sctp_ssnmap *ssnmap;
......
......@@ -485,6 +485,11 @@ struct sctp_paddrinfo {
__u32 spinfo_mtu;
};
/* Peer addresses's state. */
enum sctp_spinfo_state {
SCTP_INACTIVE,
SCTP_ACTIVE,
};
/*
* 7.1.1 Retransmission Timeout Parameters (SCTP_RTOINFO)
......
......@@ -96,7 +96,6 @@ struct sctp_association *sctp_association_init(struct sctp_association *asoc,
int gfp)
{
struct sctp_opt *sp;
struct sctp_protocol *proto = sctp_get_protocol();
int i;
/* Retrieve the SCTP per socket area. */
......@@ -129,26 +128,26 @@ struct sctp_association *sctp_association_init(struct sctp_association *asoc,
asoc->state_timestamp = jiffies;
/* Set things that have constant value. */
asoc->cookie_life.tv_sec = sctp_proto.valid_cookie_life / HZ;
asoc->cookie_life.tv_usec = (sctp_proto.valid_cookie_life % HZ) *
asoc->cookie_life.tv_sec = sctp_valid_cookie_life / HZ;
asoc->cookie_life.tv_usec = (sctp_valid_cookie_life % HZ) *
1000000L / HZ;
asoc->pmtu = 0;
asoc->frag_point = 0;
/* Initialize the default association max_retrans and RTO values. */
asoc->max_retrans = proto->max_retrans_association;
asoc->rto_initial = proto->rto_initial;
asoc->rto_max = proto->rto_max;
asoc->rto_min = proto->rto_min;
asoc->max_retrans = sctp_max_retrans_association;
asoc->rto_initial = sctp_rto_initial;
asoc->rto_max = sctp_rto_max;
asoc->rto_min = sctp_rto_min;
asoc->overall_error_threshold = 0;
asoc->overall_error_threshold = asoc->max_retrans;
asoc->overall_error_count = 0;
/* Initialize the maximum mumber of new data packets that can be sent
* in a burst.
*/
asoc->max_burst = proto->max_burst;
asoc->max_burst = sctp_max_burst;
/* Copy things from the endpoint. */
for (i = SCTP_EVENT_TIMEOUT_NONE; i < SCTP_NUM_TIMEOUT_TYPES; ++i) {
......@@ -277,6 +276,12 @@ struct sctp_association *sctp_association_init(struct sctp_association *asoc,
asoc->autoclose = sp->autoclose;
asoc->default_stream = sp->default_stream;
asoc->default_ppid = sp->default_ppid;
asoc->default_flags = sp->default_flags;
asoc->default_context = sp->default_context;
asoc->default_timetolive = sp->default_timetolive;
return asoc;
fail_init:
......@@ -478,16 +483,8 @@ struct sctp_transport *sctp_assoc_add_peer(struct sctp_association *asoc,
peer->partial_bytes_acked = 0;
peer->flight_size = 0;
peer->error_threshold = peer->max_retrans;
/* Update the overall error threshold value of the association
* taking the new peer's error threshold into account.
*/
asoc->overall_error_threshold =
min(asoc->overall_error_threshold + peer->error_threshold,
asoc->max_retrans);
/* By default, enable heartbeat for peer address. */
peer->hb_allowed = 1;
......@@ -550,12 +547,12 @@ void sctp_assoc_control_transport(struct sctp_association *asoc,
/* Record the transition on the transport. */
switch (command) {
case SCTP_TRANSPORT_UP:
transport->active = 1;
transport->active = SCTP_ACTIVE;
spc_state = ADDRESS_AVAILABLE;
break;
case SCTP_TRANSPORT_DOWN:
transport->active = 0;
transport->active = SCTP_INACTIVE;
spc_state = ADDRESS_UNREACHABLE;
break;
......
......@@ -329,12 +329,10 @@ static int sctp_copy_one_addr(struct sctp_bind_addr *dest,
union sctp_addr *addr,
sctp_scope_t scope, int gfp, int flags)
{
struct sctp_protocol *proto = sctp_get_protocol();
int error = 0;
if (sctp_is_any(addr)) {
error = sctp_copy_local_addr_list(proto, dest, scope,
gfp, flags);
error = sctp_copy_local_addr_list(dest, scope, gfp, flags);
} else if (sctp_in_scope(addr, scope)) {
/* Now that the address is in scope, check to see if
* the address type is supported by local sock as
......
......@@ -503,10 +503,11 @@ int sctp_rcv_ootb(struct sk_buff *skb)
goto discard;
if (SCTP_CID_ERROR == ch->type) {
err = (sctp_errhdr_t *)(ch + sizeof(sctp_chunkhdr_t));
sctp_walk_errors(err, ch) {
if (SCTP_ERROR_STALE_COOKIE == err->cause)
goto discard;
}
}
ch = (sctp_chunkhdr_t *) ch_end;
} while (ch_end < skb->tail);
......@@ -522,12 +523,12 @@ void __sctp_hash_endpoint(struct sctp_endpoint *ep)
{
struct sctp_ep_common **epp;
struct sctp_ep_common *epb;
sctp_hashbucket_t *head;
struct sctp_hashbucket *head;
epb = &ep->base;
epb->hashent = sctp_ep_hashfn(epb->bind_addr.port);
head = &sctp_proto.ep_hashbucket[epb->hashent];
head = &sctp_ep_hashbucket[epb->hashent];
sctp_write_lock(&head->lock);
epp = &head->chain;
......@@ -550,14 +551,14 @@ void sctp_hash_endpoint(struct sctp_endpoint *ep)
/* Remove endpoint from the hash table. */
void __sctp_unhash_endpoint(struct sctp_endpoint *ep)
{
sctp_hashbucket_t *head;
struct sctp_hashbucket *head;
struct sctp_ep_common *epb;
epb = &ep->base;
epb->hashent = sctp_ep_hashfn(epb->bind_addr.port);
head = &sctp_proto.ep_hashbucket[epb->hashent];
head = &sctp_ep_hashbucket[epb->hashent];
sctp_write_lock(&head->lock);
......@@ -582,13 +583,13 @@ void sctp_unhash_endpoint(struct sctp_endpoint *ep)
/* Look up an endpoint. */
struct sctp_endpoint *__sctp_rcv_lookup_endpoint(const union sctp_addr *laddr)
{
sctp_hashbucket_t *head;
struct sctp_hashbucket *head;
struct sctp_ep_common *epb;
struct sctp_endpoint *ep;
int hash;
hash = sctp_ep_hashfn(laddr->v4.sin_port);
head = &sctp_proto.ep_hashbucket[hash];
head = &sctp_ep_hashbucket[hash];
read_lock(&head->lock);
for (epb = head->chain; epb; epb = epb->next) {
ep = sctp_ep(epb);
......@@ -619,14 +620,14 @@ void __sctp_hash_established(struct sctp_association *asoc)
{
struct sctp_ep_common **epp;
struct sctp_ep_common *epb;
sctp_hashbucket_t *head;
struct sctp_hashbucket *head;
epb = &asoc->base;
/* Calculate which chain this entry will belong to. */
epb->hashent = sctp_assoc_hashfn(epb->bind_addr.port, asoc->peer.port);
head = &sctp_proto.assoc_hashbucket[epb->hashent];
head = &sctp_assoc_hashbucket[epb->hashent];
sctp_write_lock(&head->lock);
epp = &head->chain;
......@@ -649,7 +650,7 @@ void sctp_unhash_established(struct sctp_association *asoc)
/* Remove association from the hash table. */
void __sctp_unhash_established(struct sctp_association *asoc)
{
sctp_hashbucket_t *head;
struct sctp_hashbucket *head;
struct sctp_ep_common *epb;
epb = &asoc->base;
......@@ -657,7 +658,7 @@ void __sctp_unhash_established(struct sctp_association *asoc)
epb->hashent = sctp_assoc_hashfn(epb->bind_addr.port,
asoc->peer.port);
head = &sctp_proto.assoc_hashbucket[epb->hashent];
head = &sctp_assoc_hashbucket[epb->hashent];
sctp_write_lock(&head->lock);
......@@ -677,7 +678,7 @@ struct sctp_association *__sctp_lookup_association(
const union sctp_addr *peer,
struct sctp_transport **pt)
{
sctp_hashbucket_t *head;
struct sctp_hashbucket *head;
struct sctp_ep_common *epb;
struct sctp_association *asoc;
struct sctp_transport *transport;
......@@ -687,7 +688,7 @@ struct sctp_association *__sctp_lookup_association(
* have wildcards anyways.
*/
hash = sctp_assoc_hashfn(local->v4.sin_port, peer->v4.sin_port);
head = &sctp_proto.assoc_hashbucket[hash];
head = &sctp_assoc_hashbucket[hash];
read_lock(&head->lock);
for (epb = head->chain; epb; epb = epb->next) {
asoc = sctp_assoc(epb);
......@@ -766,6 +767,7 @@ static struct sctp_association *__sctp_rcv_init_lookup(struct sk_buff *skb,
sctp_chunkhdr_t *ch;
union sctp_params params;
sctp_init_chunk_t *init;
struct sctp_transport *transport;
ch = (sctp_chunkhdr_t *) skb->data;
......@@ -805,7 +807,7 @@ static struct sctp_association *__sctp_rcv_init_lookup(struct sk_buff *skb,
continue;
sctp_param2sockaddr(paddr, params.addr, ntohs(sh->source), 0);
asoc = __sctp_lookup_association(laddr, paddr, transportp);
asoc = __sctp_lookup_association(laddr, paddr, &transport);
if (asoc)
return asoc;
}
......
......@@ -61,6 +61,7 @@
#include <linux/ipv6.h>
#include <linux/icmpv6.h>
#include <linux/random.h>
#include <linux/seq_file.h>
#include <net/protocol.h>
#include <net/tcp.h>
......@@ -578,6 +579,13 @@ static int sctp_v6_is_ce(const struct sk_buff *skb)
return *((__u32 *)(skb->nh.ipv6h)) & htonl(1<<20);
}
/* Dump the v6 addr to the seq file. */
static void sctp_v6_seq_dump_addr(struct seq_file *seq, union sctp_addr *addr)
{
seq_printf(seq, "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ",
NIP6(addr->v6.sin6_addr));
}
/* Initialize a PF_INET6 socket msg_name. */
static void sctp_inet6_msgname(char *msgname, int *addr_len)
{
......@@ -840,6 +848,7 @@ static struct sctp_af sctp_ipv6_specific = {
.available = sctp_v6_available,
.skb_iif = sctp_v6_skb_iif,
.is_ce = sctp_v6_is_ce,
.seq_dump_addr = sctp_v6_seq_dump_addr,
.net_header_len = sizeof(struct ipv6hdr),
.sockaddr_len = sizeof(struct sockaddr_in6),
.sa_family = AF_INET6,
......
......@@ -53,6 +53,7 @@ SCTP_DBG_OBJCNT(ep);
SCTP_DBG_OBJCNT(transport);
SCTP_DBG_OBJCNT(assoc);
SCTP_DBG_OBJCNT(bind_addr);
SCTP_DBG_OBJCNT(bind_bucket);
SCTP_DBG_OBJCNT(chunk);
SCTP_DBG_OBJCNT(addr);
SCTP_DBG_OBJCNT(ssnmap);
......@@ -68,6 +69,7 @@ sctp_dbg_objcnt_entry_t sctp_dbg_objcnt[] = {
SCTP_DBG_OBJCNT_ENTRY(transport),
SCTP_DBG_OBJCNT_ENTRY(chunk),
SCTP_DBG_OBJCNT_ENTRY(bind_addr),
SCTP_DBG_OBJCNT_ENTRY(bind_bucket),
SCTP_DBG_OBJCNT_ENTRY(addr),
SCTP_DBG_OBJCNT_ENTRY(ssnmap),
SCTP_DBG_OBJCNT_ENTRY(datamsg),
......
......@@ -128,3 +128,162 @@ void sctp_snmp_proc_exit(void)
{
remove_proc_entry("snmp", proc_net_sctp);
}
/* Dump local addresses of an association/endpoint. */
static void sctp_seq_dump_local_addrs(struct seq_file *seq, struct sctp_ep_common *epb)
{
struct list_head *pos;
struct sockaddr_storage_list *laddr;
union sctp_addr *addr;
struct sctp_af *af;
list_for_each(pos, &epb->bind_addr.address_list) {
laddr = list_entry(pos, struct sockaddr_storage_list, list);
addr = (union sctp_addr *)&laddr->a;
af = sctp_get_af_specific(addr->sa.sa_family);
af->seq_dump_addr(seq, addr);
}
}
/* Dump remote addresses of an association. */
static void sctp_seq_dump_remote_addrs(struct seq_file *seq, struct sctp_association *assoc)
{
struct list_head *pos;
struct sctp_transport *transport;
union sctp_addr *addr;
struct sctp_af *af;
list_for_each(pos, &assoc->peer.transport_addr_list) {
transport = list_entry(pos, struct sctp_transport, transports);
addr = (union sctp_addr *)&transport->ipaddr;
af = sctp_get_af_specific(addr->sa.sa_family);
af->seq_dump_addr(seq, addr);
}
}
/* Display sctp endpoints (/proc/net/sctp/eps). */
static int sctp_eps_seq_show(struct seq_file *seq, void *v)
{
struct sctp_hashbucket *head;
struct sctp_ep_common *epb;
struct sctp_endpoint *ep;
struct sock *sk;
int hash;
seq_printf(seq, " ENDPT SOCK STY SST HBKT LPORT LADDRS\n");
for (hash = 0; hash < sctp_ep_hashsize; hash++) {
head = &sctp_ep_hashbucket[hash];
read_lock(&head->lock);
for (epb = head->chain; epb; epb = epb->next) {
ep = sctp_ep(epb);
sk = epb->sk;
seq_printf(seq, "%8p %8p %-3d %-3d %-4d %-5d ", ep, sk,
sctp_sk(sk)->type, sk->sk_state, hash,
epb->bind_addr.port);
sctp_seq_dump_local_addrs(seq, epb);
seq_printf(seq, "\n");
}
read_unlock(&head->lock);
}
return 0;
}
/* Initialize the seq file operations for 'eps' object. */
static int sctp_eps_seq_open(struct inode *inode, struct file *file)
{
return single_open(file, sctp_eps_seq_show, NULL);
}
static struct file_operations sctp_eps_seq_fops = {
.open = sctp_eps_seq_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
/* Set up the proc fs entry for 'eps' object. */
int __init sctp_eps_proc_init(void)
{
struct proc_dir_entry *p;
p = create_proc_entry("eps", S_IRUGO, proc_net_sctp);
if (!p)
return -ENOMEM;
p->proc_fops = &sctp_eps_seq_fops;
return 0;
}
/* Cleanup the proc fs entry for 'eps' object. */
void sctp_eps_proc_exit(void)
{
remove_proc_entry("eps", proc_net_sctp);
}
/* Display sctp associations (/proc/net/sctp/assocs). */
static int sctp_assocs_seq_show(struct seq_file *seq, void *v)
{
struct sctp_hashbucket *head;
struct sctp_ep_common *epb;
struct sctp_association *assoc;
struct sock *sk;
int hash;
seq_printf(seq, " ASSOC SOCK STY SST ST HBKT LPORT RPORT "
"LADDRS <-> RADDRS\n");
for (hash = 0; hash < sctp_assoc_hashsize; hash++) {
head = &sctp_assoc_hashbucket[hash];
read_lock(&head->lock);
for (epb = head->chain; epb; epb = epb->next) {
assoc = sctp_assoc(epb);
sk = epb->sk;
seq_printf(seq,
"%8p %8p %-3d %-3d %-2d %-4d %-5d %-5d ",
assoc, sk, sctp_sk(sk)->type, sk->sk_state,
assoc->state, hash, epb->bind_addr.port,
assoc->peer.port);
sctp_seq_dump_local_addrs(seq, epb);
seq_printf(seq, "<-> ");
sctp_seq_dump_remote_addrs(seq, assoc);
seq_printf(seq, "\n");
}
read_unlock(&head->lock);
}
return 0;
}
/* Initialize the seq file operations for 'assocs' object. */
static int sctp_assocs_seq_open(struct inode *inode, struct file *file)
{
return single_open(file, sctp_assocs_seq_show, NULL);
}
static struct file_operations sctp_assocs_seq_fops = {
.open = sctp_assocs_seq_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
/* Set up the proc fs entry for 'assocs' object. */
int __init sctp_assocs_proc_init(void)
{
struct proc_dir_entry *p;
p = create_proc_entry("assocs", S_IRUGO, proc_net_sctp);
if (!p)
return -ENOMEM;
p->proc_fops = &sctp_assocs_seq_fops;
return 0;
}
/* Cleanup the proc fs entry for 'assocs' object. */
void sctp_assocs_proc_exit(void)
{
remove_proc_entry("assocs", proc_net_sctp);
}
This diff is collapsed.
......@@ -68,6 +68,8 @@
#include <net/sctp/sctp.h>
#include <net/sctp/sm.h>
extern kmem_cache_t *sctp_chunk_cachep;
/* What was the inbound interface for this chunk? */
int sctp_chunk_iif(const struct sctp_chunk *chunk)
{
......@@ -976,7 +978,9 @@ struct sctp_chunk *sctp_chunkify(struct sk_buff *skb,
const struct sctp_association *asoc,
struct sock *sk)
{
struct sctp_chunk *retval = t_new(struct sctp_chunk, GFP_ATOMIC);
struct sctp_chunk *retval;
retval = kmem_cache_alloc(sctp_chunk_cachep, SLAB_ATOMIC);
if (!retval)
goto nodata;
......@@ -1075,13 +1079,12 @@ struct sctp_chunk *sctp_make_chunk(const struct sctp_association *asoc,
}
retval->chunk_hdr = chunk_hdr;
retval->chunk_end = ((__u8 *)chunk_hdr) + sizeof(sctp_chunkhdr_t);
retval->chunk_end = ((__u8 *)chunk_hdr) + sizeof(struct sctp_chunkhdr);
/* Set the skb to the belonging sock for accounting. */
skb->sk = sk;
return retval;
nodata:
return NULL;
}
......@@ -1090,12 +1093,11 @@ struct sctp_chunk *sctp_make_chunk(const struct sctp_association *asoc,
/* Release the memory occupied by a chunk. */
static void sctp_chunk_destroy(struct sctp_chunk *chunk)
{
/* Free the chunk skb data and the SCTP_chunk stub itself. */
dev_kfree_skb(chunk->skb);
kfree(chunk);
SCTP_DBG_OBJCNT_DEC(chunk);
kmem_cache_free(sctp_chunk_cachep, chunk);
}
/* Possibly, free the chunk. */
......@@ -1728,8 +1730,12 @@ int sctp_verify_init(const struct sctp_association *asoc,
sctp_walk_params(param, peer_init, init_hdr.params) {
if (!sctp_verify_param(asoc, param, cid, chunk, errp))
if (!sctp_verify_param(asoc, param, cid, chunk, errp)) {
if (SCTP_PARAM_HOST_NAME_ADDRESS == param.p->type)
return 0;
else
return 1;
}
} /* for (loop through all parameters) */
......@@ -1907,7 +1913,7 @@ int sctp_process_param(struct sctp_association *asoc, union sctp_params param,
break;
case SCTP_PARAM_COOKIE_PRESERVATIVE:
if (!sctp_proto.cookie_preserve_enable)
if (!sctp_cookie_preserve_enable)
break;
stale = ntohl(param.life->lifespan_increment);
......
......@@ -415,7 +415,8 @@ static void sctp_cmd_init_failed(sctp_cmd_seq_t *commands,
struct sctp_ulpevent *event;
event = sctp_ulpevent_make_assoc_change(asoc,0, SCTP_CANT_STR_ASSOC,
0, 0, 0, GFP_ATOMIC);
(__u16)error, 0, 0,
GFP_ATOMIC);
if (event)
sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP,
......
......@@ -738,7 +738,7 @@ sctp_disposition_t sctp_sf_sendbeat_8_3(const struct sctp_endpoint *ep,
{
struct sctp_transport *transport = (struct sctp_transport *) arg;
if (asoc->overall_error_count >= asoc->overall_error_threshold) {
if (asoc->overall_error_count > asoc->overall_error_threshold) {
/* CMD_ASSOC_FAILED calls CMD_DELETE_TCB. */
sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED,
SCTP_U32(SCTP_ERROR_NO_ERROR));
......@@ -1238,7 +1238,6 @@ static sctp_disposition_t sctp_sf_do_unexpected_init(
* parameter type.
*/
sctp_addto_chunk(repl, len, unk_param);
sctp_chunk_free(err_chunk);
}
sctp_add_cmd_sf(commands, SCTP_CMD_NEW_ASOC, SCTP_ASOC(new_asoc));
......@@ -1788,24 +1787,17 @@ sctp_disposition_t sctp_sf_cookie_echoed_err(const struct sctp_endpoint *ep,
struct sctp_chunk *chunk = arg;
sctp_errhdr_t *err;
err = (sctp_errhdr_t *)(chunk->skb->data);
/* If we have gotten too many failures, give up. */
if (1 + asoc->counters[SCTP_COUNTER_INIT_ERROR] >
asoc->max_init_attempts) {
/* INIT_FAILED will issue an ulpevent. */
sctp_add_cmd_sf(commands, SCTP_CMD_INIT_FAILED,
SCTP_U32(err->cause));
return SCTP_DISPOSITION_DELETE_TCB;
}
/* Process the error here */
switch (err->cause) {
case SCTP_ERROR_STALE_COOKIE:
return sctp_sf_do_5_2_6_stale(ep, asoc, type, arg, commands);
default:
return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
/* FUTURE FIXME: When PR-SCTP related and other optional
* parms are emitted, this will have to change to handle multiple
* errors.
*/
sctp_walk_errors(err, chunk->chunk_hdr) {
if (SCTP_ERROR_STALE_COOKIE == err->cause)
return sctp_sf_do_5_2_6_stale(ep, asoc, type,
arg, commands);
}
return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
}
/*
......@@ -2067,6 +2059,7 @@ sctp_disposition_t sctp_sf_do_9_2_shutdown(const struct sctp_endpoint *ep,
struct sctp_chunk *chunk = arg;
sctp_shutdownhdr_t *sdh;
sctp_disposition_t disposition;
struct sctp_ulpevent *ev;
/* Convert the elaborate header. */
sdh = (sctp_shutdownhdr_t *)chunk->skb->data;
......@@ -2097,12 +2090,28 @@ sctp_disposition_t sctp_sf_do_9_2_shutdown(const struct sctp_endpoint *ep,
arg, commands);
}
if (SCTP_DISPOSITION_NOMEM == disposition)
goto out;
/* - verify, by checking the Cumulative TSN Ack field of the
* chunk, that all its outstanding DATA chunks have been
* received by the SHUTDOWN sender.
*/
sctp_add_cmd_sf(commands, SCTP_CMD_PROCESS_CTSN,
SCTP_U32(chunk->subh.shutdown_hdr->cum_tsn_ack));
/* API 5.3.1.5 SCTP_SHUTDOWN_EVENT
* When a peer sends a SHUTDOWN, SCTP delivers this notification to
* inform the application that it should cease sending data.
*/
ev = sctp_ulpevent_make_shutdown_event(asoc, 0, GFP_ATOMIC);
if (!ev) {
disposition = SCTP_DISPOSITION_NOMEM;
goto out;
}
sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, SCTP_ULPEVENT(ev));
out:
return disposition;
}
......@@ -2740,6 +2749,9 @@ sctp_disposition_t sctp_sf_eat_sack_6_2(const struct sctp_endpoint *ep,
/* Pull the SACK chunk from the data buffer */
sackh = sctp_sm_pull_sack(chunk);
/* Was this a bogus SACK? */
if (!sackh)
return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
chunk->subh.sack_hdr = sackh;
ctsn = ntohl(sackh->cum_tsn_ack);
......@@ -4406,22 +4418,27 @@ sctp_disposition_t sctp_sf_timer_ignore(const struct sctp_endpoint *ep,
********************************************************************/
/* Pull the SACK chunk based on the SACK header. */
sctp_sackhdr_t *sctp_sm_pull_sack(struct sctp_chunk *chunk)
struct sctp_sackhdr *sctp_sm_pull_sack(struct sctp_chunk *chunk)
{
sctp_sackhdr_t *sack;
struct sctp_sackhdr *sack;
unsigned int len;
__u16 num_blocks;
__u16 num_dup_tsns;
/* FIXME: Protect ourselves from reading too far into
/* Protect ourselves from reading too far into
* the skb from a bogus sender.
*/
sack = (sctp_sackhdr_t *) chunk->skb->data;
skb_pull(chunk->skb, sizeof(sctp_sackhdr_t));
sack = (struct sctp_sackhdr *) chunk->skb->data;
num_blocks = ntohs(sack->num_gap_ack_blocks);
num_dup_tsns = ntohs(sack->num_dup_tsns);
len = sizeof(struct sctp_sackhdr);
len = (num_blocks + num_dup_tsns) * sizeof(__u32);
if (len > chunk->skb->len)
return NULL;
skb_pull(chunk->skb, len);
skb_pull(chunk->skb, (num_blocks + num_dup_tsns) * sizeof(__u32));
return sack;
}
......
......@@ -436,51 +436,6 @@ sctp_sm_table_entry_t chunk_event_table[SCTP_NUM_BASE_CHUNK_TYPES][SCTP_STATE_NU
TYPE_SCTP_SHUTDOWN_COMPLETE,
}; /* state_fn_t chunk_event_table[][] */
static sctp_sm_table_entry_t
chunk_event_table_asconf[SCTP_STATE_NUM_STATES] = {
/* SCTP_STATE_EMPTY */
{.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"},
/* SCTP_STATE_CLOSED */
{.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"},
/* SCTP_STATE_COOKIE_WAIT */
{.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"},
/* SCTP_STATE_COOKIE_ECHOED */
{.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"},
/* SCTP_STATE_ESTABLISHED */
{.fn = sctp_sf_discard_chunk,
.name = "sctp_sf_discard_chunk (will be sctp_addip_do_asconf)"},
/* SCTP_STATE_SHUTDOWN_PENDING */
{.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"},
/* SCTP_STATE_SHUTDOWN_SENT */
{.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"},
/* SCTP_STATE_SHUTDOWN_RECEIVED */
{.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"},
/* SCTP_STATE_SHUTDOWN_ACK_SENT */
{.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"},
}; /* chunk asconf */
static sctp_sm_table_entry_t
chunk_event_table_asconf_ack[SCTP_STATE_NUM_STATES] = {
/* SCTP_STATE_EMPTY */
{.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"},
/* SCTP_STATE_CLOSED */
{.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"},
/* SCTP_STATE_COOKIE_WAIT */
{.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"},
/* SCTP_STATE_COOKIE_ECHOED */
{.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"},
/* SCTP_STATE_ESTABLISHED */
{.fn = sctp_sf_discard_chunk,
.name = "sctp_sf_discard_chunk (will be sctp_addip_do_asconf_ack)"},
/* SCTP_STATE_SHUTDOWN_PENDING */
{.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"},
/* SCTP_STATE_SHUTDOWN_SENT */
{.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"},
/* SCTP_STATE_SHUTDOWN_RECEIVED */
{.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"},
/* SCTP_STATE_SHUTDOWN_ACK_SENT */
{.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"},
}; /* chunk asconf_ack */
static sctp_sm_table_entry_t
chunk_event_table_unknown[SCTP_STATE_NUM_STATES] = {
......@@ -783,7 +738,7 @@ sctp_sm_table_entry_t other_event_table[SCTP_NUM_OTHER_TYPES][SCTP_STATE_NUM_STA
/* SCTP_STATE_ESTABLISHED */ \
{.fn = sctp_sf_timer_ignore, .name = "sctp_sf_timer_ignore"}, \
/* SCTP_STATE_SHUTDOWN_PENDING */ \
{.fn = sctp_sf_timer_ignore, .name = "sctp_sf_timer_ignore"}, \
{.fn = sctp_sf_t5_timer_expire, .name = "sctp_sf_t5_timer_expire"}, \
/* SCTP_STATE_SHUTDOWN_SENT */ \
{.fn = sctp_sf_t5_timer_expire, .name = "sctp_sf_t5_timer_expire"}, \
/* SCTP_STATE_SHUTDOWN_RECEIVED */ \
......@@ -877,13 +832,5 @@ sctp_sm_table_entry_t *sctp_chunk_event_lookup(sctp_cid_t cid, sctp_state_t stat
return &chunk_event_table[cid][state];
}
switch (cid) {
case SCTP_CID_ASCONF:
return &chunk_event_table_asconf[state];
case SCTP_CID_ASCONF_ACK:
return &chunk_event_table_asconf_ack[state];
default:
return &chunk_event_table_unknown[state];
}
}
This diff is collapsed.
......@@ -42,13 +42,11 @@
#include <net/sctp/structs.h>
#include <linux/sysctl.h>
extern struct sctp_protocol sctp_proto;
static ctl_table sctp_table[] = {
{
.ctl_name = NET_SCTP_RTO_INITIAL,
.procname = "rto_initial",
.data = &sctp_proto.rto_initial,
.data = &sctp_rto_initial,
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = &proc_dointvec_jiffies,
......@@ -57,7 +55,7 @@ static ctl_table sctp_table[] = {
{
.ctl_name = NET_SCTP_RTO_MIN,
.procname = "rto_min",
.data = &sctp_proto.rto_min,
.data = &sctp_rto_min,
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = &proc_dointvec_jiffies,
......@@ -66,7 +64,7 @@ static ctl_table sctp_table[] = {
{
.ctl_name = NET_SCTP_RTO_MAX,
.procname = "rto_max",
.data = &sctp_proto.rto_max,
.data = &sctp_rto_max,
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = &proc_dointvec_jiffies,
......@@ -75,7 +73,7 @@ static ctl_table sctp_table[] = {
{
.ctl_name = NET_SCTP_VALID_COOKIE_LIFE,
.procname = "valid_cookie_life",
.data = &sctp_proto.valid_cookie_life,
.data = &sctp_valid_cookie_life,
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = &proc_dointvec_jiffies,
......@@ -84,7 +82,7 @@ static ctl_table sctp_table[] = {
{
.ctl_name = NET_SCTP_MAX_BURST,
.procname = "max_burst",
.data = &sctp_proto.max_burst,
.data = &sctp_max_burst,
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = &proc_dointvec
......@@ -92,7 +90,7 @@ static ctl_table sctp_table[] = {
{
.ctl_name = NET_SCTP_ASSOCIATION_MAX_RETRANS,
.procname = "association_max_retrans",
.data = &sctp_proto.max_retrans_association,
.data = &sctp_max_retrans_association,
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = &proc_dointvec
......@@ -100,7 +98,7 @@ static ctl_table sctp_table[] = {
{
.ctl_name = NET_SCTP_PATH_MAX_RETRANS,
.procname = "path_max_retrans",
.data = &sctp_proto.max_retrans_path,
.data = &sctp_max_retrans_path,
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = &proc_dointvec
......@@ -108,7 +106,7 @@ static ctl_table sctp_table[] = {
{
.ctl_name = NET_SCTP_MAX_INIT_RETRANSMITS,
.procname = "max_init_retransmits",
.data = &sctp_proto.max_retrans_init,
.data = &sctp_max_retrans_init,
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = &proc_dointvec
......@@ -116,7 +114,7 @@ static ctl_table sctp_table[] = {
{
.ctl_name = NET_SCTP_HB_INTERVAL,
.procname = "hb_interval",
.data = &sctp_proto.hb_interval,
.data = &sctp_hb_interval,
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = &proc_dointvec_jiffies,
......@@ -125,7 +123,7 @@ static ctl_table sctp_table[] = {
{
.ctl_name = NET_SCTP_PRESERVE_ENABLE,
.procname = "cookie_preserve_enable",
.data = &sctp_proto.cookie_preserve_enable,
.data = &sctp_cookie_preserve_enable,
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = &proc_dointvec_jiffies,
......@@ -134,7 +132,7 @@ static ctl_table sctp_table[] = {
{
.ctl_name = NET_SCTP_RTO_ALPHA,
.procname = "rto_alpha_exp_divisor",
.data = &sctp_proto.rto_alpha,
.data = &sctp_rto_alpha,
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = &proc_dointvec
......@@ -142,7 +140,7 @@ static ctl_table sctp_table[] = {
{
.ctl_name = NET_SCTP_RTO_BETA,
.procname = "rto_beta_exp_divisor",
.data = &sctp_proto.rto_beta,
.data = &sctp_rto_beta,
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = &proc_dointvec
......
......@@ -82,8 +82,6 @@ struct sctp_transport *sctp_transport_init(struct sctp_transport *peer,
const union sctp_addr *addr,
int gfp)
{
struct sctp_protocol *proto = sctp_get_protocol();
/* Copy in the address. */
peer->ipaddr = *addr;
peer->af_specific = sctp_get_af_specific(addr->sa.sa_family);
......@@ -99,7 +97,7 @@ struct sctp_transport *sctp_transport_init(struct sctp_transport *peer,
* parameter 'RTO.Initial'.
*/
peer->rtt = 0;
peer->rto = proto->rto_initial;
peer->rto = sctp_rto_initial;
peer->rttvar = 0;
peer->srtt = 0;
peer->rto_pending = 0;
......@@ -108,11 +106,11 @@ struct sctp_transport *sctp_transport_init(struct sctp_transport *peer,
peer->last_time_used = jiffies;
peer->last_time_ecne_reduced = jiffies;
peer->active = 1;
peer->active = SCTP_ACTIVE;
peer->hb_allowed = 0;
/* Initialize the default path max_retrans. */
peer->max_retrans = proto->max_retrans_path;
peer->max_retrans = sctp_max_retrans_path;
peer->error_threshold = 0;
peer->error_count = 0;
......@@ -272,8 +270,6 @@ void sctp_transport_put(struct sctp_transport *transport)
/* Update transport's RTO based on the newly calculated RTT. */
void sctp_transport_update_rto(struct sctp_transport *tp, __u32 rtt)
{
struct sctp_protocol *proto = sctp_get_protocol();
/* Check for valid transport. */
SCTP_ASSERT(tp, "NULL transport", return);
......@@ -292,10 +288,10 @@ void sctp_transport_update_rto(struct sctp_transport *tp, __u32 rtt)
* For example, assuming the default value of RTO.Alpha of
* 1/8, rto_alpha would be expressed as 3.
*/
tp->rttvar = tp->rttvar - (tp->rttvar >> proto->rto_beta)
+ ((abs(tp->srtt - rtt)) >> proto->rto_beta);
tp->srtt = tp->srtt - (tp->srtt >> proto->rto_alpha)
+ (rtt >> proto->rto_alpha);
tp->rttvar = tp->rttvar - (tp->rttvar >> sctp_rto_beta)
+ ((abs(tp->srtt - rtt)) >> sctp_rto_beta);
tp->srtt = tp->srtt - (tp->srtt >> sctp_rto_alpha)
+ (rtt >> sctp_rto_alpha);
} else {
/* 6.3.1 C2) When the first RTT measurement R is made, set
* SRTT <- R, RTTVAR <- R/2.
......
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