diff options
-rw-r--r-- | net/ipv6/mcast.c | 66 |
1 files changed, 45 insertions, 21 deletions
diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c index 8ce894d90063..a373b8e7f241 100644 --- a/net/ipv6/mcast.c +++ b/net/ipv6/mcast.c | |||
@@ -1433,25 +1433,6 @@ static struct sk_buff *mld_newpack(struct net_device *dev, int size) | |||
1433 | return skb; | 1433 | return skb; |
1434 | } | 1434 | } |
1435 | 1435 | ||
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) | 1436 | static void mld_sendpack(struct sk_buff *skb) |
1456 | { | 1437 | { |
1457 | struct ipv6hdr *pip6 = ipv6_hdr(skb); | 1438 | struct ipv6hdr *pip6 = ipv6_hdr(skb); |
@@ -1460,6 +1441,7 @@ static void mld_sendpack(struct sk_buff *skb) | |||
1460 | int payload_len, mldlen; | 1441 | int payload_len, mldlen; |
1461 | struct inet6_dev *idev = in6_dev_get(skb->dev); | 1442 | struct inet6_dev *idev = in6_dev_get(skb->dev); |
1462 | int err; | 1443 | int err; |
1444 | struct flowi fl; | ||
1463 | 1445 | ||
1464 | IP6_INC_STATS(idev, IPSTATS_MIB_OUTREQUESTS); | 1446 | IP6_INC_STATS(idev, IPSTATS_MIB_OUTREQUESTS); |
1465 | payload_len = (skb->tail - skb->network_header) - sizeof(*pip6); | 1447 | payload_len = (skb->tail - skb->network_header) - sizeof(*pip6); |
@@ -1469,8 +1451,25 @@ static void mld_sendpack(struct sk_buff *skb) | |||
1469 | pmr->csum = csum_ipv6_magic(&pip6->saddr, &pip6->daddr, mldlen, | 1451 | pmr->csum = csum_ipv6_magic(&pip6->saddr, &pip6->daddr, mldlen, |
1470 | IPPROTO_ICMPV6, csum_partial(skb_transport_header(skb), | 1452 | IPPROTO_ICMPV6, csum_partial(skb_transport_header(skb), |
1471 | mldlen, 0)); | 1453 | mldlen, 0)); |
1454 | |||
1455 | skb->dst = icmp6_dst_alloc(skb->dev, NULL, &ipv6_hdr(skb)->daddr); | ||
1456 | |||
1457 | if (!skb->dst) { | ||
1458 | err = -ENOMEM; | ||
1459 | goto err_out; | ||
1460 | } | ||
1461 | |||
1462 | icmpv6_flow_init(igmp6_socket->sk, &fl, ICMPV6_MLD2_REPORT, | ||
1463 | &ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr, | ||
1464 | skb->dev->ifindex); | ||
1465 | |||
1466 | err = xfrm_lookup(&skb->dst, &fl, NULL, 0); | ||
1467 | if (err) | ||
1468 | goto err_out; | ||
1469 | |||
1472 | err = NF_HOOK(PF_INET6, NF_INET_LOCAL_OUT, skb, NULL, skb->dev, | 1470 | err = NF_HOOK(PF_INET6, NF_INET_LOCAL_OUT, skb, NULL, skb->dev, |
1473 | mld_dev_queue_xmit); | 1471 | dst_output); |
1472 | out: | ||
1474 | if (!err) { | 1473 | if (!err) { |
1475 | ICMP6MSGOUT_INC_STATS_BH(idev, ICMPV6_MLD2_REPORT); | 1474 | ICMP6MSGOUT_INC_STATS_BH(idev, ICMPV6_MLD2_REPORT); |
1476 | ICMP6_INC_STATS_BH(idev, ICMP6_MIB_OUTMSGS); | 1475 | ICMP6_INC_STATS_BH(idev, ICMP6_MIB_OUTMSGS); |
@@ -1480,6 +1479,11 @@ static void mld_sendpack(struct sk_buff *skb) | |||
1480 | 1479 | ||
1481 | if (likely(idev != NULL)) | 1480 | if (likely(idev != NULL)) |
1482 | in6_dev_put(idev); | 1481 | in6_dev_put(idev); |
1482 | return; | ||
1483 | |||
1484 | err_out: | ||
1485 | kfree_skb(skb); | ||
1486 | goto out; | ||
1483 | } | 1487 | } |
1484 | 1488 | ||
1485 | static int grec_size(struct ifmcaddr6 *pmc, int type, int gdel, int sdel) | 1489 | static int grec_size(struct ifmcaddr6 *pmc, int type, int gdel, int sdel) |
@@ -1761,6 +1765,7 @@ static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type) | |||
1761 | u8 ra[8] = { IPPROTO_ICMPV6, 0, | 1765 | u8 ra[8] = { IPPROTO_ICMPV6, 0, |
1762 | IPV6_TLV_ROUTERALERT, 2, 0, 0, | 1766 | IPV6_TLV_ROUTERALERT, 2, 0, 0, |
1763 | IPV6_TLV_PADN, 0 }; | 1767 | IPV6_TLV_PADN, 0 }; |
1768 | struct flowi fl; | ||
1764 | 1769 | ||
1765 | rcu_read_lock(); | 1770 | rcu_read_lock(); |
1766 | IP6_INC_STATS(__in6_dev_get(dev), | 1771 | IP6_INC_STATS(__in6_dev_get(dev), |
@@ -1813,8 +1818,23 @@ static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type) | |||
1813 | 1818 | ||
1814 | idev = in6_dev_get(skb->dev); | 1819 | idev = in6_dev_get(skb->dev); |
1815 | 1820 | ||
1821 | skb->dst = icmp6_dst_alloc(skb->dev, NULL, &ipv6_hdr(skb)->daddr); | ||
1822 | if (!skb->dst) { | ||
1823 | err = -ENOMEM; | ||
1824 | goto err_out; | ||
1825 | } | ||
1826 | |||
1827 | icmpv6_flow_init(igmp6_socket->sk, &fl, type, | ||
1828 | &ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr, | ||
1829 | skb->dev->ifindex); | ||
1830 | |||
1831 | err = xfrm_lookup(&skb->dst, &fl, NULL, 0); | ||
1832 | if (err) | ||
1833 | goto err_out; | ||
1834 | |||
1816 | err = NF_HOOK(PF_INET6, NF_INET_LOCAL_OUT, skb, NULL, skb->dev, | 1835 | err = NF_HOOK(PF_INET6, NF_INET_LOCAL_OUT, skb, NULL, skb->dev, |
1817 | mld_dev_queue_xmit); | 1836 | dst_output); |
1837 | out: | ||
1818 | if (!err) { | 1838 | if (!err) { |
1819 | ICMP6MSGOUT_INC_STATS(idev, type); | 1839 | ICMP6MSGOUT_INC_STATS(idev, type); |
1820 | ICMP6_INC_STATS(idev, ICMP6_MIB_OUTMSGS); | 1840 | ICMP6_INC_STATS(idev, ICMP6_MIB_OUTMSGS); |
@@ -1825,6 +1845,10 @@ static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type) | |||
1825 | if (likely(idev != NULL)) | 1845 | if (likely(idev != NULL)) |
1826 | in6_dev_put(idev); | 1846 | in6_dev_put(idev); |
1827 | return; | 1847 | return; |
1848 | |||
1849 | err_out: | ||
1850 | kfree_skb(skb); | ||
1851 | goto out; | ||
1828 | } | 1852 | } |
1829 | 1853 | ||
1830 | static int ip6_mc_del1_src(struct ifmcaddr6 *pmc, int sfmode, | 1854 | static int ip6_mc_del1_src(struct ifmcaddr6 *pmc, int sfmode, |