Commit d9441eda authored by Sridhar Samudrala's avatar Sridhar Samudrala

Merge us.ibm.com:/home/sridhar/BK/linux-2.5.70

into us.ibm.com:/home/sridhar/BK/lksctp-2.5.70
parents 6e9445e6 d1cd8a96
...@@ -119,12 +119,10 @@ ...@@ -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 struct sock *sctp_get_ctl_sock(void);
extern int sctp_copy_local_addr_list(struct sctp_protocol *, extern int sctp_copy_local_addr_list(struct sctp_bind_addr *,
struct sctp_bind_addr *,
sctp_scope_t, int gfp, int flags); sctp_scope_t, int gfp, int flags);
extern struct sctp_pf *sctp_get_pf_specific(sa_family_t family); extern struct sctp_pf *sctp_get_pf_specific(sa_family_t family);
extern int sctp_register_pf(struct sctp_pf *, sa_family_t); extern int sctp_register_pf(struct sctp_pf *, sa_family_t);
...@@ -275,6 +273,7 @@ extern atomic_t sctp_dbg_objcnt_assoc; ...@@ -275,6 +273,7 @@ extern atomic_t sctp_dbg_objcnt_assoc;
extern atomic_t sctp_dbg_objcnt_transport; extern atomic_t sctp_dbg_objcnt_transport;
extern atomic_t sctp_dbg_objcnt_chunk; extern atomic_t sctp_dbg_objcnt_chunk;
extern atomic_t sctp_dbg_objcnt_bind_addr; 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_addr;
extern atomic_t sctp_dbg_objcnt_ssnmap; extern atomic_t sctp_dbg_objcnt_ssnmap;
extern atomic_t sctp_dbg_objcnt_datamsg; extern atomic_t sctp_dbg_objcnt_datamsg;
...@@ -456,6 +455,18 @@ for (pos.v = chunk->member;\ ...@@ -456,6 +455,18 @@ for (pos.v = chunk->member;\
pos.v <= (void *)chunk + end - WORD_ROUND(ntohs(pos.p->length)); \ pos.v <= (void *)chunk + end - WORD_ROUND(ntohs(pos.p->length)); \
pos.v += 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. */ /* Round an int up to the next multiple of 4. */
#define WORD_ROUND(s) (((s)+3)&~3) #define WORD_ROUND(s) (((s)+3)&~3)
...@@ -491,12 +502,6 @@ void sctp_put_port(struct sock *sk); ...@@ -491,12 +502,6 @@ void sctp_put_port(struct sock *sk);
/* Static inline functions. */ /* 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. */ /* Convert from an IP version number to an Address Family symbol. */
static inline int ipver2af(__u8 ipver) static inline int ipver2af(__u8 ipver)
{ {
...@@ -524,24 +529,21 @@ static inline int sctp_sanity_check(void) ...@@ -524,24 +529,21 @@ static inline int sctp_sanity_check(void)
/* This is the hash function for the SCTP port hash table. */ /* This is the hash function for the SCTP port hash table. */
static inline int sctp_phashfn(__u16 lport) static inline int sctp_phashfn(__u16 lport)
{ {
struct sctp_protocol *sctp_proto = sctp_get_protocol(); return (lport & (sctp_port_hashsize - 1));
return (lport & (sctp_proto->port_hashsize - 1));
} }
/* This is the hash function for the endpoint hash table. */ /* This is the hash function for the endpoint hash table. */
static inline int sctp_ep_hashfn(__u16 lport) static inline int sctp_ep_hashfn(__u16 lport)
{ {
struct sctp_protocol *sctp_proto = sctp_get_protocol(); return (lport & (sctp_ep_hashsize - 1));
return (lport & (sctp_proto->ep_hashsize - 1));
} }
/* This is the hash function for the association hash table. */ /* This is the hash function for the association hash table. */
static inline int sctp_assoc_hashfn(__u16 lport, __u16 rport) static inline int sctp_assoc_hashfn(__u16 lport, __u16 rport)
{ {
struct sctp_protocol *sctp_proto = sctp_get_protocol();
int h = (lport << 16) + rport; int h = (lport << 16) + rport;
h ^= h>>8; 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 /* This is the hash function for the association hash table. This is
...@@ -550,10 +552,9 @@ static inline int sctp_assoc_hashfn(__u16 lport, __u16 rport) ...@@ -550,10 +552,9 @@ static inline int sctp_assoc_hashfn(__u16 lport, __u16 rport)
*/ */
static inline int sctp_vtag_hashfn(__u16 lport, __u16 rport, __u32 vtag) 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; int h = (lport << 16) + rport;
h ^= vtag; 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! */ /* WARNING: Do not change the layout of the members in sctp_sock! */
......
...@@ -71,7 +71,7 @@ union sctp_addr { ...@@ -71,7 +71,7 @@ union sctp_addr {
}; };
/* Forward declarations for data structures. */ /* Forward declarations for data structures. */
struct sctp_protocol; struct sctp_globals;
struct sctp_endpoint; struct sctp_endpoint;
struct sctp_association; struct sctp_association;
struct sctp_transport; struct sctp_transport;
...@@ -92,28 +92,28 @@ struct sctp_ssnmap; ...@@ -92,28 +92,28 @@ struct sctp_ssnmap;
/* Structures useful for managing bind/connect. */ /* Structures useful for managing bind/connect. */
typedef struct sctp_bind_bucket { struct sctp_bind_bucket {
unsigned short port; unsigned short port;
unsigned short fastreuse; unsigned short fastreuse;
struct sctp_bind_bucket *next; struct sctp_bind_bucket *next;
struct sctp_bind_bucket **pprev; struct sctp_bind_bucket **pprev;
struct sock *sk; struct sock *sk;
} sctp_bind_bucket_t; };
typedef struct sctp_bind_hashbucket { struct sctp_bind_hashbucket {
spinlock_t lock; spinlock_t lock;
struct sctp_bind_bucket *chain; struct sctp_bind_bucket *chain;
} sctp_bind_hashbucket_t; };
/* Used for hashing all associations. */ /* Used for hashing all associations. */
typedef struct sctp_hashbucket { struct sctp_hashbucket {
rwlock_t lock; rwlock_t lock;
struct sctp_ep_common *chain; struct sctp_ep_common *chain;
} sctp_hashbucket_t __attribute__((__aligned__(8))); } __attribute__((__aligned__(8)));
/* The SCTP protocol structure. */ /* The SCTP globals structure. */
struct sctp_protocol { extern struct sctp_globals {
/* RFC2960 Section 14. Suggested SCTP Protocol Parameter Values /* RFC2960 Section 14. Suggested SCTP Protocol Parameter Values
* *
* The following protocol parameters are RECOMMENDED: * The following protocol parameters are RECOMMENDED:
...@@ -167,17 +167,17 @@ struct sctp_protocol { ...@@ -167,17 +167,17 @@ struct sctp_protocol {
/* This is the hash of all endpoints. */ /* This is the hash of all endpoints. */
int ep_hashsize; int ep_hashsize;
sctp_hashbucket_t *ep_hashbucket; struct sctp_hashbucket *ep_hashbucket;
/* This is the hash of all associations. */ /* This is the hash of all associations. */
int assoc_hashsize; int assoc_hashsize;
sctp_hashbucket_t *assoc_hashbucket; struct sctp_hashbucket *assoc_hashbucket;
/* This is the sctp port control hash. */ /* This is the sctp port control hash. */
int port_hashsize; int port_hashsize;
int port_rover; int port_rover;
spinlock_t port_alloc_lock; /* Protects 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. /* This is the global local address list.
* We actively maintain this complete list of interfaces on * We actively maintain this complete list of interfaces on
...@@ -187,8 +187,33 @@ struct sctp_protocol { ...@@ -187,8 +187,33 @@ struct sctp_protocol {
*/ */
struct list_head local_addr_list; struct list_head local_addr_list;
spinlock_t local_addr_lock; 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. * Pointers to address related SCTP functions.
...@@ -289,6 +314,10 @@ struct sctp_opt { ...@@ -289,6 +314,10 @@ struct sctp_opt {
/* Various Socket Options. */ /* Various Socket Options. */
__u16 default_stream; __u16 default_stream;
__u32 default_ppid; __u32 default_ppid;
__u16 default_flags;
__u32 default_context;
__u32 default_timetolive;
struct sctp_initmsg initmsg; struct sctp_initmsg initmsg;
struct sctp_rtoinfo rtoinfo; struct sctp_rtoinfo rtoinfo;
struct sctp_paddrparams paddrparam; struct sctp_paddrparams paddrparam;
...@@ -1492,13 +1521,12 @@ struct sctp_association { ...@@ -1492,13 +1521,12 @@ struct sctp_association {
*/ */
int counters[SCTP_NUMBER_COUNTERS]; int counters[SCTP_NUMBER_COUNTERS];
struct { /* Default send parameters. */
__u16 stream; __u16 default_stream;
__u16 flags; __u16 default_flags;
__u32 ppid; __u32 default_ppid;
__u32 context; __u32 default_context;
__u32 timetolive; __u32 default_timetolive;
} defaults;
/* This tracks outbound ssn for a given stream. */ /* This tracks outbound ssn for a given stream. */
struct sctp_ssnmap *ssnmap; struct sctp_ssnmap *ssnmap;
......
...@@ -485,6 +485,11 @@ struct sctp_paddrinfo { ...@@ -485,6 +485,11 @@ struct sctp_paddrinfo {
__u32 spinfo_mtu; __u32 spinfo_mtu;
}; };
/* Peer addresses's state. */
enum sctp_spinfo_state {
SCTP_INACTIVE,
SCTP_ACTIVE,
};
/* /*
* 7.1.1 Retransmission Timeout Parameters (SCTP_RTOINFO) * 7.1.1 Retransmission Timeout Parameters (SCTP_RTOINFO)
......
...@@ -96,7 +96,6 @@ struct sctp_association *sctp_association_init(struct sctp_association *asoc, ...@@ -96,7 +96,6 @@ struct sctp_association *sctp_association_init(struct sctp_association *asoc,
int gfp) int gfp)
{ {
struct sctp_opt *sp; struct sctp_opt *sp;
struct sctp_protocol *proto = sctp_get_protocol();
int i; int i;
/* Retrieve the SCTP per socket area. */ /* Retrieve the SCTP per socket area. */
...@@ -129,26 +128,26 @@ struct sctp_association *sctp_association_init(struct sctp_association *asoc, ...@@ -129,26 +128,26 @@ struct sctp_association *sctp_association_init(struct sctp_association *asoc,
asoc->state_timestamp = jiffies; asoc->state_timestamp = jiffies;
/* Set things that have constant value. */ /* Set things that have constant value. */
asoc->cookie_life.tv_sec = sctp_proto.valid_cookie_life / HZ; asoc->cookie_life.tv_sec = sctp_valid_cookie_life / HZ;
asoc->cookie_life.tv_usec = (sctp_proto.valid_cookie_life % HZ) * asoc->cookie_life.tv_usec = (sctp_valid_cookie_life % HZ) *
1000000L / HZ; 1000000L / HZ;
asoc->pmtu = 0; asoc->pmtu = 0;
asoc->frag_point = 0; asoc->frag_point = 0;
/* Initialize the default association max_retrans and RTO values. */ /* Initialize the default association max_retrans and RTO values. */
asoc->max_retrans = proto->max_retrans_association; asoc->max_retrans = sctp_max_retrans_association;
asoc->rto_initial = proto->rto_initial; asoc->rto_initial = sctp_rto_initial;
asoc->rto_max = proto->rto_max; asoc->rto_max = sctp_rto_max;
asoc->rto_min = proto->rto_min; asoc->rto_min = sctp_rto_min;
asoc->overall_error_threshold = 0; asoc->overall_error_threshold = asoc->max_retrans;
asoc->overall_error_count = 0; asoc->overall_error_count = 0;
/* Initialize the maximum mumber of new data packets that can be sent /* Initialize the maximum mumber of new data packets that can be sent
* in a burst. * in a burst.
*/ */
asoc->max_burst = proto->max_burst; asoc->max_burst = sctp_max_burst;
/* Copy things from the endpoint. */ /* Copy things from the endpoint. */
for (i = SCTP_EVENT_TIMEOUT_NONE; i < SCTP_NUM_TIMEOUT_TYPES; ++i) { 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, ...@@ -277,6 +276,12 @@ struct sctp_association *sctp_association_init(struct sctp_association *asoc,
asoc->autoclose = sp->autoclose; 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; return asoc;
fail_init: fail_init:
...@@ -478,16 +483,8 @@ struct sctp_transport *sctp_assoc_add_peer(struct sctp_association *asoc, ...@@ -478,16 +483,8 @@ struct sctp_transport *sctp_assoc_add_peer(struct sctp_association *asoc,
peer->partial_bytes_acked = 0; peer->partial_bytes_acked = 0;
peer->flight_size = 0; peer->flight_size = 0;
peer->error_threshold = peer->max_retrans; 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. */ /* By default, enable heartbeat for peer address. */
peer->hb_allowed = 1; peer->hb_allowed = 1;
...@@ -550,12 +547,12 @@ void sctp_assoc_control_transport(struct sctp_association *asoc, ...@@ -550,12 +547,12 @@ void sctp_assoc_control_transport(struct sctp_association *asoc,
/* Record the transition on the transport. */ /* Record the transition on the transport. */
switch (command) { switch (command) {
case SCTP_TRANSPORT_UP: case SCTP_TRANSPORT_UP:
transport->active = 1; transport->active = SCTP_ACTIVE;
spc_state = ADDRESS_AVAILABLE; spc_state = ADDRESS_AVAILABLE;
break; break;
case SCTP_TRANSPORT_DOWN: case SCTP_TRANSPORT_DOWN:
transport->active = 0; transport->active = SCTP_INACTIVE;
spc_state = ADDRESS_UNREACHABLE; spc_state = ADDRESS_UNREACHABLE;
break; break;
......
...@@ -329,12 +329,10 @@ static int sctp_copy_one_addr(struct sctp_bind_addr *dest, ...@@ -329,12 +329,10 @@ static int sctp_copy_one_addr(struct sctp_bind_addr *dest,
union sctp_addr *addr, union sctp_addr *addr,
sctp_scope_t scope, int gfp, int flags) sctp_scope_t scope, int gfp, int flags)
{ {
struct sctp_protocol *proto = sctp_get_protocol();
int error = 0; int error = 0;
if (sctp_is_any(addr)) { if (sctp_is_any(addr)) {
error = sctp_copy_local_addr_list(proto, dest, scope, error = sctp_copy_local_addr_list(dest, scope, gfp, flags);
gfp, flags);
} else if (sctp_in_scope(addr, scope)) { } else if (sctp_in_scope(addr, scope)) {
/* Now that the address is in scope, check to see if /* Now that the address is in scope, check to see if
* the address type is supported by local sock as * the address type is supported by local sock as
......
...@@ -209,7 +209,7 @@ void sctp_endpoint_destroy(struct sctp_endpoint *ep) ...@@ -209,7 +209,7 @@ void sctp_endpoint_destroy(struct sctp_endpoint *ep)
sctp_bind_addr_free(&ep->base.bind_addr); sctp_bind_addr_free(&ep->base.bind_addr);
/* Remove and free the port */ /* Remove and free the port */
if (ep->base.sk->prev != NULL) if (ep->base.sk->prev)
sctp_put_port(ep->base.sk); sctp_put_port(ep->base.sk);
/* Give up our hold on the sock. */ /* Give up our hold on the sock. */
......
...@@ -503,10 +503,11 @@ int sctp_rcv_ootb(struct sk_buff *skb) ...@@ -503,10 +503,11 @@ int sctp_rcv_ootb(struct sk_buff *skb)
goto discard; goto discard;
if (SCTP_CID_ERROR == ch->type) { 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) if (SCTP_ERROR_STALE_COOKIE == err->cause)
goto discard; goto discard;
} }
}
ch = (sctp_chunkhdr_t *) ch_end; ch = (sctp_chunkhdr_t *) ch_end;
} while (ch_end < skb->tail); } while (ch_end < skb->tail);
...@@ -522,12 +523,12 @@ void __sctp_hash_endpoint(struct sctp_endpoint *ep) ...@@ -522,12 +523,12 @@ void __sctp_hash_endpoint(struct sctp_endpoint *ep)
{ {
struct sctp_ep_common **epp; struct sctp_ep_common **epp;
struct sctp_ep_common *epb; struct sctp_ep_common *epb;
sctp_hashbucket_t *head; struct sctp_hashbucket *head;
epb = &ep->base; epb = &ep->base;
epb->hashent = sctp_ep_hashfn(epb->bind_addr.port); 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); sctp_write_lock(&head->lock);
epp = &head->chain; epp = &head->chain;
...@@ -550,14 +551,14 @@ void sctp_hash_endpoint(struct sctp_endpoint *ep) ...@@ -550,14 +551,14 @@ void sctp_hash_endpoint(struct sctp_endpoint *ep)
/* Remove endpoint from the hash table. */ /* Remove endpoint from the hash table. */
void __sctp_unhash_endpoint(struct sctp_endpoint *ep) void __sctp_unhash_endpoint(struct sctp_endpoint *ep)
{ {
sctp_hashbucket_t *head; struct sctp_hashbucket *head;
struct sctp_ep_common *epb; struct sctp_ep_common *epb;
epb = &ep->base; epb = &ep->base;
epb->hashent = sctp_ep_hashfn(epb->bind_addr.port); 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); sctp_write_lock(&head->lock);
...@@ -582,13 +583,13 @@ void sctp_unhash_endpoint(struct sctp_endpoint *ep) ...@@ -582,13 +583,13 @@ void sctp_unhash_endpoint(struct sctp_endpoint *ep)
/* Look up an endpoint. */ /* Look up an endpoint. */
struct sctp_endpoint *__sctp_rcv_lookup_endpoint(const union sctp_addr *laddr) 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_ep_common *epb;
struct sctp_endpoint *ep; struct sctp_endpoint *ep;
int hash; int hash;
hash = sctp_ep_hashfn(laddr->v4.sin_port); hash = sctp_ep_hashfn(laddr->v4.sin_port);
head = &sctp_proto.ep_hashbucket[hash]; head = &sctp_ep_hashbucket[hash];
read_lock(&head->lock); read_lock(&head->lock);
for (epb = head->chain; epb; epb = epb->next) { for (epb = head->chain; epb; epb = epb->next) {
ep = sctp_ep(epb); ep = sctp_ep(epb);
...@@ -619,14 +620,14 @@ void __sctp_hash_established(struct sctp_association *asoc) ...@@ -619,14 +620,14 @@ void __sctp_hash_established(struct sctp_association *asoc)
{ {
struct sctp_ep_common **epp; struct sctp_ep_common **epp;
struct sctp_ep_common *epb; struct sctp_ep_common *epb;
sctp_hashbucket_t *head; struct sctp_hashbucket *head;
epb = &asoc->base; epb = &asoc->base;
/* Calculate which chain this entry will belong to. */ /* Calculate which chain this entry will belong to. */
epb->hashent = sctp_assoc_hashfn(epb->bind_addr.port, asoc->peer.port); 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); sctp_write_lock(&head->lock);
epp = &head->chain; epp = &head->chain;
...@@ -649,7 +650,7 @@ void sctp_unhash_established(struct sctp_association *asoc) ...@@ -649,7 +650,7 @@ void sctp_unhash_established(struct sctp_association *asoc)
/* Remove association from the hash table. */ /* Remove association from the hash table. */
void __sctp_unhash_established(struct sctp_association *asoc) void __sctp_unhash_established(struct sctp_association *asoc)
{ {
sctp_hashbucket_t *head; struct sctp_hashbucket *head;
struct sctp_ep_common *epb; struct sctp_ep_common *epb;
epb = &asoc->base; epb = &asoc->base;
...@@ -657,7 +658,7 @@ void __sctp_unhash_established(struct sctp_association *asoc) ...@@ -657,7 +658,7 @@ void __sctp_unhash_established(struct sctp_association *asoc)
epb->hashent = sctp_assoc_hashfn(epb->bind_addr.port, epb->hashent = sctp_assoc_hashfn(epb->bind_addr.port,
asoc->peer.port); asoc->peer.port);
head = &sctp_proto.assoc_hashbucket[epb->hashent]; head = &sctp_assoc_hashbucket[epb->hashent];
sctp_write_lock(&head->lock); sctp_write_lock(&head->lock);
...@@ -677,7 +678,7 @@ struct sctp_association *__sctp_lookup_association( ...@@ -677,7 +678,7 @@ struct sctp_association *__sctp_lookup_association(
const union sctp_addr *peer, const union sctp_addr *peer,
struct sctp_transport **pt) struct sctp_transport **pt)
{ {
sctp_hashbucket_t *head; struct sctp_hashbucket *head;
struct sctp_ep_common *epb; struct sctp_ep_common *epb;
struct sctp_association *asoc; struct sctp_association *asoc;
struct sctp_transport *transport; struct sctp_transport *transport;
...@@ -687,7 +688,7 @@ struct sctp_association *__sctp_lookup_association( ...@@ -687,7 +688,7 @@ struct sctp_association *__sctp_lookup_association(
* have wildcards anyways. * have wildcards anyways.
*/ */
hash = sctp_assoc_hashfn(local->v4.sin_port, peer->v4.sin_port); 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); read_lock(&head->lock);
for (epb = head->chain; epb; epb = epb->next) { for (epb = head->chain; epb; epb = epb->next) {
asoc = sctp_assoc(epb); asoc = sctp_assoc(epb);
......
...@@ -53,6 +53,7 @@ SCTP_DBG_OBJCNT(ep); ...@@ -53,6 +53,7 @@ SCTP_DBG_OBJCNT(ep);
SCTP_DBG_OBJCNT(transport); SCTP_DBG_OBJCNT(transport);
SCTP_DBG_OBJCNT(assoc); SCTP_DBG_OBJCNT(assoc);
SCTP_DBG_OBJCNT(bind_addr); SCTP_DBG_OBJCNT(bind_addr);
SCTP_DBG_OBJCNT(bind_bucket);
SCTP_DBG_OBJCNT(chunk); SCTP_DBG_OBJCNT(chunk);
SCTP_DBG_OBJCNT(addr); SCTP_DBG_OBJCNT(addr);
SCTP_DBG_OBJCNT(ssnmap); SCTP_DBG_OBJCNT(ssnmap);
...@@ -68,6 +69,7 @@ sctp_dbg_objcnt_entry_t sctp_dbg_objcnt[] = { ...@@ -68,6 +69,7 @@ sctp_dbg_objcnt_entry_t sctp_dbg_objcnt[] = {
SCTP_DBG_OBJCNT_ENTRY(transport), SCTP_DBG_OBJCNT_ENTRY(transport),
SCTP_DBG_OBJCNT_ENTRY(chunk), SCTP_DBG_OBJCNT_ENTRY(chunk),
SCTP_DBG_OBJCNT_ENTRY(bind_addr), SCTP_DBG_OBJCNT_ENTRY(bind_addr),
SCTP_DBG_OBJCNT_ENTRY(bind_bucket),
SCTP_DBG_OBJCNT_ENTRY(addr), SCTP_DBG_OBJCNT_ENTRY(addr),
SCTP_DBG_OBJCNT_ENTRY(ssnmap), SCTP_DBG_OBJCNT_ENTRY(ssnmap),
SCTP_DBG_OBJCNT_ENTRY(datamsg), SCTP_DBG_OBJCNT_ENTRY(datamsg),
......
/* SCTP kernel reference Implementation /* SCTP kernel reference Implementation
* 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-2003 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
...@@ -59,7 +59,7 @@ ...@@ -59,7 +59,7 @@
#include <net/inet_ecn.h> #include <net/inet_ecn.h>
/* Global data structures. */ /* Global data structures. */
struct sctp_protocol sctp_proto; struct sctp_globals sctp_globals;
struct proc_dir_entry *proc_net_sctp; struct proc_dir_entry *proc_net_sctp;
DEFINE_SNMP_STAT(struct sctp_mib, sctp_statistics); DEFINE_SNMP_STAT(struct sctp_mib, sctp_statistics);
...@@ -74,6 +74,9 @@ static struct sctp_pf *sctp_pf_inet_specific; ...@@ -74,6 +74,9 @@ static struct sctp_pf *sctp_pf_inet_specific;
static struct sctp_af *sctp_af_v4_specific; static struct sctp_af *sctp_af_v4_specific;
static struct sctp_af *sctp_af_v6_specific; static struct sctp_af *sctp_af_v6_specific;
kmem_cache_t *sctp_chunk_cachep;
kmem_cache_t *sctp_bucket_cachep;
extern struct net_proto_family inet_family_ops; extern struct net_proto_family inet_family_ops;
extern int sctp_snmp_proc_init(void); extern int sctp_snmp_proc_init(void);
...@@ -106,10 +109,12 @@ __init int sctp_proc_init(void) ...@@ -106,10 +109,12 @@ __init int sctp_proc_init(void)
return rc; return rc;
} }
/* Clean up the proc fs entry for the SCTP protocol. */ /* Clean up the proc fs entry for the SCTP protocol.
* Note: Do not make this __exit as it is used in the init error
* path.
*/
void sctp_proc_exit(void) void sctp_proc_exit(void)
{ {
sctp_snmp_proc_exit(); sctp_snmp_proc_exit();
if (proc_net_sctp) { if (proc_net_sctp) {
...@@ -153,7 +158,7 @@ static void sctp_v4_copy_addrlist(struct list_head *addrlist, ...@@ -153,7 +158,7 @@ static void sctp_v4_copy_addrlist(struct list_head *addrlist,
/* Extract our IP addresses from the system and stash them in the /* Extract our IP addresses from the system and stash them in the
* protocol structure. * protocol structure.
*/ */
static void __sctp_get_local_addr_list(struct sctp_protocol *proto) static void __sctp_get_local_addr_list(void)
{ {
struct net_device *dev; struct net_device *dev;
struct list_head *pos; struct list_head *pos;
...@@ -161,30 +166,30 @@ static void __sctp_get_local_addr_list(struct sctp_protocol *proto) ...@@ -161,30 +166,30 @@ static void __sctp_get_local_addr_list(struct sctp_protocol *proto)
read_lock(&dev_base_lock); read_lock(&dev_base_lock);
for (dev = dev_base; dev; dev = dev->next) { for (dev = dev_base; dev; dev = dev->next) {
list_for_each(pos, &proto->address_families) { __list_for_each(pos, &sctp_address_families) {
af = list_entry(pos, struct sctp_af, list); af = list_entry(pos, struct sctp_af, list);
af->copy_addrlist(&proto->local_addr_list, dev); af->copy_addrlist(&sctp_local_addr_list, dev);
} }
} }
read_unlock(&dev_base_lock); read_unlock(&dev_base_lock);
} }
static void sctp_get_local_addr_list(struct sctp_protocol *proto) static void sctp_get_local_addr_list(void)
{ {
unsigned long flags; unsigned long flags;
sctp_spin_lock_irqsave(&sctp_proto.local_addr_lock, flags); sctp_spin_lock_irqsave(&sctp_local_addr_lock, flags);
__sctp_get_local_addr_list(&sctp_proto); __sctp_get_local_addr_list();
sctp_spin_unlock_irqrestore(&sctp_proto.local_addr_lock, flags); sctp_spin_unlock_irqrestore(&sctp_local_addr_lock, flags);
} }
/* Free the existing local addresses. */ /* Free the existing local addresses. */
static void __sctp_free_local_addr_list(struct sctp_protocol *proto) static void __sctp_free_local_addr_list(void)
{ {
struct sockaddr_storage_list *addr; struct sockaddr_storage_list *addr;
struct list_head *pos, *temp; struct list_head *pos, *temp;
list_for_each_safe(pos, temp, &proto->local_addr_list) { list_for_each_safe(pos, temp, &sctp_local_addr_list) {
addr = list_entry(pos, struct sockaddr_storage_list, list); addr = list_entry(pos, struct sockaddr_storage_list, list);
list_del(pos); list_del(pos);
kfree(addr); kfree(addr);
...@@ -192,18 +197,17 @@ static void __sctp_free_local_addr_list(struct sctp_protocol *proto) ...@@ -192,18 +197,17 @@ static void __sctp_free_local_addr_list(struct sctp_protocol *proto)
} }
/* Free the existing local addresses. */ /* Free the existing local addresses. */
static void sctp_free_local_addr_list(struct sctp_protocol *proto) static void sctp_free_local_addr_list(void)
{ {
unsigned long flags; unsigned long flags;
sctp_spin_lock_irqsave(&proto->local_addr_lock, flags); sctp_spin_lock_irqsave(&sctp_local_addr_lock, flags);
__sctp_free_local_addr_list(proto); __sctp_free_local_addr_list();
sctp_spin_unlock_irqrestore(&proto->local_addr_lock, flags); sctp_spin_unlock_irqrestore(&sctp_local_addr_lock, flags);
} }
/* Copy the local addresses which are valid for 'scope' into 'bp'. */ /* Copy the local addresses which are valid for 'scope' into 'bp'. */
int sctp_copy_local_addr_list(struct sctp_protocol *proto, int sctp_copy_local_addr_list(struct sctp_bind_addr *bp, sctp_scope_t scope,
struct sctp_bind_addr *bp, sctp_scope_t scope,
int gfp, int copy_flags) int gfp, int copy_flags)
{ {
struct sockaddr_storage_list *addr; struct sockaddr_storage_list *addr;
...@@ -211,8 +215,8 @@ int sctp_copy_local_addr_list(struct sctp_protocol *proto, ...@@ -211,8 +215,8 @@ int sctp_copy_local_addr_list(struct sctp_protocol *proto,
struct list_head *pos; struct list_head *pos;
unsigned long flags; unsigned long flags;
sctp_spin_lock_irqsave(&proto->local_addr_lock, flags); sctp_spin_lock_irqsave(&sctp_local_addr_lock, flags);
list_for_each(pos, &proto->local_addr_list) { list_for_each(pos, &sctp_local_addr_list) {
addr = list_entry(pos, struct sockaddr_storage_list, list); addr = list_entry(pos, struct sockaddr_storage_list, list);
if (sctp_in_scope(&addr->a, scope)) { if (sctp_in_scope(&addr->a, scope)) {
/* Now that the address is in scope, check to see if /* Now that the address is in scope, check to see if
...@@ -233,7 +237,7 @@ int sctp_copy_local_addr_list(struct sctp_protocol *proto, ...@@ -233,7 +237,7 @@ int sctp_copy_local_addr_list(struct sctp_protocol *proto,
} }
end_copy: end_copy:
sctp_spin_unlock_irqrestore(&proto->local_addr_lock, flags); sctp_spin_unlock_irqrestore(&sctp_local_addr_lock, flags);
return error; return error;
} }
...@@ -572,10 +576,10 @@ static int sctp_inetaddr_event(struct notifier_block *this, unsigned long ev, ...@@ -572,10 +576,10 @@ static int sctp_inetaddr_event(struct notifier_block *this, unsigned long ev,
{ {
unsigned long flags; unsigned long flags;
sctp_spin_lock_irqsave(&sctp_proto.local_addr_lock, flags); sctp_spin_lock_irqsave(&sctp_local_addr_lock, flags);
__sctp_free_local_addr_list(&sctp_proto); __sctp_free_local_addr_list();
__sctp_get_local_addr_list(&sctp_proto); __sctp_get_local_addr_list();
sctp_spin_unlock_irqrestore(&sctp_proto.local_addr_lock, flags); sctp_spin_unlock_irqrestore(&sctp_local_addr_lock, flags);
return NOTIFY_DONE; return NOTIFY_DONE;
} }
...@@ -626,7 +630,7 @@ int sctp_register_af(struct sctp_af *af) ...@@ -626,7 +630,7 @@ int sctp_register_af(struct sctp_af *af)
} }
INIT_LIST_HEAD(&af->list); INIT_LIST_HEAD(&af->list);
list_add_tail(&af->list, &sctp_proto.address_families); list_add_tail(&af->list, &sctp_address_families);
return 1; return 1;
} }
...@@ -928,6 +932,22 @@ __init int sctp_init(void) ...@@ -928,6 +932,22 @@ __init int sctp_init(void)
inet_register_protosw(&sctp_seqpacket_protosw); inet_register_protosw(&sctp_seqpacket_protosw);
inet_register_protosw(&sctp_stream_protosw); inet_register_protosw(&sctp_stream_protosw);
/* Allocate a cache pools. */
sctp_bucket_cachep = kmem_cache_create("sctp_bind_bucket",
sizeof(struct sctp_bind_bucket),
0, SLAB_HWCACHE_ALIGN,
NULL, NULL);
if (!sctp_bucket_cachep)
goto err_bucket_cachep;
sctp_chunk_cachep = kmem_cache_create("sctp_chunk",
sizeof(struct sctp_chunk),
0, SLAB_HWCACHE_ALIGN,
NULL, NULL);
if (!sctp_chunk_cachep)
goto err_chunk_cachep;
/* Allocate and initialise sctp mibs. */ /* Allocate and initialise sctp mibs. */
status = init_sctp_mibs(); status = init_sctp_mibs();
if (status) if (status)
...@@ -946,91 +966,91 @@ __init int sctp_init(void) ...@@ -946,91 +966,91 @@ __init int sctp_init(void)
*/ */
/* The following protocol parameters are RECOMMENDED: */ /* The following protocol parameters are RECOMMENDED: */
/* RTO.Initial - 3 seconds */ /* RTO.Initial - 3 seconds */
sctp_proto.rto_initial = SCTP_RTO_INITIAL; sctp_rto_initial = SCTP_RTO_INITIAL;
/* RTO.Min - 1 second */ /* RTO.Min - 1 second */
sctp_proto.rto_min = SCTP_RTO_MIN; sctp_rto_min = SCTP_RTO_MIN;
/* RTO.Max - 60 seconds */ /* RTO.Max - 60 seconds */
sctp_proto.rto_max = SCTP_RTO_MAX; sctp_rto_max = SCTP_RTO_MAX;
/* RTO.Alpha - 1/8 */ /* RTO.Alpha - 1/8 */
sctp_proto.rto_alpha = SCTP_RTO_ALPHA; sctp_rto_alpha = SCTP_RTO_ALPHA;
/* RTO.Beta - 1/4 */ /* RTO.Beta - 1/4 */
sctp_proto.rto_beta = SCTP_RTO_BETA; sctp_rto_beta = SCTP_RTO_BETA;
/* Valid.Cookie.Life - 60 seconds */ /* Valid.Cookie.Life - 60 seconds */
sctp_proto.valid_cookie_life = 60 * HZ; sctp_valid_cookie_life = 60 * HZ;
/* Whether Cookie Preservative is enabled(1) or not(0) */ /* Whether Cookie Preservative is enabled(1) or not(0) */
sctp_proto.cookie_preserve_enable = 1; sctp_cookie_preserve_enable = 1;
/* Max.Burst - 4 */ /* Max.Burst - 4 */
sctp_proto.max_burst = SCTP_MAX_BURST; sctp_max_burst = SCTP_MAX_BURST;
/* Association.Max.Retrans - 10 attempts /* Association.Max.Retrans - 10 attempts
* Path.Max.Retrans - 5 attempts (per destination address) * Path.Max.Retrans - 5 attempts (per destination address)
* Max.Init.Retransmits - 8 attempts * Max.Init.Retransmits - 8 attempts
*/ */
sctp_proto.max_retrans_association = 10; sctp_max_retrans_association = 10;
sctp_proto.max_retrans_path = 5; sctp_max_retrans_path = 5;
sctp_proto.max_retrans_init = 8; sctp_max_retrans_init = 8;
/* HB.interval - 30 seconds */ /* HB.interval - 30 seconds */
sctp_proto.hb_interval = 30 * HZ; sctp_hb_interval = 30 * HZ;
/* Implementation specific variables. */ /* Implementation specific variables. */
/* Initialize default stream count setup information. */ /* Initialize default stream count setup information. */
sctp_proto.max_instreams = SCTP_DEFAULT_INSTREAMS; sctp_max_instreams = SCTP_DEFAULT_INSTREAMS;
sctp_proto.max_outstreams = SCTP_DEFAULT_OUTSTREAMS; sctp_max_outstreams = SCTP_DEFAULT_OUTSTREAMS;
/* Allocate and initialize the association hash table. */ /* Allocate and initialize the association hash table. */
sctp_proto.assoc_hashsize = 4096; sctp_assoc_hashsize = 4096;
sctp_proto.assoc_hashbucket = (sctp_hashbucket_t *) sctp_assoc_hashbucket = (struct sctp_hashbucket *)
kmalloc(4096 * sizeof(sctp_hashbucket_t), GFP_KERNEL); kmalloc(4096 * sizeof(struct sctp_hashbucket), GFP_KERNEL);
if (!sctp_proto.assoc_hashbucket) { if (!sctp_assoc_hashbucket) {
printk(KERN_ERR "SCTP: Failed association hash alloc.\n"); printk(KERN_ERR "SCTP: Failed association hash alloc.\n");
status = -ENOMEM; status = -ENOMEM;
goto err_ahash_alloc; goto err_ahash_alloc;
} }
for (i = 0; i < sctp_proto.assoc_hashsize; i++) { for (i = 0; i < sctp_assoc_hashsize; i++) {
sctp_proto.assoc_hashbucket[i].lock = RW_LOCK_UNLOCKED; sctp_assoc_hashbucket[i].lock = RW_LOCK_UNLOCKED;
sctp_proto.assoc_hashbucket[i].chain = NULL; sctp_assoc_hashbucket[i].chain = NULL;
} }
/* Allocate and initialize the endpoint hash table. */ /* Allocate and initialize the endpoint hash table. */
sctp_proto.ep_hashsize = 64; sctp_ep_hashsize = 64;
sctp_proto.ep_hashbucket = (sctp_hashbucket_t *) sctp_ep_hashbucket = (struct sctp_hashbucket *)
kmalloc(64 * sizeof(sctp_hashbucket_t), GFP_KERNEL); kmalloc(64 * sizeof(struct sctp_hashbucket), GFP_KERNEL);
if (!sctp_proto.ep_hashbucket) { if (!sctp_ep_hashbucket) {
printk(KERN_ERR "SCTP: Failed endpoint_hash alloc.\n"); printk(KERN_ERR "SCTP: Failed endpoint_hash alloc.\n");
status = -ENOMEM; status = -ENOMEM;
goto err_ehash_alloc; goto err_ehash_alloc;
} }
for (i = 0; i < sctp_proto.ep_hashsize; i++) { for (i = 0; i < sctp_ep_hashsize; i++) {
sctp_proto.ep_hashbucket[i].lock = RW_LOCK_UNLOCKED; sctp_ep_hashbucket[i].lock = RW_LOCK_UNLOCKED;
sctp_proto.ep_hashbucket[i].chain = NULL; sctp_ep_hashbucket[i].chain = NULL;
} }
/* Allocate and initialize the SCTP port hash table. */ /* Allocate and initialize the SCTP port hash table. */
sctp_proto.port_hashsize = 4096; sctp_port_hashsize = 4096;
sctp_proto.port_hashtable = (sctp_bind_hashbucket_t *) sctp_port_hashtable = (struct sctp_bind_hashbucket *)
kmalloc(4096 * sizeof(sctp_bind_hashbucket_t), GFP_KERNEL); kmalloc(4096 * sizeof(struct sctp_bind_hashbucket),GFP_KERNEL);
if (!sctp_proto.port_hashtable) { if (!sctp_port_hashtable) {
printk(KERN_ERR "SCTP: Failed bind hash alloc."); printk(KERN_ERR "SCTP: Failed bind hash alloc.");
status = -ENOMEM; status = -ENOMEM;
goto err_bhash_alloc; goto err_bhash_alloc;
} }
sctp_proto.port_alloc_lock = SPIN_LOCK_UNLOCKED; sctp_port_alloc_lock = SPIN_LOCK_UNLOCKED;
sctp_proto.port_rover = sysctl_local_port_range[0] - 1; sctp_port_rover = sysctl_local_port_range[0] - 1;
for (i = 0; i < sctp_proto.port_hashsize; i++) { for (i = 0; i < sctp_port_hashsize; i++) {
sctp_proto.port_hashtable[i].lock = SPIN_LOCK_UNLOCKED; sctp_port_hashtable[i].lock = SPIN_LOCK_UNLOCKED;
sctp_proto.port_hashtable[i].chain = NULL; sctp_port_hashtable[i].chain = NULL;
} }
sctp_sysctl_register(); sctp_sysctl_register();
INIT_LIST_HEAD(&sctp_proto.address_families); INIT_LIST_HEAD(&sctp_address_families);
sctp_register_af(&sctp_ipv4_specific); sctp_register_af(&sctp_ipv4_specific);
status = sctp_v6_init(); status = sctp_v6_init();
...@@ -1045,13 +1065,13 @@ __init int sctp_init(void) ...@@ -1045,13 +1065,13 @@ __init int sctp_init(void)
} }
/* Initialize the local address list. */ /* Initialize the local address list. */
INIT_LIST_HEAD(&sctp_proto.local_addr_list); INIT_LIST_HEAD(&sctp_local_addr_list);
sctp_proto.local_addr_lock = SPIN_LOCK_UNLOCKED; sctp_local_addr_lock = SPIN_LOCK_UNLOCKED;
/* Register notifier for inet address additions/deletions. */ /* Register notifier for inet address additions/deletions. */
register_inetaddr_notifier(&sctp_inetaddr_notifier); register_inetaddr_notifier(&sctp_inetaddr_notifier);
sctp_get_local_addr_list(&sctp_proto); sctp_get_local_addr_list();
__unsafe(THIS_MODULE); __unsafe(THIS_MODULE);
return 0; return 0;
...@@ -1061,16 +1081,20 @@ __init int sctp_init(void) ...@@ -1061,16 +1081,20 @@ __init int sctp_init(void)
err_v6_init: err_v6_init:
sctp_sysctl_unregister(); sctp_sysctl_unregister();
list_del(&sctp_ipv4_specific.list); list_del(&sctp_ipv4_specific.list);
kfree(sctp_proto.port_hashtable); kfree(sctp_port_hashtable);
err_bhash_alloc: err_bhash_alloc:
kfree(sctp_proto.ep_hashbucket); kfree(sctp_ep_hashbucket);
err_ehash_alloc: err_ehash_alloc:
kfree(sctp_proto.assoc_hashbucket); kfree(sctp_assoc_hashbucket);
err_ahash_alloc: err_ahash_alloc:
sctp_dbg_objcnt_exit(); sctp_dbg_objcnt_exit();
sctp_proc_exit(); sctp_proc_exit();
cleanup_sctp_mibs(); cleanup_sctp_mibs();
err_init_mibs: err_init_mibs:
kmem_cache_destroy(sctp_chunk_cachep);
err_chunk_cachep:
kmem_cache_destroy(sctp_bucket_cachep);
err_bucket_cachep:
inet_del_protocol(&sctp_protocol, IPPROTO_SCTP); inet_del_protocol(&sctp_protocol, IPPROTO_SCTP);
inet_unregister_protosw(&sctp_seqpacket_protosw); inet_unregister_protosw(&sctp_seqpacket_protosw);
inet_unregister_protosw(&sctp_stream_protosw); inet_unregister_protosw(&sctp_stream_protosw);
...@@ -1088,7 +1112,7 @@ __exit void sctp_exit(void) ...@@ -1088,7 +1112,7 @@ __exit void sctp_exit(void)
unregister_inetaddr_notifier(&sctp_inetaddr_notifier); unregister_inetaddr_notifier(&sctp_inetaddr_notifier);
/* Free the local address list. */ /* Free the local address list. */
sctp_free_local_addr_list(&sctp_proto); sctp_free_local_addr_list();
/* Free the control endpoint. */ /* Free the control endpoint. */
sock_release(sctp_ctl_socket); sock_release(sctp_ctl_socket);
...@@ -1097,9 +1121,12 @@ __exit void sctp_exit(void) ...@@ -1097,9 +1121,12 @@ __exit void sctp_exit(void)
sctp_sysctl_unregister(); sctp_sysctl_unregister();
list_del(&sctp_ipv4_specific.list); list_del(&sctp_ipv4_specific.list);
kfree(sctp_proto.assoc_hashbucket); kfree(sctp_assoc_hashbucket);
kfree(sctp_proto.ep_hashbucket); kfree(sctp_ep_hashbucket);
kfree(sctp_proto.port_hashtable); kfree(sctp_port_hashtable);
kmem_cache_destroy(sctp_chunk_cachep);
kmem_cache_destroy(sctp_bucket_cachep);
sctp_dbg_objcnt_exit(); sctp_dbg_objcnt_exit();
sctp_proc_exit(); sctp_proc_exit();
......
...@@ -68,6 +68,8 @@ ...@@ -68,6 +68,8 @@
#include <net/sctp/sctp.h> #include <net/sctp/sctp.h>
#include <net/sctp/sm.h> #include <net/sctp/sm.h>
extern kmem_cache_t *sctp_chunk_cachep;
/* What was the inbound interface for this chunk? */ /* What was the inbound interface for this chunk? */
int sctp_chunk_iif(const struct sctp_chunk *chunk) int sctp_chunk_iif(const struct sctp_chunk *chunk)
{ {
...@@ -976,7 +978,9 @@ struct sctp_chunk *sctp_chunkify(struct sk_buff *skb, ...@@ -976,7 +978,9 @@ struct sctp_chunk *sctp_chunkify(struct sk_buff *skb,
const struct sctp_association *asoc, const struct sctp_association *asoc,
struct sock *sk) 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) if (!retval)
goto nodata; goto nodata;
...@@ -1075,13 +1079,12 @@ struct sctp_chunk *sctp_make_chunk(const struct sctp_association *asoc, ...@@ -1075,13 +1079,12 @@ struct sctp_chunk *sctp_make_chunk(const struct sctp_association *asoc,
} }
retval->chunk_hdr = chunk_hdr; 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. */ /* Set the skb to the belonging sock for accounting. */
skb->sk = sk; skb->sk = sk;
return retval; return retval;
nodata: nodata:
return NULL; return NULL;
} }
...@@ -1090,12 +1093,11 @@ struct sctp_chunk *sctp_make_chunk(const struct sctp_association *asoc, ...@@ -1090,12 +1093,11 @@ struct sctp_chunk *sctp_make_chunk(const struct sctp_association *asoc,
/* Release the memory occupied by a chunk. */ /* Release the memory occupied by a chunk. */
static void sctp_chunk_destroy(struct sctp_chunk *chunk) static void sctp_chunk_destroy(struct sctp_chunk *chunk)
{ {
/* Free the chunk skb data and the SCTP_chunk stub itself. */ /* Free the chunk skb data and the SCTP_chunk stub itself. */
dev_kfree_skb(chunk->skb); dev_kfree_skb(chunk->skb);
kfree(chunk);
SCTP_DBG_OBJCNT_DEC(chunk); SCTP_DBG_OBJCNT_DEC(chunk);
kmem_cache_free(sctp_chunk_cachep, chunk);
} }
/* Possibly, free the chunk. */ /* Possibly, free the chunk. */
...@@ -1907,7 +1909,7 @@ int sctp_process_param(struct sctp_association *asoc, union sctp_params param, ...@@ -1907,7 +1909,7 @@ int sctp_process_param(struct sctp_association *asoc, union sctp_params param,
break; break;
case SCTP_PARAM_COOKIE_PRESERVATIVE: case SCTP_PARAM_COOKIE_PRESERVATIVE:
if (!sctp_proto.cookie_preserve_enable) if (!sctp_cookie_preserve_enable)
break; break;
stale = ntohl(param.life->lifespan_increment); stale = ntohl(param.life->lifespan_increment);
......
...@@ -415,7 +415,8 @@ static void sctp_cmd_init_failed(sctp_cmd_seq_t *commands, ...@@ -415,7 +415,8 @@ static void sctp_cmd_init_failed(sctp_cmd_seq_t *commands,
struct sctp_ulpevent *event; struct sctp_ulpevent *event;
event = sctp_ulpevent_make_assoc_change(asoc,0, SCTP_CANT_STR_ASSOC, 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) if (event)
sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP,
......
...@@ -737,7 +737,7 @@ sctp_disposition_t sctp_sf_sendbeat_8_3(const struct sctp_endpoint *ep, ...@@ -737,7 +737,7 @@ sctp_disposition_t sctp_sf_sendbeat_8_3(const struct sctp_endpoint *ep,
{ {
struct sctp_transport *transport = (struct sctp_transport *) arg; 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. */ /* CMD_ASSOC_FAILED calls CMD_DELETE_TCB. */
sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED,
SCTP_U32(SCTP_ERROR_NO_ERROR)); SCTP_U32(SCTP_ERROR_NO_ERROR));
...@@ -1787,24 +1787,17 @@ sctp_disposition_t sctp_sf_cookie_echoed_err(const struct sctp_endpoint *ep, ...@@ -1787,24 +1787,17 @@ sctp_disposition_t sctp_sf_cookie_echoed_err(const struct sctp_endpoint *ep,
struct sctp_chunk *chunk = arg; struct sctp_chunk *chunk = arg;
sctp_errhdr_t *err; 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 */ /* Process the error here */
switch (err->cause) { /* FUTURE FIXME: When PR-SCTP related and other optional
case SCTP_ERROR_STALE_COOKIE: * parms are emitted, this will have to change to handle multiple
return sctp_sf_do_5_2_6_stale(ep, asoc, type, arg, commands); * errors.
default: */
return sctp_sf_pdiscard(ep, asoc, type, arg, commands); 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);
} }
/* /*
...@@ -2066,6 +2059,7 @@ sctp_disposition_t sctp_sf_do_9_2_shutdown(const struct sctp_endpoint *ep, ...@@ -2066,6 +2059,7 @@ sctp_disposition_t sctp_sf_do_9_2_shutdown(const struct sctp_endpoint *ep,
struct sctp_chunk *chunk = arg; struct sctp_chunk *chunk = arg;
sctp_shutdownhdr_t *sdh; sctp_shutdownhdr_t *sdh;
sctp_disposition_t disposition; sctp_disposition_t disposition;
struct sctp_ulpevent *ev;
/* Convert the elaborate header. */ /* Convert the elaborate header. */
sdh = (sctp_shutdownhdr_t *)chunk->skb->data; sdh = (sctp_shutdownhdr_t *)chunk->skb->data;
...@@ -2096,12 +2090,28 @@ sctp_disposition_t sctp_sf_do_9_2_shutdown(const struct sctp_endpoint *ep, ...@@ -2096,12 +2090,28 @@ sctp_disposition_t sctp_sf_do_9_2_shutdown(const struct sctp_endpoint *ep,
arg, commands); arg, commands);
} }
if (SCTP_DISPOSITION_NOMEM == disposition)
goto out;
/* - verify, by checking the Cumulative TSN Ack field of the /* - verify, by checking the Cumulative TSN Ack field of the
* chunk, that all its outstanding DATA chunks have been * chunk, that all its outstanding DATA chunks have been
* received by the SHUTDOWN sender. * received by the SHUTDOWN sender.
*/ */
sctp_add_cmd_sf(commands, SCTP_CMD_PROCESS_CTSN, sctp_add_cmd_sf(commands, SCTP_CMD_PROCESS_CTSN,
SCTP_U32(chunk->subh.shutdown_hdr->cum_tsn_ack)); 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; return disposition;
} }
...@@ -2739,6 +2749,9 @@ sctp_disposition_t sctp_sf_eat_sack_6_2(const struct sctp_endpoint *ep, ...@@ -2739,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 */ /* Pull the SACK chunk from the data buffer */
sackh = sctp_sm_pull_sack(chunk); 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; chunk->subh.sack_hdr = sackh;
ctsn = ntohl(sackh->cum_tsn_ack); ctsn = ntohl(sackh->cum_tsn_ack);
...@@ -4405,22 +4418,27 @@ sctp_disposition_t sctp_sf_timer_ignore(const struct sctp_endpoint *ep, ...@@ -4405,22 +4418,27 @@ sctp_disposition_t sctp_sf_timer_ignore(const struct sctp_endpoint *ep,
********************************************************************/ ********************************************************************/
/* Pull the SACK chunk based on the SACK header. */ /* 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_blocks;
__u16 num_dup_tsns; __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. * the skb from a bogus sender.
*/ */
sack = (sctp_sackhdr_t *) chunk->skb->data; sack = (struct sctp_sackhdr *) chunk->skb->data;
skb_pull(chunk->skb, sizeof(sctp_sackhdr_t));
num_blocks = ntohs(sack->num_gap_ack_blocks); num_blocks = ntohs(sack->num_gap_ack_blocks);
num_dup_tsns = ntohs(sack->num_dup_tsns); 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; return sack;
} }
......
...@@ -99,6 +99,8 @@ static void sctp_sock_migrate(struct sock *, struct sock *, ...@@ -99,6 +99,8 @@ static void sctp_sock_migrate(struct sock *, struct sock *,
struct sctp_association *, sctp_socket_type_t); struct sctp_association *, sctp_socket_type_t);
static char *sctp_hmac_alg = SCTP_COOKIE_HMAC_ALG; static char *sctp_hmac_alg = SCTP_COOKIE_HMAC_ALG;
extern kmem_cache_t *sctp_bucket_cachep;
/* Look up the association by its id. If this is not a UDP-style /* Look up the association by its id. If this is not a UDP-style
* socket, the ID field is always ignored. * socket, the ID field is always ignored.
*/ */
...@@ -106,10 +108,16 @@ struct sctp_association *sctp_id2assoc(struct sock *sk, sctp_assoc_t id) ...@@ -106,10 +108,16 @@ struct sctp_association *sctp_id2assoc(struct sock *sk, sctp_assoc_t id)
{ {
struct sctp_association *asoc = NULL; struct sctp_association *asoc = NULL;
/* If this is not a UDP-style socket, assoc id should be /* If this is not a UDP-style socket, assoc id should be ignored. */
* ignored.
*/
if (!sctp_style(sk, UDP)) { if (!sctp_style(sk, UDP)) {
/* Return NULL if the socket state is not ESTABLISHED. It
* could be a TCP-style listening socket or a socket which
* hasn't yet called connect() to establish an association.
*/
if (!sctp_sstate(sk, ESTABLISHED))
return NULL;
/* Get the first and the only association from the list. */
if (!list_empty(&sctp_sk(sk)->ep->asocs)) if (!list_empty(&sctp_sk(sk)->ep->asocs))
asoc = list_entry(sctp_sk(sk)->ep->asocs.next, asoc = list_entry(sctp_sk(sk)->ep->asocs.next,
struct sctp_association, asocs); struct sctp_association, asocs);
...@@ -132,6 +140,30 @@ struct sctp_association *sctp_id2assoc(struct sock *sk, sctp_assoc_t id) ...@@ -132,6 +140,30 @@ struct sctp_association *sctp_id2assoc(struct sock *sk, sctp_assoc_t id)
return asoc; return asoc;
} }
/* Look up the transport from an address and an assoc id. If both address and
* id are specified, the associations matching the address and the id should be
* the same.
*/
struct sctp_transport *sctp_addr_id2transport(struct sock *sk,
struct sockaddr_storage *addr,
sctp_assoc_t id)
{
struct sctp_association *addr_asoc = NULL, *id_asoc = NULL;
struct sctp_transport *transport;
addr_asoc = sctp_endpoint_lookup_assoc(sctp_sk(sk)->ep,
(union sctp_addr *)addr,
&transport);
if (!addr_asoc)
return NULL;
id_asoc = sctp_id2assoc(sk, id);
if (id_asoc && (id_asoc != addr_asoc))
return NULL;
return transport;
}
/* API 3.1.2 bind() - UDP Style Syntax /* API 3.1.2 bind() - UDP Style Syntax
* The syntax of bind() is, * The syntax of bind() is,
* *
...@@ -710,7 +742,7 @@ SCTP_STATIC void sctp_close(struct sock *sk, long timeout) ...@@ -710,7 +742,7 @@ SCTP_STATIC void sctp_close(struct sock *sk, long timeout)
struct sctp_association *asoc; struct sctp_association *asoc;
struct list_head *pos, *temp; struct list_head *pos, *temp;
printk("sctp_close(sk: 0x%p, timeout:%ld)\n", sk, timeout); SCTP_DEBUG_PRINTK("sctp_close(sk: 0x%p, timeout:%ld)\n", sk, timeout);
sctp_lock_sock(sk); sctp_lock_sock(sk);
sk->shutdown = SHUTDOWN_MASK; sk->shutdown = SHUTDOWN_MASK;
...@@ -1061,11 +1093,11 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk, ...@@ -1061,11 +1093,11 @@ SCTP_STATIC int sctp_sendmsg(struct kiocb *iocb, struct sock *sk,
/* If the user didn't specify SNDRCVINFO, make up one with /* If the user didn't specify SNDRCVINFO, make up one with
* some defaults. * some defaults.
*/ */
default_sinfo.sinfo_stream = asoc->defaults.stream; default_sinfo.sinfo_stream = asoc->default_stream;
default_sinfo.sinfo_flags = asoc->defaults.flags; default_sinfo.sinfo_flags = asoc->default_flags;
default_sinfo.sinfo_ppid = asoc->defaults.ppid; default_sinfo.sinfo_ppid = asoc->default_ppid;
default_sinfo.sinfo_context = asoc->defaults.context; default_sinfo.sinfo_context = asoc->default_context;
default_sinfo.sinfo_timetolive = asoc->defaults.timetolive; default_sinfo.sinfo_timetolive = asoc->default_timetolive;
default_sinfo.sinfo_assoc_id = sctp_assoc2id(asoc); default_sinfo.sinfo_assoc_id = sctp_assoc2id(asoc);
sinfo = &default_sinfo; sinfo = &default_sinfo;
} }
...@@ -1333,6 +1365,13 @@ SCTP_STATIC int sctp_recvmsg(struct kiocb *iocb, struct sock *sk, ...@@ -1333,6 +1365,13 @@ SCTP_STATIC int sctp_recvmsg(struct kiocb *iocb, struct sock *sk,
return err; return err;
} }
/* 7.1.12 Enable/Disable message fragmentation (SCTP_DISABLE_FRAGMENTS)
*
* This option is a on/off flag. If enabled no SCTP message
* fragmentation will be performed. Instead if a message being sent
* exceeds the current PMTU size, the message will NOT be sent and
* instead a error will be indicated to the user.
*/
static int sctp_setsockopt_disable_fragments(struct sock *sk, static int sctp_setsockopt_disable_fragments(struct sock *sk,
char *optval, int optlen) char *optval, int optlen)
{ {
...@@ -1359,6 +1398,17 @@ static int sctp_setsockopt_events(struct sock *sk, char *optval, ...@@ -1359,6 +1398,17 @@ static int sctp_setsockopt_events(struct sock *sk, char *optval,
return 0; return 0;
} }
/* 7.1.8 Automatic Close of associations (SCTP_AUTOCLOSE)
*
* This socket option is applicable to the UDP-style socket only. When
* set it will cause associations that are idle for more than the
* specified number of seconds to automatically close. An association
* being idle is defined an association that has NOT sent or received
* user data. The special value of '0' indicates that no automatic
* close of any associations should be performed. The option expects an
* integer defining the number of seconds of idle time before an
* association is closed.
*/
static int sctp_setsockopt_autoclose(struct sock *sk, char *optval, static int sctp_setsockopt_autoclose(struct sock *sk, char *optval,
int optlen) int optlen)
{ {
...@@ -1376,12 +1426,41 @@ static int sctp_setsockopt_autoclose(struct sock *sk, char *optval, ...@@ -1376,12 +1426,41 @@ static int sctp_setsockopt_autoclose(struct sock *sk, char *optval,
return 0; return 0;
} }
/* 7.1.13 Peer Address Parameters (SCTP_SET_PEER_ADDR_PARAMS)
*
* Applications can enable or disable heartbeats for any peer address of
* an association, modify an address's heartbeat interval, force a
* heartbeat to be sent immediately, and adjust the address's maximum
* number of retransmissions sent before an address is considered
* unreachable. The following structure is used to access and modify an
* address's parameters:
*
* struct sctp_paddrparams {
* sctp_assoc_t spp_assoc_id;
* struct sockaddr_storage spp_address;
* uint32_t spp_hbinterval;
* uint16_t spp_pathmaxrxt;
* };
*
* spp_assoc_id - (UDP style socket) This is filled in the application,
* and identifies the association for this query.
* spp_address - This specifies which address is of interest.
* spp_hbinterval - This contains the value of the heartbeat interval,
* in milliseconds. A value of 0, when modifying the
* parameter, specifies that the heartbeat on this
* address should be disabled. A value of UINT32_MAX
* (4294967295), when modifying the parameter,
* specifies that a heartbeat should be sent
* immediately to the peer address, and the current
* interval should remain unchanged.
* spp_pathmaxrxt - This contains the maximum number of
* retransmissions before this address shall be
* considered unreachable.
*/
static int sctp_setsockopt_peer_addr_params(struct sock *sk, static int sctp_setsockopt_peer_addr_params(struct sock *sk,
char *optval, int optlen) char *optval, int optlen)
{ {
struct sctp_paddrparams params; struct sctp_paddrparams params;
struct sctp_association *asoc;
union sctp_addr *addr;
struct sctp_transport *trans; struct sctp_transport *trans;
int error; int error;
...@@ -1390,15 +1469,10 @@ static int sctp_setsockopt_peer_addr_params(struct sock *sk, ...@@ -1390,15 +1469,10 @@ static int sctp_setsockopt_peer_addr_params(struct sock *sk,
if (copy_from_user(&params, optval, optlen)) if (copy_from_user(&params, optval, optlen))
return -EFAULT; return -EFAULT;
asoc = sctp_id2assoc(sk, params.spp_assoc_id); trans = sctp_addr_id2transport(sk, &params.spp_address,
if (!asoc) params.spp_assoc_id);
return -EINVAL;
addr = (union sctp_addr *) &(params.spp_address);
trans = sctp_assoc_lookup_paddr(asoc, addr);
if (!trans) if (!trans)
return -ENOENT; return -EINVAL;
/* Applications can enable or disable heartbeats for any peer address /* Applications can enable or disable heartbeats for any peer address
* of an association, modify an address's heartbeat interval, force a * of an association, modify an address's heartbeat interval, force a
...@@ -1412,7 +1486,7 @@ static int sctp_setsockopt_peer_addr_params(struct sock *sk, ...@@ -1412,7 +1486,7 @@ static int sctp_setsockopt_peer_addr_params(struct sock *sk,
* and the current interval should remain unchanged. * and the current interval should remain unchanged.
*/ */
if (0xffffffff == params.spp_hbinterval) { if (0xffffffff == params.spp_hbinterval) {
error = sctp_primitive_REQUESTHEARTBEAT (asoc, trans); error = sctp_primitive_REQUESTHEARTBEAT (trans->asoc, trans);
if (error) if (error)
return error; return error;
} else { } else {
...@@ -1435,6 +1509,17 @@ static int sctp_setsockopt_peer_addr_params(struct sock *sk, ...@@ -1435,6 +1509,17 @@ static int sctp_setsockopt_peer_addr_params(struct sock *sk,
return 0; return 0;
} }
/* 7.1.3 Initialization Parameters (SCTP_INITMSG)
*
* Applications can specify protocol parameters for the default association
* initialization. The option name argument to setsockopt() and getsockopt()
* is SCTP_INITMSG.
*
* Setting initialization parameters is effective only on an unconnected
* socket (for UDP-style sockets only future associations are effected
* by the change). With TCP-style sockets, this option is inherited by
* sockets derived from a listener socket.
*/
static int sctp_setsockopt_initmsg(struct sock *sk, char *optval, int optlen) static int sctp_setsockopt_initmsg(struct sock *sk, char *optval, int optlen)
{ {
if (optlen != sizeof(struct sctp_initmsg)) if (optlen != sizeof(struct sctp_initmsg))
...@@ -1445,7 +1530,7 @@ static int sctp_setsockopt_initmsg(struct sock *sk, char *optval, int optlen) ...@@ -1445,7 +1530,7 @@ static int sctp_setsockopt_initmsg(struct sock *sk, char *optval, int optlen)
} }
/* /*
* 7.1.15 Set default send parameters (SET_DEFAULT_SEND_PARAM) * 7.1.14 Set default send parameters (SET_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
...@@ -1463,6 +1548,7 @@ static int sctp_setsockopt_default_send_param(struct sock *sk, ...@@ -1463,6 +1548,7 @@ static int sctp_setsockopt_default_send_param(struct sock *sk,
{ {
struct sctp_sndrcvinfo info; struct sctp_sndrcvinfo info;
struct sctp_association *asoc; struct sctp_association *asoc;
struct sctp_opt *sp = sctp_sk(sk);
if (optlen != sizeof(struct sctp_sndrcvinfo)) if (optlen != sizeof(struct sctp_sndrcvinfo))
return -EINVAL; return -EINVAL;
...@@ -1470,14 +1556,23 @@ static int sctp_setsockopt_default_send_param(struct sock *sk, ...@@ -1470,14 +1556,23 @@ static int sctp_setsockopt_default_send_param(struct sock *sk,
return -EFAULT; return -EFAULT;
asoc = sctp_id2assoc(sk, info.sinfo_assoc_id); asoc = sctp_id2assoc(sk, info.sinfo_assoc_id);
if (!asoc) if (!asoc && info.sinfo_assoc_id && sctp_style(sk, UDP))
return -EINVAL; return -EINVAL;
asoc->defaults.stream = info.sinfo_stream; if (asoc) {
asoc->defaults.flags = info.sinfo_flags; asoc->default_stream = info.sinfo_stream;
asoc->defaults.ppid = info.sinfo_ppid; asoc->default_flags = info.sinfo_flags;
asoc->defaults.context = info.sinfo_context; asoc->default_ppid = info.sinfo_ppid;
asoc->defaults.timetolive = info.sinfo_timetolive; asoc->default_context = info.sinfo_context;
asoc->default_timetolive = info.sinfo_timetolive;
} else {
sp->default_stream = info.sinfo_stream;
sp->default_flags = info.sinfo_flags;
sp->default_ppid = info.sinfo_ppid;
sp->default_context = info.sinfo_context;
sp->default_timetolive = info.sinfo_timetolive;
}
return 0; return 0;
} }
...@@ -1490,8 +1585,6 @@ static int sctp_setsockopt_default_send_param(struct sock *sk, ...@@ -1490,8 +1585,6 @@ static int sctp_setsockopt_default_send_param(struct sock *sk,
static int sctp_setsockopt_peer_prim(struct sock *sk, char *optval, int optlen) static int sctp_setsockopt_peer_prim(struct sock *sk, char *optval, int optlen)
{ {
struct sctp_setpeerprim prim; struct sctp_setpeerprim prim;
struct sctp_association *asoc;
union sctp_addr *addr;
struct sctp_transport *trans; struct sctp_transport *trans;
if (optlen != sizeof(struct sctp_setpeerprim)) if (optlen != sizeof(struct sctp_setpeerprim))
...@@ -1500,18 +1593,11 @@ static int sctp_setsockopt_peer_prim(struct sock *sk, char *optval, int optlen) ...@@ -1500,18 +1593,11 @@ static int sctp_setsockopt_peer_prim(struct sock *sk, char *optval, int optlen)
if (copy_from_user(&prim, optval, sizeof(struct sctp_setpeerprim))) if (copy_from_user(&prim, optval, sizeof(struct sctp_setpeerprim)))
return -EFAULT; return -EFAULT;
asoc = sctp_id2assoc(sk, prim.sspp_assoc_id); trans = sctp_addr_id2transport(sk, &prim.sspp_addr, prim.sspp_assoc_id);
if (!asoc)
return -EINVAL;
/* Find the requested address. */
addr = (union sctp_addr *) &(prim.sspp_addr);
trans = sctp_assoc_lookup_paddr(asoc, addr);
if (!trans) if (!trans)
return -ENOENT; return -EINVAL;
sctp_assoc_set_primary(asoc, trans); sctp_assoc_set_primary(trans->asoc, trans);
return 0; return 0;
} }
...@@ -1906,13 +1992,10 @@ SCTP_STATIC int sctp_ioctl(struct sock *sk, int cmd, unsigned long arg) ...@@ -1906,13 +1992,10 @@ SCTP_STATIC int sctp_ioctl(struct sock *sk, int cmd, unsigned long arg)
SCTP_STATIC int sctp_init_sock(struct sock *sk) SCTP_STATIC int sctp_init_sock(struct sock *sk)
{ {
struct sctp_endpoint *ep; struct sctp_endpoint *ep;
struct sctp_protocol *proto;
struct sctp_opt *sp; struct sctp_opt *sp;
SCTP_DEBUG_PRINTK("sctp_init_sock(sk: %p)\n", sk); SCTP_DEBUG_PRINTK("sctp_init_sock(sk: %p)\n", sk);
proto = sctp_get_protocol();
sp = sctp_sk(sk); sp = sctp_sk(sk);
/* Initialize the SCTP per socket area. */ /* Initialize the SCTP per socket area. */
...@@ -1933,23 +2016,26 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk) ...@@ -1933,23 +2016,26 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk)
*/ */
sp->default_stream = 0; sp->default_stream = 0;
sp->default_ppid = 0; sp->default_ppid = 0;
sp->default_flags = 0;
sp->default_context = 0;
sp->default_timetolive = 0;
/* Initialize default setup parameters. These parameters /* Initialize default setup parameters. These parameters
* can be modified with the SCTP_INITMSG socket option or * can be modified with the SCTP_INITMSG socket option or
* overridden by the SCTP_INIT CMSG. * overridden by the SCTP_INIT CMSG.
*/ */
sp->initmsg.sinit_num_ostreams = proto->max_outstreams; sp->initmsg.sinit_num_ostreams = sctp_max_outstreams;
sp->initmsg.sinit_max_instreams = proto->max_instreams; sp->initmsg.sinit_max_instreams = sctp_max_instreams;
sp->initmsg.sinit_max_attempts = proto->max_retrans_init; sp->initmsg.sinit_max_attempts = sctp_max_retrans_init;
sp->initmsg.sinit_max_init_timeo = proto->rto_max / HZ; sp->initmsg.sinit_max_init_timeo = sctp_rto_max / HZ;
/* 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. * FIXME: These are not used yet.
*/ */
sp->rtoinfo.srto_initial = proto->rto_initial; sp->rtoinfo.srto_initial = sctp_rto_initial;
sp->rtoinfo.srto_max = proto->rto_max; sp->rtoinfo.srto_max = sctp_rto_max;
sp->rtoinfo.srto_min = proto->rto_min; sp->rtoinfo.srto_min = sctp_rto_min;
/* Initialize default event subscriptions. /* Initialize default event subscriptions.
* the struct sock is initialized to zero, so only * the struct sock is initialized to zero, so only
...@@ -1964,8 +2050,8 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk) ...@@ -1964,8 +2050,8 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk)
/* Default Peer Address Parameters. These defaults can /* Default Peer Address Parameters. These defaults can
* be modified via SCTP_SET_PEER_ADDR_PARAMS * be modified via SCTP_SET_PEER_ADDR_PARAMS
*/ */
sp->paddrparam.spp_hbinterval = proto->hb_interval / HZ; sp->paddrparam.spp_hbinterval = sctp_hb_interval / HZ;
sp->paddrparam.spp_pathmaxrxt = proto->max_retrans_path; sp->paddrparam.spp_pathmaxrxt = sctp_max_retrans_path;
/* If enabled no SCTP message fragmentation will be performed. /* If enabled no SCTP message fragmentation will be performed.
* Configure through SCTP_DISABLE_FRAGMENTS socket option. * Configure through SCTP_DISABLE_FRAGMENTS socket option.
...@@ -2131,6 +2217,64 @@ static int sctp_getsockopt_sctp_status(struct sock *sk, int len, char *optval, ...@@ -2131,6 +2217,64 @@ static int sctp_getsockopt_sctp_status(struct sock *sk, int len, char *optval,
return (retval); return (retval);
} }
/* 7.2.2 Peer Address Information (SCTP_GET_PEER_ADDR_INFO)
*
* Applications can retrieve information about a specific peer address
* of an association, including its reachability state, congestion
* window, and retransmission timer values. This information is
* read-only.
*/
static int sctp_getsockopt_peer_addr_info(struct sock *sk, int len,
char *optval, int *optlen)
{
struct sctp_paddrinfo pinfo;
struct sctp_transport *transport;
int retval = 0;
if (len != sizeof(pinfo)) {
retval = -EINVAL;
goto out;
}
if (copy_from_user(&pinfo, optval, sizeof(pinfo))) {
retval = -EFAULT;
goto out;
}
transport = sctp_addr_id2transport(sk, &pinfo.spinfo_address,
pinfo.spinfo_assoc_id);
if (!transport)
return -EINVAL;
pinfo.spinfo_assoc_id = sctp_assoc2id(transport->asoc);
pinfo.spinfo_state = transport->active;
pinfo.spinfo_cwnd = transport->cwnd;
pinfo.spinfo_srtt = transport->srtt;
pinfo.spinfo_rto = transport->rto;
pinfo.spinfo_mtu = transport->pmtu;
if (put_user(len, optlen)) {
retval = -EFAULT;
goto out;
}
if (copy_to_user(optval, &pinfo, len)) {
retval = -EFAULT;
goto out;
}
out:
return (retval);
}
/* 7.1.12 Enable/Disable message fragmentation (SCTP_DISABLE_FRAGMENTS)
*
* This option is a on/off flag. If enabled no SCTP message
* fragmentation will be performed. Instead if a message being sent
* exceeds the current PMTU size, the message will NOT be sent and
* instead a error will be indicated to the user.
*/
static int sctp_getsockopt_disable_fragments(struct sock *sk, int len, static int sctp_getsockopt_disable_fragments(struct sock *sk, int len,
char *optval, int *optlen) char *optval, int *optlen)
{ {
...@@ -2148,6 +2292,11 @@ static int sctp_getsockopt_disable_fragments(struct sock *sk, int len, ...@@ -2148,6 +2292,11 @@ static int sctp_getsockopt_disable_fragments(struct sock *sk, int len,
return 0; return 0;
} }
/* 7.1.15 Set notification and ancillary events (SCTP_SET_EVENTS)
*
* This socket option is used to specify various notifications and
* ancillary data the user wishes to receive.
*/
static int sctp_getsockopt_set_events(struct sock *sk, int len, char *optval, int *optlen) static int sctp_getsockopt_set_events(struct sock *sk, int len, char *optval, int *optlen)
{ {
if (len != sizeof(struct sctp_event_subscribe)) if (len != sizeof(struct sctp_event_subscribe))
...@@ -2157,6 +2306,17 @@ static int sctp_getsockopt_set_events(struct sock *sk, int len, char *optval, in ...@@ -2157,6 +2306,17 @@ static int sctp_getsockopt_set_events(struct sock *sk, int len, char *optval, in
return 0; return 0;
} }
/* 7.1.8 Automatic Close of associations (SCTP_AUTOCLOSE)
*
* This socket option is applicable to the UDP-style socket only. When
* set it will cause associations that are idle for more than the
* specified number of seconds to automatically close. An association
* being idle is defined an association that has NOT sent or received
* user data. The special value of '0' indicates that no automatic
* close of any associations should be performed. The option expects an
* integer defining the number of seconds of idle time before an
* association is closed.
*/
static int sctp_getsockopt_autoclose(struct sock *sk, int len, char *optval, int *optlen) static int sctp_getsockopt_autoclose(struct sock *sk, int len, char *optval, int *optlen)
{ {
/* Applicable to UDP-style socket only */ /* Applicable to UDP-style socket only */
...@@ -2240,12 +2400,41 @@ static int sctp_getsockopt_peeloff(struct sock *sk, int len, char *optval, int * ...@@ -2240,12 +2400,41 @@ static int sctp_getsockopt_peeloff(struct sock *sk, int len, char *optval, int *
return retval; return retval;
} }
/* 7.1.13 Peer Address Parameters (SCTP_SET_PEER_ADDR_PARAMS)
*
* Applications can enable or disable heartbeats for any peer address of
* an association, modify an address's heartbeat interval, force a
* heartbeat to be sent immediately, and adjust the address's maximum
* number of retransmissions sent before an address is considered
* unreachable. The following structure is used to access and modify an
* address's parameters:
*
* struct sctp_paddrparams {
* sctp_assoc_t spp_assoc_id;
* struct sockaddr_storage spp_address;
* uint32_t spp_hbinterval;
* uint16_t spp_pathmaxrxt;
* };
*
* spp_assoc_id - (UDP style socket) This is filled in the application,
* and identifies the association for this query.
* spp_address - This specifies which address is of interest.
* spp_hbinterval - This contains the value of the heartbeat interval,
* in milliseconds. A value of 0, when modifying the
* parameter, specifies that the heartbeat on this
* address should be disabled. A value of UINT32_MAX
* (4294967295), when modifying the parameter,
* specifies that a heartbeat should be sent
* immediately to the peer address, and the current
* interval should remain unchanged.
* spp_pathmaxrxt - This contains the maximum number of
* retransmissions before this address shall be
* considered unreachable.
*/
static int sctp_getsockopt_peer_addr_params(struct sock *sk, int len, static int sctp_getsockopt_peer_addr_params(struct sock *sk, int len,
char *optval, int *optlen) char *optval, int *optlen)
{ {
struct sctp_paddrparams params; struct sctp_paddrparams params;
struct sctp_association *asoc;
union sctp_addr *addr;
struct sctp_transport *trans; struct sctp_transport *trans;
if (len != sizeof(struct sctp_paddrparams)) if (len != sizeof(struct sctp_paddrparams))
...@@ -2253,15 +2442,10 @@ static int sctp_getsockopt_peer_addr_params(struct sock *sk, int len, ...@@ -2253,15 +2442,10 @@ static int sctp_getsockopt_peer_addr_params(struct sock *sk, int len,
if (copy_from_user(&params, optval, *optlen)) if (copy_from_user(&params, optval, *optlen))
return -EFAULT; return -EFAULT;
asoc = sctp_id2assoc(sk, params.spp_assoc_id); trans = sctp_addr_id2transport(sk, &params.spp_address,
if (!asoc) params.spp_assoc_id);
return -EINVAL;
addr = (union sctp_addr *) &(params.spp_address);
trans = sctp_assoc_lookup_paddr(asoc, addr);
if (!trans) if (!trans)
return -ENOENT; return -EINVAL;
/* The value of the heartbeat interval, in milliseconds. A value of 0, /* The value of the heartbeat interval, in milliseconds. A value of 0,
* when modifying the parameter, specifies that the heartbeat on this * when modifying the parameter, specifies that the heartbeat on this
...@@ -2286,6 +2470,17 @@ static int sctp_getsockopt_peer_addr_params(struct sock *sk, int len, ...@@ -2286,6 +2470,17 @@ static int sctp_getsockopt_peer_addr_params(struct sock *sk, int len,
return 0; return 0;
} }
/* 7.1.3 Initialization Parameters (SCTP_INITMSG)
*
* Applications can specify protocol parameters for the default association
* initialization. The option name argument to setsockopt() and getsockopt()
* is SCTP_INITMSG.
*
* Setting initialization parameters is effective only on an unconnected
* socket (for UDP-style sockets only future associations are effected
* by the change). With TCP-style sockets, this option is inherited by
* sockets derived from a listener socket.
*/
static int sctp_getsockopt_initmsg(struct sock *sk, int len, char *optval, int *optlen) static int sctp_getsockopt_initmsg(struct sock *sk, int len, char *optval, int *optlen)
{ {
if (len != sizeof(struct sctp_initmsg)) if (len != sizeof(struct sctp_initmsg))
...@@ -2491,7 +2686,7 @@ static int sctp_getsockopt_peer_prim(struct sock *sk, int len, ...@@ -2491,7 +2686,7 @@ static int sctp_getsockopt_peer_prim(struct sock *sk, int len,
/* /*
* *
* 7.1.15 Set default send parameters (SET_DEFAULT_SEND_PARAM) * 7.1.14 Set default send parameters (SET_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
...@@ -2511,6 +2706,7 @@ static int sctp_getsockopt_default_send_param(struct sock *sk, ...@@ -2511,6 +2706,7 @@ static int sctp_getsockopt_default_send_param(struct sock *sk,
{ {
struct sctp_sndrcvinfo info; struct sctp_sndrcvinfo info;
struct sctp_association *asoc; struct sctp_association *asoc;
struct sctp_opt *sp = sctp_sk(sk);
if (len != sizeof(struct sctp_sndrcvinfo)) if (len != sizeof(struct sctp_sndrcvinfo))
return -EINVAL; return -EINVAL;
...@@ -2518,14 +2714,22 @@ static int sctp_getsockopt_default_send_param(struct sock *sk, ...@@ -2518,14 +2714,22 @@ static int sctp_getsockopt_default_send_param(struct sock *sk,
return -EFAULT; return -EFAULT;
asoc = sctp_id2assoc(sk, info.sinfo_assoc_id); asoc = sctp_id2assoc(sk, info.sinfo_assoc_id);
if (!asoc) if (!asoc && info.sinfo_assoc_id && sctp_style(sk, UDP))
return -EINVAL; return -EINVAL;
info.sinfo_stream = asoc->defaults.stream; if (asoc) {
info.sinfo_flags = asoc->defaults.flags; info.sinfo_stream = asoc->default_stream;
info.sinfo_ppid = asoc->defaults.ppid; info.sinfo_flags = asoc->default_flags;
info.sinfo_context = asoc->defaults.context; info.sinfo_ppid = asoc->default_ppid;
info.sinfo_timetolive = asoc->defaults.timetolive; info.sinfo_context = asoc->default_context;
info.sinfo_timetolive = asoc->default_timetolive;
} else {
info.sinfo_stream = sp->default_stream;
info.sinfo_flags = sp->default_flags;
info.sinfo_ppid = sp->default_ppid;
info.sinfo_context = sp->default_context;
info.sinfo_timetolive = sp->default_timetolive;
}
if (copy_to_user(optval, &info, sizeof(struct sctp_sndrcvinfo))) if (copy_to_user(optval, &info, sizeof(struct sctp_sndrcvinfo)))
return -EFAULT; return -EFAULT;
...@@ -2698,6 +2902,10 @@ SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname, ...@@ -2698,6 +2902,10 @@ SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname,
case SCTP_MAXSEG: case SCTP_MAXSEG:
retval = sctp_getsockopt_maxseg(sk, len, optval, optlen); retval = sctp_getsockopt_maxseg(sk, len, optval, optlen);
break; break;
case SCTP_GET_PEER_ADDR_INFO:
retval = sctp_getsockopt_peer_addr_info(sk, len, optval,
optlen);
break;
default: default:
retval = -ENOPROTOOPT; retval = -ENOPROTOOPT;
break; break;
...@@ -2721,7 +2929,7 @@ static void sctp_unhash(struct sock *sk) ...@@ -2721,7 +2929,7 @@ static void sctp_unhash(struct sock *sk)
* *
* The port hash table (contained in the 'global' SCTP protocol storage * The port hash table (contained in the 'global' SCTP protocol storage
* returned by struct sctp_protocol *sctp_get_protocol()). The hash * returned by struct sctp_protocol *sctp_get_protocol()). The hash
* table is an array of 4096 lists (sctp_bind_hashbucket_t). Each * table is an array of 4096 lists (sctp_bind_hashbucket). Each
* list (the list number is the port number hashed out, so as you * list (the list number is the port number hashed out, so as you
* would expect from a hash function, all the ports in a given list have * would expect from a hash function, all the ports in a given list have
* such a number that hashes out to the same list number; you were * such a number that hashes out to the same list number; you were
...@@ -2729,13 +2937,13 @@ static void sctp_unhash(struct sock *sk) ...@@ -2729,13 +2937,13 @@ static void sctp_unhash(struct sock *sk)
* link to the socket (struct sock) that uses it, the port number and * link to the socket (struct sock) that uses it, the port number and
* a fastreuse flag (FIXME: NPI ipg). * a fastreuse flag (FIXME: NPI ipg).
*/ */
static sctp_bind_bucket_t *sctp_bucket_create(sctp_bind_hashbucket_t *head, static struct sctp_bind_bucket *sctp_bucket_create(
unsigned short snum); struct sctp_bind_hashbucket *head, unsigned short snum);
static long sctp_get_port_local(struct sock *sk, union sctp_addr *addr) static long sctp_get_port_local(struct sock *sk, union sctp_addr *addr)
{ {
sctp_bind_hashbucket_t *head; /* hash list */ struct sctp_bind_hashbucket *head; /* hash list */
sctp_bind_bucket_t *pp; /* hash list port iterator */ struct sctp_bind_bucket *pp; /* hash list port iterator */
struct sctp_protocol *sctp = sctp_get_protocol();
unsigned short snum; unsigned short snum;
int ret; int ret;
...@@ -2750,8 +2958,8 @@ static long sctp_get_port_local(struct sock *sk, union sctp_addr *addr) ...@@ -2750,8 +2958,8 @@ static long sctp_get_port_local(struct sock *sk, union sctp_addr *addr)
if (snum == 0) { if (snum == 0) {
/* Search for an available port. /* Search for an available port.
* *
* 'sctp->port_rover' was the last port assigned, so * 'sctp_port_rover' was the last port assigned, so
* we start to search from 'sctp->port_rover + * we start to search from 'sctp_port_rover +
* 1'. What we do is first check if port 'rover' is * 1'. What we do is first check if port 'rover' is
* already in the hash table; if not, we use that; if * already in the hash table; if not, we use that; if
* it is, we try next. * it is, we try next.
...@@ -2762,14 +2970,14 @@ static long sctp_get_port_local(struct sock *sk, union sctp_addr *addr) ...@@ -2762,14 +2970,14 @@ static long sctp_get_port_local(struct sock *sk, union sctp_addr *addr)
int rover; int rover;
int index; int index;
sctp_spin_lock(&sctp->port_alloc_lock); sctp_spin_lock(&sctp_port_alloc_lock);
rover = sctp->port_rover; rover = sctp_port_rover;
do { do {
rover++; rover++;
if ((rover < low) || (rover > high)) if ((rover < low) || (rover > high))
rover = low; rover = low;
index = sctp_phashfn(rover); index = sctp_phashfn(rover);
head = &sctp->port_hashtable[index]; head = &sctp_port_hashtable[index];
sctp_spin_lock(&head->lock); sctp_spin_lock(&head->lock);
for (pp = head->chain; pp; pp = pp->next) for (pp = head->chain; pp; pp = pp->next)
if (pp->port == rover) if (pp->port == rover)
...@@ -2778,8 +2986,8 @@ static long sctp_get_port_local(struct sock *sk, union sctp_addr *addr) ...@@ -2778,8 +2986,8 @@ static long sctp_get_port_local(struct sock *sk, union sctp_addr *addr)
next: next:
sctp_spin_unlock(&head->lock); sctp_spin_unlock(&head->lock);
} while (--remaining > 0); } while (--remaining > 0);
sctp->port_rover = rover; sctp_port_rover = rover;
sctp_spin_unlock(&sctp->port_alloc_lock); sctp_spin_unlock(&sctp_port_alloc_lock);
/* Exhausted local port range during search? */ /* Exhausted local port range during search? */
ret = 1; ret = 1;
...@@ -2799,7 +3007,7 @@ static long sctp_get_port_local(struct sock *sk, union sctp_addr *addr) ...@@ -2799,7 +3007,7 @@ static long sctp_get_port_local(struct sock *sk, union sctp_addr *addr)
* to the port number (snum) - we detect that with the * to the port number (snum) - we detect that with the
* port iterator, pp being NULL. * port iterator, pp being NULL.
*/ */
head = &sctp->port_hashtable[sctp_phashfn(snum)]; head = &sctp_port_hashtable[sctp_phashfn(snum)];
sctp_spin_lock(&head->lock); sctp_spin_lock(&head->lock);
for (pp = head->chain; pp; pp = pp->next) { for (pp = head->chain; pp; pp = pp->next) {
if (pp->port == snum) if (pp->port == snum)
...@@ -3105,12 +3313,13 @@ unsigned int sctp_poll(struct file *file, struct socket *sock, poll_table *wait) ...@@ -3105,12 +3313,13 @@ unsigned int sctp_poll(struct file *file, struct socket *sock, poll_table *wait)
* 2nd Level Abstractions * 2nd Level Abstractions
********************************************************************/ ********************************************************************/
static sctp_bind_bucket_t *sctp_bucket_create(sctp_bind_hashbucket_t *head, unsigned short snum) static struct sctp_bind_bucket *sctp_bucket_create(
struct sctp_bind_hashbucket *head, unsigned short snum)
{ {
sctp_bind_bucket_t *pp; struct sctp_bind_bucket *pp;
SCTP_DEBUG_PRINTK( "sctp_bucket_create() begins, snum=%d\n", snum); pp = kmem_cache_alloc(sctp_bucket_cachep, SLAB_ATOMIC);
pp = kmalloc(sizeof(sctp_bind_bucket_t), GFP_ATOMIC); SCTP_DBG_OBJCNT_INC(bind_bucket);
if (pp) { if (pp) {
pp->port = snum; pp->port = snum;
pp->fastreuse = 0; pp->fastreuse = 0;
...@@ -3120,31 +3329,36 @@ static sctp_bind_bucket_t *sctp_bucket_create(sctp_bind_hashbucket_t *head, unsi ...@@ -3120,31 +3329,36 @@ static sctp_bind_bucket_t *sctp_bucket_create(sctp_bind_hashbucket_t *head, unsi
head->chain = pp; head->chain = pp;
pp->pprev = &head->chain; pp->pprev = &head->chain;
} }
SCTP_DEBUG_PRINTK("sctp_bucket_create() ends, pp=%p\n", pp);
return pp; return pp;
} }
/* Caller must hold hashbucket lock for this tb with local BH disabled */
static void sctp_bucket_destroy(struct sctp_bind_bucket *pp)
{
if (!pp->sk) {
if (pp->next)
pp->next->pprev = pp->pprev;
*(pp->pprev) = pp->next;
kmem_cache_free(sctp_bucket_cachep, pp);
SCTP_DBG_OBJCNT_DEC(bind_bucket);
}
}
/* FIXME: Comments! */ /* FIXME: Comments! */
static __inline__ void __sctp_put_port(struct sock *sk) static __inline__ void __sctp_put_port(struct sock *sk)
{ {
struct sctp_protocol *sctp_proto = sctp_get_protocol(); struct sctp_bind_hashbucket *head =
sctp_bind_hashbucket_t *head = &sctp_port_hashtable[sctp_phashfn(inet_sk(sk)->num)];
&sctp_proto->port_hashtable[sctp_phashfn(inet_sk(sk)->num)]; struct sctp_bind_bucket *pp;
sctp_bind_bucket_t *pp;
sctp_spin_lock(&head->lock); sctp_spin_lock(&head->lock);
pp = (sctp_bind_bucket_t *) sk->prev; pp = (struct sctp_bind_bucket *) sk->prev;
if (sk->bind_next) if (sk->bind_next)
sk->bind_next->bind_pprev = sk->bind_pprev; sk->bind_next->bind_pprev = sk->bind_pprev;
*(sk->bind_pprev) = sk->bind_next; *(sk->bind_pprev) = sk->bind_next;
sk->prev = NULL; sk->prev = NULL;
inet_sk(sk)->num = 0; inet_sk(sk)->num = 0;
if (pp->sk) { sctp_bucket_destroy(pp);
if (pp->next)
pp->next->pprev = pp->pprev;
*(pp->pprev) = pp->next;
kfree(pp);
}
sctp_spin_unlock(&head->lock); sctp_spin_unlock(&head->lock);
} }
......
...@@ -42,13 +42,11 @@ ...@@ -42,13 +42,11 @@
#include <net/sctp/structs.h> #include <net/sctp/structs.h>
#include <linux/sysctl.h> #include <linux/sysctl.h>
extern struct sctp_protocol sctp_proto;
static ctl_table sctp_table[] = { static ctl_table sctp_table[] = {
{ {
.ctl_name = NET_SCTP_RTO_INITIAL, .ctl_name = NET_SCTP_RTO_INITIAL,
.procname = "rto_initial", .procname = "rto_initial",
.data = &sctp_proto.rto_initial, .data = &sctp_rto_initial,
.maxlen = sizeof(int), .maxlen = sizeof(int),
.mode = 0644, .mode = 0644,
.proc_handler = &proc_dointvec_jiffies, .proc_handler = &proc_dointvec_jiffies,
...@@ -57,7 +55,7 @@ static ctl_table sctp_table[] = { ...@@ -57,7 +55,7 @@ static ctl_table sctp_table[] = {
{ {
.ctl_name = NET_SCTP_RTO_MIN, .ctl_name = NET_SCTP_RTO_MIN,
.procname = "rto_min", .procname = "rto_min",
.data = &sctp_proto.rto_min, .data = &sctp_rto_min,
.maxlen = sizeof(int), .maxlen = sizeof(int),
.mode = 0644, .mode = 0644,
.proc_handler = &proc_dointvec_jiffies, .proc_handler = &proc_dointvec_jiffies,
...@@ -66,7 +64,7 @@ static ctl_table sctp_table[] = { ...@@ -66,7 +64,7 @@ static ctl_table sctp_table[] = {
{ {
.ctl_name = NET_SCTP_RTO_MAX, .ctl_name = NET_SCTP_RTO_MAX,
.procname = "rto_max", .procname = "rto_max",
.data = &sctp_proto.rto_max, .data = &sctp_rto_max,
.maxlen = sizeof(int), .maxlen = sizeof(int),
.mode = 0644, .mode = 0644,
.proc_handler = &proc_dointvec_jiffies, .proc_handler = &proc_dointvec_jiffies,
...@@ -75,7 +73,7 @@ static ctl_table sctp_table[] = { ...@@ -75,7 +73,7 @@ static ctl_table sctp_table[] = {
{ {
.ctl_name = NET_SCTP_VALID_COOKIE_LIFE, .ctl_name = NET_SCTP_VALID_COOKIE_LIFE,
.procname = "valid_cookie_life", .procname = "valid_cookie_life",
.data = &sctp_proto.valid_cookie_life, .data = &sctp_valid_cookie_life,
.maxlen = sizeof(int), .maxlen = sizeof(int),
.mode = 0644, .mode = 0644,
.proc_handler = &proc_dointvec_jiffies, .proc_handler = &proc_dointvec_jiffies,
...@@ -84,7 +82,7 @@ static ctl_table sctp_table[] = { ...@@ -84,7 +82,7 @@ static ctl_table sctp_table[] = {
{ {
.ctl_name = NET_SCTP_MAX_BURST, .ctl_name = NET_SCTP_MAX_BURST,
.procname = "max_burst", .procname = "max_burst",
.data = &sctp_proto.max_burst, .data = &sctp_max_burst,
.maxlen = sizeof(int), .maxlen = sizeof(int),
.mode = 0644, .mode = 0644,
.proc_handler = &proc_dointvec .proc_handler = &proc_dointvec
...@@ -92,7 +90,7 @@ static ctl_table sctp_table[] = { ...@@ -92,7 +90,7 @@ static ctl_table sctp_table[] = {
{ {
.ctl_name = NET_SCTP_ASSOCIATION_MAX_RETRANS, .ctl_name = NET_SCTP_ASSOCIATION_MAX_RETRANS,
.procname = "association_max_retrans", .procname = "association_max_retrans",
.data = &sctp_proto.max_retrans_association, .data = &sctp_max_retrans_association,
.maxlen = sizeof(int), .maxlen = sizeof(int),
.mode = 0644, .mode = 0644,
.proc_handler = &proc_dointvec .proc_handler = &proc_dointvec
...@@ -100,7 +98,7 @@ static ctl_table sctp_table[] = { ...@@ -100,7 +98,7 @@ static ctl_table sctp_table[] = {
{ {
.ctl_name = NET_SCTP_PATH_MAX_RETRANS, .ctl_name = NET_SCTP_PATH_MAX_RETRANS,
.procname = "path_max_retrans", .procname = "path_max_retrans",
.data = &sctp_proto.max_retrans_path, .data = &sctp_max_retrans_path,
.maxlen = sizeof(int), .maxlen = sizeof(int),
.mode = 0644, .mode = 0644,
.proc_handler = &proc_dointvec .proc_handler = &proc_dointvec
...@@ -108,7 +106,7 @@ static ctl_table sctp_table[] = { ...@@ -108,7 +106,7 @@ static ctl_table sctp_table[] = {
{ {
.ctl_name = NET_SCTP_MAX_INIT_RETRANSMITS, .ctl_name = NET_SCTP_MAX_INIT_RETRANSMITS,
.procname = "max_init_retransmits", .procname = "max_init_retransmits",
.data = &sctp_proto.max_retrans_init, .data = &sctp_max_retrans_init,
.maxlen = sizeof(int), .maxlen = sizeof(int),
.mode = 0644, .mode = 0644,
.proc_handler = &proc_dointvec .proc_handler = &proc_dointvec
...@@ -116,7 +114,7 @@ static ctl_table sctp_table[] = { ...@@ -116,7 +114,7 @@ static ctl_table sctp_table[] = {
{ {
.ctl_name = NET_SCTP_HB_INTERVAL, .ctl_name = NET_SCTP_HB_INTERVAL,
.procname = "hb_interval", .procname = "hb_interval",
.data = &sctp_proto.hb_interval, .data = &sctp_hb_interval,
.maxlen = sizeof(int), .maxlen = sizeof(int),
.mode = 0644, .mode = 0644,
.proc_handler = &proc_dointvec_jiffies, .proc_handler = &proc_dointvec_jiffies,
...@@ -125,7 +123,7 @@ static ctl_table sctp_table[] = { ...@@ -125,7 +123,7 @@ static ctl_table sctp_table[] = {
{ {
.ctl_name = NET_SCTP_PRESERVE_ENABLE, .ctl_name = NET_SCTP_PRESERVE_ENABLE,
.procname = "cookie_preserve_enable", .procname = "cookie_preserve_enable",
.data = &sctp_proto.cookie_preserve_enable, .data = &sctp_cookie_preserve_enable,
.maxlen = sizeof(int), .maxlen = sizeof(int),
.mode = 0644, .mode = 0644,
.proc_handler = &proc_dointvec_jiffies, .proc_handler = &proc_dointvec_jiffies,
...@@ -134,7 +132,7 @@ static ctl_table sctp_table[] = { ...@@ -134,7 +132,7 @@ static ctl_table sctp_table[] = {
{ {
.ctl_name = NET_SCTP_RTO_ALPHA, .ctl_name = NET_SCTP_RTO_ALPHA,
.procname = "rto_alpha_exp_divisor", .procname = "rto_alpha_exp_divisor",
.data = &sctp_proto.rto_alpha, .data = &sctp_rto_alpha,
.maxlen = sizeof(int), .maxlen = sizeof(int),
.mode = 0644, .mode = 0644,
.proc_handler = &proc_dointvec .proc_handler = &proc_dointvec
...@@ -142,7 +140,7 @@ static ctl_table sctp_table[] = { ...@@ -142,7 +140,7 @@ static ctl_table sctp_table[] = {
{ {
.ctl_name = NET_SCTP_RTO_BETA, .ctl_name = NET_SCTP_RTO_BETA,
.procname = "rto_beta_exp_divisor", .procname = "rto_beta_exp_divisor",
.data = &sctp_proto.rto_beta, .data = &sctp_rto_beta,
.maxlen = sizeof(int), .maxlen = sizeof(int),
.mode = 0644, .mode = 0644,
.proc_handler = &proc_dointvec .proc_handler = &proc_dointvec
......
...@@ -82,8 +82,6 @@ struct sctp_transport *sctp_transport_init(struct sctp_transport *peer, ...@@ -82,8 +82,6 @@ struct sctp_transport *sctp_transport_init(struct sctp_transport *peer,
const union sctp_addr *addr, const union sctp_addr *addr,
int gfp) int gfp)
{ {
struct sctp_protocol *proto = sctp_get_protocol();
/* Copy in the address. */ /* Copy in the address. */
peer->ipaddr = *addr; peer->ipaddr = *addr;
peer->af_specific = sctp_get_af_specific(addr->sa.sa_family); 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, ...@@ -99,7 +97,7 @@ struct sctp_transport *sctp_transport_init(struct sctp_transport *peer,
* parameter 'RTO.Initial'. * parameter 'RTO.Initial'.
*/ */
peer->rtt = 0; peer->rtt = 0;
peer->rto = proto->rto_initial; peer->rto = sctp_rto_initial;
peer->rttvar = 0; peer->rttvar = 0;
peer->srtt = 0; peer->srtt = 0;
peer->rto_pending = 0; peer->rto_pending = 0;
...@@ -108,11 +106,11 @@ struct sctp_transport *sctp_transport_init(struct sctp_transport *peer, ...@@ -108,11 +106,11 @@ struct sctp_transport *sctp_transport_init(struct sctp_transport *peer,
peer->last_time_used = jiffies; peer->last_time_used = jiffies;
peer->last_time_ecne_reduced = jiffies; peer->last_time_ecne_reduced = jiffies;
peer->active = 1; peer->active = SCTP_ACTIVE;
peer->hb_allowed = 0; peer->hb_allowed = 0;
/* Initialize the default path max_retrans. */ /* 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_threshold = 0;
peer->error_count = 0; peer->error_count = 0;
...@@ -272,8 +270,6 @@ void sctp_transport_put(struct sctp_transport *transport) ...@@ -272,8 +270,6 @@ void sctp_transport_put(struct sctp_transport *transport)
/* Update transport's RTO based on the newly calculated RTT. */ /* Update transport's RTO based on the newly calculated RTT. */
void sctp_transport_update_rto(struct sctp_transport *tp, __u32 rtt) void sctp_transport_update_rto(struct sctp_transport *tp, __u32 rtt)
{ {
struct sctp_protocol *proto = sctp_get_protocol();
/* Check for valid transport. */ /* Check for valid transport. */
SCTP_ASSERT(tp, "NULL transport", return); SCTP_ASSERT(tp, "NULL transport", return);
...@@ -292,10 +288,10 @@ void sctp_transport_update_rto(struct sctp_transport *tp, __u32 rtt) ...@@ -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 * For example, assuming the default value of RTO.Alpha of
* 1/8, rto_alpha would be expressed as 3. * 1/8, rto_alpha would be expressed as 3.
*/ */
tp->rttvar = tp->rttvar - (tp->rttvar >> proto->rto_beta) tp->rttvar = tp->rttvar - (tp->rttvar >> sctp_rto_beta)
+ ((abs(tp->srtt - rtt)) >> proto->rto_beta); + ((abs(tp->srtt - rtt)) >> sctp_rto_beta);
tp->srtt = tp->srtt - (tp->srtt >> proto->rto_alpha) tp->srtt = tp->srtt - (tp->srtt >> sctp_rto_alpha)
+ (rtt >> proto->rto_alpha); + (rtt >> sctp_rto_alpha);
} else { } else {
/* 6.3.1 C2) When the first RTT measurement R is made, set /* 6.3.1 C2) When the first RTT measurement R is made, set
* SRTT <- R, RTTVAR <- R/2. * 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