sctp: Make the address lists per network namespace

- Move the address lists into struct net
- Add per network namespace initialization and cleanup
- Pass around struct net so it is everywhere I need it.
- Rename all of the global variable references into references
  to the variables moved into struct net

Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
Acked-by: Vlad Yasevich <vyasevich@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Eric W. Biederman 2012-08-06 08:42:04 +00:00 committed by David S. Miller
parent 4110cc255d
commit 4db67e8086
9 changed files with 132 additions and 103 deletions

View file

@ -15,6 +15,7 @@
#include <net/netns/packet.h> #include <net/netns/packet.h>
#include <net/netns/ipv4.h> #include <net/netns/ipv4.h>
#include <net/netns/ipv6.h> #include <net/netns/ipv6.h>
#include <net/netns/sctp.h>
#include <net/netns/dccp.h> #include <net/netns/dccp.h>
#include <net/netns/x_tables.h> #include <net/netns/x_tables.h>
#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE) #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE)
@ -81,6 +82,9 @@ struct net {
#if IS_ENABLED(CONFIG_IPV6) #if IS_ENABLED(CONFIG_IPV6)
struct netns_ipv6 ipv6; struct netns_ipv6 ipv6;
#endif #endif
#if defined(CONFIG_IP_SCTP) || defined(CONFIG_IP_SCTP_MODULE)
struct netns_sctp sctp;
#endif
#if defined(CONFIG_IP_DCCP) || defined(CONFIG_IP_DCCP_MODULE) #if defined(CONFIG_IP_DCCP) || defined(CONFIG_IP_DCCP_MODULE)
struct netns_dccp dccp; struct netns_dccp dccp;
#endif #endif

21
include/net/netns/sctp.h Normal file
View file

@ -0,0 +1,21 @@
#ifndef __NETNS_SCTP_H__
#define __NETNS_SCTP_H__
struct netns_sctp {
/* This is the global local address list.
* We actively maintain this complete list of addresses on
* the system by catching address add/delete events.
*
* It is a list of sctp_sockaddr_entry.
*/
struct list_head local_addr_list;
struct list_head addr_waitq;
struct timer_list addr_wq_timer;
struct list_head auto_asconf_splist;
spinlock_t addr_wq_lock;
/* Lock that protects the local_addr_list writers */
spinlock_t local_addr_lock;
};
#endif /* __NETNS_SCTP_H__ */

View file

@ -115,12 +115,12 @@
* sctp/protocol.c * sctp/protocol.c
*/ */
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_bind_addr *, extern int sctp_copy_local_addr_list(struct net *, struct sctp_bind_addr *,
sctp_scope_t, gfp_t gfp, sctp_scope_t, gfp_t gfp,
int flags); 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);
extern void sctp_addr_wq_mgmt(struct sctp_sockaddr_entry *, int); extern void sctp_addr_wq_mgmt(struct net *, struct sctp_sockaddr_entry *, int);
/* /*
* sctp/socket.c * sctp/socket.c

View file

@ -205,21 +205,7 @@ extern struct sctp_globals {
int port_hashsize; int port_hashsize;
struct sctp_bind_hashbucket *port_hashtable; struct sctp_bind_hashbucket *port_hashtable;
/* This is the global local address list.
* We actively maintain this complete list of addresses on
* the system by catching address add/delete events.
*
* It is a list of sctp_sockaddr_entry.
*/
struct list_head local_addr_list;
int default_auto_asconf; int default_auto_asconf;
struct list_head addr_waitq;
struct timer_list addr_wq_timer;
struct list_head auto_asconf_splist;
spinlock_t addr_wq_lock;
/* Lock that protects the local_addr_list writers */
spinlock_t addr_list_lock;
/* Flag to indicate if addip is enabled. */ /* Flag to indicate if addip is enabled. */
int addip_enable; int addip_enable;
@ -278,12 +264,6 @@ extern struct sctp_globals {
#define sctp_assoc_hashtable (sctp_globals.assoc_hashtable) #define sctp_assoc_hashtable (sctp_globals.assoc_hashtable)
#define sctp_port_hashsize (sctp_globals.port_hashsize) #define sctp_port_hashsize (sctp_globals.port_hashsize)
#define sctp_port_hashtable (sctp_globals.port_hashtable) #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.addr_list_lock)
#define sctp_auto_asconf_splist (sctp_globals.auto_asconf_splist)
#define sctp_addr_waitq (sctp_globals.addr_waitq)
#define sctp_addr_wq_timer (sctp_globals.addr_wq_timer)
#define sctp_addr_wq_lock (sctp_globals.addr_wq_lock)
#define sctp_default_auto_asconf (sctp_globals.default_auto_asconf) #define sctp_default_auto_asconf (sctp_globals.default_auto_asconf)
#define sctp_scope_policy (sctp_globals.ipv4_scope_policy) #define sctp_scope_policy (sctp_globals.ipv4_scope_policy)
#define sctp_addip_enable (sctp_globals.addip_enable) #define sctp_addip_enable (sctp_globals.addip_enable)
@ -1241,7 +1221,7 @@ struct sctp_bind_addr {
void sctp_bind_addr_init(struct sctp_bind_addr *, __u16 port); void sctp_bind_addr_init(struct sctp_bind_addr *, __u16 port);
void sctp_bind_addr_free(struct sctp_bind_addr *); void sctp_bind_addr_free(struct sctp_bind_addr *);
int sctp_bind_addr_copy(struct sctp_bind_addr *dest, int sctp_bind_addr_copy(struct net *net, struct sctp_bind_addr *dest,
const struct sctp_bind_addr *src, const struct sctp_bind_addr *src,
sctp_scope_t scope, gfp_t gfp, sctp_scope_t scope, gfp_t gfp,
int flags); int flags);

View file

@ -1544,7 +1544,8 @@ int sctp_assoc_set_bind_addr_from_ep(struct sctp_association *asoc,
if (asoc->peer.ipv6_address) if (asoc->peer.ipv6_address)
flags |= SCTP_ADDR6_PEERSUPP; flags |= SCTP_ADDR6_PEERSUPP;
return sctp_bind_addr_copy(&asoc->base.bind_addr, return sctp_bind_addr_copy(sock_net(asoc->base.sk),
&asoc->base.bind_addr,
&asoc->ep->base.bind_addr, &asoc->ep->base.bind_addr,
scope, gfp, flags); scope, gfp, flags);
} }

View file

@ -52,8 +52,8 @@
#include <net/sctp/sm.h> #include <net/sctp/sm.h>
/* Forward declarations for internal helpers. */ /* Forward declarations for internal helpers. */
static int sctp_copy_one_addr(struct sctp_bind_addr *, union sctp_addr *, static int sctp_copy_one_addr(struct net *, struct sctp_bind_addr *,
sctp_scope_t scope, gfp_t gfp, union sctp_addr *, sctp_scope_t scope, gfp_t gfp,
int flags); int flags);
static void sctp_bind_addr_clean(struct sctp_bind_addr *); static void sctp_bind_addr_clean(struct sctp_bind_addr *);
@ -62,7 +62,7 @@ static void sctp_bind_addr_clean(struct sctp_bind_addr *);
/* Copy 'src' to 'dest' taking 'scope' into account. Omit addresses /* Copy 'src' to 'dest' taking 'scope' into account. Omit addresses
* in 'src' which have a broader scope than 'scope'. * in 'src' which have a broader scope than 'scope'.
*/ */
int sctp_bind_addr_copy(struct sctp_bind_addr *dest, int sctp_bind_addr_copy(struct net *net, struct sctp_bind_addr *dest,
const struct sctp_bind_addr *src, const struct sctp_bind_addr *src,
sctp_scope_t scope, gfp_t gfp, sctp_scope_t scope, gfp_t gfp,
int flags) int flags)
@ -75,7 +75,7 @@ int sctp_bind_addr_copy(struct sctp_bind_addr *dest,
/* Extract the addresses which are relevant for this scope. */ /* Extract the addresses which are relevant for this scope. */
list_for_each_entry(addr, &src->address_list, list) { list_for_each_entry(addr, &src->address_list, list) {
error = sctp_copy_one_addr(dest, &addr->a, scope, error = sctp_copy_one_addr(net, dest, &addr->a, scope,
gfp, flags); gfp, flags);
if (error < 0) if (error < 0)
goto out; goto out;
@ -87,7 +87,7 @@ int sctp_bind_addr_copy(struct sctp_bind_addr *dest,
*/ */
if (list_empty(&dest->address_list) && (SCTP_SCOPE_GLOBAL == scope)) { if (list_empty(&dest->address_list) && (SCTP_SCOPE_GLOBAL == scope)) {
list_for_each_entry(addr, &src->address_list, list) { list_for_each_entry(addr, &src->address_list, list) {
error = sctp_copy_one_addr(dest, &addr->a, error = sctp_copy_one_addr(net, dest, &addr->a,
SCTP_SCOPE_LINK, gfp, SCTP_SCOPE_LINK, gfp,
flags); flags);
if (error < 0) if (error < 0)
@ -448,7 +448,7 @@ union sctp_addr *sctp_find_unmatch_addr(struct sctp_bind_addr *bp,
} }
/* Copy out addresses from the global local address list. */ /* Copy out addresses from the global local address list. */
static int sctp_copy_one_addr(struct sctp_bind_addr *dest, static int sctp_copy_one_addr(struct net *net, struct sctp_bind_addr *dest,
union sctp_addr *addr, union sctp_addr *addr,
sctp_scope_t scope, gfp_t gfp, sctp_scope_t scope, gfp_t gfp,
int flags) int flags)
@ -456,7 +456,7 @@ static int sctp_copy_one_addr(struct sctp_bind_addr *dest,
int error = 0; int error = 0;
if (sctp_is_any(NULL, addr)) { if (sctp_is_any(NULL, addr)) {
error = sctp_copy_local_addr_list(dest, scope, gfp, flags); error = sctp_copy_local_addr_list(net, dest, scope, 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

View file

@ -99,6 +99,7 @@ static int sctp_inet6addr_event(struct notifier_block *this, unsigned long ev,
struct inet6_ifaddr *ifa = (struct inet6_ifaddr *)ptr; struct inet6_ifaddr *ifa = (struct inet6_ifaddr *)ptr;
struct sctp_sockaddr_entry *addr = NULL; struct sctp_sockaddr_entry *addr = NULL;
struct sctp_sockaddr_entry *temp; struct sctp_sockaddr_entry *temp;
struct net *net = dev_net(ifa->idev->dev);
int found = 0; int found = 0;
switch (ev) { switch (ev) {
@ -110,27 +111,27 @@ static int sctp_inet6addr_event(struct notifier_block *this, unsigned long ev,
addr->a.v6.sin6_addr = ifa->addr; addr->a.v6.sin6_addr = ifa->addr;
addr->a.v6.sin6_scope_id = ifa->idev->dev->ifindex; addr->a.v6.sin6_scope_id = ifa->idev->dev->ifindex;
addr->valid = 1; addr->valid = 1;
spin_lock_bh(&sctp_local_addr_lock); spin_lock_bh(&net->sctp.local_addr_lock);
list_add_tail_rcu(&addr->list, &sctp_local_addr_list); list_add_tail_rcu(&addr->list, &net->sctp.local_addr_list);
sctp_addr_wq_mgmt(addr, SCTP_ADDR_NEW); sctp_addr_wq_mgmt(net, addr, SCTP_ADDR_NEW);
spin_unlock_bh(&sctp_local_addr_lock); spin_unlock_bh(&net->sctp.local_addr_lock);
} }
break; break;
case NETDEV_DOWN: case NETDEV_DOWN:
spin_lock_bh(&sctp_local_addr_lock); spin_lock_bh(&net->sctp.local_addr_lock);
list_for_each_entry_safe(addr, temp, list_for_each_entry_safe(addr, temp,
&sctp_local_addr_list, list) { &net->sctp.local_addr_list, list) {
if (addr->a.sa.sa_family == AF_INET6 && if (addr->a.sa.sa_family == AF_INET6 &&
ipv6_addr_equal(&addr->a.v6.sin6_addr, ipv6_addr_equal(&addr->a.v6.sin6_addr,
&ifa->addr)) { &ifa->addr)) {
sctp_addr_wq_mgmt(addr, SCTP_ADDR_DEL); sctp_addr_wq_mgmt(net, addr, SCTP_ADDR_DEL);
found = 1; found = 1;
addr->valid = 0; addr->valid = 0;
list_del_rcu(&addr->list); list_del_rcu(&addr->list);
break; break;
} }
} }
spin_unlock_bh(&sctp_local_addr_lock); spin_unlock_bh(&net->sctp.local_addr_lock);
if (found) if (found)
kfree_rcu(addr, rcu); kfree_rcu(addr, rcu);
break; break;

View file

@ -201,29 +201,29 @@ 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(void) static void sctp_get_local_addr_list(struct net *net)
{ {
struct net_device *dev; struct net_device *dev;
struct list_head *pos; struct list_head *pos;
struct sctp_af *af; struct sctp_af *af;
rcu_read_lock(); rcu_read_lock();
for_each_netdev_rcu(&init_net, dev) { for_each_netdev_rcu(net, dev) {
__list_for_each(pos, &sctp_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(&sctp_local_addr_list, dev); af->copy_addrlist(&net->sctp.local_addr_list, dev);
} }
} }
rcu_read_unlock(); rcu_read_unlock();
} }
/* Free the existing local addresses. */ /* Free the existing local addresses. */
static void sctp_free_local_addr_list(void) static void sctp_free_local_addr_list(struct net *net)
{ {
struct sctp_sockaddr_entry *addr; struct sctp_sockaddr_entry *addr;
struct list_head *pos, *temp; struct list_head *pos, *temp;
list_for_each_safe(pos, temp, &sctp_local_addr_list) { list_for_each_safe(pos, temp, &net->sctp.local_addr_list) {
addr = list_entry(pos, struct sctp_sockaddr_entry, list); addr = list_entry(pos, struct sctp_sockaddr_entry, list);
list_del(pos); list_del(pos);
kfree(addr); kfree(addr);
@ -231,14 +231,14 @@ static void sctp_free_local_addr_list(void)
} }
/* 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_bind_addr *bp, sctp_scope_t scope, int sctp_copy_local_addr_list(struct net *net, struct sctp_bind_addr *bp,
gfp_t gfp, int copy_flags) sctp_scope_t scope, gfp_t gfp, int copy_flags)
{ {
struct sctp_sockaddr_entry *addr; struct sctp_sockaddr_entry *addr;
int error = 0; int error = 0;
rcu_read_lock(); rcu_read_lock();
list_for_each_entry_rcu(addr, &sctp_local_addr_list, list) { list_for_each_entry_rcu(addr, &net->sctp.local_addr_list, list) {
if (!addr->valid) if (!addr->valid)
continue; continue;
if (sctp_in_scope(&addr->a, scope)) { if (sctp_in_scope(&addr->a, scope)) {
@ -627,14 +627,15 @@ static void sctp_v4_ecn_capable(struct sock *sk)
void sctp_addr_wq_timeout_handler(unsigned long arg) void sctp_addr_wq_timeout_handler(unsigned long arg)
{ {
struct net *net = (struct net *)arg;
struct sctp_sockaddr_entry *addrw, *temp; struct sctp_sockaddr_entry *addrw, *temp;
struct sctp_sock *sp; struct sctp_sock *sp;
spin_lock_bh(&sctp_addr_wq_lock); spin_lock_bh(&net->sctp.addr_wq_lock);
list_for_each_entry_safe(addrw, temp, &sctp_addr_waitq, list) { list_for_each_entry_safe(addrw, temp, &net->sctp.addr_waitq, list) {
SCTP_DEBUG_PRINTK_IPADDR("sctp_addrwq_timo_handler: the first ent in wq %p is ", SCTP_DEBUG_PRINTK_IPADDR("sctp_addrwq_timo_handler: the first ent in wq %p is ",
" for cmd %d at entry %p\n", &sctp_addr_waitq, &addrw->a, addrw->state, " for cmd %d at entry %p\n", &net->sctp.addr_waitq, &addrw->a, addrw->state,
addrw); addrw);
#if IS_ENABLED(CONFIG_IPV6) #if IS_ENABLED(CONFIG_IPV6)
@ -648,7 +649,7 @@ void sctp_addr_wq_timeout_handler(unsigned long arg)
goto free_next; goto free_next;
in6 = (struct in6_addr *)&addrw->a.v6.sin6_addr; in6 = (struct in6_addr *)&addrw->a.v6.sin6_addr;
if (ipv6_chk_addr(&init_net, in6, NULL, 0) == 0 && if (ipv6_chk_addr(net, in6, NULL, 0) == 0 &&
addrw->state == SCTP_ADDR_NEW) { addrw->state == SCTP_ADDR_NEW) {
unsigned long timeo_val; unsigned long timeo_val;
@ -656,12 +657,12 @@ void sctp_addr_wq_timeout_handler(unsigned long arg)
SCTP_ADDRESS_TICK_DELAY); SCTP_ADDRESS_TICK_DELAY);
timeo_val = jiffies; timeo_val = jiffies;
timeo_val += msecs_to_jiffies(SCTP_ADDRESS_TICK_DELAY); timeo_val += msecs_to_jiffies(SCTP_ADDRESS_TICK_DELAY);
mod_timer(&sctp_addr_wq_timer, timeo_val); mod_timer(&net->sctp.addr_wq_timer, timeo_val);
break; break;
} }
} }
#endif #endif
list_for_each_entry(sp, &sctp_auto_asconf_splist, auto_asconf_list) { list_for_each_entry(sp, &net->sctp.auto_asconf_splist, auto_asconf_list) {
struct sock *sk; struct sock *sk;
sk = sctp_opt2sk(sp); sk = sctp_opt2sk(sp);
@ -679,31 +680,32 @@ free_next:
list_del(&addrw->list); list_del(&addrw->list);
kfree(addrw); kfree(addrw);
} }
spin_unlock_bh(&sctp_addr_wq_lock); spin_unlock_bh(&net->sctp.addr_wq_lock);
} }
static void sctp_free_addr_wq(void) static void sctp_free_addr_wq(struct net *net)
{ {
struct sctp_sockaddr_entry *addrw; struct sctp_sockaddr_entry *addrw;
struct sctp_sockaddr_entry *temp; struct sctp_sockaddr_entry *temp;
spin_lock_bh(&sctp_addr_wq_lock); spin_lock_bh(&net->sctp.addr_wq_lock);
del_timer(&sctp_addr_wq_timer); del_timer(&net->sctp.addr_wq_timer);
list_for_each_entry_safe(addrw, temp, &sctp_addr_waitq, list) { list_for_each_entry_safe(addrw, temp, &net->sctp.addr_waitq, list) {
list_del(&addrw->list); list_del(&addrw->list);
kfree(addrw); kfree(addrw);
} }
spin_unlock_bh(&sctp_addr_wq_lock); spin_unlock_bh(&net->sctp.addr_wq_lock);
} }
/* lookup the entry for the same address in the addr_waitq /* lookup the entry for the same address in the addr_waitq
* sctp_addr_wq MUST be locked * sctp_addr_wq MUST be locked
*/ */
static struct sctp_sockaddr_entry *sctp_addr_wq_lookup(struct sctp_sockaddr_entry *addr) static struct sctp_sockaddr_entry *sctp_addr_wq_lookup(struct net *net,
struct sctp_sockaddr_entry *addr)
{ {
struct sctp_sockaddr_entry *addrw; struct sctp_sockaddr_entry *addrw;
list_for_each_entry(addrw, &sctp_addr_waitq, list) { list_for_each_entry(addrw, &net->sctp.addr_waitq, list) {
if (addrw->a.sa.sa_family != addr->a.sa.sa_family) if (addrw->a.sa.sa_family != addr->a.sa.sa_family)
continue; continue;
if (addrw->a.sa.sa_family == AF_INET) { if (addrw->a.sa.sa_family == AF_INET) {
@ -719,7 +721,7 @@ static struct sctp_sockaddr_entry *sctp_addr_wq_lookup(struct sctp_sockaddr_entr
return NULL; return NULL;
} }
void sctp_addr_wq_mgmt(struct sctp_sockaddr_entry *addr, int cmd) void sctp_addr_wq_mgmt(struct net *net, struct sctp_sockaddr_entry *addr, int cmd)
{ {
struct sctp_sockaddr_entry *addrw; struct sctp_sockaddr_entry *addrw;
unsigned long timeo_val; unsigned long timeo_val;
@ -730,38 +732,38 @@ void sctp_addr_wq_mgmt(struct sctp_sockaddr_entry *addr, int cmd)
* new address after a couple of addition and deletion of that address * new address after a couple of addition and deletion of that address
*/ */
spin_lock_bh(&sctp_addr_wq_lock); spin_lock_bh(&net->sctp.addr_wq_lock);
/* Offsets existing events in addr_wq */ /* Offsets existing events in addr_wq */
addrw = sctp_addr_wq_lookup(addr); addrw = sctp_addr_wq_lookup(net, addr);
if (addrw) { if (addrw) {
if (addrw->state != cmd) { if (addrw->state != cmd) {
SCTP_DEBUG_PRINTK_IPADDR("sctp_addr_wq_mgmt offsets existing entry for %d ", SCTP_DEBUG_PRINTK_IPADDR("sctp_addr_wq_mgmt offsets existing entry for %d ",
" in wq %p\n", addrw->state, &addrw->a, " in wq %p\n", addrw->state, &addrw->a,
&sctp_addr_waitq); &net->sctp.addr_waitq);
list_del(&addrw->list); list_del(&addrw->list);
kfree(addrw); kfree(addrw);
} }
spin_unlock_bh(&sctp_addr_wq_lock); spin_unlock_bh(&net->sctp.addr_wq_lock);
return; return;
} }
/* OK, we have to add the new address to the wait queue */ /* OK, we have to add the new address to the wait queue */
addrw = kmemdup(addr, sizeof(struct sctp_sockaddr_entry), GFP_ATOMIC); addrw = kmemdup(addr, sizeof(struct sctp_sockaddr_entry), GFP_ATOMIC);
if (addrw == NULL) { if (addrw == NULL) {
spin_unlock_bh(&sctp_addr_wq_lock); spin_unlock_bh(&net->sctp.addr_wq_lock);
return; return;
} }
addrw->state = cmd; addrw->state = cmd;
list_add_tail(&addrw->list, &sctp_addr_waitq); list_add_tail(&addrw->list, &net->sctp.addr_waitq);
SCTP_DEBUG_PRINTK_IPADDR("sctp_addr_wq_mgmt add new entry for cmd:%d ", SCTP_DEBUG_PRINTK_IPADDR("sctp_addr_wq_mgmt add new entry for cmd:%d ",
" in wq %p\n", addrw->state, &addrw->a, &sctp_addr_waitq); " in wq %p\n", addrw->state, &addrw->a, &net->sctp.addr_waitq);
if (!timer_pending(&sctp_addr_wq_timer)) { if (!timer_pending(&net->sctp.addr_wq_timer)) {
timeo_val = jiffies; timeo_val = jiffies;
timeo_val += msecs_to_jiffies(SCTP_ADDRESS_TICK_DELAY); timeo_val += msecs_to_jiffies(SCTP_ADDRESS_TICK_DELAY);
mod_timer(&sctp_addr_wq_timer, timeo_val); mod_timer(&net->sctp.addr_wq_timer, timeo_val);
} }
spin_unlock_bh(&sctp_addr_wq_lock); spin_unlock_bh(&net->sctp.addr_wq_lock);
} }
/* Event handler for inet address addition/deletion events. /* Event handler for inet address addition/deletion events.
@ -776,11 +778,9 @@ static int sctp_inetaddr_event(struct notifier_block *this, unsigned long ev,
struct in_ifaddr *ifa = (struct in_ifaddr *)ptr; struct in_ifaddr *ifa = (struct in_ifaddr *)ptr;
struct sctp_sockaddr_entry *addr = NULL; struct sctp_sockaddr_entry *addr = NULL;
struct sctp_sockaddr_entry *temp; struct sctp_sockaddr_entry *temp;
struct net *net = dev_net(ifa->ifa_dev->dev);
int found = 0; int found = 0;
if (!net_eq(dev_net(ifa->ifa_dev->dev), &init_net))
return NOTIFY_DONE;
switch (ev) { switch (ev) {
case NETDEV_UP: case NETDEV_UP:
addr = kmalloc(sizeof(struct sctp_sockaddr_entry), GFP_ATOMIC); addr = kmalloc(sizeof(struct sctp_sockaddr_entry), GFP_ATOMIC);
@ -789,27 +789,27 @@ static int sctp_inetaddr_event(struct notifier_block *this, unsigned long ev,
addr->a.v4.sin_port = 0; addr->a.v4.sin_port = 0;
addr->a.v4.sin_addr.s_addr = ifa->ifa_local; addr->a.v4.sin_addr.s_addr = ifa->ifa_local;
addr->valid = 1; addr->valid = 1;
spin_lock_bh(&sctp_local_addr_lock); spin_lock_bh(&net->sctp.local_addr_lock);
list_add_tail_rcu(&addr->list, &sctp_local_addr_list); list_add_tail_rcu(&addr->list, &net->sctp.local_addr_list);
sctp_addr_wq_mgmt(addr, SCTP_ADDR_NEW); sctp_addr_wq_mgmt(net, addr, SCTP_ADDR_NEW);
spin_unlock_bh(&sctp_local_addr_lock); spin_unlock_bh(&net->sctp.local_addr_lock);
} }
break; break;
case NETDEV_DOWN: case NETDEV_DOWN:
spin_lock_bh(&sctp_local_addr_lock); spin_lock_bh(&net->sctp.local_addr_lock);
list_for_each_entry_safe(addr, temp, list_for_each_entry_safe(addr, temp,
&sctp_local_addr_list, list) { &net->sctp.local_addr_list, list) {
if (addr->a.sa.sa_family == AF_INET && if (addr->a.sa.sa_family == AF_INET &&
addr->a.v4.sin_addr.s_addr == addr->a.v4.sin_addr.s_addr ==
ifa->ifa_local) { ifa->ifa_local) {
sctp_addr_wq_mgmt(addr, SCTP_ADDR_DEL); sctp_addr_wq_mgmt(net, addr, SCTP_ADDR_DEL);
found = 1; found = 1;
addr->valid = 0; addr->valid = 0;
list_del_rcu(&addr->list); list_del_rcu(&addr->list);
break; break;
} }
} }
spin_unlock_bh(&sctp_local_addr_lock); spin_unlock_bh(&net->sctp.local_addr_lock);
if (found) if (found)
kfree_rcu(addr, rcu); kfree_rcu(addr, rcu);
break; break;
@ -1194,6 +1194,36 @@ static void sctp_v4_del_protocol(void)
unregister_inetaddr_notifier(&sctp_inetaddr_notifier); unregister_inetaddr_notifier(&sctp_inetaddr_notifier);
} }
static int sctp_net_init(struct net *net)
{
/* Initialize the local address list. */
INIT_LIST_HEAD(&net->sctp.local_addr_list);
spin_lock_init(&net->sctp.local_addr_lock);
sctp_get_local_addr_list(net);
/* Initialize the address event list */
INIT_LIST_HEAD(&net->sctp.addr_waitq);
INIT_LIST_HEAD(&net->sctp.auto_asconf_splist);
spin_lock_init(&net->sctp.addr_wq_lock);
net->sctp.addr_wq_timer.expires = 0;
setup_timer(&net->sctp.addr_wq_timer, sctp_addr_wq_timeout_handler,
(unsigned long)net);
return 0;
}
static void sctp_net_exit(struct net *net)
{
/* Free the local address list */
sctp_free_addr_wq(net);
sctp_free_local_addr_list(net);
}
static struct pernet_operations sctp_net_ops = {
.init = sctp_net_init,
.exit = sctp_net_exit,
};
/* Initialize the universe into something sensible. */ /* Initialize the universe into something sensible. */
SCTP_STATIC __init int sctp_init(void) SCTP_STATIC __init int sctp_init(void)
{ {
@ -1399,18 +1429,6 @@ SCTP_STATIC __init int sctp_init(void)
sctp_v4_pf_init(); sctp_v4_pf_init();
sctp_v6_pf_init(); sctp_v6_pf_init();
/* Initialize the local address list. */
INIT_LIST_HEAD(&sctp_local_addr_list);
spin_lock_init(&sctp_local_addr_lock);
sctp_get_local_addr_list();
/* Initialize the address event list */
INIT_LIST_HEAD(&sctp_addr_waitq);
INIT_LIST_HEAD(&sctp_auto_asconf_splist);
spin_lock_init(&sctp_addr_wq_lock);
sctp_addr_wq_timer.expires = 0;
setup_timer(&sctp_addr_wq_timer, sctp_addr_wq_timeout_handler, 0);
status = sctp_v4_protosw_init(); status = sctp_v4_protosw_init();
if (status) if (status)
@ -1426,6 +1444,10 @@ SCTP_STATIC __init int sctp_init(void)
goto err_ctl_sock_init; goto err_ctl_sock_init;
} }
status = register_pernet_subsys(&sctp_net_ops);
if (status)
goto err_register_pernet_subsys;
status = sctp_v4_add_protocol(); status = sctp_v4_add_protocol();
if (status) if (status)
goto err_add_protocol; goto err_add_protocol;
@ -1441,13 +1463,14 @@ out:
err_v6_add_protocol: err_v6_add_protocol:
sctp_v4_del_protocol(); sctp_v4_del_protocol();
err_add_protocol: err_add_protocol:
unregister_pernet_subsys(&sctp_net_ops);
err_register_pernet_subsys:
inet_ctl_sock_destroy(sctp_ctl_sock); inet_ctl_sock_destroy(sctp_ctl_sock);
err_ctl_sock_init: err_ctl_sock_init:
sctp_v6_protosw_exit(); sctp_v6_protosw_exit();
err_v6_protosw_init: err_v6_protosw_init:
sctp_v4_protosw_exit(); sctp_v4_protosw_exit();
err_protosw_init: err_protosw_init:
sctp_free_local_addr_list();
sctp_v4_pf_exit(); sctp_v4_pf_exit();
sctp_v6_pf_exit(); sctp_v6_pf_exit();
sctp_sysctl_unregister(); sctp_sysctl_unregister();
@ -1482,18 +1505,16 @@ SCTP_STATIC __exit void sctp_exit(void)
/* Unregister with inet6/inet layers. */ /* Unregister with inet6/inet layers. */
sctp_v6_del_protocol(); sctp_v6_del_protocol();
sctp_v4_del_protocol(); sctp_v4_del_protocol();
sctp_free_addr_wq();
/* Free the control endpoint. */ /* Free the control endpoint. */
inet_ctl_sock_destroy(sctp_ctl_sock); inet_ctl_sock_destroy(sctp_ctl_sock);
unregister_pernet_subsys(&sctp_net_ops);
/* Free protosw registrations */ /* Free protosw registrations */
sctp_v6_protosw_exit(); sctp_v6_protosw_exit();
sctp_v4_protosw_exit(); sctp_v4_protosw_exit();
/* Free the local address list. */
sctp_free_local_addr_list();
/* Unregister with socket layer. */ /* Unregister with socket layer. */
sctp_v6_pf_exit(); sctp_v6_pf_exit();
sctp_v4_pf_exit(); sctp_v4_pf_exit();

View file

@ -3471,7 +3471,7 @@ static int sctp_setsockopt_auto_asconf(struct sock *sk, char __user *optval,
sp->do_auto_asconf = 0; sp->do_auto_asconf = 0;
} else if (val && !sp->do_auto_asconf) { } else if (val && !sp->do_auto_asconf) {
list_add_tail(&sp->auto_asconf_list, list_add_tail(&sp->auto_asconf_list,
&sctp_auto_asconf_splist); &sock_net(sk)->sctp.auto_asconf_splist);
sp->do_auto_asconf = 1; sp->do_auto_asconf = 1;
} }
return 0; return 0;
@ -3964,7 +3964,7 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk)
sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1); sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1);
if (sctp_default_auto_asconf) { if (sctp_default_auto_asconf) {
list_add_tail(&sp->auto_asconf_list, list_add_tail(&sp->auto_asconf_list,
&sctp_auto_asconf_splist); &sock_net(sk)->sctp.auto_asconf_splist);
sp->do_auto_asconf = 1; sp->do_auto_asconf = 1;
} else } else
sp->do_auto_asconf = 0; sp->do_auto_asconf = 0;
@ -4653,9 +4653,10 @@ static int sctp_copy_laddrs(struct sock *sk, __u16 port, void *to,
union sctp_addr temp; union sctp_addr temp;
int cnt = 0; int cnt = 0;
int addrlen; int addrlen;
struct net *net = sock_net(sk);
rcu_read_lock(); rcu_read_lock();
list_for_each_entry_rcu(addr, &sctp_local_addr_list, list) { list_for_each_entry_rcu(addr, &net->sctp.local_addr_list, list) {
if (!addr->valid) if (!addr->valid)
continue; continue;