patch-2.4.26 linux-2.4.26/net/sctp/protocol.c
Next file: linux-2.4.26/net/sctp/sm_make_chunk.c
Previous file: linux-2.4.26/net/sctp/proc.c
Back to the patch index
Back to the overall index
- Lines: 751
- Date:
2004-04-14 06:05:41.000000000 -0700
- Orig file:
linux-2.4.25/net/sctp/protocol.c
- Orig date:
2003-11-28 10:26:21.000000000 -0800
diff -urN linux-2.4.25/net/sctp/protocol.c linux-2.4.26/net/sctp/protocol.c
@@ -1,7 +1,7 @@
/* SCTP kernel reference Implementation
+ * (C) Copyright IBM Corp. 2001, 2004
* Copyright (c) 1999-2000 Cisco, Inc.
* Copyright (c) 1999-2001 Motorola, Inc.
- * Copyright (c) 2001-2002 International Business Machines, Corp.
* Copyright (c) 2001 Intel Corp.
* Copyright (c) 2001 Nokia, Inc.
* Copyright (c) 2001 La Monte H.P. Yarroll
@@ -50,15 +50,17 @@
#include <linux/init.h>
#include <linux/netdevice.h>
#include <linux/inetdevice.h>
+#include <linux/seq_file.h>
#include <net/protocol.h>
#include <net/ip.h>
#include <net/ipv6.h>
#include <net/sctp/sctp.h>
#include <net/addrconf.h>
#include <net/inet_common.h>
+#include <net/inet_ecn.h>
/* Global data structures. */
-struct sctp_protocol sctp_proto;
+struct sctp_globals sctp_globals;
struct proc_dir_entry *proc_net_sctp;
DEFINE_SNMP_STAT(struct sctp_mib, sctp_statistics);
@@ -73,10 +75,16 @@
static struct sctp_af *sctp_af_v4_specific;
static struct sctp_af *sctp_af_v6_specific;
+kmem_cache_t *sctp_chunk_cachep;
+
extern struct net_proto_family inet_family_ops;
extern int sctp_snmp_proc_init(void);
extern int sctp_snmp_proc_exit(void);
+extern int sctp_eps_proc_init(void);
+extern int sctp_eps_proc_exit(void);
+extern int sctp_assocs_proc_init(void);
+extern int sctp_assocs_proc_exit(void);
/* Return the address of the control sock. */
struct sock *sctp_get_ctl_sock(void)
@@ -87,8 +95,6 @@
/* Set up the proc fs entry for the SCTP protocol. */
__init int sctp_proc_init(void)
{
- int rc = 0;
-
if (!proc_net_sctp) {
struct proc_dir_entry *ent;
ent = proc_mkdir("net/sctp", 0);
@@ -96,20 +102,31 @@
ent->owner = THIS_MODULE;
proc_net_sctp = ent;
} else
- rc = -ENOMEM;
+ goto out_nomem;
}
if (sctp_snmp_proc_init())
- rc = -ENOMEM;
+ goto out_nomem;
+ if (sctp_eps_proc_init())
+ goto out_nomem;
+ if (sctp_assocs_proc_init())
+ goto out_nomem;
+
+ return 0;
- return rc;
+out_nomem:
+ return -ENOMEM;
}
-/* 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)
{
-
sctp_snmp_proc_exit();
+ sctp_eps_proc_exit();
+ sctp_assocs_proc_exit();
if (proc_net_sctp) {
proc_net_sctp = NULL;
@@ -125,7 +142,7 @@
{
struct in_device *in_dev;
struct in_ifaddr *ifa;
- struct sockaddr_storage_list *addr;
+ struct sctp_sockaddr_entry *addr;
read_lock(&inetdev_lock);
if ((in_dev = __in_dev_get(dev)) == NULL) {
@@ -136,7 +153,7 @@
read_lock(&in_dev->lock);
for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) {
/* Add the address to the local list. */
- addr = t_new(struct sockaddr_storage_list, GFP_ATOMIC);
+ addr = t_new(struct sctp_sockaddr_entry, GFP_ATOMIC);
if (addr) {
addr->a.v4.sin_family = AF_INET;
addr->a.v4.sin_port = 0;
@@ -152,7 +169,7 @@
/* Extract our IP addresses from the system and stash them in the
* 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 list_head *pos;
@@ -160,59 +177,58 @@
read_lock(&dev_base_lock);
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->copy_addrlist(&proto->local_addr_list, dev);
+ af->copy_addrlist(&sctp_local_addr_list, dev);
}
}
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;
- sctp_spin_lock_irqsave(&sctp_proto.local_addr_lock, flags);
- __sctp_get_local_addr_list(&sctp_proto);
- sctp_spin_unlock_irqrestore(&sctp_proto.local_addr_lock, flags);
+ sctp_spin_lock_irqsave(&sctp_local_addr_lock, flags);
+ __sctp_get_local_addr_list();
+ sctp_spin_unlock_irqrestore(&sctp_local_addr_lock, flags);
}
/* 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 sctp_sockaddr_entry *addr;
struct list_head *pos, *temp;
- list_for_each_safe(pos, temp, &proto->local_addr_list) {
- addr = list_entry(pos, struct sockaddr_storage_list, list);
+ list_for_each_safe(pos, temp, &sctp_local_addr_list) {
+ addr = list_entry(pos, struct sctp_sockaddr_entry, list);
list_del(pos);
kfree(addr);
}
}
/* 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;
- sctp_spin_lock_irqsave(&proto->local_addr_lock, flags);
- __sctp_free_local_addr_list(proto);
- sctp_spin_unlock_irqrestore(&proto->local_addr_lock, flags);
+ sctp_spin_lock_irqsave(&sctp_local_addr_lock, flags);
+ __sctp_free_local_addr_list();
+ sctp_spin_unlock_irqrestore(&sctp_local_addr_lock, flags);
}
/* Copy the local addresses which are valid for 'scope' into 'bp'. */
-int sctp_copy_local_addr_list(struct sctp_protocol *proto,
- struct sctp_bind_addr *bp, sctp_scope_t scope,
+int sctp_copy_local_addr_list(struct sctp_bind_addr *bp, sctp_scope_t scope,
int gfp, int copy_flags)
{
- struct sockaddr_storage_list *addr;
+ struct sctp_sockaddr_entry *addr;
int error = 0;
struct list_head *pos;
unsigned long flags;
- sctp_spin_lock_irqsave(&proto->local_addr_lock, flags);
- list_for_each(pos, &proto->local_addr_list) {
- addr = list_entry(pos, struct sockaddr_storage_list, list);
+ sctp_spin_lock_irqsave(&sctp_local_addr_lock, flags);
+ list_for_each(pos, &sctp_local_addr_list) {
+ addr = list_entry(pos, struct sctp_sockaddr_entry, list);
if (sctp_in_scope(&addr->a, scope)) {
/* Now that the address is in scope, check to see if
* the address type is really supported by the local
@@ -232,7 +248,7 @@
}
end_copy:
- sctp_spin_unlock_irqrestore(&proto->local_addr_lock, flags);
+ sctp_spin_unlock_irqrestore(&sctp_local_addr_lock, flags);
return error;
}
@@ -262,20 +278,45 @@
static void sctp_v4_from_sk(union sctp_addr *addr, struct sock *sk)
{
addr->v4.sin_family = AF_INET;
- addr->v4.sin_port = (sk)->num;
- addr->v4.sin_addr.s_addr = (sk)->rcv_saddr;
+ addr->v4.sin_port = sk->num;
+ addr->v4.sin_addr.s_addr = sk->rcv_saddr;
}
-/* Initialize sk->rcv_saddr from sctp_addr. */
+/* Initialize sk->sk_rcv_saddr from sctp_addr. */
static void sctp_v4_to_sk_saddr(union sctp_addr *addr, struct sock *sk)
{
- (sk)->rcv_saddr = addr->v4.sin_addr.s_addr;
+ sk->rcv_saddr = addr->v4.sin_addr.s_addr;
}
-/* Initialize sk->daddr from sctp_addr. */
+/* Initialize sk->sk_daddr from sctp_addr. */
static void sctp_v4_to_sk_daddr(union sctp_addr *addr, struct sock *sk)
{
- (sk)->daddr = addr->v4.sin_addr.s_addr;
+ sk->daddr = addr->v4.sin_addr.s_addr;
+}
+
+/* Initialize a sctp_addr from an address parameter. */
+static void sctp_v4_from_addr_param(union sctp_addr *addr,
+ union sctp_addr_param *param,
+ __u16 port, int iif)
+{
+ addr->v4.sin_family = AF_INET;
+ addr->v4.sin_port = port;
+ addr->v4.sin_addr.s_addr = param->v4.addr.s_addr;
+}
+
+/* Initialize an address parameter from a sctp_addr and return the length
+ * of the address parameter.
+ */
+static int sctp_v4_to_addr_param(const union sctp_addr *addr,
+ union sctp_addr_param *param)
+{
+ int length = sizeof(sctp_ipv4addr_param_t);
+
+ param->v4.param_hdr.type = SCTP_PARAM_IPV4_ADDRESS;
+ param->v4.param_hdr.length = ntohs(length);
+ param->v4.addr.s_addr = addr->v4.sin_addr.s_addr;
+
+ return length;
}
/* Initialize a sctp_addr from a dst_entry. */
@@ -323,7 +364,7 @@
* Return 0 - If the address is a non-unicast or an illegal address.
* Return 1 - If the address is a unicast.
*/
-static int sctp_v4_addr_valid(union sctp_addr *addr)
+static int sctp_v4_addr_valid(union sctp_addr *addr, struct sctp_opt *sp)
{
/* Is this a non-unicast address or a unusable SCTP address? */
if (IS_IPV4_UNUSABLE_ADDRESS(&addr->v4.sin_addr.s_addr))
@@ -333,7 +374,7 @@
}
/* Should this be available for binding? */
-static int sctp_v4_available(const union sctp_addr *addr)
+static int sctp_v4_available(union sctp_addr *addr, struct sctp_opt *sp)
{
int ret = inet_addr_type(addr->v4.sin_addr.s_addr);
@@ -393,16 +434,20 @@
{
struct rtable *rt;
struct rt_key key;
- sctp_bind_addr_t *bp;
+ struct sctp_bind_addr *bp;
rwlock_t *addr_lock;
- struct sockaddr_storage_list *laddr;
+ struct sctp_sockaddr_entry *laddr;
struct list_head *pos;
struct dst_entry *dst = NULL;
union sctp_addr dst_saddr;
-
+
memset(&key, 0x0, sizeof(struct rt_key));
key.dst = daddr->v4.sin_addr.s_addr;
-
+
+ if (asoc) {
+ key.tos = RT_CONN_FLAGS(asoc->base.sk);
+ key.oif = asoc->base.sk->bound_dev_if;
+ }
if (saddr)
key.src = saddr->v4.sin_addr.s_addr;
@@ -429,7 +474,7 @@
*/
sctp_read_lock(addr_lock);
list_for_each(pos, &bp->address_list) {
- laddr = list_entry(pos, struct sockaddr_storage_list,
+ laddr = list_entry(pos, struct sctp_sockaddr_entry,
list);
sctp_v4_dst_saddr(&dst_saddr, dst, bp->port);
if (sctp_v4_cmp_addr(&dst_saddr, &laddr->a))
@@ -449,7 +494,7 @@
*/
sctp_read_lock(addr_lock);
list_for_each(pos, &bp->address_list) {
- laddr = list_entry(pos, struct sockaddr_storage_list, list);
+ laddr = list_entry(pos, struct sctp_sockaddr_entry, list);
if (AF_INET == laddr->a.sa.sa_family) {
key.src = laddr->a.v4.sin_addr.s_addr;
@@ -490,11 +535,17 @@
}
/* What interface did this skb arrive on? */
-int sctp_v4_skb_iif(const struct sk_buff *skb)
+static int sctp_v4_skb_iif(const struct sk_buff *skb)
{
return ((struct rtable *)skb->dst)->rt_iif;
}
+/* Was this packet marked by Explicit Congestion Notification? */
+static int sctp_v4_is_ce(const struct sk_buff *skb)
+{
+ return INET_ECN_is_ce(skb->nh.iph->tos);
+}
+
/* Create and initialize a new sk for the socket returned by accept(). */
struct sock *sctp_v4_create_accept_sk(struct sock *sk,
struct sctp_association *asoc)
@@ -510,18 +561,18 @@
sock_init_data(NULL, newsk);
sk_set_owner(newsk, THIS_MODULE);
- newsk->type = SOCK_STREAM;
+ newsk->sk_type = SOCK_STREAM;
- newsk->prot = sk->prot;
- newsk->no_check = sk->no_check;
- newsk->reuse = sk->reuse;
- newsk->shutdown = sk->shutdown;
-
- newsk->destruct = inet_sock_destruct;
- newsk->zapped = 0;
- newsk->family = PF_INET;
- newsk->protocol = IPPROTO_SCTP;
- newsk->backlog_rcv = sk->prot->backlog_rcv;
+ newsk->sk_prot = sk->sk_prot;
+ newsk->sk_no_check = sk->sk_no_check;
+ newsk->sk_reuse = sk->sk_reuse;
+ newsk->sk_shutdown = sk->sk_shutdown;
+
+ newsk->sk_destruct = inet_sock_destruct;
+ newsk->sk_zapped = 0;
+ newsk->sk_family = PF_INET;
+ newsk->sk_protocol = IPPROTO_SCTP;
+ newsk->sk_backlog_rcv = sk->sk_prot->backlog_rcv;
newinet = inet_sk(newsk);
@@ -546,7 +597,7 @@
atomic_inc(&inet_sock_nr);
#endif
- if (0 != newsk->prot->init(newsk)) {
+ if (newsk->sk_prot->init(newsk)) {
inet_sock_release(newsk);
newsk = NULL;
}
@@ -555,6 +606,18 @@
return newsk;
}
+/* Map address, empty for v4 family */
+static void sctp_v4_addr_v4map(struct sctp_opt *sp, union sctp_addr *addr)
+{
+ /* Empty */
+}
+
+/* Dump the v4 addr to the seq file. */
+static void sctp_v4_seq_dump_addr(struct seq_file *seq, union sctp_addr *addr)
+{
+ seq_printf(seq, "%d.%d.%d.%d ", NIPQUAD(addr->v4.sin_addr));
+}
+
/* Event handler for inet address addition/deletion events.
* Basically, whenever there is an event, we re-build our local address list.
*/
@@ -563,10 +626,10 @@
{
unsigned long flags;
- sctp_spin_lock_irqsave(&sctp_proto.local_addr_lock, flags);
- __sctp_free_local_addr_list(&sctp_proto);
- __sctp_get_local_addr_list(&sctp_proto);
- sctp_spin_unlock_irqrestore(&sctp_proto.local_addr_lock, flags);
+ sctp_spin_lock_irqsave(&sctp_local_addr_lock, flags);
+ __sctp_free_local_addr_list();
+ __sctp_get_local_addr_list();
+ sctp_spin_unlock_irqrestore(&sctp_local_addr_lock, flags);
return NOTIFY_DONE;
}
@@ -592,7 +655,7 @@
"SCTP: Failed to create the SCTP control socket.\n");
return err;
}
- sctp_ctl_socket->sk->allocation = GFP_ATOMIC;
+ sctp_ctl_socket->sk->sk_allocation = GFP_ATOMIC;
inet_sk(sctp_ctl_socket->sk)->ttl = MAXTTL;
return 0;
@@ -617,7 +680,7 @@
}
INIT_LIST_HEAD(&af->list);
- list_add_tail(&af->list, &sctp_proto.address_families);
+ list_add_tail(&af->list, &sctp_address_families);
return 1;
}
@@ -654,10 +717,13 @@
struct sockaddr_in *sin, *sinfrom;
if (msgname) {
+ struct sctp_association *asoc;
+
+ asoc = event->sndrcvinfo.sinfo_assoc_id;
sctp_inet_msgname(msgname, addr_len);
sin = (struct sockaddr_in *)msgname;
- sinfrom = &event->event_asoc->peer.primary_addr.v4;
- sin->sin_port = htons(event->event_asoc->peer.port);
+ sinfrom = &asoc->peer.primary_addr.v4;
+ sin->sin_port = htons(asoc->peer.port);
sin->sin_addr.s_addr = sinfrom->sin_addr.s_addr;
}
}
@@ -678,7 +744,7 @@
}
/* Do we support this AF? */
-static int sctp_inet_af_supported(sa_family_t family)
+static int sctp_inet_af_supported(sa_family_t family, struct sctp_opt *sp)
{
/* PF_INET only supports AF_INET addresses. */
return (AF_INET == family);
@@ -706,7 +772,7 @@
*/
static int sctp_inet_bind_verify(struct sctp_opt *opt, union sctp_addr *addr)
{
- return sctp_v4_available(addr);
+ return sctp_v4_available(addr, opt);
}
/* Verify that sockaddr looks sendable. Common verification has already
@@ -752,6 +818,7 @@
.send_verify = sctp_inet_send_verify,
.supported_addrs = sctp_inet_supported_addrs,
.create_accept_sk = sctp_v4_create_accept_sk,
+ .addr_v4map = sctp_v4_addr_v4map,
.af = &sctp_ipv4_specific,
};
@@ -821,6 +888,8 @@
.from_sk = sctp_v4_from_sk,
.to_sk_saddr = sctp_v4_to_sk_saddr,
.to_sk_daddr = sctp_v4_to_sk_daddr,
+ .from_addr_param= sctp_v4_from_addr_param,
+ .to_addr_param = sctp_v4_to_addr_param,
.dst_saddr = sctp_v4_dst_saddr,
.cmp_addr = sctp_v4_cmp_addr,
.addr_valid = sctp_v4_addr_valid,
@@ -829,6 +898,8 @@
.available = sctp_v4_available,
.scope = sctp_v4_scope,
.skb_iif = sctp_v4_skb_iif,
+ .is_ce = sctp_v4_is_ce,
+ .seq_dump_addr = sctp_v4_seq_dump_addr,
.net_header_len = sizeof(struct iphdr),
.sockaddr_len = sizeof(struct sockaddr_in),
.sa_family = AF_INET,
@@ -873,6 +944,7 @@
static void cleanup_sctp_mibs(void)
{
+ return;
}
/* Initialize the universe into something sensible. */
@@ -880,6 +952,8 @@
{
int i;
int status = 0;
+ unsigned long goal;
+ int order;
/* SCTP_DEBUG sanity check. */
if (!sctp_sanity_check())
@@ -892,6 +966,14 @@
inet_register_protosw(&sctp_seqpacket_protosw);
inet_register_protosw(&sctp_stream_protosw);
+ /* Allocate cache pools. */
+ 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. */
status = init_sctp_mibs();
if (status)
@@ -910,91 +992,116 @@
*/
/* The following protocol parameters are RECOMMENDED: */
/* RTO.Initial - 3 seconds */
- sctp_proto.rto_initial = SCTP_RTO_INITIAL;
+ sctp_rto_initial = SCTP_RTO_INITIAL;
/* RTO.Min - 1 second */
- sctp_proto.rto_min = SCTP_RTO_MIN;
+ sctp_rto_min = SCTP_RTO_MIN;
/* RTO.Max - 60 seconds */
- sctp_proto.rto_max = SCTP_RTO_MAX;
+ sctp_rto_max = SCTP_RTO_MAX;
/* RTO.Alpha - 1/8 */
- sctp_proto.rto_alpha = SCTP_RTO_ALPHA;
+ sctp_rto_alpha = SCTP_RTO_ALPHA;
/* RTO.Beta - 1/4 */
- sctp_proto.rto_beta = SCTP_RTO_BETA;
-
+ sctp_rto_beta = SCTP_RTO_BETA;
/* 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) */
- sctp_proto.cookie_preserve_enable = 1;
+ sctp_cookie_preserve_enable = 1;
/* Max.Burst - 4 */
- sctp_proto.max_burst = SCTP_MAX_BURST;
+ sctp_max_burst = SCTP_MAX_BURST;
/* Association.Max.Retrans - 10 attempts
* Path.Max.Retrans - 5 attempts (per destination address)
* Max.Init.Retransmits - 8 attempts
*/
- sctp_proto.max_retrans_association = 10;
- sctp_proto.max_retrans_path = 5;
- sctp_proto.max_retrans_init = 8;
+ sctp_max_retrans_association = 10;
+ sctp_max_retrans_path = 5;
+ sctp_max_retrans_init = 8;
/* HB.interval - 30 seconds */
- sctp_proto.hb_interval = 30 * HZ;
+ sctp_hb_interval = 30 * HZ;
/* Implementation specific variables. */
/* Initialize default stream count setup information. */
- sctp_proto.max_instreams = SCTP_DEFAULT_INSTREAMS;
- sctp_proto.max_outstreams = SCTP_DEFAULT_OUTSTREAMS;
+ sctp_max_instreams = SCTP_DEFAULT_INSTREAMS;
+ sctp_max_outstreams = SCTP_DEFAULT_OUTSTREAMS;
- /* Allocate and initialize the association hash table. */
- sctp_proto.assoc_hashsize = 4096;
- sctp_proto.assoc_hashbucket = (sctp_hashbucket_t *)
- kmalloc(4096 * sizeof(sctp_hashbucket_t), GFP_KERNEL);
- if (!sctp_proto.assoc_hashbucket) {
+ /* Size and allocate the association hash table.
+ * The methodology is similar to that of the tcp hash tables.
+ */
+ if (num_physpages >= (128 * 1024))
+ goal = num_physpages >> (22 - PAGE_SHIFT);
+ else
+ goal = num_physpages >> (24 - PAGE_SHIFT);
+
+ for (order = 0; (1UL << order) < goal; order++)
+ ;
+
+ do {
+ sctp_assoc_hashsize = (1UL << order) * PAGE_SIZE /
+ sizeof(struct sctp_hashbucket);
+ if ((sctp_assoc_hashsize > (64 * 1024)) && order > 0)
+ continue;
+ sctp_assoc_hashtable = (struct sctp_hashbucket *)
+ __get_free_pages(GFP_ATOMIC, order);
+ } while (!sctp_assoc_hashtable && --order > 0);
+ if (!sctp_assoc_hashtable) {
printk(KERN_ERR "SCTP: Failed association hash alloc.\n");
status = -ENOMEM;
goto err_ahash_alloc;
}
- for (i = 0; i < sctp_proto.assoc_hashsize; i++) {
- sctp_proto.assoc_hashbucket[i].lock = RW_LOCK_UNLOCKED;
- sctp_proto.assoc_hashbucket[i].chain = NULL;
+ for (i = 0; i < sctp_assoc_hashsize; i++) {
+ sctp_assoc_hashtable[i].lock = RW_LOCK_UNLOCKED;
+ sctp_assoc_hashtable[i].chain = NULL;
}
/* Allocate and initialize the endpoint hash table. */
- sctp_proto.ep_hashsize = 64;
- sctp_proto.ep_hashbucket = (sctp_hashbucket_t *)
- kmalloc(64 * sizeof(sctp_hashbucket_t), GFP_KERNEL);
- if (!sctp_proto.ep_hashbucket) {
+ sctp_ep_hashsize = 64;
+ sctp_ep_hashtable = (struct sctp_hashbucket *)
+ kmalloc(64 * sizeof(struct sctp_hashbucket), GFP_KERNEL);
+ if (!sctp_ep_hashtable) {
printk(KERN_ERR "SCTP: Failed endpoint_hash alloc.\n");
status = -ENOMEM;
goto err_ehash_alloc;
}
-
- for (i = 0; i < sctp_proto.ep_hashsize; i++) {
- sctp_proto.ep_hashbucket[i].lock = RW_LOCK_UNLOCKED;
- sctp_proto.ep_hashbucket[i].chain = NULL;
+ for (i = 0; i < sctp_ep_hashsize; i++) {
+ sctp_ep_hashtable[i].lock = RW_LOCK_UNLOCKED;
+ sctp_ep_hashtable[i].chain = NULL;
}
/* Allocate and initialize the SCTP port hash table. */
- sctp_proto.port_hashsize = 4096;
- sctp_proto.port_hashtable = (sctp_bind_hashbucket_t *)
- kmalloc(4096 * sizeof(sctp_bind_hashbucket_t), GFP_KERNEL);
- if (!sctp_proto.port_hashtable) {
+ do {
+ sctp_port_hashsize = (1UL << order) * PAGE_SIZE /
+ sizeof(struct sctp_bind_hashbucket);
+ if ((sctp_port_hashsize > (64 * 1024)) && order > 0)
+ continue;
+ sctp_port_hashtable = (struct sctp_bind_hashbucket *)
+ __get_free_pages(GFP_ATOMIC, order);
+ } while (!sctp_port_hashtable && --order > 0);
+ if (!sctp_port_hashtable) {
printk(KERN_ERR "SCTP: Failed bind hash alloc.");
status = -ENOMEM;
goto err_bhash_alloc;
}
-
- sctp_proto.port_alloc_lock = SPIN_LOCK_UNLOCKED;
- sctp_proto.port_rover = sysctl_local_port_range[0] - 1;
- for (i = 0; i < sctp_proto.port_hashsize; i++) {
- sctp_proto.port_hashtable[i].lock = SPIN_LOCK_UNLOCKED;
- sctp_proto.port_hashtable[i].chain = NULL;
+ for (i = 0; i < sctp_port_hashsize; i++) {
+ sctp_port_hashtable[i].lock = SPIN_LOCK_UNLOCKED;
+ sctp_port_hashtable[i].chain = NULL;
}
+ sctp_port_alloc_lock = SPIN_LOCK_UNLOCKED;
+ sctp_port_rover = sysctl_local_port_range[0] - 1;
+
+ printk(KERN_INFO "SCTP: Hash tables configured "
+ "(established %d bind %d)\n",
+ sctp_assoc_hashsize, sctp_port_hashsize);
+
+ /* Disable ADDIP by default. */
+ sctp_addip_enable = 0;
+
sctp_sysctl_register();
- INIT_LIST_HEAD(&sctp_proto.address_families);
+ INIT_LIST_HEAD(&sctp_address_families);
sctp_register_af(&sctp_ipv4_specific);
status = sctp_v6_init();
@@ -1009,13 +1116,13 @@
}
/* Initialize the local address list. */
- INIT_LIST_HEAD(&sctp_proto.local_addr_list);
- sctp_proto.local_addr_lock = SPIN_LOCK_UNLOCKED;
+ INIT_LIST_HEAD(&sctp_local_addr_list);
+ sctp_local_addr_lock = SPIN_LOCK_UNLOCKED;
/* Register notifier for inet address additions/deletions. */
register_inetaddr_notifier(&sctp_inetaddr_notifier);
- sctp_get_local_addr_list(&sctp_proto);
+ sctp_get_local_addr_list();
__unsafe(THIS_MODULE);
return 0;
@@ -1025,16 +1132,22 @@
err_v6_init:
sctp_sysctl_unregister();
list_del(&sctp_ipv4_specific.list);
- kfree(sctp_proto.port_hashtable);
+ free_pages((unsigned long)sctp_port_hashtable,
+ get_order(sctp_port_hashsize *
+ sizeof(struct sctp_bind_hashbucket)));
err_bhash_alloc:
- kfree(sctp_proto.ep_hashbucket);
+ kfree(sctp_ep_hashtable);
err_ehash_alloc:
- kfree(sctp_proto.assoc_hashbucket);
+ free_pages((unsigned long)sctp_assoc_hashtable,
+ get_order(sctp_assoc_hashsize *
+ sizeof(struct sctp_hashbucket)));
err_ahash_alloc:
sctp_dbg_objcnt_exit();
sctp_proc_exit();
cleanup_sctp_mibs();
err_init_mibs:
+ kmem_cache_destroy(sctp_chunk_cachep);
+err_chunk_cachep:
inet_del_protocol(&sctp_protocol);
inet_unregister_protosw(&sctp_seqpacket_protosw);
inet_unregister_protosw(&sctp_stream_protosw);
@@ -1052,7 +1165,7 @@
unregister_inetaddr_notifier(&sctp_inetaddr_notifier);
/* Free the local address list. */
- sctp_free_local_addr_list(&sctp_proto);
+ sctp_free_local_addr_list();
/* Free the control endpoint. */
sock_release(sctp_ctl_socket);
@@ -1061,9 +1174,15 @@
sctp_sysctl_unregister();
list_del(&sctp_ipv4_specific.list);
- kfree(sctp_proto.assoc_hashbucket);
- kfree(sctp_proto.ep_hashbucket);
- kfree(sctp_proto.port_hashtable);
+ free_pages((unsigned long)sctp_assoc_hashtable,
+ get_order(sctp_assoc_hashsize *
+ sizeof(struct sctp_hashbucket)));
+ kfree(sctp_ep_hashtable);
+ free_pages((unsigned long)sctp_port_hashtable,
+ get_order(sctp_port_hashsize *
+ sizeof(struct sctp_bind_hashbucket)));
+
+ kmem_cache_destroy(sctp_chunk_cachep);
sctp_dbg_objcnt_exit();
sctp_proc_exit();
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)