⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 igmp.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
		return;	spin_lock_bh(&im->lock);	pmc->interface = im->interface;	in_dev_hold(in_dev);	pmc->multiaddr = im->multiaddr;	pmc->crcount = in_dev->mr_qrv ? in_dev->mr_qrv :		IGMP_Unsolicited_Report_Count;	pmc->sfmode = im->sfmode;	if (pmc->sfmode == MCAST_INCLUDE) {		struct ip_sf_list *psf;		pmc->tomb = im->tomb;		pmc->sources = im->sources;		im->tomb = im->sources = NULL;		for (psf=pmc->sources; psf; psf=psf->sf_next)			psf->sf_crcount = pmc->crcount;	}	spin_unlock_bh(&im->lock);	spin_lock_bh(&in_dev->mc_tomb_lock);	pmc->next = in_dev->mc_tomb;	in_dev->mc_tomb = pmc;	spin_unlock_bh(&in_dev->mc_tomb_lock);}static void igmpv3_del_delrec(struct in_device *in_dev, __be32 multiaddr){	struct ip_mc_list *pmc, *pmc_prev;	struct ip_sf_list *psf, *psf_next;	spin_lock_bh(&in_dev->mc_tomb_lock);	pmc_prev = NULL;	for (pmc=in_dev->mc_tomb; pmc; pmc=pmc->next) {		if (pmc->multiaddr == multiaddr)			break;		pmc_prev = pmc;	}	if (pmc) {		if (pmc_prev)			pmc_prev->next = pmc->next;		else			in_dev->mc_tomb = pmc->next;	}	spin_unlock_bh(&in_dev->mc_tomb_lock);	if (pmc) {		for (psf=pmc->tomb; psf; psf=psf_next) {			psf_next = psf->sf_next;			kfree(psf);		}		in_dev_put(pmc->interface);		kfree(pmc);	}}static void igmpv3_clear_delrec(struct in_device *in_dev){	struct ip_mc_list *pmc, *nextpmc;	spin_lock_bh(&in_dev->mc_tomb_lock);	pmc = in_dev->mc_tomb;	in_dev->mc_tomb = NULL;	spin_unlock_bh(&in_dev->mc_tomb_lock);	for (; pmc; pmc = nextpmc) {		nextpmc = pmc->next;		ip_mc_clear_src(pmc);		in_dev_put(pmc->interface);		kfree(pmc);	}	/* clear dead sources, too */	read_lock(&in_dev->mc_list_lock);	for (pmc=in_dev->mc_list; pmc; pmc=pmc->next) {		struct ip_sf_list *psf, *psf_next;		spin_lock_bh(&pmc->lock);		psf = pmc->tomb;		pmc->tomb = NULL;		spin_unlock_bh(&pmc->lock);		for (; psf; psf=psf_next) {			psf_next = psf->sf_next;			kfree(psf);		}	}	read_unlock(&in_dev->mc_list_lock);}#endifstatic void igmp_group_dropped(struct ip_mc_list *im){	struct in_device *in_dev = im->interface;#ifdef CONFIG_IP_MULTICAST	int reporter;#endif	if (im->loaded) {		im->loaded = 0;		ip_mc_filter_del(in_dev, im->multiaddr);	}#ifdef CONFIG_IP_MULTICAST	if (im->multiaddr == IGMP_ALL_HOSTS)		return;	reporter = im->reporter;	igmp_stop_timer(im);	if (!in_dev->dead) {		if (IGMP_V1_SEEN(in_dev))			goto done;		if (IGMP_V2_SEEN(in_dev)) {			if (reporter)				igmp_send_report(in_dev, im, IGMP_HOST_LEAVE_MESSAGE);			goto done;		}		/* IGMPv3 */		igmpv3_add_delrec(in_dev, im);		igmp_ifc_event(in_dev);	}done:#endif	ip_mc_clear_src(im);}static void igmp_group_added(struct ip_mc_list *im){	struct in_device *in_dev = im->interface;	if (im->loaded == 0) {		im->loaded = 1;		ip_mc_filter_add(in_dev, im->multiaddr);	}#ifdef CONFIG_IP_MULTICAST	if (im->multiaddr == IGMP_ALL_HOSTS)		return;	if (in_dev->dead)		return;	if (IGMP_V1_SEEN(in_dev) || IGMP_V2_SEEN(in_dev)) {		spin_lock_bh(&im->lock);		igmp_start_timer(im, IGMP_Initial_Report_Delay);		spin_unlock_bh(&im->lock);		return;	}	/* else, v3 */	im->crcount = in_dev->mr_qrv ? in_dev->mr_qrv :		IGMP_Unsolicited_Report_Count;	igmp_ifc_event(in_dev);#endif}/* *	Multicast list managers *//* *	A socket has joined a multicast group on device dev. */void ip_mc_inc_group(struct in_device *in_dev, __be32 addr){	struct ip_mc_list *im;	ASSERT_RTNL();	for (im=in_dev->mc_list; im; im=im->next) {		if (im->multiaddr == addr) {			im->users++;			ip_mc_add_src(in_dev, &addr, MCAST_EXCLUDE, 0, NULL, 0);			goto out;		}	}	im = kmalloc(sizeof(*im), GFP_KERNEL);	if (!im)		goto out;	im->users=1;	im->interface=in_dev;	in_dev_hold(in_dev);	im->multiaddr=addr;	/* initial mode is (EX, empty) */	im->sfmode = MCAST_EXCLUDE;	im->sfcount[MCAST_INCLUDE] = 0;	im->sfcount[MCAST_EXCLUDE] = 1;	im->sources = NULL;	im->tomb = NULL;	im->crcount = 0;	atomic_set(&im->refcnt, 1);	spin_lock_init(&im->lock);#ifdef CONFIG_IP_MULTICAST	im->tm_running=0;	init_timer(&im->timer);	im->timer.data=(unsigned long)im;	im->timer.function=&igmp_timer_expire;	im->unsolicit_count = IGMP_Unsolicited_Report_Count;	im->reporter = 0;	im->gsquery = 0;#endif	im->loaded = 0;	write_lock_bh(&in_dev->mc_list_lock);	im->next=in_dev->mc_list;	in_dev->mc_list=im;	write_unlock_bh(&in_dev->mc_list_lock);#ifdef CONFIG_IP_MULTICAST	igmpv3_del_delrec(in_dev, im->multiaddr);#endif	igmp_group_added(im);	if (!in_dev->dead)		ip_rt_multicast_event(in_dev);out:	return;}/* *	Resend IGMP JOIN report; used for bonding. */void ip_mc_rejoin_group(struct ip_mc_list *im){#ifdef CONFIG_IP_MULTICAST	struct in_device *in_dev = im->interface;	if (im->multiaddr == IGMP_ALL_HOSTS)		return;	if (IGMP_V1_SEEN(in_dev) || IGMP_V2_SEEN(in_dev)) {		igmp_mod_timer(im, IGMP_Initial_Report_Delay);		return;	}	/* else, v3 */	im->crcount = in_dev->mr_qrv ? in_dev->mr_qrv :		IGMP_Unsolicited_Report_Count;	igmp_ifc_event(in_dev);#endif}/* *	A socket has left a multicast group on device dev */void ip_mc_dec_group(struct in_device *in_dev, __be32 addr){	struct ip_mc_list *i, **ip;	ASSERT_RTNL();	for (ip=&in_dev->mc_list; (i=*ip)!=NULL; ip=&i->next) {		if (i->multiaddr==addr) {			if (--i->users == 0) {				write_lock_bh(&in_dev->mc_list_lock);				*ip = i->next;				write_unlock_bh(&in_dev->mc_list_lock);				igmp_group_dropped(i);				if (!in_dev->dead)					ip_rt_multicast_event(in_dev);				ip_ma_put(i);				return;			}			break;		}	}}/* Device going down */void ip_mc_down(struct in_device *in_dev){	struct ip_mc_list *i;	ASSERT_RTNL();	for (i=in_dev->mc_list; i; i=i->next)		igmp_group_dropped(i);#ifdef CONFIG_IP_MULTICAST	in_dev->mr_ifc_count = 0;	if (del_timer(&in_dev->mr_ifc_timer))		__in_dev_put(in_dev);	in_dev->mr_gq_running = 0;	if (del_timer(&in_dev->mr_gq_timer))		__in_dev_put(in_dev);	igmpv3_clear_delrec(in_dev);#endif	ip_mc_dec_group(in_dev, IGMP_ALL_HOSTS);}void ip_mc_init_dev(struct in_device *in_dev){	ASSERT_RTNL();	in_dev->mc_tomb = NULL;#ifdef CONFIG_IP_MULTICAST	in_dev->mr_gq_running = 0;	init_timer(&in_dev->mr_gq_timer);	in_dev->mr_gq_timer.data=(unsigned long) in_dev;	in_dev->mr_gq_timer.function=&igmp_gq_timer_expire;	in_dev->mr_ifc_count = 0;	init_timer(&in_dev->mr_ifc_timer);	in_dev->mr_ifc_timer.data=(unsigned long) in_dev;	in_dev->mr_ifc_timer.function=&igmp_ifc_timer_expire;	in_dev->mr_qrv = IGMP_Unsolicited_Report_Count;#endif	rwlock_init(&in_dev->mc_list_lock);	spin_lock_init(&in_dev->mc_tomb_lock);}/* Device going up */void ip_mc_up(struct in_device *in_dev){	struct ip_mc_list *i;	ASSERT_RTNL();	ip_mc_inc_group(in_dev, IGMP_ALL_HOSTS);	for (i=in_dev->mc_list; i; i=i->next)		igmp_group_added(i);}/* *	Device is about to be destroyed: clean up. */void ip_mc_destroy_dev(struct in_device *in_dev){	struct ip_mc_list *i;	ASSERT_RTNL();	/* Deactivate timers */	ip_mc_down(in_dev);	write_lock_bh(&in_dev->mc_list_lock);	while ((i = in_dev->mc_list) != NULL) {		in_dev->mc_list = i->next;		write_unlock_bh(&in_dev->mc_list_lock);		igmp_group_dropped(i);		ip_ma_put(i);		write_lock_bh(&in_dev->mc_list_lock);	}	write_unlock_bh(&in_dev->mc_list_lock);}static struct in_device * ip_mc_find_dev(struct ip_mreqn *imr){	struct flowi fl = { .nl_u = { .ip4_u =				      { .daddr = imr->imr_multiaddr.s_addr } } };	struct rtable *rt;	struct net_device *dev = NULL;	struct in_device *idev = NULL;	if (imr->imr_ifindex) {		idev = inetdev_by_index(imr->imr_ifindex);		if (idev)			__in_dev_put(idev);		return idev;	}	if (imr->imr_address.s_addr) {		dev = ip_dev_find(imr->imr_address.s_addr);		if (!dev)			return NULL;		dev_put(dev);	}	if (!dev && !ip_route_output_key(&rt, &fl)) {		dev = rt->u.dst.dev;		ip_rt_put(rt);	}	if (dev) {		imr->imr_ifindex = dev->ifindex;		idev = __in_dev_get_rtnl(dev);	}	return idev;}/* *	Join a socket to a group */int sysctl_igmp_max_memberships __read_mostly = IP_MAX_MEMBERSHIPS;int sysctl_igmp_max_msf __read_mostly = IP_MAX_MSF;static int ip_mc_del1_src(struct ip_mc_list *pmc, int sfmode,	__be32 *psfsrc){	struct ip_sf_list *psf, *psf_prev;	int rv = 0;	psf_prev = NULL;	for (psf=pmc->sources; psf; psf=psf->sf_next) {		if (psf->sf_inaddr == *psfsrc)			break;		psf_prev = psf;	}	if (!psf || psf->sf_count[sfmode] == 0) {		/* source filter not found, or count wrong =>  bug */		return -ESRCH;	}	psf->sf_count[sfmode]--;	if (psf->sf_count[sfmode] == 0) {		ip_rt_multicast_event(pmc->interface);	}	if (!psf->sf_count[MCAST_INCLUDE] && !psf->sf_count[MCAST_EXCLUDE]) {#ifdef CONFIG_IP_MULTICAST		struct in_device *in_dev = pmc->interface;#endif		/* no more filters for this source */		if (psf_prev)			psf_prev->sf_next = psf->sf_next;		else			pmc->sources = psf->sf_next;#ifdef CONFIG_IP_MULTICAST		if (psf->sf_oldin &&		    !IGMP_V1_SEEN(in_dev) && !IGMP_V2_SEEN(in_dev)) {			psf->sf_crcount = in_dev->mr_qrv ? in_dev->mr_qrv :				IGMP_Unsolicited_Report_Count;			psf->sf_next = pmc->tomb;			pmc->tomb = psf;			rv = 1;		} else#endif			kfree(psf);	}	return rv;}#ifndef CONFIG_IP_MULTICAST#define igmp_ifc_event(x)	do { } while (0)#endifstatic int ip_mc_del_src(struct in_device *in_dev, __be32 *pmca, int sfmode,			 int sfcount, __be32 *psfsrc, int delta){	struct ip_mc_list *pmc;	int	changerec = 0;	int	i, err;	if (!in_dev)		return -ENODEV;	read_lock(&in_dev->mc_list_lock);	for (pmc=in_dev->mc_list; pmc; pmc=pmc->next) {		if (*pmca == pmc->multiaddr)			break;	}	if (!pmc) {		/* MCA not found?? bug */		read_unlock(&in_dev->mc_list_lock);		return -ESRCH;	}	spin_lock_bh(&pmc->lock);	read_unlock(&in_dev->mc_list_lock);#ifdef CONFIG_IP_MULTICAST	sf_markstate(pmc);#endif	if (!delta) {		err = -EINVAL;		if (!pmc->sfcount[sfmode])			goto out_unlock;		pmc->sfcount[sfmode]--;	}	err = 0;	for (i=0; i<sfcount; i++) {		int rv = ip_mc_del1_src(pmc, sfmode, &psfsrc[i]);		changerec |= rv > 0;		if (!err && rv < 0)			err = rv;	}	if (pmc->sfmode == MCAST_EXCLUDE &&	    pmc->sfcount[MCAST_EXCLUDE] == 0 &&	    pmc->sfcount[MCAST_INCLUDE]) {#ifdef CONFIG_IP_MULTICAST		struct ip_sf_list *psf;#endif		/* filter mode change */		pmc->sfmode = MCAST_INCLUDE;#ifdef CONFIG_IP_MULTICAST		pmc->crcount = in_dev->mr_qrv ? in_dev->mr_qrv :			IGMP_Unsolicited_Report_Count;		in_dev->mr_ifc_count = pmc->crcount;		for (psf=pmc->sources; psf; psf = psf->sf_next)			psf->sf_crcount = 0;		igmp_ifc_event(pmc->interface);	} else if (sf_setstate(pmc) || changerec) {		igmp_ifc_event(pmc->interface);#endif	}out_unlock:	spin_unlock_bh(&pmc->lock);	return err;}/* * Add multicast single-source filter to the interface list */static int ip_mc_add1_src(struct ip_mc_list *pmc, int sfmode,	__be32 *psfsrc, int delta){	struct ip_sf_list *psf, *psf_prev;	psf_prev = NULL;	for (psf=pmc->sources; psf; psf=psf->sf_next) {		if (psf->sf_inaddr == *psfsrc)			break;		psf_prev = psf;	}	if (!psf) {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -