diff options
Diffstat (limited to 'net/ipv6/mcast.c')
-rw-r--r-- | net/ipv6/mcast.c | 207 |
1 files changed, 147 insertions, 60 deletions
diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c index ab228d1ea114..957ac7e9e929 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(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(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; |
@@ -1433,25 +1441,6 @@ static struct sk_buff *mld_newpack(struct net_device *dev, int size) | |||
1433 | return skb; | 1441 | return skb; |
1434 | } | 1442 | } |
1435 | 1443 | ||
1436 | static inline int mld_dev_queue_xmit2(struct sk_buff *skb) | ||
1437 | { | ||
1438 | struct net_device *dev = skb->dev; | ||
1439 | unsigned char ha[MAX_ADDR_LEN]; | ||
1440 | |||
1441 | ndisc_mc_map(&ipv6_hdr(skb)->daddr, ha, dev, 1); | ||
1442 | if (dev_hard_header(skb, dev, ETH_P_IPV6, ha, NULL, skb->len) < 0) { | ||
1443 | kfree_skb(skb); | ||
1444 | return -EINVAL; | ||
1445 | } | ||
1446 | return dev_queue_xmit(skb); | ||
1447 | } | ||
1448 | |||
1449 | static inline int mld_dev_queue_xmit(struct sk_buff *skb) | ||
1450 | { | ||
1451 | return NF_HOOK(PF_INET6, NF_INET_POST_ROUTING, skb, NULL, skb->dev, | ||
1452 | mld_dev_queue_xmit2); | ||
1453 | } | ||
1454 | |||
1455 | static void mld_sendpack(struct sk_buff *skb) | 1444 | static void mld_sendpack(struct sk_buff *skb) |
1456 | { | 1445 | { |
1457 | struct ipv6hdr *pip6 = ipv6_hdr(skb); | 1446 | struct ipv6hdr *pip6 = ipv6_hdr(skb); |
@@ -1459,7 +1448,9 @@ static void mld_sendpack(struct sk_buff *skb) | |||
1459 | (struct mld2_report *)skb_transport_header(skb); | 1448 | (struct mld2_report *)skb_transport_header(skb); |
1460 | int payload_len, mldlen; | 1449 | int payload_len, mldlen; |
1461 | 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; | ||
1462 | int err; | 1452 | int err; |
1453 | struct flowi fl; | ||
1463 | 1454 | ||
1464 | IP6_INC_STATS(idev, IPSTATS_MIB_OUTREQUESTS); | 1455 | IP6_INC_STATS(idev, IPSTATS_MIB_OUTREQUESTS); |
1465 | payload_len = (skb->tail - skb->network_header) - sizeof(*pip6); | 1456 | payload_len = (skb->tail - skb->network_header) - sizeof(*pip6); |
@@ -1469,8 +1460,25 @@ static void mld_sendpack(struct sk_buff *skb) | |||
1469 | pmr->csum = csum_ipv6_magic(&pip6->saddr, &pip6->daddr, mldlen, | 1460 | pmr->csum = csum_ipv6_magic(&pip6->saddr, &pip6->daddr, mldlen, |
1470 | IPPROTO_ICMPV6, csum_partial(skb_transport_header(skb), | 1461 | IPPROTO_ICMPV6, csum_partial(skb_transport_header(skb), |
1471 | mldlen, 0)); | 1462 | mldlen, 0)); |
1463 | |||
1464 | skb->dst = icmp6_dst_alloc(skb->dev, NULL, &ipv6_hdr(skb)->daddr); | ||
1465 | |||
1466 | if (!skb->dst) { | ||
1467 | err = -ENOMEM; | ||
1468 | goto err_out; | ||
1469 | } | ||
1470 | |||
1471 | icmpv6_flow_init(net->ipv6.igmp_sk, &fl, ICMPV6_MLD2_REPORT, | ||
1472 | &ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr, | ||
1473 | skb->dev->ifindex); | ||
1474 | |||
1475 | err = xfrm_lookup(&skb->dst, &fl, NULL, 0); | ||
1476 | if (err) | ||
1477 | goto err_out; | ||
1478 | |||
1472 | err = NF_HOOK(PF_INET6, NF_INET_LOCAL_OUT, skb, NULL, skb->dev, | 1479 | err = NF_HOOK(PF_INET6, NF_INET_LOCAL_OUT, skb, NULL, skb->dev, |
1473 | mld_dev_queue_xmit); | 1480 | dst_output); |
1481 | out: | ||
1474 | if (!err) { | 1482 | if (!err) { |
1475 | ICMP6MSGOUT_INC_STATS_BH(idev, ICMPV6_MLD2_REPORT); | 1483 | ICMP6MSGOUT_INC_STATS_BH(idev, ICMPV6_MLD2_REPORT); |
1476 | ICMP6_INC_STATS_BH(idev, ICMP6_MIB_OUTMSGS); | 1484 | ICMP6_INC_STATS_BH(idev, ICMP6_MIB_OUTMSGS); |
@@ -1480,6 +1488,11 @@ static void mld_sendpack(struct sk_buff *skb) | |||
1480 | 1488 | ||
1481 | if (likely(idev != NULL)) | 1489 | if (likely(idev != NULL)) |
1482 | in6_dev_put(idev); | 1490 | in6_dev_put(idev); |
1491 | return; | ||
1492 | |||
1493 | err_out: | ||
1494 | kfree_skb(skb); | ||
1495 | goto out; | ||
1483 | } | 1496 | } |
1484 | 1497 | ||
1485 | static int grec_size(struct ifmcaddr6 *pmc, int type, int gdel, int sdel) | 1498 | static int grec_size(struct ifmcaddr6 *pmc, int type, int gdel, int sdel) |
@@ -1749,7 +1762,8 @@ static void mld_send_cr(struct inet6_dev *idev) | |||
1749 | 1762 | ||
1750 | 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) |
1751 | { | 1764 | { |
1752 | struct sock *sk = igmp6_socket->sk; | 1765 | struct net *net = dev->nd_net; |
1766 | struct sock *sk = net->ipv6.igmp_sk; | ||
1753 | struct inet6_dev *idev; | 1767 | struct inet6_dev *idev; |
1754 | struct sk_buff *skb; | 1768 | struct sk_buff *skb; |
1755 | struct icmp6hdr *hdr; | 1769 | struct icmp6hdr *hdr; |
@@ -1761,6 +1775,7 @@ static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type) | |||
1761 | u8 ra[8] = { IPPROTO_ICMPV6, 0, | 1775 | u8 ra[8] = { IPPROTO_ICMPV6, 0, |
1762 | IPV6_TLV_ROUTERALERT, 2, 0, 0, | 1776 | IPV6_TLV_ROUTERALERT, 2, 0, 0, |
1763 | IPV6_TLV_PADN, 0 }; | 1777 | IPV6_TLV_PADN, 0 }; |
1778 | struct flowi fl; | ||
1764 | 1779 | ||
1765 | rcu_read_lock(); | 1780 | rcu_read_lock(); |
1766 | IP6_INC_STATS(__in6_dev_get(dev), | 1781 | IP6_INC_STATS(__in6_dev_get(dev), |
@@ -1813,8 +1828,23 @@ static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type) | |||
1813 | 1828 | ||
1814 | idev = in6_dev_get(skb->dev); | 1829 | idev = in6_dev_get(skb->dev); |
1815 | 1830 | ||
1831 | skb->dst = icmp6_dst_alloc(skb->dev, NULL, &ipv6_hdr(skb)->daddr); | ||
1832 | if (!skb->dst) { | ||
1833 | err = -ENOMEM; | ||
1834 | goto err_out; | ||
1835 | } | ||
1836 | |||
1837 | icmpv6_flow_init(sk, &fl, type, | ||
1838 | &ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr, | ||
1839 | skb->dev->ifindex); | ||
1840 | |||
1841 | err = xfrm_lookup(&skb->dst, &fl, NULL, 0); | ||
1842 | if (err) | ||
1843 | goto err_out; | ||
1844 | |||
1816 | err = NF_HOOK(PF_INET6, NF_INET_LOCAL_OUT, skb, NULL, skb->dev, | 1845 | err = NF_HOOK(PF_INET6, NF_INET_LOCAL_OUT, skb, NULL, skb->dev, |
1817 | mld_dev_queue_xmit); | 1846 | dst_output); |
1847 | out: | ||
1818 | if (!err) { | 1848 | if (!err) { |
1819 | ICMP6MSGOUT_INC_STATS(idev, type); | 1849 | ICMP6MSGOUT_INC_STATS(idev, type); |
1820 | ICMP6_INC_STATS(idev, ICMP6_MIB_OUTMSGS); | 1850 | ICMP6_INC_STATS(idev, ICMP6_MIB_OUTMSGS); |
@@ -1825,6 +1855,10 @@ static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type) | |||
1825 | if (likely(idev != NULL)) | 1855 | if (likely(idev != NULL)) |
1826 | in6_dev_put(idev); | 1856 | in6_dev_put(idev); |
1827 | return; | 1857 | return; |
1858 | |||
1859 | err_out: | ||
1860 | kfree_skb(skb); | ||
1861 | goto out; | ||
1828 | } | 1862 | } |
1829 | 1863 | ||
1830 | static int ip6_mc_del1_src(struct ifmcaddr6 *pmc, int sfmode, | 1864 | static int ip6_mc_del1_src(struct ifmcaddr6 *pmc, int sfmode, |
@@ -2310,6 +2344,7 @@ void ipv6_mc_destroy_dev(struct inet6_dev *idev) | |||
2310 | 2344 | ||
2311 | #ifdef CONFIG_PROC_FS | 2345 | #ifdef CONFIG_PROC_FS |
2312 | struct igmp6_mc_iter_state { | 2346 | struct igmp6_mc_iter_state { |
2347 | struct seq_net_private p; | ||
2313 | struct net_device *dev; | 2348 | struct net_device *dev; |
2314 | struct inet6_dev *idev; | 2349 | struct inet6_dev *idev; |
2315 | }; | 2350 | }; |
@@ -2320,9 +2355,10 @@ static inline struct ifmcaddr6 *igmp6_mc_get_first(struct seq_file *seq) | |||
2320 | { | 2355 | { |
2321 | struct ifmcaddr6 *im = NULL; | 2356 | struct ifmcaddr6 *im = NULL; |
2322 | 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; | ||
2323 | 2359 | ||
2324 | state->idev = NULL; | 2360 | state->idev = NULL; |
2325 | for_each_netdev(&init_net, state->dev) { | 2361 | for_each_netdev(net, state->dev) { |
2326 | struct inet6_dev *idev; | 2362 | struct inet6_dev *idev; |
2327 | idev = in6_dev_get(state->dev); | 2363 | idev = in6_dev_get(state->dev); |
2328 | if (!idev) | 2364 | if (!idev) |
@@ -2424,8 +2460,8 @@ static const struct seq_operations igmp6_mc_seq_ops = { | |||
2424 | 2460 | ||
2425 | 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) |
2426 | { | 2462 | { |
2427 | return seq_open_private(file, &igmp6_mc_seq_ops, | 2463 | return seq_open_net(inode, file, &igmp6_mc_seq_ops, |
2428 | sizeof(struct igmp6_mc_iter_state)); | 2464 | sizeof(struct igmp6_mc_iter_state)); |
2429 | } | 2465 | } |
2430 | 2466 | ||
2431 | static const struct file_operations igmp6_mc_seq_fops = { | 2467 | static const struct file_operations igmp6_mc_seq_fops = { |
@@ -2433,10 +2469,11 @@ static const struct file_operations igmp6_mc_seq_fops = { | |||
2433 | .open = igmp6_mc_seq_open, | 2469 | .open = igmp6_mc_seq_open, |
2434 | .read = seq_read, | 2470 | .read = seq_read, |
2435 | .llseek = seq_lseek, | 2471 | .llseek = seq_lseek, |
2436 | .release = seq_release_private, | 2472 | .release = seq_release_net, |
2437 | }; | 2473 | }; |
2438 | 2474 | ||
2439 | struct igmp6_mcf_iter_state { | 2475 | struct igmp6_mcf_iter_state { |
2476 | struct seq_net_private p; | ||
2440 | struct net_device *dev; | 2477 | struct net_device *dev; |
2441 | struct inet6_dev *idev; | 2478 | struct inet6_dev *idev; |
2442 | struct ifmcaddr6 *im; | 2479 | struct ifmcaddr6 *im; |
@@ -2449,10 +2486,11 @@ static inline struct ip6_sf_list *igmp6_mcf_get_first(struct seq_file *seq) | |||
2449 | struct ip6_sf_list *psf = NULL; | 2486 | struct ip6_sf_list *psf = NULL; |
2450 | struct ifmcaddr6 *im = NULL; | 2487 | struct ifmcaddr6 *im = NULL; |
2451 | 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; | ||
2452 | 2490 | ||
2453 | state->idev = NULL; | 2491 | state->idev = NULL; |
2454 | state->im = NULL; | 2492 | state->im = NULL; |
2455 | for_each_netdev(&init_net, state->dev) { | 2493 | for_each_netdev(net, state->dev) { |
2456 | struct inet6_dev *idev; | 2494 | struct inet6_dev *idev; |
2457 | idev = in6_dev_get(state->dev); | 2495 | idev = in6_dev_get(state->dev); |
2458 | if (unlikely(idev == NULL)) | 2496 | if (unlikely(idev == NULL)) |
@@ -2584,8 +2622,8 @@ static const struct seq_operations igmp6_mcf_seq_ops = { | |||
2584 | 2622 | ||
2585 | 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) |
2586 | { | 2624 | { |
2587 | return seq_open_private(file, &igmp6_mcf_seq_ops, | 2625 | return seq_open_net(inode, file, &igmp6_mcf_seq_ops, |
2588 | sizeof(struct igmp6_mcf_iter_state)); | 2626 | sizeof(struct igmp6_mcf_iter_state)); |
2589 | } | 2627 | } |
2590 | 2628 | ||
2591 | static const struct file_operations igmp6_mcf_seq_fops = { | 2629 | static const struct file_operations igmp6_mcf_seq_fops = { |
@@ -2593,47 +2631,96 @@ static const struct file_operations igmp6_mcf_seq_fops = { | |||
2593 | .open = igmp6_mcf_seq_open, | 2631 | .open = igmp6_mcf_seq_open, |
2594 | .read = seq_read, | 2632 | .read = seq_read, |
2595 | .llseek = seq_lseek, | 2633 | .llseek = seq_lseek, |
2596 | .release = seq_release_private, | 2634 | .release = seq_release_net, |
2597 | }; | 2635 | }; |
2636 | |||
2637 | static int igmp6_proc_init(struct net *net) | ||
2638 | { | ||
2639 | int err; | ||
2640 | |||
2641 | err = -ENOMEM; | ||
2642 | if (!proc_net_fops_create(net, "igmp6", S_IRUGO, &igmp6_mc_seq_fops)) | ||
2643 | goto out; | ||
2644 | if (!proc_net_fops_create(net, "mcfilter6", S_IRUGO, | ||
2645 | &igmp6_mcf_seq_fops)) | ||
2646 | goto out_proc_net_igmp6; | ||
2647 | |||
2648 | err = 0; | ||
2649 | out: | ||
2650 | return err; | ||
2651 | |||
2652 | out_proc_net_igmp6: | ||
2653 | proc_net_remove(net, "igmp6"); | ||
2654 | goto out; | ||
2655 | } | ||
2656 | |||
2657 | static void igmp6_proc_exit(struct net *net) | ||
2658 | { | ||
2659 | proc_net_remove(net, "mcfilter6"); | ||
2660 | proc_net_remove(net, "igmp6"); | ||
2661 | } | ||
2662 | #else | ||
2663 | static int igmp6_proc_init(struct net *net) | ||
2664 | { | ||
2665 | return 0; | ||
2666 | } | ||
2667 | static void igmp6_proc_exit(struct net *net) | ||
2668 | { | ||
2669 | ; | ||
2670 | } | ||
2598 | #endif | 2671 | #endif |
2599 | 2672 | ||
2600 | int __init igmp6_init(struct net_proto_family *ops) | 2673 | static int igmp6_net_init(struct net *net) |
2601 | { | 2674 | { |
2602 | struct ipv6_pinfo *np; | 2675 | struct ipv6_pinfo *np; |
2676 | struct socket *sock; | ||
2603 | struct sock *sk; | 2677 | struct sock *sk; |
2604 | int err; | 2678 | int err; |
2605 | 2679 | ||
2606 | err = sock_create_kern(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6, &igmp6_socket); | 2680 | err = sock_create_kern(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6, &sock); |
2607 | if (err < 0) { | 2681 | if (err < 0) { |
2608 | printk(KERN_ERR | 2682 | printk(KERN_ERR |
2609 | "Failed to initialize the IGMP6 control socket (err %d).\n", | 2683 | "Failed to initialize the IGMP6 control socket (err %d).\n", |
2610 | err); | 2684 | err); |
2611 | igmp6_socket = NULL; /* For safety. */ | 2685 | goto out; |
2612 | return err; | ||
2613 | } | 2686 | } |
2614 | 2687 | ||
2615 | sk = igmp6_socket->sk; | 2688 | net->ipv6.igmp_sk = sk = sock->sk; |
2689 | sk_change_net(sk, net); | ||
2616 | sk->sk_allocation = GFP_ATOMIC; | 2690 | sk->sk_allocation = GFP_ATOMIC; |
2617 | sk->sk_prot->unhash(sk); | 2691 | sk->sk_prot->unhash(sk); |
2618 | 2692 | ||
2619 | np = inet6_sk(sk); | 2693 | np = inet6_sk(sk); |
2620 | np->hop_limit = 1; | 2694 | np->hop_limit = 1; |
2621 | 2695 | ||
2622 | #ifdef CONFIG_PROC_FS | 2696 | err = igmp6_proc_init(net); |
2623 | proc_net_fops_create(&init_net, "igmp6", S_IRUGO, &igmp6_mc_seq_fops); | 2697 | if (err) |
2624 | proc_net_fops_create(&init_net, "mcfilter6", S_IRUGO, &igmp6_mcf_seq_fops); | 2698 | goto out_sock_create; |
2625 | #endif | 2699 | out: |
2700 | return err; | ||
2626 | 2701 | ||
2627 | return 0; | 2702 | out_sock_create: |
2703 | sk_release_kernel(net->ipv6.igmp_sk); | ||
2704 | goto out; | ||
2628 | } | 2705 | } |
2629 | 2706 | ||
2630 | void igmp6_cleanup(void) | 2707 | static void igmp6_net_exit(struct net *net) |
2631 | { | 2708 | { |
2632 | sock_release(igmp6_socket); | 2709 | sk_release_kernel(net->ipv6.igmp_sk); |
2633 | igmp6_socket = NULL; /* for safety */ | 2710 | igmp6_proc_exit(net); |
2711 | } | ||
2634 | 2712 | ||
2635 | #ifdef CONFIG_PROC_FS | 2713 | static struct pernet_operations igmp6_net_ops = { |
2636 | proc_net_remove(&init_net, "mcfilter6"); | 2714 | .init = igmp6_net_init, |
2637 | proc_net_remove(&init_net, "igmp6"); | 2715 | .exit = igmp6_net_exit, |
2638 | #endif | 2716 | }; |
2717 | |||
2718 | int __init igmp6_init(void) | ||
2719 | { | ||
2720 | return register_pernet_subsys(&igmp6_net_ops); | ||
2721 | } | ||
2722 | |||
2723 | void igmp6_cleanup(void) | ||
2724 | { | ||
2725 | unregister_pernet_subsys(&igmp6_net_ops); | ||
2639 | } | 2726 | } |