int ip6_mc_msfget(struct sock *sk, struct group_filter *gsf,
		  struct sockaddr_storage __user *p)
{
	struct ipv6_pinfo *inet6 = inet6_sk(sk);
	const struct in6_addr *group;
	struct ipv6_mc_socklist *pmc;
	struct ip6_sf_socklist *psl;
	int i, count, copycount;

	group = &((struct sockaddr_in6 *)&gsf->gf_group)->sin6_addr;

	if (!ipv6_addr_is_multicast(group))
		return -EINVAL;

	/* changes to the ipv6_mc_list require the socket lock and
	 * rtnl lock. We have the socket lock, so reading the list is safe.
	 */

	for_each_pmc_socklock(inet6, sk, pmc) {
		if (pmc->ifindex != gsf->gf_interface)
			continue;
		if (ipv6_addr_equal(group, &pmc->addr))
			break;
	}
	if (!pmc)		/* must have a prior join */
		return -EADDRNOTAVAIL;

	gsf->gf_fmode = pmc->sfmode;
	psl = sock_dereference(pmc->sflist, sk);
	count = psl ? psl->sl_count : 0;

	copycount = count < gsf->gf_numsrc ? count : gsf->gf_numsrc;
	gsf->gf_numsrc = count;

	for (i = 0; i < copycount; i++, p++) {
		struct sockaddr_in6 *psin6;
		struct sockaddr_storage ss;

		psin6 = (struct sockaddr_in6 *)&ss;
		memset(&ss, 0, sizeof(ss));
		psin6->sin6_family = AF_INET6;
		psin6->sin6_addr = psl->sl_addr[i];
		if (copy_to_user(p, &ss, sizeof(ss)))
			return -EFAULT;
	}
	return 0;
}
int ip6_mc_msfget(struct sock *sk, struct group_filter *gsf,
		  struct sockaddr_storage __user *p)
{
	struct ipv6_pinfo *inet6 = inet6_sk(sk);
	const struct in6_addr *group;
	struct ipv6_mc_socklist *pmc;
	struct ip6_sf_socklist *psl;
	int i, count, copycount;

	group = &((struct sockaddr_in6 *)&gsf->gf_group)->sin6_addr;

	if (!ipv6_addr_is_multicast(group))
		return -EINVAL;

	 

	for_each_pmc_socklock(inet6, sk, pmc) {
		if (pmc->ifindex != gsf->gf_interface)
			continue;
		if (ipv6_addr_equal(group, &pmc->addr))
			break;
	}
	if (!pmc)		 
		return -EADDRNOTAVAIL;

	gsf->gf_fmode = pmc->sfmode;
	psl = sock_dereference(pmc->sflist, sk);
	count = psl ? psl->sl_count : 0;

	copycount = count < gsf->gf_numsrc ? count : gsf->gf_numsrc;
	gsf->gf_numsrc = count;

	for (i = 0; i < copycount; i++, p++) {
		struct sockaddr_in6 *psin6;
		struct sockaddr_storage ss;

		psin6 = (struct sockaddr_in6 *)&ss;
		memset(&ss, 0, sizeof(ss));
		psin6->sin6_family = AF_INET6;
		psin6->sin6_addr = psl->sl_addr[i];
		if (copy_to_user(p, &ss, sizeof(ss)))
			return -EFAULT;
	}
	return 0;
}