diff options
Diffstat (limited to 'net/ipv6/mcast.c')
-rw-r--r-- | net/ipv6/mcast.c | 272 |
1 files changed, 173 insertions, 99 deletions
diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c index ab228d1ea114..54f91efdae58 100644 --- a/net/ipv6/mcast.c +++ b/net/ipv6/mcast.c | |||
@@ -59,6 +59,7 @@ | |||
59 | #include <net/ndisc.h> | 59 | #include <net/ndisc.h> |
60 | #include <net/addrconf.h> | 60 | #include <net/addrconf.h> |
61 | #include <net/ip6_route.h> | 61 | #include <net/ip6_route.h> |
62 | #include <net/inet_common.h> | ||
62 | 63 | ||
63 | #include <net/ip6_checksum.h> | 64 | #include <net/ip6_checksum.h> |
64 | 65 | ||
@@ -126,10 +127,6 @@ static struct in6_addr mld2_all_mcr = MLD2_ALL_MCR_INIT; | |||
126 | /* Big mc list lock for all the sockets */ | 127 | /* Big mc list lock for all the sockets */ |
127 | static DEFINE_RWLOCK(ipv6_sk_mc_lock); | 128 | static DEFINE_RWLOCK(ipv6_sk_mc_lock); |
128 | 129 | ||
129 | static struct socket *igmp6_socket; | ||
130 | |||
131 | int __ipv6_dev_mc_dec(struct inet6_dev *idev, struct in6_addr *addr); | ||
132 | |||
133 | static void igmp6_join_group(struct ifmcaddr6 *ma); | 130 | static void igmp6_join_group(struct ifmcaddr6 *ma); |
134 | static void igmp6_leave_group(struct ifmcaddr6 *ma); | 131 | static void igmp6_leave_group(struct ifmcaddr6 *ma); |
135 | static void igmp6_timer_handler(unsigned long data); | 132 | static void igmp6_timer_handler(unsigned long data); |
@@ -178,11 +175,12 @@ int sysctl_mld_max_msf __read_mostly = IPV6_MLD_MAX_MSF; | |||
178 | * socket join on multicast group | 175 | * socket join on multicast group |
179 | */ | 176 | */ |
180 | 177 | ||
181 | int ipv6_sock_mc_join(struct sock *sk, int ifindex, struct in6_addr *addr) | 178 | int ipv6_sock_mc_join(struct sock *sk, int ifindex, const struct in6_addr *addr) |
182 | { | 179 | { |
183 | struct net_device *dev = NULL; | 180 | struct net_device *dev = NULL; |
184 | struct ipv6_mc_socklist *mc_lst; | 181 | struct ipv6_mc_socklist *mc_lst; |
185 | struct ipv6_pinfo *np = inet6_sk(sk); | 182 | struct ipv6_pinfo *np = inet6_sk(sk); |
183 | struct net *net = sock_net(sk); | ||
186 | int err; | 184 | int err; |
187 | 185 | ||
188 | if (!ipv6_addr_is_multicast(addr)) | 186 | if (!ipv6_addr_is_multicast(addr)) |
@@ -208,14 +206,14 @@ int ipv6_sock_mc_join(struct sock *sk, int ifindex, struct in6_addr *addr) | |||
208 | 206 | ||
209 | if (ifindex == 0) { | 207 | if (ifindex == 0) { |
210 | struct rt6_info *rt; | 208 | struct rt6_info *rt; |
211 | rt = rt6_lookup(addr, NULL, 0, 0); | 209 | rt = rt6_lookup(net, addr, NULL, 0, 0); |
212 | if (rt) { | 210 | if (rt) { |
213 | dev = rt->rt6i_dev; | 211 | dev = rt->rt6i_dev; |
214 | dev_hold(dev); | 212 | dev_hold(dev); |
215 | dst_release(&rt->u.dst); | 213 | dst_release(&rt->u.dst); |
216 | } | 214 | } |
217 | } else | 215 | } else |
218 | dev = dev_get_by_index(&init_net, ifindex); | 216 | dev = dev_get_by_index(net, ifindex); |
219 | 217 | ||
220 | if (dev == NULL) { | 218 | if (dev == NULL) { |
221 | sock_kfree_s(sk, mc_lst, sizeof(*mc_lst)); | 219 | sock_kfree_s(sk, mc_lst, sizeof(*mc_lst)); |
@@ -252,10 +250,11 @@ int ipv6_sock_mc_join(struct sock *sk, int ifindex, struct in6_addr *addr) | |||
252 | /* | 250 | /* |
253 | * socket leave on multicast group | 251 | * socket leave on multicast group |
254 | */ | 252 | */ |
255 | int ipv6_sock_mc_drop(struct sock *sk, int ifindex, struct in6_addr *addr) | 253 | int ipv6_sock_mc_drop(struct sock *sk, int ifindex, const struct in6_addr *addr) |
256 | { | 254 | { |
257 | struct ipv6_pinfo *np = inet6_sk(sk); | 255 | struct ipv6_pinfo *np = inet6_sk(sk); |
258 | struct ipv6_mc_socklist *mc_lst, **lnk; | 256 | struct ipv6_mc_socklist *mc_lst, **lnk; |
257 | struct net *net = sock_net(sk); | ||
259 | 258 | ||
260 | write_lock_bh(&ipv6_sk_mc_lock); | 259 | write_lock_bh(&ipv6_sk_mc_lock); |
261 | for (lnk = &np->ipv6_mc_list; (mc_lst = *lnk) !=NULL ; lnk = &mc_lst->next) { | 260 | for (lnk = &np->ipv6_mc_list; (mc_lst = *lnk) !=NULL ; lnk = &mc_lst->next) { |
@@ -266,7 +265,8 @@ int ipv6_sock_mc_drop(struct sock *sk, int ifindex, struct in6_addr *addr) | |||
266 | *lnk = mc_lst->next; | 265 | *lnk = mc_lst->next; |
267 | write_unlock_bh(&ipv6_sk_mc_lock); | 266 | write_unlock_bh(&ipv6_sk_mc_lock); |
268 | 267 | ||
269 | if ((dev = dev_get_by_index(&init_net, mc_lst->ifindex)) != NULL) { | 268 | dev = dev_get_by_index(net, mc_lst->ifindex); |
269 | if (dev != NULL) { | ||
270 | struct inet6_dev *idev = in6_dev_get(dev); | 270 | struct inet6_dev *idev = in6_dev_get(dev); |
271 | 271 | ||
272 | (void) ip6_mc_leave_src(sk, mc_lst, idev); | 272 | (void) ip6_mc_leave_src(sk, mc_lst, idev); |
@@ -286,7 +286,9 @@ int ipv6_sock_mc_drop(struct sock *sk, int ifindex, struct in6_addr *addr) | |||
286 | return -EADDRNOTAVAIL; | 286 | return -EADDRNOTAVAIL; |
287 | } | 287 | } |
288 | 288 | ||
289 | static struct inet6_dev *ip6_mc_find_dev(struct in6_addr *group, int ifindex) | 289 | static struct inet6_dev *ip6_mc_find_dev(struct net *net, |
290 | struct in6_addr *group, | ||
291 | int ifindex) | ||
290 | { | 292 | { |
291 | struct net_device *dev = NULL; | 293 | struct net_device *dev = NULL; |
292 | struct inet6_dev *idev = NULL; | 294 | struct inet6_dev *idev = NULL; |
@@ -294,14 +296,14 @@ static struct inet6_dev *ip6_mc_find_dev(struct in6_addr *group, int ifindex) | |||
294 | if (ifindex == 0) { | 296 | if (ifindex == 0) { |
295 | struct rt6_info *rt; | 297 | struct rt6_info *rt; |
296 | 298 | ||
297 | rt = rt6_lookup(group, NULL, 0, 0); | 299 | rt = rt6_lookup(net, group, NULL, 0, 0); |
298 | if (rt) { | 300 | if (rt) { |
299 | dev = rt->rt6i_dev; | 301 | dev = rt->rt6i_dev; |
300 | dev_hold(dev); | 302 | dev_hold(dev); |
301 | dst_release(&rt->u.dst); | 303 | dst_release(&rt->u.dst); |
302 | } | 304 | } |
303 | } else | 305 | } else |
304 | dev = dev_get_by_index(&init_net, ifindex); | 306 | dev = dev_get_by_index(net, ifindex); |
305 | 307 | ||
306 | if (!dev) | 308 | if (!dev) |
307 | return NULL; | 309 | return NULL; |
@@ -324,6 +326,7 @@ void ipv6_sock_mc_close(struct sock *sk) | |||
324 | { | 326 | { |
325 | struct ipv6_pinfo *np = inet6_sk(sk); | 327 | struct ipv6_pinfo *np = inet6_sk(sk); |
326 | struct ipv6_mc_socklist *mc_lst; | 328 | struct ipv6_mc_socklist *mc_lst; |
329 | struct net *net = sock_net(sk); | ||
327 | 330 | ||
328 | write_lock_bh(&ipv6_sk_mc_lock); | 331 | write_lock_bh(&ipv6_sk_mc_lock); |
329 | while ((mc_lst = np->ipv6_mc_list) != NULL) { | 332 | while ((mc_lst = np->ipv6_mc_list) != NULL) { |
@@ -332,7 +335,7 @@ void ipv6_sock_mc_close(struct sock *sk) | |||
332 | np->ipv6_mc_list = mc_lst->next; | 335 | np->ipv6_mc_list = mc_lst->next; |
333 | write_unlock_bh(&ipv6_sk_mc_lock); | 336 | write_unlock_bh(&ipv6_sk_mc_lock); |
334 | 337 | ||
335 | dev = dev_get_by_index(&init_net, mc_lst->ifindex); | 338 | dev = dev_get_by_index(net, mc_lst->ifindex); |
336 | if (dev) { | 339 | if (dev) { |
337 | struct inet6_dev *idev = in6_dev_get(dev); | 340 | struct inet6_dev *idev = in6_dev_get(dev); |
338 | 341 | ||
@@ -361,6 +364,7 @@ int ip6_mc_source(int add, int omode, struct sock *sk, | |||
361 | struct inet6_dev *idev; | 364 | struct inet6_dev *idev; |
362 | struct ipv6_pinfo *inet6 = inet6_sk(sk); | 365 | struct ipv6_pinfo *inet6 = inet6_sk(sk); |
363 | struct ip6_sf_socklist *psl; | 366 | struct ip6_sf_socklist *psl; |
367 | struct net *net = sock_net(sk); | ||
364 | int i, j, rv; | 368 | int i, j, rv; |
365 | int leavegroup = 0; | 369 | int leavegroup = 0; |
366 | int pmclocked = 0; | 370 | int pmclocked = 0; |
@@ -376,7 +380,7 @@ int ip6_mc_source(int add, int omode, struct sock *sk, | |||
376 | if (!ipv6_addr_is_multicast(group)) | 380 | if (!ipv6_addr_is_multicast(group)) |
377 | return -EINVAL; | 381 | return -EINVAL; |
378 | 382 | ||
379 | idev = ip6_mc_find_dev(group, pgsr->gsr_interface); | 383 | idev = ip6_mc_find_dev(net, group, pgsr->gsr_interface); |
380 | if (!idev) | 384 | if (!idev) |
381 | return -ENODEV; | 385 | return -ENODEV; |
382 | dev = idev->dev; | 386 | dev = idev->dev; |
@@ -500,6 +504,7 @@ int ip6_mc_msfilter(struct sock *sk, struct group_filter *gsf) | |||
500 | struct inet6_dev *idev; | 504 | struct inet6_dev *idev; |
501 | struct ipv6_pinfo *inet6 = inet6_sk(sk); | 505 | struct ipv6_pinfo *inet6 = inet6_sk(sk); |
502 | struct ip6_sf_socklist *newpsl, *psl; | 506 | struct ip6_sf_socklist *newpsl, *psl; |
507 | struct net *net = sock_net(sk); | ||
503 | int leavegroup = 0; | 508 | int leavegroup = 0; |
504 | int i, err; | 509 | int i, err; |
505 | 510 | ||
@@ -511,7 +516,7 @@ int ip6_mc_msfilter(struct sock *sk, struct group_filter *gsf) | |||
511 | gsf->gf_fmode != MCAST_EXCLUDE) | 516 | gsf->gf_fmode != MCAST_EXCLUDE) |
512 | return -EINVAL; | 517 | return -EINVAL; |
513 | 518 | ||
514 | idev = ip6_mc_find_dev(group, gsf->gf_interface); | 519 | idev = ip6_mc_find_dev(net, group, gsf->gf_interface); |
515 | 520 | ||
516 | if (!idev) | 521 | if (!idev) |
517 | return -ENODEV; | 522 | return -ENODEV; |
@@ -592,13 +597,14 @@ int ip6_mc_msfget(struct sock *sk, struct group_filter *gsf, | |||
592 | struct net_device *dev; | 597 | struct net_device *dev; |
593 | struct ipv6_pinfo *inet6 = inet6_sk(sk); | 598 | struct ipv6_pinfo *inet6 = inet6_sk(sk); |
594 | struct ip6_sf_socklist *psl; | 599 | struct ip6_sf_socklist *psl; |
600 | struct net *net = sock_net(sk); | ||
595 | 601 | ||
596 | group = &((struct sockaddr_in6 *)&gsf->gf_group)->sin6_addr; | 602 | group = &((struct sockaddr_in6 *)&gsf->gf_group)->sin6_addr; |
597 | 603 | ||
598 | if (!ipv6_addr_is_multicast(group)) | 604 | if (!ipv6_addr_is_multicast(group)) |
599 | return -EINVAL; | 605 | return -EINVAL; |
600 | 606 | ||
601 | idev = ip6_mc_find_dev(group, gsf->gf_interface); | 607 | idev = ip6_mc_find_dev(net, group, gsf->gf_interface); |
602 | 608 | ||
603 | if (!idev) | 609 | if (!idev) |
604 | return -ENODEV; | 610 | return -ENODEV; |
@@ -656,8 +662,8 @@ done: | |||
656 | return err; | 662 | return err; |
657 | } | 663 | } |
658 | 664 | ||
659 | int inet6_mc_check(struct sock *sk, struct in6_addr *mc_addr, | 665 | int inet6_mc_check(struct sock *sk, const struct in6_addr *mc_addr, |
660 | struct in6_addr *src_addr) | 666 | const struct in6_addr *src_addr) |
661 | { | 667 | { |
662 | struct ipv6_pinfo *np = inet6_sk(sk); | 668 | struct ipv6_pinfo *np = inet6_sk(sk); |
663 | struct ipv6_mc_socklist *mc; | 669 | struct ipv6_mc_socklist *mc; |
@@ -863,7 +869,7 @@ static void mld_clear_delrec(struct inet6_dev *idev) | |||
863 | /* | 869 | /* |
864 | * device multicast group inc (add if not found) | 870 | * device multicast group inc (add if not found) |
865 | */ | 871 | */ |
866 | int ipv6_dev_mc_inc(struct net_device *dev, struct in6_addr *addr) | 872 | int ipv6_dev_mc_inc(struct net_device *dev, const struct in6_addr *addr) |
867 | { | 873 | { |
868 | struct ifmcaddr6 *mc; | 874 | struct ifmcaddr6 *mc; |
869 | struct inet6_dev *idev; | 875 | struct inet6_dev *idev; |
@@ -934,7 +940,7 @@ int ipv6_dev_mc_inc(struct net_device *dev, struct in6_addr *addr) | |||
934 | /* | 940 | /* |
935 | * device multicast group del | 941 | * device multicast group del |
936 | */ | 942 | */ |
937 | int __ipv6_dev_mc_dec(struct inet6_dev *idev, struct in6_addr *addr) | 943 | int __ipv6_dev_mc_dec(struct inet6_dev *idev, const struct in6_addr *addr) |
938 | { | 944 | { |
939 | struct ifmcaddr6 *ma, **map; | 945 | struct ifmcaddr6 *ma, **map; |
940 | 946 | ||
@@ -959,7 +965,7 @@ int __ipv6_dev_mc_dec(struct inet6_dev *idev, struct in6_addr *addr) | |||
959 | return -ENOENT; | 965 | return -ENOENT; |
960 | } | 966 | } |
961 | 967 | ||
962 | int ipv6_dev_mc_dec(struct net_device *dev, struct in6_addr *addr) | 968 | int ipv6_dev_mc_dec(struct net_device *dev, const struct in6_addr *addr) |
963 | { | 969 | { |
964 | struct inet6_dev *idev = in6_dev_get(dev); | 970 | struct inet6_dev *idev = in6_dev_get(dev); |
965 | int err; | 971 | int err; |
@@ -1004,8 +1010,8 @@ int ipv6_is_mld(struct sk_buff *skb, int nexthdr) | |||
1004 | /* | 1010 | /* |
1005 | * check if the interface/address pair is valid | 1011 | * check if the interface/address pair is valid |
1006 | */ | 1012 | */ |
1007 | int ipv6_chk_mcast_addr(struct net_device *dev, struct in6_addr *group, | 1013 | int ipv6_chk_mcast_addr(struct net_device *dev, const struct in6_addr *group, |
1008 | struct in6_addr *src_addr) | 1014 | const struct in6_addr *src_addr) |
1009 | { | 1015 | { |
1010 | struct inet6_dev *idev; | 1016 | struct inet6_dev *idev; |
1011 | struct ifmcaddr6 *mc; | 1017 | struct ifmcaddr6 *mc; |
@@ -1393,10 +1399,12 @@ mld_scount(struct ifmcaddr6 *pmc, int type, int gdeleted, int sdeleted) | |||
1393 | 1399 | ||
1394 | static struct sk_buff *mld_newpack(struct net_device *dev, int size) | 1400 | static struct sk_buff *mld_newpack(struct net_device *dev, int size) |
1395 | { | 1401 | { |
1396 | struct sock *sk = igmp6_socket->sk; | 1402 | struct net *net = dev_net(dev); |
1403 | struct sock *sk = net->ipv6.igmp_sk; | ||
1397 | struct sk_buff *skb; | 1404 | struct sk_buff *skb; |
1398 | struct mld2_report *pmr; | 1405 | struct mld2_report *pmr; |
1399 | struct in6_addr addr_buf; | 1406 | struct in6_addr addr_buf; |
1407 | const struct in6_addr *saddr; | ||
1400 | int err; | 1408 | int err; |
1401 | u8 ra[8] = { IPPROTO_ICMPV6, 0, | 1409 | u8 ra[8] = { IPPROTO_ICMPV6, 0, |
1402 | IPV6_TLV_ROUTERALERT, 2, 0, 0, | 1410 | IPV6_TLV_ROUTERALERT, 2, 0, 0, |
@@ -1415,10 +1423,11 @@ static struct sk_buff *mld_newpack(struct net_device *dev, int size) | |||
1415 | * use unspecified address as the source address | 1423 | * use unspecified address as the source address |
1416 | * when a valid link-local address is not available. | 1424 | * when a valid link-local address is not available. |
1417 | */ | 1425 | */ |
1418 | memset(&addr_buf, 0, sizeof(addr_buf)); | 1426 | saddr = &in6addr_any; |
1419 | } | 1427 | } else |
1428 | saddr = &addr_buf; | ||
1420 | 1429 | ||
1421 | ip6_nd_hdr(sk, skb, dev, &addr_buf, &mld2_all_mcr, NEXTHDR_HOP, 0); | 1430 | ip6_nd_hdr(sk, skb, dev, saddr, &mld2_all_mcr, NEXTHDR_HOP, 0); |
1422 | 1431 | ||
1423 | memcpy(skb_put(skb, sizeof(ra)), ra, sizeof(ra)); | 1432 | memcpy(skb_put(skb, sizeof(ra)), ra, sizeof(ra)); |
1424 | 1433 | ||
@@ -1433,25 +1442,6 @@ static struct sk_buff *mld_newpack(struct net_device *dev, int size) | |||
1433 | return skb; | 1442 | return skb; |
1434 | } | 1443 | } |
1435 | 1444 | ||
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) | 1445 | static void mld_sendpack(struct sk_buff *skb) |
1456 | { | 1446 | { |
1457 | struct ipv6hdr *pip6 = ipv6_hdr(skb); | 1447 | struct ipv6hdr *pip6 = ipv6_hdr(skb); |
@@ -1459,7 +1449,9 @@ static void mld_sendpack(struct sk_buff *skb) | |||
1459 | (struct mld2_report *)skb_transport_header(skb); | 1449 | (struct mld2_report *)skb_transport_header(skb); |
1460 | int payload_len, mldlen; | 1450 | int payload_len, mldlen; |
1461 | struct inet6_dev *idev = in6_dev_get(skb->dev); | 1451 | struct inet6_dev *idev = in6_dev_get(skb->dev); |
1452 | struct net *net = dev_net(skb->dev); | ||
1462 | int err; | 1453 | int err; |
1454 | struct flowi fl; | ||
1463 | 1455 | ||
1464 | IP6_INC_STATS(idev, IPSTATS_MIB_OUTREQUESTS); | 1456 | IP6_INC_STATS(idev, IPSTATS_MIB_OUTREQUESTS); |
1465 | payload_len = (skb->tail - skb->network_header) - sizeof(*pip6); | 1457 | payload_len = (skb->tail - skb->network_header) - sizeof(*pip6); |
@@ -1469,8 +1461,25 @@ static void mld_sendpack(struct sk_buff *skb) | |||
1469 | pmr->csum = csum_ipv6_magic(&pip6->saddr, &pip6->daddr, mldlen, | 1461 | pmr->csum = csum_ipv6_magic(&pip6->saddr, &pip6->daddr, mldlen, |
1470 | IPPROTO_ICMPV6, csum_partial(skb_transport_header(skb), | 1462 | IPPROTO_ICMPV6, csum_partial(skb_transport_header(skb), |
1471 | mldlen, 0)); | 1463 | mldlen, 0)); |
1464 | |||
1465 | skb->dst = icmp6_dst_alloc(skb->dev, NULL, &ipv6_hdr(skb)->daddr); | ||
1466 | |||
1467 | if (!skb->dst) { | ||
1468 | err = -ENOMEM; | ||
1469 | goto err_out; | ||
1470 | } | ||
1471 | |||
1472 | icmpv6_flow_init(net->ipv6.igmp_sk, &fl, ICMPV6_MLD2_REPORT, | ||
1473 | &ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr, | ||
1474 | skb->dev->ifindex); | ||
1475 | |||
1476 | err = xfrm_lookup(&skb->dst, &fl, NULL, 0); | ||
1477 | if (err) | ||
1478 | goto err_out; | ||
1479 | |||
1472 | err = NF_HOOK(PF_INET6, NF_INET_LOCAL_OUT, skb, NULL, skb->dev, | 1480 | err = NF_HOOK(PF_INET6, NF_INET_LOCAL_OUT, skb, NULL, skb->dev, |
1473 | mld_dev_queue_xmit); | 1481 | dst_output); |
1482 | out: | ||
1474 | if (!err) { | 1483 | if (!err) { |
1475 | ICMP6MSGOUT_INC_STATS_BH(idev, ICMPV6_MLD2_REPORT); | 1484 | ICMP6MSGOUT_INC_STATS_BH(idev, ICMPV6_MLD2_REPORT); |
1476 | ICMP6_INC_STATS_BH(idev, ICMP6_MIB_OUTMSGS); | 1485 | ICMP6_INC_STATS_BH(idev, ICMP6_MIB_OUTMSGS); |
@@ -1480,6 +1489,11 @@ static void mld_sendpack(struct sk_buff *skb) | |||
1480 | 1489 | ||
1481 | if (likely(idev != NULL)) | 1490 | if (likely(idev != NULL)) |
1482 | in6_dev_put(idev); | 1491 | in6_dev_put(idev); |
1492 | return; | ||
1493 | |||
1494 | err_out: | ||
1495 | kfree_skb(skb); | ||
1496 | goto out; | ||
1483 | } | 1497 | } |
1484 | 1498 | ||
1485 | static int grec_size(struct ifmcaddr6 *pmc, int type, int gdel, int sdel) | 1499 | static int grec_size(struct ifmcaddr6 *pmc, int type, int gdel, int sdel) |
@@ -1749,28 +1763,28 @@ static void mld_send_cr(struct inet6_dev *idev) | |||
1749 | 1763 | ||
1750 | static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type) | 1764 | static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type) |
1751 | { | 1765 | { |
1752 | struct sock *sk = igmp6_socket->sk; | 1766 | struct net *net = dev_net(dev); |
1767 | struct sock *sk = net->ipv6.igmp_sk; | ||
1753 | struct inet6_dev *idev; | 1768 | struct inet6_dev *idev; |
1754 | struct sk_buff *skb; | 1769 | struct sk_buff *skb; |
1755 | struct icmp6hdr *hdr; | 1770 | struct icmp6hdr *hdr; |
1756 | struct in6_addr *snd_addr; | 1771 | const struct in6_addr *snd_addr, *saddr; |
1757 | struct in6_addr *addrp; | 1772 | struct in6_addr *addrp; |
1758 | struct in6_addr addr_buf; | 1773 | struct in6_addr addr_buf; |
1759 | struct in6_addr all_routers; | ||
1760 | int err, len, payload_len, full_len; | 1774 | int err, len, payload_len, full_len; |
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), |
1767 | IPSTATS_MIB_OUTREQUESTS); | 1782 | IPSTATS_MIB_OUTREQUESTS); |
1768 | rcu_read_unlock(); | 1783 | rcu_read_unlock(); |
1769 | snd_addr = addr; | 1784 | if (type == ICMPV6_MGM_REDUCTION) |
1770 | if (type == ICMPV6_MGM_REDUCTION) { | 1785 | snd_addr = &in6addr_linklocal_allrouters; |
1771 | snd_addr = &all_routers; | 1786 | else |
1772 | ipv6_addr_all_routers(&all_routers); | 1787 | snd_addr = addr; |
1773 | } | ||
1774 | 1788 | ||
1775 | len = sizeof(struct icmp6hdr) + sizeof(struct in6_addr); | 1789 | len = sizeof(struct icmp6hdr) + sizeof(struct in6_addr); |
1776 | payload_len = len + sizeof(ra); | 1790 | payload_len = len + sizeof(ra); |
@@ -1793,10 +1807,11 @@ static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type) | |||
1793 | * use unspecified address as the source address | 1807 | * use unspecified address as the source address |
1794 | * when a valid link-local address is not available. | 1808 | * when a valid link-local address is not available. |
1795 | */ | 1809 | */ |
1796 | memset(&addr_buf, 0, sizeof(addr_buf)); | 1810 | saddr = &in6addr_any; |
1797 | } | 1811 | } else |
1812 | saddr = &addr_buf; | ||
1798 | 1813 | ||
1799 | ip6_nd_hdr(sk, skb, dev, &addr_buf, snd_addr, NEXTHDR_HOP, payload_len); | 1814 | ip6_nd_hdr(sk, skb, dev, saddr, snd_addr, NEXTHDR_HOP, payload_len); |
1800 | 1815 | ||
1801 | memcpy(skb_put(skb, sizeof(ra)), ra, sizeof(ra)); | 1816 | memcpy(skb_put(skb, sizeof(ra)), ra, sizeof(ra)); |
1802 | 1817 | ||
@@ -1807,14 +1822,29 @@ static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type) | |||
1807 | addrp = (struct in6_addr *) skb_put(skb, sizeof(struct in6_addr)); | 1822 | addrp = (struct in6_addr *) skb_put(skb, sizeof(struct in6_addr)); |
1808 | ipv6_addr_copy(addrp, addr); | 1823 | ipv6_addr_copy(addrp, addr); |
1809 | 1824 | ||
1810 | hdr->icmp6_cksum = csum_ipv6_magic(&addr_buf, snd_addr, len, | 1825 | hdr->icmp6_cksum = csum_ipv6_magic(saddr, snd_addr, len, |
1811 | IPPROTO_ICMPV6, | 1826 | IPPROTO_ICMPV6, |
1812 | csum_partial((__u8 *) hdr, len, 0)); | 1827 | csum_partial((__u8 *) hdr, len, 0)); |
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, |
@@ -2276,24 +2310,19 @@ void ipv6_mc_init_dev(struct inet6_dev *idev) | |||
2276 | void ipv6_mc_destroy_dev(struct inet6_dev *idev) | 2310 | void ipv6_mc_destroy_dev(struct inet6_dev *idev) |
2277 | { | 2311 | { |
2278 | struct ifmcaddr6 *i; | 2312 | struct ifmcaddr6 *i; |
2279 | struct in6_addr maddr; | ||
2280 | 2313 | ||
2281 | /* Deactivate timers */ | 2314 | /* Deactivate timers */ |
2282 | ipv6_mc_down(idev); | 2315 | ipv6_mc_down(idev); |
2283 | 2316 | ||
2284 | /* Delete all-nodes address. */ | 2317 | /* Delete all-nodes address. */ |
2285 | ipv6_addr_all_nodes(&maddr); | ||
2286 | |||
2287 | /* We cannot call ipv6_dev_mc_dec() directly, our caller in | 2318 | /* We cannot call ipv6_dev_mc_dec() directly, our caller in |
2288 | * addrconf.c has NULL'd out dev->ip6_ptr so in6_dev_get() will | 2319 | * addrconf.c has NULL'd out dev->ip6_ptr so in6_dev_get() will |
2289 | * fail. | 2320 | * fail. |
2290 | */ | 2321 | */ |
2291 | __ipv6_dev_mc_dec(idev, &maddr); | 2322 | __ipv6_dev_mc_dec(idev, &in6addr_linklocal_allnodes); |
2292 | 2323 | ||
2293 | if (idev->cnf.forwarding) { | 2324 | if (idev->cnf.forwarding) |
2294 | ipv6_addr_all_routers(&maddr); | 2325 | __ipv6_dev_mc_dec(idev, &in6addr_linklocal_allrouters); |
2295 | __ipv6_dev_mc_dec(idev, &maddr); | ||
2296 | } | ||
2297 | 2326 | ||
2298 | write_lock_bh(&idev->lock); | 2327 | write_lock_bh(&idev->lock); |
2299 | while ((i = idev->mc_list) != NULL) { | 2328 | while ((i = idev->mc_list) != NULL) { |
@@ -2310,6 +2339,7 @@ void ipv6_mc_destroy_dev(struct inet6_dev *idev) | |||
2310 | 2339 | ||
2311 | #ifdef CONFIG_PROC_FS | 2340 | #ifdef CONFIG_PROC_FS |
2312 | struct igmp6_mc_iter_state { | 2341 | struct igmp6_mc_iter_state { |
2342 | struct seq_net_private p; | ||
2313 | struct net_device *dev; | 2343 | struct net_device *dev; |
2314 | struct inet6_dev *idev; | 2344 | struct inet6_dev *idev; |
2315 | }; | 2345 | }; |
@@ -2320,9 +2350,10 @@ static inline struct ifmcaddr6 *igmp6_mc_get_first(struct seq_file *seq) | |||
2320 | { | 2350 | { |
2321 | struct ifmcaddr6 *im = NULL; | 2351 | struct ifmcaddr6 *im = NULL; |
2322 | struct igmp6_mc_iter_state *state = igmp6_mc_seq_private(seq); | 2352 | struct igmp6_mc_iter_state *state = igmp6_mc_seq_private(seq); |
2353 | struct net *net = seq_file_net(seq); | ||
2323 | 2354 | ||
2324 | state->idev = NULL; | 2355 | state->idev = NULL; |
2325 | for_each_netdev(&init_net, state->dev) { | 2356 | for_each_netdev(net, state->dev) { |
2326 | struct inet6_dev *idev; | 2357 | struct inet6_dev *idev; |
2327 | idev = in6_dev_get(state->dev); | 2358 | idev = in6_dev_get(state->dev); |
2328 | if (!idev) | 2359 | if (!idev) |
@@ -2424,8 +2455,8 @@ static const struct seq_operations igmp6_mc_seq_ops = { | |||
2424 | 2455 | ||
2425 | static int igmp6_mc_seq_open(struct inode *inode, struct file *file) | 2456 | static int igmp6_mc_seq_open(struct inode *inode, struct file *file) |
2426 | { | 2457 | { |
2427 | return seq_open_private(file, &igmp6_mc_seq_ops, | 2458 | return seq_open_net(inode, file, &igmp6_mc_seq_ops, |
2428 | sizeof(struct igmp6_mc_iter_state)); | 2459 | sizeof(struct igmp6_mc_iter_state)); |
2429 | } | 2460 | } |
2430 | 2461 | ||
2431 | static const struct file_operations igmp6_mc_seq_fops = { | 2462 | static const struct file_operations igmp6_mc_seq_fops = { |
@@ -2433,10 +2464,11 @@ static const struct file_operations igmp6_mc_seq_fops = { | |||
2433 | .open = igmp6_mc_seq_open, | 2464 | .open = igmp6_mc_seq_open, |
2434 | .read = seq_read, | 2465 | .read = seq_read, |
2435 | .llseek = seq_lseek, | 2466 | .llseek = seq_lseek, |
2436 | .release = seq_release_private, | 2467 | .release = seq_release_net, |
2437 | }; | 2468 | }; |
2438 | 2469 | ||
2439 | struct igmp6_mcf_iter_state { | 2470 | struct igmp6_mcf_iter_state { |
2471 | struct seq_net_private p; | ||
2440 | struct net_device *dev; | 2472 | struct net_device *dev; |
2441 | struct inet6_dev *idev; | 2473 | struct inet6_dev *idev; |
2442 | struct ifmcaddr6 *im; | 2474 | struct ifmcaddr6 *im; |
@@ -2449,10 +2481,11 @@ static inline struct ip6_sf_list *igmp6_mcf_get_first(struct seq_file *seq) | |||
2449 | struct ip6_sf_list *psf = NULL; | 2481 | struct ip6_sf_list *psf = NULL; |
2450 | struct ifmcaddr6 *im = NULL; | 2482 | struct ifmcaddr6 *im = NULL; |
2451 | struct igmp6_mcf_iter_state *state = igmp6_mcf_seq_private(seq); | 2483 | struct igmp6_mcf_iter_state *state = igmp6_mcf_seq_private(seq); |
2484 | struct net *net = seq_file_net(seq); | ||
2452 | 2485 | ||
2453 | state->idev = NULL; | 2486 | state->idev = NULL; |
2454 | state->im = NULL; | 2487 | state->im = NULL; |
2455 | for_each_netdev(&init_net, state->dev) { | 2488 | for_each_netdev(net, state->dev) { |
2456 | struct inet6_dev *idev; | 2489 | struct inet6_dev *idev; |
2457 | idev = in6_dev_get(state->dev); | 2490 | idev = in6_dev_get(state->dev); |
2458 | if (unlikely(idev == NULL)) | 2491 | if (unlikely(idev == NULL)) |
@@ -2584,8 +2617,8 @@ static const struct seq_operations igmp6_mcf_seq_ops = { | |||
2584 | 2617 | ||
2585 | static int igmp6_mcf_seq_open(struct inode *inode, struct file *file) | 2618 | static int igmp6_mcf_seq_open(struct inode *inode, struct file *file) |
2586 | { | 2619 | { |
2587 | return seq_open_private(file, &igmp6_mcf_seq_ops, | 2620 | return seq_open_net(inode, file, &igmp6_mcf_seq_ops, |
2588 | sizeof(struct igmp6_mcf_iter_state)); | 2621 | sizeof(struct igmp6_mcf_iter_state)); |
2589 | } | 2622 | } |
2590 | 2623 | ||
2591 | static const struct file_operations igmp6_mcf_seq_fops = { | 2624 | static const struct file_operations igmp6_mcf_seq_fops = { |
@@ -2593,47 +2626,88 @@ static const struct file_operations igmp6_mcf_seq_fops = { | |||
2593 | .open = igmp6_mcf_seq_open, | 2626 | .open = igmp6_mcf_seq_open, |
2594 | .read = seq_read, | 2627 | .read = seq_read, |
2595 | .llseek = seq_lseek, | 2628 | .llseek = seq_lseek, |
2596 | .release = seq_release_private, | 2629 | .release = seq_release_net, |
2597 | }; | 2630 | }; |
2631 | |||
2632 | static int igmp6_proc_init(struct net *net) | ||
2633 | { | ||
2634 | int err; | ||
2635 | |||
2636 | err = -ENOMEM; | ||
2637 | if (!proc_net_fops_create(net, "igmp6", S_IRUGO, &igmp6_mc_seq_fops)) | ||
2638 | goto out; | ||
2639 | if (!proc_net_fops_create(net, "mcfilter6", S_IRUGO, | ||
2640 | &igmp6_mcf_seq_fops)) | ||
2641 | goto out_proc_net_igmp6; | ||
2642 | |||
2643 | err = 0; | ||
2644 | out: | ||
2645 | return err; | ||
2646 | |||
2647 | out_proc_net_igmp6: | ||
2648 | proc_net_remove(net, "igmp6"); | ||
2649 | goto out; | ||
2650 | } | ||
2651 | |||
2652 | static void igmp6_proc_exit(struct net *net) | ||
2653 | { | ||
2654 | proc_net_remove(net, "mcfilter6"); | ||
2655 | proc_net_remove(net, "igmp6"); | ||
2656 | } | ||
2657 | #else | ||
2658 | static int igmp6_proc_init(struct net *net) | ||
2659 | { | ||
2660 | return 0; | ||
2661 | } | ||
2662 | static void igmp6_proc_exit(struct net *net) | ||
2663 | { | ||
2664 | ; | ||
2665 | } | ||
2598 | #endif | 2666 | #endif |
2599 | 2667 | ||
2600 | int __init igmp6_init(struct net_proto_family *ops) | 2668 | static int igmp6_net_init(struct net *net) |
2601 | { | 2669 | { |
2602 | struct ipv6_pinfo *np; | ||
2603 | struct sock *sk; | ||
2604 | int err; | 2670 | int err; |
2605 | 2671 | ||
2606 | err = sock_create_kern(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6, &igmp6_socket); | 2672 | err = inet_ctl_sock_create(&net->ipv6.igmp_sk, PF_INET6, |
2673 | SOCK_RAW, IPPROTO_ICMPV6, net); | ||
2607 | if (err < 0) { | 2674 | if (err < 0) { |
2608 | printk(KERN_ERR | 2675 | printk(KERN_ERR |
2609 | "Failed to initialize the IGMP6 control socket (err %d).\n", | 2676 | "Failed to initialize the IGMP6 control socket (err %d).\n", |
2610 | err); | 2677 | err); |
2611 | igmp6_socket = NULL; /* For safety. */ | 2678 | goto out; |
2612 | return err; | ||
2613 | } | 2679 | } |
2614 | 2680 | ||
2615 | sk = igmp6_socket->sk; | 2681 | inet6_sk(net->ipv6.igmp_sk)->hop_limit = 1; |
2616 | sk->sk_allocation = GFP_ATOMIC; | ||
2617 | sk->sk_prot->unhash(sk); | ||
2618 | 2682 | ||
2619 | np = inet6_sk(sk); | 2683 | err = igmp6_proc_init(net); |
2620 | np->hop_limit = 1; | 2684 | if (err) |
2685 | goto out_sock_create; | ||
2686 | out: | ||
2687 | return err; | ||
2621 | 2688 | ||
2622 | #ifdef CONFIG_PROC_FS | 2689 | out_sock_create: |
2623 | proc_net_fops_create(&init_net, "igmp6", S_IRUGO, &igmp6_mc_seq_fops); | 2690 | inet_ctl_sock_destroy(net->ipv6.igmp_sk); |
2624 | proc_net_fops_create(&init_net, "mcfilter6", S_IRUGO, &igmp6_mcf_seq_fops); | 2691 | goto out; |
2625 | #endif | 2692 | } |
2626 | 2693 | ||
2627 | return 0; | 2694 | static void igmp6_net_exit(struct net *net) |
2695 | { | ||
2696 | inet_ctl_sock_destroy(net->ipv6.igmp_sk); | ||
2697 | igmp6_proc_exit(net); | ||
2628 | } | 2698 | } |
2629 | 2699 | ||
2630 | void igmp6_cleanup(void) | 2700 | static struct pernet_operations igmp6_net_ops = { |
2701 | .init = igmp6_net_init, | ||
2702 | .exit = igmp6_net_exit, | ||
2703 | }; | ||
2704 | |||
2705 | int __init igmp6_init(void) | ||
2631 | { | 2706 | { |
2632 | sock_release(igmp6_socket); | 2707 | return register_pernet_subsys(&igmp6_net_ops); |
2633 | igmp6_socket = NULL; /* for safety */ | 2708 | } |
2634 | 2709 | ||
2635 | #ifdef CONFIG_PROC_FS | 2710 | void igmp6_cleanup(void) |
2636 | proc_net_remove(&init_net, "mcfilter6"); | 2711 | { |
2637 | proc_net_remove(&init_net, "igmp6"); | 2712 | unregister_pernet_subsys(&igmp6_net_ops); |
2638 | #endif | ||
2639 | } | 2713 | } |