aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/ipv6/mcast.c66
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
1436static 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
1449static 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
1455static void mld_sendpack(struct sk_buff *skb) 1436static 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);
1472out:
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
1484err_out:
1485 kfree_skb(skb);
1486 goto out;
1483} 1487}
1484 1488
1485static int grec_size(struct ifmcaddr6 *pmc, int type, int gdel, int sdel) 1489static 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);
1837out:
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
1849err_out:
1850 kfree_skb(skb);
1851 goto out;
1828} 1852}
1829 1853
1830static int ip6_mc_del1_src(struct ifmcaddr6 *pmc, int sfmode, 1854static int ip6_mc_del1_src(struct ifmcaddr6 *pmc, int sfmode,