if (leavegroup) return ipv6_sock_mc_drop(sk, pgsr->gsr_interface, group); 
int ip6_mc_source(int add, int omode, struct sock *sk,	struct group_source_req *pgsr){	struct in6_addr *source, *group;	struct ipv6_mc_socklist *pmc;	struct net_device *dev;	struct inet6_dev *idev;	struct ipv6_pinfo *inet6 = inet6_sk(sk);	struct ip6_sf_socklist *psl;	int i, j, rv;	int err;	if (pgsr->gsr_group.ss_family != AF_INET6 ||	    pgsr->gsr_source.ss_family != AF_INET6)		return -EINVAL;	source = &((struct sockaddr_in6 *)&pgsr->gsr_source)->sin6_addr;	group = &((struct sockaddr_in6 *)&pgsr->gsr_group)->sin6_addr;	if (!ipv6_addr_is_multicast(group))		return -EINVAL;	idev = ip6_mc_find_dev(group, pgsr->gsr_interface);	if (!idev)		return -ENODEV;	dev = idev->dev;	err = -EADDRNOTAVAIL;	for (pmc=inet6->ipv6_mc_list; pmc; pmc=pmc->next) {		if (pgsr->gsr_interface && pmc->ifindex != pgsr->gsr_interface)			continue;		if (ipv6_addr_equal(&pmc->addr, group))			break;	}	if (!pmc)		/* must have a prior join */		goto done;	/* if a source filter was set, must be the same mode as before */	if (pmc->sflist) {		if (pmc->sfmode != omode)			goto done;	} else if (pmc->sfmode != omode) {		/* allow mode switches for empty-set filters */		ip6_mc_add_src(idev, group, omode, 0, NULL, 0);		ip6_mc_del_src(idev, group, pmc->sfmode, 0, NULL, 0);		pmc->sfmode = omode;	}	psl = pmc->sflist;	if (!add) {		if (!psl)			goto done;		rv = !0;		for (i=0; i<psl->sl_count; i++) {			rv = memcmp(&psl->sl_addr[i], source,				sizeof(struct in6_addr));			if (rv == 0)				break;		}		if (rv)		/* source not found */			goto done;		/* update the interface filter */		ip6_mc_del_src(idev, group, omode, 1, source, 1);		for (j=i+1; j<psl->sl_count; j++)			psl->sl_addr[j-1] = psl->sl_addr[j];		psl->sl_count--;		err = 0;		goto done;	}	/* else, add a new source to the filter */	if (psl && psl->sl_count >= sysctl_mld_max_msf) {		err = -ENOBUFS;		goto done;	}	if (!psl || psl->sl_count == psl->sl_max) {		struct ip6_sf_socklist *newpsl;		int count = IP6_SFBLOCK;		if (psl)			count += psl->sl_max;		newpsl = (struct ip6_sf_socklist *)sock_kmalloc(sk,			IP6_SFLSIZE(count), GFP_ATOMIC);		if (!newpsl) {			err = -ENOBUFS;			goto done;		}		newpsl->sl_max = count;		newpsl->sl_count = count - IP6_SFBLOCK;		if (psl) {			for (i=0; i<psl->sl_count; i++)				newpsl->sl_addr[i] = psl->sl_addr[i];			sock_kfree_s(sk, psl, IP6_SFLSIZE(psl->sl_max));		}		pmc->sflist = psl = newpsl;	}	rv = 1;	/* > 0 for insert logic below if sl_count is 0 */	for (i=0; i<psl->sl_count; i++) {		rv = memcmp(&psl->sl_addr[i], source, sizeof(struct in6_addr));		if (rv == 0)			break;	}	if (rv == 0)		/* address already there is an error */		goto done;	for (j=psl->sl_count-1; j>=i; j--)		psl->sl_addr[j+1] = psl->sl_addr[j];	psl->sl_addr[i] = *source;	psl->sl_count++;	err = 0;	/* update the interface list */	ip6_mc_add_src(idev, group, omode, 1, source, 1);done:	read_unlock_bh(&idev->lock);	in6_dev_put(idev);	dev_put(dev);	return err;}
4520	/local/tlutelli/issta_data/temp/c/2005_temp/2005/4520/c9e3e8b6958e02230079e6817862ea2968509866/mcast.c/clean/net/ipv6/mcast.c