|
@@ -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
|
|
|
* 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 list_head *pos;
|
|
|
struct sctp_af *af;
|
|
|
|
|
|
rcu_read_lock();
|
|
|
- for_each_netdev_rcu(&init_net, dev) {
|
|
|
+ for_each_netdev_rcu(net, dev) {
|
|
|
__list_for_each(pos, &sctp_address_families) {
|
|
|
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();
|
|
|
}
|
|
|
|
|
|
/* 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 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);
|
|
|
list_del(pos);
|
|
|
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'. */
|
|
|
-int sctp_copy_local_addr_list(struct sctp_bind_addr *bp, sctp_scope_t scope,
|
|
|
- gfp_t gfp, int copy_flags)
|
|
|
+int sctp_copy_local_addr_list(struct net *net, struct sctp_bind_addr *bp,
|
|
|
+ sctp_scope_t scope, gfp_t gfp, int copy_flags)
|
|
|
{
|
|
|
struct sctp_sockaddr_entry *addr;
|
|
|
int error = 0;
|
|
|
|
|
|
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)
|
|
|
continue;
|
|
|
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)
|
|
|
{
|
|
|
+ struct net *net = (struct net *)arg;
|
|
|
struct sctp_sockaddr_entry *addrw, *temp;
|
|
|
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 ",
|
|
|
- " 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);
|
|
|
|
|
|
#if IS_ENABLED(CONFIG_IPV6)
|
|
@@ -648,7 +649,7 @@ void sctp_addr_wq_timeout_handler(unsigned long arg)
|
|
|
goto free_next;
|
|
|
|
|
|
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) {
|
|
|
unsigned long timeo_val;
|
|
|
|
|
@@ -656,12 +657,12 @@ void sctp_addr_wq_timeout_handler(unsigned long arg)
|
|
|
SCTP_ADDRESS_TICK_DELAY);
|
|
|
timeo_val = jiffies;
|
|
|
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;
|
|
|
}
|
|
|
}
|
|
|
#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;
|
|
|
|
|
|
sk = sctp_opt2sk(sp);
|
|
@@ -679,31 +680,32 @@ free_next:
|
|
|
list_del(&addrw->list);
|
|
|
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 *temp;
|
|
|
|
|
|
- spin_lock_bh(&sctp_addr_wq_lock);
|
|
|
- del_timer(&sctp_addr_wq_timer);
|
|
|
- list_for_each_entry_safe(addrw, temp, &sctp_addr_waitq, list) {
|
|
|
+ spin_lock_bh(&net->sctp.addr_wq_lock);
|
|
|
+ del_timer(&net->sctp.addr_wq_timer);
|
|
|
+ list_for_each_entry_safe(addrw, temp, &net->sctp.addr_waitq, list) {
|
|
|
list_del(&addrw->list);
|
|
|
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
|
|
|
* 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;
|
|
|
|
|
|
- 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)
|
|
|
continue;
|
|
|
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;
|
|
|
}
|
|
|
|
|
|
-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;
|
|
|
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
|
|
|
*/
|
|
|
|
|
|
- spin_lock_bh(&sctp_addr_wq_lock);
|
|
|
+ spin_lock_bh(&net->sctp.addr_wq_lock);
|
|
|
/* Offsets existing events in addr_wq */
|
|
|
- addrw = sctp_addr_wq_lookup(addr);
|
|
|
+ addrw = sctp_addr_wq_lookup(net, addr);
|
|
|
if (addrw) {
|
|
|
if (addrw->state != cmd) {
|
|
|
SCTP_DEBUG_PRINTK_IPADDR("sctp_addr_wq_mgmt offsets existing entry for %d ",
|
|
|
" in wq %p\n", addrw->state, &addrw->a,
|
|
|
- &sctp_addr_waitq);
|
|
|
+ &net->sctp.addr_waitq);
|
|
|
list_del(&addrw->list);
|
|
|
kfree(addrw);
|
|
|
}
|
|
|
- spin_unlock_bh(&sctp_addr_wq_lock);
|
|
|
+ spin_unlock_bh(&net->sctp.addr_wq_lock);
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
/* OK, we have to add the new address to the wait queue */
|
|
|
addrw = kmemdup(addr, sizeof(struct sctp_sockaddr_entry), GFP_ATOMIC);
|
|
|
if (addrw == NULL) {
|
|
|
- spin_unlock_bh(&sctp_addr_wq_lock);
|
|
|
+ spin_unlock_bh(&net->sctp.addr_wq_lock);
|
|
|
return;
|
|
|
}
|
|
|
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 ",
|
|
|
- " 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 += 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.
|
|
@@ -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 sctp_sockaddr_entry *addr = NULL;
|
|
|
struct sctp_sockaddr_entry *temp;
|
|
|
+ struct net *net = dev_net(ifa->ifa_dev->dev);
|
|
|
int found = 0;
|
|
|
|
|
|
- if (!net_eq(dev_net(ifa->ifa_dev->dev), &init_net))
|
|
|
- return NOTIFY_DONE;
|
|
|
-
|
|
|
switch (ev) {
|
|
|
case NETDEV_UP:
|
|
|
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_addr.s_addr = ifa->ifa_local;
|
|
|
addr->valid = 1;
|
|
|
- spin_lock_bh(&sctp_local_addr_lock);
|
|
|
- list_add_tail_rcu(&addr->list, &sctp_local_addr_list);
|
|
|
- sctp_addr_wq_mgmt(addr, SCTP_ADDR_NEW);
|
|
|
- spin_unlock_bh(&sctp_local_addr_lock);
|
|
|
+ spin_lock_bh(&net->sctp.local_addr_lock);
|
|
|
+ list_add_tail_rcu(&addr->list, &net->sctp.local_addr_list);
|
|
|
+ sctp_addr_wq_mgmt(net, addr, SCTP_ADDR_NEW);
|
|
|
+ spin_unlock_bh(&net->sctp.local_addr_lock);
|
|
|
}
|
|
|
break;
|
|
|
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,
|
|
|
- &sctp_local_addr_list, list) {
|
|
|
+ &net->sctp.local_addr_list, list) {
|
|
|
if (addr->a.sa.sa_family == AF_INET &&
|
|
|
addr->a.v4.sin_addr.s_addr ==
|
|
|
ifa->ifa_local) {
|
|
|
- sctp_addr_wq_mgmt(addr, SCTP_ADDR_DEL);
|
|
|
+ sctp_addr_wq_mgmt(net, addr, SCTP_ADDR_DEL);
|
|
|
found = 1;
|
|
|
addr->valid = 0;
|
|
|
list_del_rcu(&addr->list);
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
- spin_unlock_bh(&sctp_local_addr_lock);
|
|
|
+ spin_unlock_bh(&net->sctp.local_addr_lock);
|
|
|
if (found)
|
|
|
kfree_rcu(addr, rcu);
|
|
|
break;
|
|
@@ -1194,6 +1194,36 @@ static void sctp_v4_del_protocol(void)
|
|
|
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. */
|
|
|
SCTP_STATIC __init int sctp_init(void)
|
|
|
{
|
|
@@ -1399,18 +1429,6 @@ SCTP_STATIC __init int sctp_init(void)
|
|
|
sctp_v4_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();
|
|
|
|
|
|
if (status)
|
|
@@ -1426,6 +1444,10 @@ SCTP_STATIC __init int sctp_init(void)
|
|
|
goto err_ctl_sock_init;
|
|
|
}
|
|
|
|
|
|
+ status = register_pernet_subsys(&sctp_net_ops);
|
|
|
+ if (status)
|
|
|
+ goto err_register_pernet_subsys;
|
|
|
+
|
|
|
status = sctp_v4_add_protocol();
|
|
|
if (status)
|
|
|
goto err_add_protocol;
|
|
@@ -1441,13 +1463,14 @@ out:
|
|
|
err_v6_add_protocol:
|
|
|
sctp_v4_del_protocol();
|
|
|
err_add_protocol:
|
|
|
+ unregister_pernet_subsys(&sctp_net_ops);
|
|
|
+err_register_pernet_subsys:
|
|
|
inet_ctl_sock_destroy(sctp_ctl_sock);
|
|
|
err_ctl_sock_init:
|
|
|
sctp_v6_protosw_exit();
|
|
|
err_v6_protosw_init:
|
|
|
sctp_v4_protosw_exit();
|
|
|
err_protosw_init:
|
|
|
- sctp_free_local_addr_list();
|
|
|
sctp_v4_pf_exit();
|
|
|
sctp_v6_pf_exit();
|
|
|
sctp_sysctl_unregister();
|
|
@@ -1482,18 +1505,16 @@ SCTP_STATIC __exit void sctp_exit(void)
|
|
|
/* Unregister with inet6/inet layers. */
|
|
|
sctp_v6_del_protocol();
|
|
|
sctp_v4_del_protocol();
|
|
|
- sctp_free_addr_wq();
|
|
|
|
|
|
/* Free the control endpoint. */
|
|
|
inet_ctl_sock_destroy(sctp_ctl_sock);
|
|
|
|
|
|
+ unregister_pernet_subsys(&sctp_net_ops);
|
|
|
+
|
|
|
/* Free protosw registrations */
|
|
|
sctp_v6_protosw_exit();
|
|
|
sctp_v4_protosw_exit();
|
|
|
|
|
|
- /* Free the local address list. */
|
|
|
- sctp_free_local_addr_list();
|
|
|
-
|
|
|
/* Unregister with socket layer. */
|
|
|
sctp_v6_pf_exit();
|
|
|
sctp_v4_pf_exit();
|