static void igmp6_group_queried(struct ifmcaddr6 *ma, unsigned long resptime) { unsigned long delay = resptime; MDBG3((KERN_DEBUG "igmp6_group_queried(ma=%p, resptime=%lu)\n", ma, resptime)); /* Do not start timer for addresses with reserved/host scope */ if (IPV6_ADDR_MC_SCOPE(&ma->mca_addr) < IPV6_ADDR_SCOPE_LINKLOCAL || ipv6_addr_is_ll_all_nodes(&ma->mca_addr)) return; spin_lock(&ma->mca_lock); if (del_timer(&ma->mca_timer)) { atomic_dec(&ma->mca_refcnt); delay = ma->mca_timer.expires - jiffies; } if (delay >= resptime) { if (resptime) { get_random_bytes(&delay, sizeof(delay)); delay %= resptime; } else delay = 1; } ma->mca_timer.expires = jiffies + delay; if (!mod_timer(&ma->mca_timer, jiffies + delay)) atomic_inc(&ma->mca_refcnt); spin_unlock(&ma->mca_lock); }
static void igmp6_join_group(struct ifmcaddr6 *ma) { unsigned long delay; #ifdef CONFIG_IPV6_MLD6_DEBUG char abuf[128]; in6_ntop(&ma->mca_addr, abuf); MDBG3((KERN_DEBUG "igmp6_join_group(ma=%p): mca_addr=%s\n", ma, abuf)); #endif if (IPV6_ADDR_MC_SCOPE(&ma->mca_addr) < IPV6_ADDR_SCOPE_LINKLOCAL || ipv6_addr_is_ll_all_nodes(&ma->mca_addr)) return; igmp6_send(&ma->mca_addr, ma->idev->dev, ICMPV6_MGM_REPORT); get_random_bytes(&delay, sizeof(delay)); delay %= IGMP6_UNSOLICITED_IVAL; spin_lock_bh(&ma->mca_lock); if (del_timer(&ma->mca_timer)) { atomic_dec(&ma->mca_refcnt); delay = ma->mca_timer.expires - jiffies; } if (!mod_timer(&ma->mca_timer, jiffies + delay)) atomic_inc(&ma->mca_refcnt); ma->mca_flags |= MAF_TIMER_RUNNING | MAF_LAST_REPORTER; spin_unlock_bh(&ma->mca_lock); }
static int ipv6_mc_check_mld_query(struct sk_buff *skb) { unsigned int transport_len = ipv6_transport_len(skb); struct mld_msg *mld; unsigned int len; /* RFC2710+RFC3810 (MLDv1+MLDv2) require link-local source addresses */ if (!(ipv6_addr_type(&ipv6_hdr(skb)->saddr) & IPV6_ADDR_LINKLOCAL)) return -EINVAL; /* MLDv1? */ if (transport_len != sizeof(struct mld_msg)) { /* or MLDv2? */ if (transport_len < sizeof(struct mld2_query)) return -EINVAL; len = skb_transport_offset(skb) + sizeof(struct mld2_query); if (!ipv6_mc_may_pull(skb, len)) return -EINVAL; } mld = (struct mld_msg *)skb_transport_header(skb); /* RFC2710+RFC3810 (MLDv1+MLDv2) require the multicast link layer * all-nodes destination address (ff02::1) for general queries */ if (ipv6_addr_any(&mld->mld_mca) && !ipv6_addr_is_ll_all_nodes(&ipv6_hdr(skb)->daddr)) return -EINVAL; return 0; }
static void igmp6_leave_group(struct ifmcaddr6 *ma) { #ifdef CONFIG_IPV6_MLD6_DEBUG char abuf[128]; in6_ntop(&ma->mca_addr, abuf); MDBG3((KERN_DEBUG "igmp6_leave_group(ma=%p): mca_addr=%s\n", ma, abuf)); #endif if (IPV6_ADDR_MC_SCOPE(&ma->mca_addr) < IPV6_ADDR_SCOPE_LINKLOCAL || ipv6_addr_is_ll_all_nodes(&ma->mca_addr)) return; if (ma->mca_flags & MAF_LAST_REPORTER) igmp6_send(&ma->mca_addr, ma->idev->dev, ICMPV6_MGM_REDUCTION); spin_lock_bh(&ma->mca_lock); if (del_timer(&ma->mca_timer)) atomic_dec(&ma->mca_refcnt); spin_unlock_bh(&ma->mca_lock); }