/* SCTP kernel implementation
* (C) Copyright IBM Corp. 2001, 2004
* Copyright (c) 1999-2000 Cisco, Inc.
* Copyright (c) 1999-2001 Motorola, Inc.
* Copyright (c) 2001 Intel Corp.
* Copyright (c) 2001 Nokia, Inc.
* Copyright (c) 2001 La Monte H.P. Yarroll
*
* This file is part of the SCTP kernel implementation
*
* Initialization/cleanup for SCTP protocol support.
*
* This SCTP implementation is free software;
* you can redistribute it and/or modify it under the terms of
* the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This SCTP implementation is distributed in the hope that it
* will be useful, but WITHOUT ANY WARRANTY; without even the implied
* ************************
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU CC; see the file COPYING. If not, see
* <http://www.gnu.org/licenses/>.
*
* Please send any bug reports or fixes you make to the
* email address(es):
* lksctp developers <linux-sctp@vger.kernel.org>
*
* Written or modified by:
* La Monte H.P. Yarroll <piggy@acm.org>
* Karl Knutson <karl@athena.chicago.il.us>
* Jon Grimm <jgrimm@us.ibm.com>
* Sridhar Samudrala <sri@us.ibm.com>
* Daisy Chang <daisyc@us.ibm.com>
* Ardelle Fan <ardelle.fan@intel.com>
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/module.h>
#include <linux/init.h>
#include <linux/netdevice.h>
#include <linux/inetdevice.h>
#include <linux/seq_file.h>
#include <linux/bootmem.h>
#include <linux/highmem.h>
#include <linux/swap.h>
#include <linux/slab.h>
#include <net/net_namespace.h>
#include <net/protocol.h>
#include <net/ip.h>
#include <net/ipv6.h>
#include <net/route.h>
#include <net/sctp/sctp.h>
#include <net/addrconf.h>
#include <net/inet_common.h>
#include <net/inet_ecn.h>
#define MAX_SCTP_PORT_HASH_ENTRIES (64 * 1024)
/* Global data structures. */
struct sctp_globals sctp_globals __read_mostly;
struct idr sctp_assocs_id;
DEFINE_SPINLOCK(sctp_assocs_id_lock);
static struct sctp_pf *sctp_pf_inet6_specific;
static struct sctp_pf *sctp_pf_inet_specific;
static struct sctp_af *sctp_af_v4_specific;
static struct sctp_af *sctp_af_v6_specific;
struct kmem_cache *sctp_chunk_cachep __read_mostly;
struct kmem_cache *sctp_bucket_cachep __read_mostly;
long sysctl_sctp_mem[3];
int sysctl_sctp_rmem[3];
int sysctl_sctp_wmem[3];
/* Set up the proc fs entry for the SCTP protocol. */
static int __net_init sctp_proc_init(struct net *net)
{
#ifdef CONFIG_PROC_FS
net->sctp.proc_net_sctp = proc_net_mkdir(net, "sctp", net->proc_net);
if (!net->sctp.proc_net_sctp)
goto out_proc_net_sctp;
if (sctp_snmp_proc_init(net))
goto out_snmp_proc_init;
if (sctp_eps_proc_init(net))
goto out_eps_proc_init;
if (sctp_assocs_proc_init(net))
goto out_assocs_proc_init;
if (sctp_remaddr_proc_init(net))
goto out_remaddr_proc_init;
return 0;
out_remaddr_proc_init:
sctp_assocs_proc_exit(net);
out_assocs_proc_init:
sctp_eps_proc_exit(net);
out_eps_proc_init:
sctp_snmp_proc_exit(net);
out_snmp_proc_init:
remove_proc_entry("sctp", net->proc_net);
net->sctp.proc_net_sctp = NULL;
out_proc_net_sctp:
return -ENOMEM;
#endif /* CONFIG_PROC_FS */
return 0;
}
/* 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.
*/
static void sctp_proc_exit(struct net *net)
{
#ifdef CONFIG_PROC_FS
sctp_snmp_proc_exit(net);
sctp_eps_proc_exit(net);
sctp_assocs_proc_exit(net);
sctp_remaddr_proc_exit(net);
remove_proc_entry("sctp", net->proc_net);
net->sctp.proc_net_sctp = NULL;
#endif
}
/* Private helper to extract ipv4 address and stash them in
* the protocol structure.
*/
static void sctp_v4_copy_addrlist(struct list_head *addrlist,
struct net_device *dev)
{
struct in_device *in_dev;
struct in_ifaddr *ifa;
struct sctp_sockaddr_entry *addr;
rcu_read_lock();
if ((in_dev = __in_dev_get_rcu(dev)) == NULL) {
rcu_read_unlock();
return;
}
for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) {
/* Add the address to the local list. */
addr = kzalloc(sizeof(*addr), GFP_ATOMIC);
if (addr) {
addr->a.v4.sin_family = AF_INET;
addr->a.v4.sin_port = 0;
addr->a.v4.sin_addr.s_addr = ifa->ifa_local;
addr->valid = 1;
INIT_LIST_HEAD(&addr->list);
list_add_tail(&addr->list, addrlist);
}
}
rcu_read_unlock();
}
/* Extract our IP addresses f
|