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

📄 igmp.c

📁 Linux Kernel 2.6.9 for OMAP1710
💻 C
📖 第 1 页 / 共 4 页
字号:
{	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	in_dev->mc_list_lock = RW_LOCK_UNLOCKED;	in_dev->mc_tomb_lock = SPIN_LOCK_UNLOCKED;}/* 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(dev);	}	return idev;}/* *	Join a socket to a group */int sysctl_igmp_max_memberships = IP_MAX_MEMBERSHIPS;int sysctl_igmp_max_msf = IP_MAX_MSF;static int ip_mc_del1_src(struct ip_mc_list *pmc, int sfmode,	__u32 *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)#endifint ip_mc_del_src(struct in_device *in_dev, __u32 *pmca, int sfmode,	int sfcount, __u32 *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,	__u32 *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) {		psf = (struct ip_sf_list *)kmalloc(sizeof(*psf), GFP_ATOMIC);		if (!psf)			return -ENOBUFS;		memset(psf, 0, sizeof(*psf));		psf->sf_inaddr = *psfsrc;		if (psf_prev) {			psf_prev->sf_next = psf;		} else			pmc->sources = psf;	}	psf->sf_count[sfmode]++;	if (psf->sf_count[sfmode] == 1) {		ip_rt_multicast_event(pmc->interface);	}	return 0;}#ifdef CONFIG_IP_MULTICASTstatic void sf_markstate(struct ip_mc_list *pmc){	struct ip_sf_list *psf;	int mca_xcount = pmc->sfcount[MCAST_EXCLUDE];	for (psf=pmc->sources; psf; psf=psf->sf_next)		if (pmc->sfcount[MCAST_EXCLUDE]) {			psf->sf_oldin = mca_xcount ==				psf->sf_count[MCAST_EXCLUDE] &&				!psf->sf_count[MCAST_INCLUDE];		} else			psf->sf_oldin = psf->sf_count[MCAST_INCLUDE] != 0;}static int sf_setstate(struct ip_mc_list *pmc){	struct ip_sf_list *psf;	int mca_xcount = pmc->sfcount[MCAST_EXCLUDE];	int qrv = pmc->interface->mr_qrv;	int new_in, rv;	rv = 0;	for (psf=pmc->sources; psf; psf=psf->sf_next) {		if (pmc->sfcount[MCAST_EXCLUDE]) {			new_in = mca_xcount == psf->sf_count[MCAST_EXCLUDE] &&				!psf->sf_count[MCAST_INCLUDE];		} else			new_in = psf->sf_count[MCAST_INCLUDE] != 0;		if (new_in != psf->sf_oldin) {			psf->sf_crcount = qrv;			rv++;		}	}	return rv;}#endif/* * Add multicast source filter list to the interface list */int ip_mc_add_src(struct in_device *in_dev, __u32 *pmca, int sfmode,	int sfcount, __u32 *psfsrc, int delta){	struct ip_mc_list *pmc;	int	isexclude;	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	isexclude = pmc->sfmode == MCAST_EXCLUDE;	if (!delta)		pmc->sfcount[sfmode]++;	err = 0;	for (i=0; i<sfcount; i++) {		err = ip_mc_add1_src(pmc, sfmode, &psfsrc[i], delta);		if (err)			break;	}	if (err) {		int j;		pmc->sfcount[sfmode]--;		for (j=0; j<i; j++)			(void) ip_mc_del1_src(pmc, sfmode, &psfsrc[i]);	} else if (isexclude != (pmc->sfcount[MCAST_EXCLUDE] != 0)) {#ifdef CONFIG_IP_MULTICAST		struct in_device *in_dev = pmc->interface;		struct ip_sf_list *psf;#endif		/* filter mode change */		if (pmc->sfcount[MCAST_EXCLUDE])			pmc->sfmode = MCAST_EXCLUDE;		else if (pmc->sfcount[MCAST_INCLUDE])			pmc->sfmode = MCAST_INCLUDE;#ifdef CONFIG_IP_MULTICAST		/* else no filters; keep old mode for reports */		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(in_dev);	} else if (sf_setstate(pmc)) {		igmp_ifc_event(in_dev);#endif	}	spin_unlock_bh(&pmc->lock);	return err;}static void ip_mc_clear_src(struct ip_mc_list *pmc){	struct ip_sf_list *psf, *nextpsf;	for (psf=pmc->tomb; psf; psf=nextpsf) {		nextpsf = psf->sf_next;		kfree(psf);	}	pmc->tomb = NULL;	for (psf=pmc->sources; psf; psf=nextpsf) {		nextpsf = psf->sf_next;		kfree(psf);	}	pmc->sources = NULL;	pmc->sfmode = MCAST_EXCLUDE;	pmc->sfcount[MCAST_EXCLUDE] = 0;	pmc->sfcount[MCAST_EXCLUDE] = 1;}/* * Join a multicast group */int ip_mc_join_group(struct sock *sk , struct ip_mreqn *imr){	int err;	u32 addr = imr->imr_multiaddr.s_addr;	struct ip_mc_socklist *iml, *i;	struct in_device *in_dev;	struct inet_opt *inet = inet_sk(sk);	int count = 0;	if (!MULTICAST(addr))		return -EINVAL;	rtnl_shlock();	in_dev = ip_mc_find_dev(imr);	if (!in_dev) {		iml = NULL;		err = -ENODEV;		goto done;	}	iml = (struct ip_mc_socklist *)sock_kmalloc(sk, sizeof(*iml), GFP_KERNEL);	err = -EADDRINUSE;	for (i = inet->mc_list; i; i = i->next) {		if (memcmp(&i->multi, imr, sizeof(*imr)) == 0) {			/* New style additions are reference counted */			if (imr->imr_address.s_addr == 0) {				i->count++;				err = 0;			}			goto done;		}		count++;	}	err = -ENOBUFS;	if (iml == NULL || count >= sysctl_igmp_max_memberships)		goto done;	memcpy(&iml->multi, imr, sizeof(*imr));	iml->next = inet->mc_list;	iml->count = 1;	iml->sflist = NULL;	iml->sfmode = MCAST_EXCLUDE;	inet->mc_list = iml;	ip_mc_inc_group(in_dev, addr);	iml = NULL;	err = 0;done:	rtnl_shunlock();	if (iml)		sock_kfree_s(sk, iml, sizeof(*iml));	return err;}int ip_mc_leave_src(struct sock *sk, struct ip_mc_socklist *iml,	struct in_device *in_dev){	int err;	if (iml->sflist == 0) {		/* any-source empty exclude case */		return ip_mc_del_src(in_dev, &iml->multi.imr_multiaddr.s_addr,			iml->sfmode, 0, NULL, 0);	}	err = ip_mc_del_src(in_dev, &iml->multi.imr_multiaddr.s_addr,			iml->sfmode, iml->sflist->sl_count,			iml->sflist->sl_addr, 0);	sock_kfree_s(sk, iml->sflist, IP_SFLSIZE(iml->sflist->sl_max));	iml->sflist = NULL;	return err;}/* *	Ask a socket to leave a group. */int ip_mc_leave_group(struct sock *sk, struct ip_mreqn *imr){	struct inet_opt *inet = inet_sk(sk);	struct ip_mc_socklist *iml, **imlp;	rtnl_lock();	for (imlp = &inet->mc_list; (iml = *imlp) != NULL; imlp = &iml->next) {		if (iml->multi.imr_multiaddr.s_addr==imr->imr_multiaddr.s_addr &&		    iml->multi.imr_address.s_addr==imr->imr_address.s_addr &&		    (!imr->imr_ifindex || iml->multi.imr_ifindex==imr->imr_ifindex)) {			struct in_device *in_dev;			in_dev = inetdev_by_index(iml->multi.imr_ifindex);			if (in_dev)				(void) ip_mc_leave_src(sk, iml, in_dev);			if (--iml->count) {				rtnl_unlock();				if (in_dev)					in_dev_put(in_dev);				return 0;			}			*imlp = iml->next;			if (in_dev) {				ip_mc_dec_group(in_dev, imr->imr_multiaddr.s_addr);				in_dev_put(in_dev);			}			rtnl_unlock();			sock_kfree_s(sk, iml, sizeof(*iml));			return 0;		}	}	rtnl_unlock();	return -EADDRNOTAVAIL;}int ip_mc_source(int add, int omode, struct sock *sk, struct	ip_mreq_source *mreqs, int ifindex){	int err;	struct ip_mreqn imr;	u32 addr = mreqs->imr_multiaddr;	struct ip_mc_socklist *pmc;	struct in_device *in_dev = NULL;	struct inet_opt *inet = inet_sk(sk);	struct ip_sf_socklist *psl;	int i, j, rv;	if (!MULTICAST(addr))		return -EINVAL;	rtnl_shlock();	imr.imr_multiaddr.s_addr = mreqs->imr_multiaddr;	imr.imr_address.s_addr = mreqs->imr_interface;	imr.imr_ifindex = ifindex;	in_dev = ip_mc_find_dev(&imr);	if (!in_dev) {		err = -ENODEV;		goto done;	}	err = -EADDRNOTAVAIL;	for (pmc=inet->mc_list; pmc; pmc=pmc->next) {		if (memcmp(&pmc->multi, mreqs, 2*sizeof(__u32)) == 0)			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 */		ip_mc_add_src(in_dev, &mreqs->imr_multiaddr, omode, 0, NULL, 0);		ip_mc_del_src(in_dev, &mreqs->imr_multiaddr, 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, &mreqs->imr_multiaddr,				sizeof(__u32));			if (rv >= 0)				break;		}		if (!rv)	/* source not found */			goto done;		/* update the interface filter */		ip_mc_del_src(in_dev, &mreqs->imr_multiaddr, omode, 1, 			&mreqs->imr_sourceaddr, 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_igmp_max_msf) {		err = -ENOBUFS;		goto done;	}	if (!psl || psl->sl_count == psl->sl_max) {		struct ip_sf_socklist *newpsl;		int count = IP_SFBLOCK;		if (psl)			count += psl->sl_max;		newpsl = (struct ip_sf_socklist *)sock_kmalloc(sk,			IP_SFLSIZE(count), GFP_KERNEL);		if (!newpsl) {			err = -ENOBUFS;			goto done;		}		newpsl->sl_max = count;		newpsl->sl_count = count - IP_SFBLOCK;		if (psl) {			for (i=0; i<psl->sl_count; i++)				newpsl->sl_addr[i] = psl->sl_addr[i];			sock_kfree_s(sk, psl, IP_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, &mreqs->imr_multiaddr,			sizeof(__u32));		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] = mreqs->imr_sourceaddr;	psl->sl_count++;	err = 0;	/* update the interface list */	ip_mc_add_src(in_dev, &mreqs->imr_multiaddr, omode, 1, 		&mreqs->imr_sourceaddr, 1);done:	rtnl_shunlock();	return err;}int ip_mc_msfilter(struct sock *sk, struct ip_msfilter *msf, int ifindex){	int err;	struct ip_mreqn	imr;	u32 addr = msf->imsf_multiaddr;	struct ip_mc_socklist *pmc;	struct in_device *in_dev;	struct inet_opt *inet = inet_sk(sk);	struct ip_sf_socklist *newpsl, *psl;

⌨️ 快捷键说明

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