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

📄 mcast.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
			return NULL;		psrc = (struct in6_addr *)skb_put(skb, sizeof(*psrc));		*psrc = psf->sf_addr;		scount++; stotal++;		if ((type == MLD2_ALLOW_NEW_SOURCES ||		     type == MLD2_BLOCK_OLD_SOURCES) && psf->sf_crcount) {			psf->sf_crcount--;			if ((sdeleted || gdeleted) && psf->sf_crcount == 0) {				if (psf_prev)					psf_prev->sf_next = psf->sf_next;				else					*psf_list = psf->sf_next;				kfree(psf);				continue;			}		}		psf_prev = psf;	}empty_source:	if (!stotal) {		if (type == MLD2_ALLOW_NEW_SOURCES ||		    type == MLD2_BLOCK_OLD_SOURCES)			return skb;		if (pmc->mca_crcount || isquery) {			/* make sure we have room for group header */			if (skb && AVAILABLE(skb) < sizeof(struct mld2_grec)) {				mld_sendpack(skb);				skb = NULL; /* add_grhead will get a new one */			}			skb = add_grhead(skb, pmc, type, &pgr);		}	}	if (pgr)		pgr->grec_nsrcs = htons(scount);	if (isquery)		pmc->mca_flags &= ~MAF_GSQUERY;	/* clear query state */	return skb;}static void mld_send_report(struct inet6_dev *idev, struct ifmcaddr6 *pmc){	struct sk_buff *skb = NULL;	int type;	if (!pmc) {		read_lock_bh(&idev->lock);		for (pmc=idev->mc_list; pmc; pmc=pmc->next) {			if (pmc->mca_flags & MAF_NOREPORT)				continue;			spin_lock_bh(&pmc->mca_lock);			if (pmc->mca_sfcount[MCAST_EXCLUDE])				type = MLD2_MODE_IS_EXCLUDE;			else				type = MLD2_MODE_IS_INCLUDE;			skb = add_grec(skb, pmc, type, 0, 0);			spin_unlock_bh(&pmc->mca_lock);		}		read_unlock_bh(&idev->lock);	} else {		spin_lock_bh(&pmc->mca_lock);		if (pmc->mca_sfcount[MCAST_EXCLUDE])			type = MLD2_MODE_IS_EXCLUDE;		else			type = MLD2_MODE_IS_INCLUDE;		skb = add_grec(skb, pmc, type, 0, 0);		spin_unlock_bh(&pmc->mca_lock);	}	if (skb)		mld_sendpack(skb);}/* * remove zero-count source records from a source filter list */static void mld_clear_zeros(struct ip6_sf_list **ppsf){	struct ip6_sf_list *psf_prev, *psf_next, *psf;	psf_prev = NULL;	for (psf=*ppsf; psf; psf = psf_next) {		psf_next = psf->sf_next;		if (psf->sf_crcount == 0) {			if (psf_prev)				psf_prev->sf_next = psf->sf_next;			else				*ppsf = psf->sf_next;			kfree(psf);		} else			psf_prev = psf;	}}static void mld_send_cr(struct inet6_dev *idev){	struct ifmcaddr6 *pmc, *pmc_prev, *pmc_next;	struct sk_buff *skb = NULL;	int type, dtype;	read_lock_bh(&idev->lock);	write_lock_bh(&idev->mc_lock);	/* deleted MCA's */	pmc_prev = NULL;	for (pmc=idev->mc_tomb; pmc; pmc=pmc_next) {		pmc_next = pmc->next;		if (pmc->mca_sfmode == MCAST_INCLUDE) {			type = MLD2_BLOCK_OLD_SOURCES;			dtype = MLD2_BLOCK_OLD_SOURCES;			skb = add_grec(skb, pmc, type, 1, 0);			skb = add_grec(skb, pmc, dtype, 1, 1);		}		if (pmc->mca_crcount) {			if (pmc->mca_sfmode == MCAST_EXCLUDE) {				type = MLD2_CHANGE_TO_INCLUDE;				skb = add_grec(skb, pmc, type, 1, 0);			}			pmc->mca_crcount--;			if (pmc->mca_crcount == 0) {				mld_clear_zeros(&pmc->mca_tomb);				mld_clear_zeros(&pmc->mca_sources);			}		}		if (pmc->mca_crcount == 0 && !pmc->mca_tomb &&		    !pmc->mca_sources) {			if (pmc_prev)				pmc_prev->next = pmc_next;			else				idev->mc_tomb = pmc_next;			in6_dev_put(pmc->idev);			kfree(pmc);		} else			pmc_prev = pmc;	}	write_unlock_bh(&idev->mc_lock);	/* change recs */	for (pmc=idev->mc_list; pmc; pmc=pmc->next) {		spin_lock_bh(&pmc->mca_lock);		if (pmc->mca_sfcount[MCAST_EXCLUDE]) {			type = MLD2_BLOCK_OLD_SOURCES;			dtype = MLD2_ALLOW_NEW_SOURCES;		} else {			type = MLD2_ALLOW_NEW_SOURCES;			dtype = MLD2_BLOCK_OLD_SOURCES;		}		skb = add_grec(skb, pmc, type, 0, 0);		skb = add_grec(skb, pmc, dtype, 0, 1);	/* deleted sources */		/* filter mode changes */		if (pmc->mca_crcount) {			if (pmc->mca_sfmode == MCAST_EXCLUDE)				type = MLD2_CHANGE_TO_EXCLUDE;			else				type = MLD2_CHANGE_TO_INCLUDE;			skb = add_grec(skb, pmc, type, 0, 0);			pmc->mca_crcount--;		}		spin_unlock_bh(&pmc->mca_lock);	}	read_unlock_bh(&idev->lock);	if (!skb)		return;	(void) mld_sendpack(skb);}static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type){	struct sock *sk = igmp6_socket->sk;	struct inet6_dev *idev;	struct sk_buff *skb;	struct icmp6hdr *hdr;	struct in6_addr *snd_addr;	struct in6_addr *addrp;	struct in6_addr addr_buf;	struct in6_addr all_routers;	int err, len, payload_len, full_len;	u8 ra[8] = { IPPROTO_ICMPV6, 0,		     IPV6_TLV_ROUTERALERT, 2, 0, 0,		     IPV6_TLV_PADN, 0 };	rcu_read_lock();	IP6_INC_STATS(__in6_dev_get(dev),		      IPSTATS_MIB_OUTREQUESTS);	rcu_read_unlock();	snd_addr = addr;	if (type == ICMPV6_MGM_REDUCTION) {		snd_addr = &all_routers;		ipv6_addr_all_routers(&all_routers);	}	len = sizeof(struct icmp6hdr) + sizeof(struct in6_addr);	payload_len = len + sizeof(ra);	full_len = sizeof(struct ipv6hdr) + payload_len;	skb = sock_alloc_send_skb(sk, LL_RESERVED_SPACE(dev) + full_len, 1, &err);	if (skb == NULL) {		rcu_read_lock();		IP6_INC_STATS(__in6_dev_get(dev),			      IPSTATS_MIB_OUTDISCARDS);		rcu_read_unlock();		return;	}	skb_reserve(skb, LL_RESERVED_SPACE(dev));	if (ipv6_get_lladdr(dev, &addr_buf, IFA_F_TENTATIVE)) {		/* <draft-ietf-magma-mld-source-05.txt>:		 * use unspecified address as the source address		 * when a valid link-local address is not available.		 */		memset(&addr_buf, 0, sizeof(addr_buf));	}	ip6_nd_hdr(sk, skb, dev, &addr_buf, snd_addr, NEXTHDR_HOP, payload_len);	memcpy(skb_put(skb, sizeof(ra)), ra, sizeof(ra));	hdr = (struct icmp6hdr *) skb_put(skb, sizeof(struct icmp6hdr));	memset(hdr, 0, sizeof(struct icmp6hdr));	hdr->icmp6_type = type;	addrp = (struct in6_addr *) skb_put(skb, sizeof(struct in6_addr));	ipv6_addr_copy(addrp, addr);	hdr->icmp6_cksum = csum_ipv6_magic(&addr_buf, snd_addr, len,					   IPPROTO_ICMPV6,					   csum_partial((__u8 *) hdr, len, 0));	idev = in6_dev_get(skb->dev);	err = NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, skb->dev,		mld_dev_queue_xmit);	if (!err) {		ICMP6MSGOUT_INC_STATS(idev, type);		ICMP6_INC_STATS(idev, ICMP6_MIB_OUTMSGS);		IP6_INC_STATS(idev, IPSTATS_MIB_OUTMCASTPKTS);	} else		IP6_INC_STATS(idev, IPSTATS_MIB_OUTDISCARDS);	if (likely(idev != NULL))		in6_dev_put(idev);	return;}static int ip6_mc_del1_src(struct ifmcaddr6 *pmc, int sfmode,	struct in6_addr *psfsrc){	struct ip6_sf_list *psf, *psf_prev;	int rv = 0;	psf_prev = NULL;	for (psf=pmc->mca_sources; psf; psf=psf->sf_next) {		if (ipv6_addr_equal(&psf->sf_addr, 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[MCAST_INCLUDE] && !psf->sf_count[MCAST_EXCLUDE]) {		struct inet6_dev *idev = pmc->idev;		/* no more filters for this source */		if (psf_prev)			psf_prev->sf_next = psf->sf_next;		else			pmc->mca_sources = psf->sf_next;		if (psf->sf_oldin && !(pmc->mca_flags & MAF_NOREPORT) &&		    !MLD_V1_SEEN(idev)) {			psf->sf_crcount = idev->mc_qrv;			psf->sf_next = pmc->mca_tomb;			pmc->mca_tomb = psf;			rv = 1;		} else			kfree(psf);	}	return rv;}static int ip6_mc_del_src(struct inet6_dev *idev, struct in6_addr *pmca,			  int sfmode, int sfcount, struct in6_addr *psfsrc,			  int delta){	struct ifmcaddr6 *pmc;	int	changerec = 0;	int	i, err;	if (!idev)		return -ENODEV;	read_lock_bh(&idev->lock);	for (pmc=idev->mc_list; pmc; pmc=pmc->next) {		if (ipv6_addr_equal(pmca, &pmc->mca_addr))			break;	}	if (!pmc) {		/* MCA not found?? bug */		read_unlock_bh(&idev->lock);		return -ESRCH;	}	spin_lock_bh(&pmc->mca_lock);	sf_markstate(pmc);	if (!delta) {		if (!pmc->mca_sfcount[sfmode]) {			spin_unlock_bh(&pmc->mca_lock);			read_unlock_bh(&idev->lock);			return -EINVAL;		}		pmc->mca_sfcount[sfmode]--;	}	err = 0;	for (i=0; i<sfcount; i++) {		int rv = ip6_mc_del1_src(pmc, sfmode, &psfsrc[i]);		changerec |= rv > 0;		if (!err && rv < 0)			err = rv;	}	if (pmc->mca_sfmode == MCAST_EXCLUDE &&	    pmc->mca_sfcount[MCAST_EXCLUDE] == 0 &&	    pmc->mca_sfcount[MCAST_INCLUDE]) {		struct ip6_sf_list *psf;		/* filter mode change */		pmc->mca_sfmode = MCAST_INCLUDE;		pmc->mca_crcount = idev->mc_qrv;		idev->mc_ifc_count = pmc->mca_crcount;		for (psf=pmc->mca_sources; psf; psf = psf->sf_next)			psf->sf_crcount = 0;		mld_ifc_event(pmc->idev);	} else if (sf_setstate(pmc) || changerec)		mld_ifc_event(pmc->idev);	spin_unlock_bh(&pmc->mca_lock);	read_unlock_bh(&idev->lock);	return err;}/* * Add multicast single-source filter to the interface list */static int ip6_mc_add1_src(struct ifmcaddr6 *pmc, int sfmode,	struct in6_addr *psfsrc, int delta){	struct ip6_sf_list *psf, *psf_prev;	psf_prev = NULL;	for (psf=pmc->mca_sources; psf; psf=psf->sf_next) {		if (ipv6_addr_equal(&psf->sf_addr, psfsrc))			break;		psf_prev = psf;	}	if (!psf) {		psf = kzalloc(sizeof(*psf), GFP_ATOMIC);		if (!psf)			return -ENOBUFS;		psf->sf_addr = *psfsrc;		if (psf_prev) {			psf_prev->sf_next = psf;		} else			pmc->mca_sources = psf;	}	psf->sf_count[sfmode]++;	return 0;}static void sf_markstate(struct ifmcaddr6 *pmc){	struct ip6_sf_list *psf;	int mca_xcount = pmc->mca_sfcount[MCAST_EXCLUDE];	for (psf=pmc->mca_sources; psf; psf=psf->sf_next)		if (pmc->mca_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 ifmcaddr6 *pmc){	struct ip6_sf_list *psf, *dpsf;	int mca_xcount = pmc->mca_sfcount[MCAST_EXCLUDE];	int qrv = pmc->idev->mc_qrv;	int new_in, rv;	rv = 0;	for (psf=pmc->mca_sources; psf; psf=psf->sf_next) {		if (pmc->mca_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 ip6_sf_list *prev = NULL;				for (dpsf=pmc->mca_tomb; dpsf;				     dpsf=dpsf->sf_next) {					if (ipv6_addr_equal(&dpsf->sf_addr,					    &psf->sf_addr))						break;					prev = dpsf;				}				if (dpsf) {					if (prev)						prev->sf_next = dpsf->sf_next;					else						pmc->mca_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->mca_tomb; dpsf; dpsf=dpsf->sf_next)				if (ipv6_addr_equal(&dpsf->sf_addr,				    &psf->sf_addr))					break;			if (!dpsf) {				dpsf = (struct ip6_sf_list *)					kmalloc(sizeof(*dpsf), GFP_ATOMIC);				if (!dpsf)					continue;				*dpsf = *psf;				/* pmc->mca_lock held by callers */				dpsf->sf_next = pmc->mca_tomb;				pmc->mca_tomb = dpsf;			}			dpsf->sf_crcount = qrv;			rv++;		}	}	return rv;}/* * Add multicast source filter list to the interface list */static int ip6_mc_add_src(struct inet6_dev *idev, struct in6_addr *pmca,			  int sfmode, int sfcount, struct in6_addr *psfsrc,			  int delta){	struct ifmcaddr6 *pmc;	int	isexclude;	int	i, err;	if (!idev)		return -ENODEV;	read_lock_bh(&idev->lock);	for (pmc=idev->mc_list; pmc; pmc=pmc->next) {		if (ipv6_addr_equal(pmca, &pmc->mca_addr))			break;	}	if (!pmc) {		/* MCA not found?? bug */		read_unlock_bh(&idev->lock);		return -ESRCH;	}	spin_lock_bh(&pmc->mca_lock);	sf_markstate(pmc);	isexclude = pmc->mca_sfmode == MCAST_EXCLUDE;	if (!delta)		pmc->mca_sfcount[sfmode]++;	err = 0;	for (i=0; i<sfcount; i++) {		err = ip6_mc_add1_src(pmc, sfmode, &psfsrc[i], delta);		if (err)			break;	}	if (err) {		int j;		if (!delta)			pmc->mca_sfcount[sfmode]--;		for (j=0; j<i; j++)			(void) ip6_mc_del1_src(pmc, sfmode, &psfsrc[i]);	} else if (isexclude != (pmc->mca_sfcount[MCAST_EXCLUDE] != 0)) {		struct inet6_dev *idev = pmc->idev;		struct ip6_sf_list *psf;		/* filter mode change */		if (pmc->mca_sfcount[MCAST_EXCLUDE])			pmc->mca_sfmode = MCAST_EXCLUDE;		else if (pmc->mca_sfcount[MCAST_INCLUDE])			pmc->mca_sfmode = MCAST_INCLUDE;		/* else no filters; keep old mode for reports */		pmc->mca_crcount = idev->mc_qrv;		idev->mc_ifc_count = pmc->mca_crcount;		for (psf=pmc->mca_sources; psf; psf = psf->sf_next)			psf->sf_crcount = 0;		mld_ifc_event(idev);	} else if (sf_setstate(pmc))		mld_ifc_event(idev);	spin_unlock_bh(&pmc->mca_lock);	read_unlock_bh(&idev->lock);	return err;}static void ip6_mc_clear_src(struct ifmcaddr6 *pmc){	struct ip6_sf_list *psf, *nextpsf;	for (psf=pmc->mca_tomb; psf; psf=nextpsf) {		nextpsf = psf->sf_next;		kfree(psf);	}	pmc->mca_tomb = NULL;	for (psf=pmc->mca_sources; psf; psf=nextpsf) {		nextpsf = psf->sf_next;		kfree(psf);	}	pmc->mca_sources = NULL;	pmc->mca_sfmode = MCAST_EXCLUDE;	pmc->mca_sfcount[MCAST_INCLUDE] = 0;	pmc->mca_sfcount[MCAST_EXCLUDE] = 1;

⌨️ 快捷键说明

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