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

📄 igmp.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
		psf = kzalloc(sizeof(*psf), GFP_ATOMIC);		if (!psf)			return -ENOBUFS;		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, *dpsf;	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) {			if (!psf->sf_oldin) {				struct ip_sf_list *prev = NULL;				for (dpsf=pmc->tomb; dpsf; dpsf=dpsf->sf_next) {					if (dpsf->sf_inaddr == psf->sf_inaddr)						break;					prev = dpsf;				}				if (dpsf) {					if (prev)						prev->sf_next = dpsf->sf_next;					else						pmc->tomb = dpsf->sf_next;					kfree(dpsf);				}				psf->sf_crcount = qrv;				rv++;			}		} else if (psf->sf_oldin) {			psf->sf_crcount = 0;			/*			 * add or update "delete" records if an active filter			 * is now inactive			 */			for (dpsf=pmc->tomb; dpsf; dpsf=dpsf->sf_next)				if (dpsf->sf_inaddr == psf->sf_inaddr)					break;			if (!dpsf) {				dpsf = (struct ip_sf_list *)					kmalloc(sizeof(*dpsf), GFP_ATOMIC);				if (!dpsf)					continue;				*dpsf = *psf;				/* pmc->lock held by callers */				dpsf->sf_next = pmc->tomb;				pmc->tomb = dpsf;			}			dpsf->sf_crcount = qrv;			rv++;		}	}	return rv;}#endif/* * Add multicast source filter list to the interface list */static int ip_mc_add_src(struct in_device *in_dev, __be32 *pmca, int sfmode,			 int sfcount, __be32 *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 ip_sf_list *psf;		in_dev = pmc->interface;#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_INCLUDE] = 0;	pmc->sfcount[MCAST_EXCLUDE] = 1;}/* * Join a multicast group */int ip_mc_join_group(struct sock *sk , struct ip_mreqn *imr){	int err;	__be32 addr = imr->imr_multiaddr.s_addr;	struct ip_mc_socklist *iml=NULL, *i;	struct in_device *in_dev;	struct inet_sock *inet = inet_sk(sk);	int ifindex;	int count = 0;	if (!MULTICAST(addr))		return -EINVAL;	rtnl_lock();	in_dev = ip_mc_find_dev(imr);	if (!in_dev) {		iml = NULL;		err = -ENODEV;		goto done;	}	err = -EADDRINUSE;	ifindex = imr->imr_ifindex;	for (i = inet->mc_list; i; i = i->next) {		if (i->multi.imr_multiaddr.s_addr == addr &&		    i->multi.imr_ifindex == ifindex)			goto done;		count++;	}	err = -ENOBUFS;	if (count >= sysctl_igmp_max_memberships)		goto done;	iml = sock_kmalloc(sk,sizeof(*iml),GFP_KERNEL);	if (iml == NULL)		goto done;	memcpy(&iml->multi, imr, sizeof(*imr));	iml->next = inet->mc_list;	iml->sflist = NULL;	iml->sfmode = MCAST_EXCLUDE;	inet->mc_list = iml;	ip_mc_inc_group(in_dev, addr);	err = 0;done:	rtnl_unlock();	return err;}static int ip_mc_leave_src(struct sock *sk, struct ip_mc_socklist *iml,			   struct in_device *in_dev){	int err;	if (iml->sflist == NULL) {		/* 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_sock *inet = inet_sk(sk);	struct ip_mc_socklist *iml, **imlp;	struct in_device *in_dev;	__be32 group = imr->imr_multiaddr.s_addr;	u32 ifindex;	int ret = -EADDRNOTAVAIL;	rtnl_lock();	in_dev = ip_mc_find_dev(imr);	ifindex = imr->imr_ifindex;	for (imlp = &inet->mc_list; (iml = *imlp) != NULL; imlp = &iml->next) {		if (iml->multi.imr_multiaddr.s_addr != group)			continue;		if (ifindex) {			if (iml->multi.imr_ifindex != ifindex)				continue;		} else if (imr->imr_address.s_addr && imr->imr_address.s_addr !=				iml->multi.imr_address.s_addr)			continue;		(void) ip_mc_leave_src(sk, iml, in_dev);		*imlp = iml->next;		if (in_dev)			ip_mc_dec_group(in_dev, group);		rtnl_unlock();		sock_kfree_s(sk, iml, sizeof(*iml));		return 0;	}	if (!in_dev)		ret = -ENODEV;	rtnl_unlock();	return ret;}int ip_mc_source(int add, int omode, struct sock *sk, struct	ip_mreq_source *mreqs, int ifindex){	int err;	struct ip_mreqn imr;	__be32 addr = mreqs->imr_multiaddr;	struct ip_mc_socklist *pmc;	struct in_device *in_dev = NULL;	struct inet_sock *inet = inet_sk(sk);	struct ip_sf_socklist *psl;	int leavegroup = 0;	int i, j, rv;	if (!MULTICAST(addr))		return -EINVAL;	rtnl_lock();	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 (pmc->multi.imr_multiaddr.s_addr == imr.imr_multiaddr.s_addr		    && pmc->multi.imr_ifindex == imr.imr_ifindex)			break;	}	if (!pmc) {		/* must have a prior join */		err = -EINVAL;		goto done;	}	/* if a source filter was set, must be the same mode as before */	if (pmc->sflist) {		if (pmc->sfmode != omode) {			err = -EINVAL;			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;	/* err = -EADDRNOTAVAIL */		rv = !0;		for (i=0; i<psl->sl_count; i++) {			rv = memcmp(&psl->sl_addr[i], &mreqs->imr_sourceaddr,				sizeof(__be32));			if (rv == 0)				break;		}		if (rv)		/* source not found */			goto done;	/* err = -EADDRNOTAVAIL */		/* special case - (INCLUDE, empty) == LEAVE_GROUP */		if (psl->sl_count == 1 && omode == MCAST_INCLUDE) {			leavegroup = 1;			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 = 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[i], &mreqs->imr_sourceaddr,			sizeof(__be32));		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_unlock();	if (leavegroup)		return ip_mc_leave_group(sk, &imr);	return err;}int ip_mc_msfilter(struct sock *sk, struct ip_msfilter *msf, int ifindex){	int err = 0;	struct ip_mreqn	imr;	__be32 addr = msf->imsf_multiaddr;	struct ip_mc_socklist *pmc;	struct in_device *in_dev;	struct inet_sock *inet = inet_sk(sk);	struct ip_sf_socklist *newpsl, *psl;	int leavegroup = 0;	if (!MULTICAST(addr))		return -EINVAL;	if (msf->imsf_fmode != MCAST_INCLUDE &&	    msf->imsf_fmode != MCAST_EXCLUDE)		return -EINVAL;	rtnl_lock();	imr.imr_multiaddr.s_addr = msf->imsf_multiaddr;	imr.imr_address.s_addr = msf->imsf_interface;	imr.imr_ifindex = ifindex;	in_dev = ip_mc_find_dev(&imr);	if (!in_dev) {		err = -ENODEV;		goto done;	}	/* special case - (INCLUDE, empty) == LEAVE_GROUP */	if (msf->imsf_fmode == MCAST_INCLUDE && msf->imsf_numsrc == 0) {		leavegroup = 1;		goto done;	}	for (pmc=inet->mc_list; pmc; pmc=pmc->next) {		if (pmc->multi.imr_multiaddr.s_addr == msf->imsf_multiaddr &&		    pmc->multi.imr_ifindex == imr.imr_ifindex)			break;	}	if (!pmc) {		/* must have a prior join */		err = -EINVAL;		goto done;	}	if (msf->imsf_numsrc) {		newpsl = sock_kmalloc(sk, IP_SFLSIZE(msf->imsf_numsrc),							   GFP_KERNEL);		if (!newpsl) {			err = -ENOBUFS;			goto done;		}		newpsl->sl_max = newpsl->sl_count = msf->imsf_numsrc;		memcpy(newpsl->sl_addr, msf->imsf_slist,			msf->imsf_numsrc * sizeof(msf->imsf_slist[0]));		err = ip_mc_add_src(in_dev, &msf->imsf_multiaddr,			msf->imsf_fmode, newpsl->sl_count, newpsl->sl_addr, 0);		if (err) {			sock_kfree_s(sk, newpsl, IP_SFLSIZE(newpsl->sl_max));			goto done;		}	} else {		newpsl = NULL;		(void) ip_mc_add_src(in_dev, &msf->imsf_multiaddr,				     msf->imsf_fmode, 0, NULL, 0);	}	psl = pmc->sflist;	if (psl) {		(void) ip_mc_del_src(in_dev, &msf->imsf_multiaddr, pmc->sfmode,			psl->sl_count, psl->sl_addr, 0);		sock_kfree_s(sk, psl, IP_SFLSIZE(psl->sl_max));	} else		(void) ip_mc_del_src(in_dev, &msf->imsf_multiaddr, pmc->sfmode,			0, NULL, 0);	pmc->sflist = newpsl;	pmc->sfmode = msf->imsf_fmode;	err = 0;done:	rtnl_unlock();	if (leavegroup)		err = ip_mc_leave_group(sk, &imr);	return err;}int ip_mc_msfget(struct sock *sk, struct ip_msfilter *msf,	struct ip_msfilter __user *optval, int __user *optlen){	int err, len, count, copycount;	struct ip_mreqn	imr;	__be32 addr = msf->imsf_multiaddr;	struct ip_mc_socklist *pmc;	struct in_device *in_dev;	struct inet_sock *inet = inet_sk(sk);

⌨️ 快捷键说明

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