diff options
Diffstat (limited to 'net/ipv6/mcast.c')
-rw-r--r-- | net/ipv6/mcast.c | 116 |
1 files changed, 78 insertions, 38 deletions
diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c index 197ca390a15d..f2879056fab0 100644 --- a/net/ipv6/mcast.c +++ b/net/ipv6/mcast.c | |||
@@ -126,8 +126,6 @@ static struct in6_addr mld2_all_mcr = MLD2_ALL_MCR_INIT; | |||
126 | /* Big mc list lock for all the sockets */ | 126 | /* Big mc list lock for all the sockets */ |
127 | static DEFINE_RWLOCK(ipv6_sk_mc_lock); | 127 | static DEFINE_RWLOCK(ipv6_sk_mc_lock); |
128 | 128 | ||
129 | static struct socket *igmp6_socket; | ||
130 | |||
131 | int __ipv6_dev_mc_dec(struct inet6_dev *idev, struct in6_addr *addr); | 129 | int __ipv6_dev_mc_dec(struct inet6_dev *idev, struct in6_addr *addr); |
132 | 130 | ||
133 | static void igmp6_join_group(struct ifmcaddr6 *ma); | 131 | static void igmp6_join_group(struct ifmcaddr6 *ma); |
@@ -183,6 +181,7 @@ int ipv6_sock_mc_join(struct sock *sk, int ifindex, struct in6_addr *addr) | |||
183 | struct net_device *dev = NULL; | 181 | struct net_device *dev = NULL; |
184 | struct ipv6_mc_socklist *mc_lst; | 182 | struct ipv6_mc_socklist *mc_lst; |
185 | struct ipv6_pinfo *np = inet6_sk(sk); | 183 | struct ipv6_pinfo *np = inet6_sk(sk); |
184 | struct net *net = sk->sk_net; | ||
186 | int err; | 185 | int err; |
187 | 186 | ||
188 | if (!ipv6_addr_is_multicast(addr)) | 187 | if (!ipv6_addr_is_multicast(addr)) |
@@ -208,14 +207,14 @@ int ipv6_sock_mc_join(struct sock *sk, int ifindex, struct in6_addr *addr) | |||
208 | 207 | ||
209 | if (ifindex == 0) { | 208 | if (ifindex == 0) { |
210 | struct rt6_info *rt; | 209 | struct rt6_info *rt; |
211 | rt = rt6_lookup(&init_net, addr, NULL, 0, 0); | 210 | rt = rt6_lookup(net, addr, NULL, 0, 0); |
212 | if (rt) { | 211 | if (rt) { |
213 | dev = rt->rt6i_dev; | 212 | dev = rt->rt6i_dev; |
214 | dev_hold(dev); | 213 | dev_hold(dev); |
215 | dst_release(&rt->u.dst); | 214 | dst_release(&rt->u.dst); |
216 | } | 215 | } |
217 | } else | 216 | } else |
218 | dev = dev_get_by_index(&init_net, ifindex); | 217 | dev = dev_get_by_index(net, ifindex); |
219 | 218 | ||
220 | if (dev == NULL) { | 219 | if (dev == NULL) { |
221 | sock_kfree_s(sk, mc_lst, sizeof(*mc_lst)); | 220 | sock_kfree_s(sk, mc_lst, sizeof(*mc_lst)); |
@@ -256,6 +255,7 @@ int ipv6_sock_mc_drop(struct sock *sk, int ifindex, struct in6_addr *addr) | |||
256 | { | 255 | { |
257 | struct ipv6_pinfo *np = inet6_sk(sk); | 256 | struct ipv6_pinfo *np = inet6_sk(sk); |
258 | struct ipv6_mc_socklist *mc_lst, **lnk; | 257 | struct ipv6_mc_socklist *mc_lst, **lnk; |
258 | struct net *net = sk->sk_net; | ||
259 | 259 | ||
260 | write_lock_bh(&ipv6_sk_mc_lock); | 260 | write_lock_bh(&ipv6_sk_mc_lock); |
261 | for (lnk = &np->ipv6_mc_list; (mc_lst = *lnk) !=NULL ; lnk = &mc_lst->next) { | 261 | for (lnk = &np->ipv6_mc_list; (mc_lst = *lnk) !=NULL ; lnk = &mc_lst->next) { |
@@ -266,7 +266,8 @@ int ipv6_sock_mc_drop(struct sock *sk, int ifindex, struct in6_addr *addr) | |||
266 | *lnk = mc_lst->next; | 266 | *lnk = mc_lst->next; |
267 | write_unlock_bh(&ipv6_sk_mc_lock); | 267 | write_unlock_bh(&ipv6_sk_mc_lock); |
268 | 268 | ||
269 | if ((dev = dev_get_by_index(&init_net, mc_lst->ifindex)) != NULL) { | 269 | dev = dev_get_by_index(net, mc_lst->ifindex); |
270 | if (dev != NULL) { | ||
270 | struct inet6_dev *idev = in6_dev_get(dev); | 271 | struct inet6_dev *idev = in6_dev_get(dev); |
271 | 272 | ||
272 | (void) ip6_mc_leave_src(sk, mc_lst, idev); | 273 | (void) ip6_mc_leave_src(sk, mc_lst, idev); |
@@ -286,7 +287,9 @@ int ipv6_sock_mc_drop(struct sock *sk, int ifindex, struct in6_addr *addr) | |||
286 | return -EADDRNOTAVAIL; | 287 | return -EADDRNOTAVAIL; |
287 | } | 288 | } |
288 | 289 | ||
289 | static struct inet6_dev *ip6_mc_find_dev(struct in6_addr *group, int ifindex) | 290 | static struct inet6_dev *ip6_mc_find_dev(struct net *net, |
291 | struct in6_addr *group, | ||
292 | int ifindex) | ||
290 | { | 293 | { |
291 | struct net_device *dev = NULL; | 294 | struct net_device *dev = NULL; |
292 | struct inet6_dev *idev = NULL; | 295 | struct inet6_dev *idev = NULL; |
@@ -294,14 +297,14 @@ static struct inet6_dev *ip6_mc_find_dev(struct in6_addr *group, int ifindex) | |||
294 | if (ifindex == 0) { | 297 | if (ifindex == 0) { |
295 | struct rt6_info *rt; | 298 | struct rt6_info *rt; |
296 | 299 | ||
297 | rt = rt6_lookup(&init_net, group, NULL, 0, 0); | 300 | rt = rt6_lookup(net, group, NULL, 0, 0); |
298 | if (rt) { | 301 | if (rt) { |
299 | dev = rt->rt6i_dev; | 302 | dev = rt->rt6i_dev; |
300 | dev_hold(dev); | 303 | dev_hold(dev); |
301 | dst_release(&rt->u.dst); | 304 | dst_release(&rt->u.dst); |
302 | } | 305 | } |
303 | } else | 306 | } else |
304 | dev = dev_get_by_index(&init_net, ifindex); | 307 | dev = dev_get_by_index(net, ifindex); |
305 | 308 | ||
306 | if (!dev) | 309 | if (!dev) |
307 | return NULL; | 310 | return NULL; |
@@ -324,6 +327,7 @@ void ipv6_sock_mc_close(struct sock *sk) | |||
324 | { | 327 | { |
325 | struct ipv6_pinfo *np = inet6_sk(sk); | 328 | struct ipv6_pinfo *np = inet6_sk(sk); |
326 | struct ipv6_mc_socklist *mc_lst; | 329 | struct ipv6_mc_socklist *mc_lst; |
330 | struct net *net = sk->sk_net; | ||
327 | 331 | ||
328 | write_lock_bh(&ipv6_sk_mc_lock); | 332 | write_lock_bh(&ipv6_sk_mc_lock); |
329 | while ((mc_lst = np->ipv6_mc_list) != NULL) { | 333 | while ((mc_lst = np->ipv6_mc_list) != NULL) { |
@@ -332,7 +336,7 @@ void ipv6_sock_mc_close(struct sock *sk) | |||
332 | np->ipv6_mc_list = mc_lst->next; | 336 | np->ipv6_mc_list = mc_lst->next; |
333 | write_unlock_bh(&ipv6_sk_mc_lock); | 337 | write_unlock_bh(&ipv6_sk_mc_lock); |
334 | 338 | ||
335 | dev = dev_get_by_index(&init_net, mc_lst->ifindex); | 339 | dev = dev_get_by_index(net, mc_lst->ifindex); |
336 | if (dev) { | 340 | if (dev) { |
337 | struct inet6_dev *idev = in6_dev_get(dev); | 341 | struct inet6_dev *idev = in6_dev_get(dev); |
338 | 342 | ||
@@ -361,6 +365,7 @@ int ip6_mc_source(int add, int omode, struct sock *sk, | |||
361 | struct inet6_dev *idev; | 365 | struct inet6_dev *idev; |
362 | struct ipv6_pinfo *inet6 = inet6_sk(sk); | 366 | struct ipv6_pinfo *inet6 = inet6_sk(sk); |
363 | struct ip6_sf_socklist *psl; | 367 | struct ip6_sf_socklist *psl; |
368 | struct net *net = sk->sk_net; | ||
364 | int i, j, rv; | 369 | int i, j, rv; |
365 | int leavegroup = 0; | 370 | int leavegroup = 0; |
366 | int pmclocked = 0; | 371 | int pmclocked = 0; |
@@ -376,7 +381,7 @@ int ip6_mc_source(int add, int omode, struct sock *sk, | |||
376 | if (!ipv6_addr_is_multicast(group)) | 381 | if (!ipv6_addr_is_multicast(group)) |
377 | return -EINVAL; | 382 | return -EINVAL; |
378 | 383 | ||
379 | idev = ip6_mc_find_dev(group, pgsr->gsr_interface); | 384 | idev = ip6_mc_find_dev(net, group, pgsr->gsr_interface); |
380 | if (!idev) | 385 | if (!idev) |
381 | return -ENODEV; | 386 | return -ENODEV; |
382 | dev = idev->dev; | 387 | dev = idev->dev; |
@@ -500,6 +505,7 @@ int ip6_mc_msfilter(struct sock *sk, struct group_filter *gsf) | |||
500 | struct inet6_dev *idev; | 505 | struct inet6_dev *idev; |
501 | struct ipv6_pinfo *inet6 = inet6_sk(sk); | 506 | struct ipv6_pinfo *inet6 = inet6_sk(sk); |
502 | struct ip6_sf_socklist *newpsl, *psl; | 507 | struct ip6_sf_socklist *newpsl, *psl; |
508 | struct net *net = sk->sk_net; | ||
503 | int leavegroup = 0; | 509 | int leavegroup = 0; |
504 | int i, err; | 510 | int i, err; |
505 | 511 | ||
@@ -511,7 +517,7 @@ int ip6_mc_msfilter(struct sock *sk, struct group_filter *gsf) | |||
511 | gsf->gf_fmode != MCAST_EXCLUDE) | 517 | gsf->gf_fmode != MCAST_EXCLUDE) |
512 | return -EINVAL; | 518 | return -EINVAL; |
513 | 519 | ||
514 | idev = ip6_mc_find_dev(group, gsf->gf_interface); | 520 | idev = ip6_mc_find_dev(net, group, gsf->gf_interface); |
515 | 521 | ||
516 | if (!idev) | 522 | if (!idev) |
517 | return -ENODEV; | 523 | return -ENODEV; |
@@ -592,13 +598,14 @@ int ip6_mc_msfget(struct sock *sk, struct group_filter *gsf, | |||
592 | struct net_device *dev; | 598 | struct net_device *dev; |
593 | struct ipv6_pinfo *inet6 = inet6_sk(sk); | 599 | struct ipv6_pinfo *inet6 = inet6_sk(sk); |
594 | struct ip6_sf_socklist *psl; | 600 | struct ip6_sf_socklist *psl; |
601 | struct net *net = sk->sk_net; | ||
595 | 602 | ||
596 | group = &((struct sockaddr_in6 *)&gsf->gf_group)->sin6_addr; | 603 | group = &((struct sockaddr_in6 *)&gsf->gf_group)->sin6_addr; |
597 | 604 | ||
598 | if (!ipv6_addr_is_multicast(group)) | 605 | if (!ipv6_addr_is_multicast(group)) |
599 | return -EINVAL; | 606 | return -EINVAL; |
600 | 607 | ||
601 | idev = ip6_mc_find_dev(group, gsf->gf_interface); | 608 | idev = ip6_mc_find_dev(net, group, gsf->gf_interface); |
602 | 609 | ||
603 | if (!idev) | 610 | if (!idev) |
604 | return -ENODEV; | 611 | return -ENODEV; |
@@ -1393,7 +1400,8 @@ mld_scount(struct ifmcaddr6 *pmc, int type, int gdeleted, int sdeleted) | |||
1393 | 1400 | ||
1394 | static struct sk_buff *mld_newpack(struct net_device *dev, int size) | 1401 | static struct sk_buff *mld_newpack(struct net_device *dev, int size) |
1395 | { | 1402 | { |
1396 | struct sock *sk = igmp6_socket->sk; | 1403 | struct net *net = dev->nd_net; |
1404 | struct sock *sk = net->ipv6.igmp_sk; | ||
1397 | struct sk_buff *skb; | 1405 | struct sk_buff *skb; |
1398 | struct mld2_report *pmr; | 1406 | struct mld2_report *pmr; |
1399 | struct in6_addr addr_buf; | 1407 | struct in6_addr addr_buf; |
@@ -1440,6 +1448,7 @@ static void mld_sendpack(struct sk_buff *skb) | |||
1440 | (struct mld2_report *)skb_transport_header(skb); | 1448 | (struct mld2_report *)skb_transport_header(skb); |
1441 | int payload_len, mldlen; | 1449 | int payload_len, mldlen; |
1442 | struct inet6_dev *idev = in6_dev_get(skb->dev); | 1450 | struct inet6_dev *idev = in6_dev_get(skb->dev); |
1451 | struct net *net = skb->dev->nd_net; | ||
1443 | int err; | 1452 | int err; |
1444 | struct flowi fl; | 1453 | struct flowi fl; |
1445 | 1454 | ||
@@ -1459,7 +1468,7 @@ static void mld_sendpack(struct sk_buff *skb) | |||
1459 | goto err_out; | 1468 | goto err_out; |
1460 | } | 1469 | } |
1461 | 1470 | ||
1462 | icmpv6_flow_init(igmp6_socket->sk, &fl, ICMPV6_MLD2_REPORT, | 1471 | icmpv6_flow_init(net->ipv6.igmp_sk, &fl, ICMPV6_MLD2_REPORT, |
1463 | &ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr, | 1472 | &ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr, |
1464 | skb->dev->ifindex); | 1473 | skb->dev->ifindex); |
1465 | 1474 | ||
@@ -1753,7 +1762,8 @@ static void mld_send_cr(struct inet6_dev *idev) | |||
1753 | 1762 | ||
1754 | static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type) | 1763 | static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type) |
1755 | { | 1764 | { |
1756 | struct sock *sk = igmp6_socket->sk; | 1765 | struct net *net = dev->nd_net; |
1766 | struct sock *sk = net->ipv6.igmp_sk; | ||
1757 | struct inet6_dev *idev; | 1767 | struct inet6_dev *idev; |
1758 | struct sk_buff *skb; | 1768 | struct sk_buff *skb; |
1759 | struct icmp6hdr *hdr; | 1769 | struct icmp6hdr *hdr; |
@@ -1824,7 +1834,7 @@ static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type) | |||
1824 | goto err_out; | 1834 | goto err_out; |
1825 | } | 1835 | } |
1826 | 1836 | ||
1827 | icmpv6_flow_init(igmp6_socket->sk, &fl, type, | 1837 | icmpv6_flow_init(sk, &fl, type, |
1828 | &ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr, | 1838 | &ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr, |
1829 | skb->dev->ifindex); | 1839 | skb->dev->ifindex); |
1830 | 1840 | ||
@@ -2334,6 +2344,7 @@ void ipv6_mc_destroy_dev(struct inet6_dev *idev) | |||
2334 | 2344 | ||
2335 | #ifdef CONFIG_PROC_FS | 2345 | #ifdef CONFIG_PROC_FS |
2336 | struct igmp6_mc_iter_state { | 2346 | struct igmp6_mc_iter_state { |
2347 | struct seq_net_private p; | ||
2337 | struct net_device *dev; | 2348 | struct net_device *dev; |
2338 | struct inet6_dev *idev; | 2349 | struct inet6_dev *idev; |
2339 | }; | 2350 | }; |
@@ -2344,9 +2355,10 @@ static inline struct ifmcaddr6 *igmp6_mc_get_first(struct seq_file *seq) | |||
2344 | { | 2355 | { |
2345 | struct ifmcaddr6 *im = NULL; | 2356 | struct ifmcaddr6 *im = NULL; |
2346 | struct igmp6_mc_iter_state *state = igmp6_mc_seq_private(seq); | 2357 | struct igmp6_mc_iter_state *state = igmp6_mc_seq_private(seq); |
2358 | struct net *net = state->p.net; | ||
2347 | 2359 | ||
2348 | state->idev = NULL; | 2360 | state->idev = NULL; |
2349 | for_each_netdev(&init_net, state->dev) { | 2361 | for_each_netdev(net, state->dev) { |
2350 | struct inet6_dev *idev; | 2362 | struct inet6_dev *idev; |
2351 | idev = in6_dev_get(state->dev); | 2363 | idev = in6_dev_get(state->dev); |
2352 | if (!idev) | 2364 | if (!idev) |
@@ -2448,8 +2460,8 @@ static const struct seq_operations igmp6_mc_seq_ops = { | |||
2448 | 2460 | ||
2449 | static int igmp6_mc_seq_open(struct inode *inode, struct file *file) | 2461 | static int igmp6_mc_seq_open(struct inode *inode, struct file *file) |
2450 | { | 2462 | { |
2451 | return seq_open_private(file, &igmp6_mc_seq_ops, | 2463 | return seq_open_net(inode, file, &igmp6_mc_seq_ops, |
2452 | sizeof(struct igmp6_mc_iter_state)); | 2464 | sizeof(struct igmp6_mc_iter_state)); |
2453 | } | 2465 | } |
2454 | 2466 | ||
2455 | static const struct file_operations igmp6_mc_seq_fops = { | 2467 | static const struct file_operations igmp6_mc_seq_fops = { |
@@ -2457,10 +2469,11 @@ static const struct file_operations igmp6_mc_seq_fops = { | |||
2457 | .open = igmp6_mc_seq_open, | 2469 | .open = igmp6_mc_seq_open, |
2458 | .read = seq_read, | 2470 | .read = seq_read, |
2459 | .llseek = seq_lseek, | 2471 | .llseek = seq_lseek, |
2460 | .release = seq_release_private, | 2472 | .release = seq_release_net, |
2461 | }; | 2473 | }; |
2462 | 2474 | ||
2463 | struct igmp6_mcf_iter_state { | 2475 | struct igmp6_mcf_iter_state { |
2476 | struct seq_net_private p; | ||
2464 | struct net_device *dev; | 2477 | struct net_device *dev; |
2465 | struct inet6_dev *idev; | 2478 | struct inet6_dev *idev; |
2466 | struct ifmcaddr6 *im; | 2479 | struct ifmcaddr6 *im; |
@@ -2473,10 +2486,11 @@ static inline struct ip6_sf_list *igmp6_mcf_get_first(struct seq_file *seq) | |||
2473 | struct ip6_sf_list *psf = NULL; | 2486 | struct ip6_sf_list *psf = NULL; |
2474 | struct ifmcaddr6 *im = NULL; | 2487 | struct ifmcaddr6 *im = NULL; |
2475 | struct igmp6_mcf_iter_state *state = igmp6_mcf_seq_private(seq); | 2488 | struct igmp6_mcf_iter_state *state = igmp6_mcf_seq_private(seq); |
2489 | struct net *net = state->p.net; | ||
2476 | 2490 | ||
2477 | state->idev = NULL; | 2491 | state->idev = NULL; |
2478 | state->im = NULL; | 2492 | state->im = NULL; |
2479 | for_each_netdev(&init_net, state->dev) { | 2493 | for_each_netdev(net, state->dev) { |
2480 | struct inet6_dev *idev; | 2494 | struct inet6_dev *idev; |
2481 | idev = in6_dev_get(state->dev); | 2495 | idev = in6_dev_get(state->dev); |
2482 | if (unlikely(idev == NULL)) | 2496 | if (unlikely(idev == NULL)) |
@@ -2608,8 +2622,8 @@ static const struct seq_operations igmp6_mcf_seq_ops = { | |||
2608 | 2622 | ||
2609 | static int igmp6_mcf_seq_open(struct inode *inode, struct file *file) | 2623 | static int igmp6_mcf_seq_open(struct inode *inode, struct file *file) |
2610 | { | 2624 | { |
2611 | return seq_open_private(file, &igmp6_mcf_seq_ops, | 2625 | return seq_open_net(inode, file, &igmp6_mcf_seq_ops, |
2612 | sizeof(struct igmp6_mcf_iter_state)); | 2626 | sizeof(struct igmp6_mcf_iter_state)); |
2613 | } | 2627 | } |
2614 | 2628 | ||
2615 | static const struct file_operations igmp6_mcf_seq_fops = { | 2629 | static const struct file_operations igmp6_mcf_seq_fops = { |
@@ -2617,26 +2631,27 @@ static const struct file_operations igmp6_mcf_seq_fops = { | |||
2617 | .open = igmp6_mcf_seq_open, | 2631 | .open = igmp6_mcf_seq_open, |
2618 | .read = seq_read, | 2632 | .read = seq_read, |
2619 | .llseek = seq_lseek, | 2633 | .llseek = seq_lseek, |
2620 | .release = seq_release_private, | 2634 | .release = seq_release_net, |
2621 | }; | 2635 | }; |
2622 | #endif | 2636 | #endif |
2623 | 2637 | ||
2624 | int __init igmp6_init(void) | 2638 | static int igmp6_net_init(struct net *net) |
2625 | { | 2639 | { |
2626 | struct ipv6_pinfo *np; | 2640 | struct ipv6_pinfo *np; |
2641 | struct socket *sock; | ||
2627 | struct sock *sk; | 2642 | struct sock *sk; |
2628 | int err; | 2643 | int err; |
2629 | 2644 | ||
2630 | err = sock_create_kern(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6, &igmp6_socket); | 2645 | err = sock_create_kern(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6, &sock); |
2631 | if (err < 0) { | 2646 | if (err < 0) { |
2632 | printk(KERN_ERR | 2647 | printk(KERN_ERR |
2633 | "Failed to initialize the IGMP6 control socket (err %d).\n", | 2648 | "Failed to initialize the IGMP6 control socket (err %d).\n", |
2634 | err); | 2649 | err); |
2635 | igmp6_socket = NULL; /* For safety. */ | 2650 | goto out; |
2636 | return err; | ||
2637 | } | 2651 | } |
2638 | 2652 | ||
2639 | sk = igmp6_socket->sk; | 2653 | net->ipv6.igmp_sk = sk = sock->sk; |
2654 | sk_change_net(sk, net); | ||
2640 | sk->sk_allocation = GFP_ATOMIC; | 2655 | sk->sk_allocation = GFP_ATOMIC; |
2641 | sk->sk_prot->unhash(sk); | 2656 | sk->sk_prot->unhash(sk); |
2642 | 2657 | ||
@@ -2644,20 +2659,45 @@ int __init igmp6_init(void) | |||
2644 | np->hop_limit = 1; | 2659 | np->hop_limit = 1; |
2645 | 2660 | ||
2646 | #ifdef CONFIG_PROC_FS | 2661 | #ifdef CONFIG_PROC_FS |
2647 | proc_net_fops_create(&init_net, "igmp6", S_IRUGO, &igmp6_mc_seq_fops); | 2662 | err = -ENOMEM; |
2648 | proc_net_fops_create(&init_net, "mcfilter6", S_IRUGO, &igmp6_mcf_seq_fops); | 2663 | if (!proc_net_fops_create(net, "igmp6", S_IRUGO, &igmp6_mc_seq_fops)) |
2664 | goto out_sock_create; | ||
2665 | if (!proc_net_fops_create(net, "mcfilter6", S_IRUGO, | ||
2666 | &igmp6_mcf_seq_fops)) { | ||
2667 | proc_net_remove(net, "igmp6"); | ||
2668 | goto out_sock_create; | ||
2669 | } | ||
2649 | #endif | 2670 | #endif |
2650 | 2671 | ||
2651 | return 0; | 2672 | err = 0; |
2673 | out: | ||
2674 | return err; | ||
2675 | |||
2676 | out_sock_create: | ||
2677 | sk_release_kernel(net->ipv6.igmp_sk); | ||
2678 | goto out; | ||
2652 | } | 2679 | } |
2653 | 2680 | ||
2654 | void igmp6_cleanup(void) | 2681 | static void igmp6_net_exit(struct net *net) |
2655 | { | 2682 | { |
2656 | sock_release(igmp6_socket); | 2683 | sk_release_kernel(net->ipv6.igmp_sk); |
2657 | igmp6_socket = NULL; /* for safety */ | ||
2658 | |||
2659 | #ifdef CONFIG_PROC_FS | 2684 | #ifdef CONFIG_PROC_FS |
2660 | proc_net_remove(&init_net, "mcfilter6"); | 2685 | proc_net_remove(net, "mcfilter6"); |
2661 | proc_net_remove(&init_net, "igmp6"); | 2686 | proc_net_remove(net, "igmp6"); |
2662 | #endif | 2687 | #endif |
2663 | } | 2688 | } |
2689 | |||
2690 | static struct pernet_operations igmp6_net_ops = { | ||
2691 | .init = igmp6_net_init, | ||
2692 | .exit = igmp6_net_exit, | ||
2693 | }; | ||
2694 | |||
2695 | int __init igmp6_init(void) | ||
2696 | { | ||
2697 | return register_pernet_subsys(&igmp6_net_ops); | ||
2698 | } | ||
2699 | |||
2700 | void igmp6_cleanup(void) | ||
2701 | { | ||
2702 | unregister_pernet_subsys(&igmp6_net_ops); | ||
2703 | } | ||