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

📄 mcast.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
}static void igmp6_join_group(struct ifmcaddr6 *ma){	unsigned long delay;	if (ma->mca_flags & MAF_NOREPORT)		return;	igmp6_send(&ma->mca_addr, ma->idev->dev, ICMPV6_MGM_REPORT);	delay = net_random() % IGMP6_UNSOLICITED_IVAL;	spin_lock_bh(&ma->mca_lock);	if (del_timer(&ma->mca_timer)) {		atomic_dec(&ma->mca_refcnt);		delay = ma->mca_timer.expires - jiffies;	}	if (!mod_timer(&ma->mca_timer, jiffies + delay))		atomic_inc(&ma->mca_refcnt);	ma->mca_flags |= MAF_TIMER_RUNNING | MAF_LAST_REPORTER;	spin_unlock_bh(&ma->mca_lock);}static int ip6_mc_leave_src(struct sock *sk, struct ipv6_mc_socklist *iml,			    struct inet6_dev *idev){	int err;	/* callers have the socket lock and a write lock on ipv6_sk_mc_lock,	 * so no other readers or writers of iml or its sflist	 */	if (!iml->sflist) {		/* any-source empty exclude case */		return ip6_mc_del_src(idev, &iml->addr, iml->sfmode, 0, NULL, 0);	}	err = ip6_mc_del_src(idev, &iml->addr, iml->sfmode,		iml->sflist->sl_count, iml->sflist->sl_addr, 0);	sock_kfree_s(sk, iml->sflist, IP6_SFLSIZE(iml->sflist->sl_max));	iml->sflist = NULL;	return err;}static void igmp6_leave_group(struct ifmcaddr6 *ma){	if (MLD_V1_SEEN(ma->idev)) {		if (ma->mca_flags & MAF_LAST_REPORTER)			igmp6_send(&ma->mca_addr, ma->idev->dev,				ICMPV6_MGM_REDUCTION);	} else {		mld_add_delrec(ma->idev, ma);		mld_ifc_event(ma->idev);	}}static void mld_gq_timer_expire(unsigned long data){	struct inet6_dev *idev = (struct inet6_dev *)data;	idev->mc_gq_running = 0;	mld_send_report(idev, NULL);	__in6_dev_put(idev);}static void mld_ifc_timer_expire(unsigned long data){	struct inet6_dev *idev = (struct inet6_dev *)data;	mld_send_cr(idev);	if (idev->mc_ifc_count) {		idev->mc_ifc_count--;		if (idev->mc_ifc_count)			mld_ifc_start_timer(idev, idev->mc_maxdelay);	}	__in6_dev_put(idev);}static void mld_ifc_event(struct inet6_dev *idev){	if (MLD_V1_SEEN(idev))		return;	idev->mc_ifc_count = idev->mc_qrv;	mld_ifc_start_timer(idev, 1);}static void igmp6_timer_handler(unsigned long data){	struct ifmcaddr6 *ma = (struct ifmcaddr6 *) data;	if (MLD_V1_SEEN(ma->idev))		igmp6_send(&ma->mca_addr, ma->idev->dev, ICMPV6_MGM_REPORT);	else		mld_send_report(ma->idev, ma);	spin_lock(&ma->mca_lock);	ma->mca_flags |=  MAF_LAST_REPORTER;	ma->mca_flags &= ~MAF_TIMER_RUNNING;	spin_unlock(&ma->mca_lock);	ma_put(ma);}/* Device going down */void ipv6_mc_down(struct inet6_dev *idev){	struct ifmcaddr6 *i;	/* Withdraw multicast list */	read_lock_bh(&idev->lock);	idev->mc_ifc_count = 0;	if (del_timer(&idev->mc_ifc_timer))		__in6_dev_put(idev);	idev->mc_gq_running = 0;	if (del_timer(&idev->mc_gq_timer))		__in6_dev_put(idev);	for (i = idev->mc_list; i; i=i->next)		igmp6_group_dropped(i);	read_unlock_bh(&idev->lock);	mld_clear_delrec(idev);}/* Device going up */void ipv6_mc_up(struct inet6_dev *idev){	struct ifmcaddr6 *i;	/* Install multicast list, except for all-nodes (already installed) */	read_lock_bh(&idev->lock);	for (i = idev->mc_list; i; i=i->next)		igmp6_group_added(i);	read_unlock_bh(&idev->lock);}/* IPv6 device initialization. */void ipv6_mc_init_dev(struct inet6_dev *idev){	write_lock_bh(&idev->lock);	rwlock_init(&idev->mc_lock);	idev->mc_gq_running = 0;	init_timer(&idev->mc_gq_timer);	idev->mc_gq_timer.data = (unsigned long) idev;	idev->mc_gq_timer.function = &mld_gq_timer_expire;	idev->mc_tomb = NULL;	idev->mc_ifc_count = 0;	init_timer(&idev->mc_ifc_timer);	idev->mc_ifc_timer.data = (unsigned long) idev;	idev->mc_ifc_timer.function = &mld_ifc_timer_expire;	idev->mc_qrv = MLD_QRV_DEFAULT;	idev->mc_maxdelay = IGMP6_UNSOLICITED_IVAL;	idev->mc_v1_seen = 0;	write_unlock_bh(&idev->lock);}/* *	Device is about to be destroyed: clean up. */void ipv6_mc_destroy_dev(struct inet6_dev *idev){	struct ifmcaddr6 *i;	struct in6_addr maddr;	/* Deactivate timers */	ipv6_mc_down(idev);	/* Delete all-nodes address. */	ipv6_addr_all_nodes(&maddr);	/* We cannot call ipv6_dev_mc_dec() directly, our caller in	 * addrconf.c has NULL'd out dev->ip6_ptr so in6_dev_get() will	 * fail.	 */	__ipv6_dev_mc_dec(idev, &maddr);	if (idev->cnf.forwarding) {		ipv6_addr_all_routers(&maddr);		__ipv6_dev_mc_dec(idev, &maddr);	}	write_lock_bh(&idev->lock);	while ((i = idev->mc_list) != NULL) {		idev->mc_list = i->next;		write_unlock_bh(&idev->lock);		igmp6_group_dropped(i);		ma_put(i);		write_lock_bh(&idev->lock);	}	write_unlock_bh(&idev->lock);}#ifdef CONFIG_PROC_FSstruct igmp6_mc_iter_state {	struct net_device *dev;	struct inet6_dev *idev;};#define igmp6_mc_seq_private(seq)	((struct igmp6_mc_iter_state *)(seq)->private)static inline struct ifmcaddr6 *igmp6_mc_get_first(struct seq_file *seq){	struct ifmcaddr6 *im = NULL;	struct igmp6_mc_iter_state *state = igmp6_mc_seq_private(seq);	state->idev = NULL;	for_each_netdev(&init_net, state->dev) {		struct inet6_dev *idev;		idev = in6_dev_get(state->dev);		if (!idev)			continue;		read_lock_bh(&idev->lock);		im = idev->mc_list;		if (im) {			state->idev = idev;			break;		}		read_unlock_bh(&idev->lock);		in6_dev_put(idev);	}	return im;}static struct ifmcaddr6 *igmp6_mc_get_next(struct seq_file *seq, struct ifmcaddr6 *im){	struct igmp6_mc_iter_state *state = igmp6_mc_seq_private(seq);	im = im->next;	while (!im) {		if (likely(state->idev != NULL)) {			read_unlock_bh(&state->idev->lock);			in6_dev_put(state->idev);		}		state->dev = next_net_device(state->dev);		if (!state->dev) {			state->idev = NULL;			break;		}		state->idev = in6_dev_get(state->dev);		if (!state->idev)			continue;		read_lock_bh(&state->idev->lock);		im = state->idev->mc_list;	}	return im;}static struct ifmcaddr6 *igmp6_mc_get_idx(struct seq_file *seq, loff_t pos){	struct ifmcaddr6 *im = igmp6_mc_get_first(seq);	if (im)		while (pos && (im = igmp6_mc_get_next(seq, im)) != NULL)			--pos;	return pos ? NULL : im;}static void *igmp6_mc_seq_start(struct seq_file *seq, loff_t *pos){	read_lock(&dev_base_lock);	return igmp6_mc_get_idx(seq, *pos);}static void *igmp6_mc_seq_next(struct seq_file *seq, void *v, loff_t *pos){	struct ifmcaddr6 *im;	im = igmp6_mc_get_next(seq, v);	++*pos;	return im;}static void igmp6_mc_seq_stop(struct seq_file *seq, void *v){	struct igmp6_mc_iter_state *state = igmp6_mc_seq_private(seq);	if (likely(state->idev != NULL)) {		read_unlock_bh(&state->idev->lock);		in6_dev_put(state->idev);		state->idev = NULL;	}	state->dev = NULL;	read_unlock(&dev_base_lock);}static int igmp6_mc_seq_show(struct seq_file *seq, void *v){	struct ifmcaddr6 *im = (struct ifmcaddr6 *)v;	struct igmp6_mc_iter_state *state = igmp6_mc_seq_private(seq);	seq_printf(seq,		   "%-4d %-15s " NIP6_SEQFMT " %5d %08X %ld\n",		   state->dev->ifindex, state->dev->name,		   NIP6(im->mca_addr),		   im->mca_users, im->mca_flags,		   (im->mca_flags&MAF_TIMER_RUNNING) ?		   jiffies_to_clock_t(im->mca_timer.expires-jiffies) : 0);	return 0;}static const struct seq_operations igmp6_mc_seq_ops = {	.start	=	igmp6_mc_seq_start,	.next	=	igmp6_mc_seq_next,	.stop	=	igmp6_mc_seq_stop,	.show	=	igmp6_mc_seq_show,};static int igmp6_mc_seq_open(struct inode *inode, struct file *file){	return seq_open_private(file, &igmp6_mc_seq_ops,			sizeof(struct igmp6_mc_iter_state));}static const struct file_operations igmp6_mc_seq_fops = {	.owner		=	THIS_MODULE,	.open		=	igmp6_mc_seq_open,	.read		=	seq_read,	.llseek		=	seq_lseek,	.release	=	seq_release_private,};struct igmp6_mcf_iter_state {	struct net_device *dev;	struct inet6_dev *idev;	struct ifmcaddr6 *im;};#define igmp6_mcf_seq_private(seq)	((struct igmp6_mcf_iter_state *)(seq)->private)static inline struct ip6_sf_list *igmp6_mcf_get_first(struct seq_file *seq){	struct ip6_sf_list *psf = NULL;	struct ifmcaddr6 *im = NULL;	struct igmp6_mcf_iter_state *state = igmp6_mcf_seq_private(seq);	state->idev = NULL;	state->im = NULL;	for_each_netdev(&init_net, state->dev) {		struct inet6_dev *idev;		idev = in6_dev_get(state->dev);		if (unlikely(idev == NULL))			continue;		read_lock_bh(&idev->lock);		im = idev->mc_list;		if (likely(im != NULL)) {			spin_lock_bh(&im->mca_lock);			psf = im->mca_sources;			if (likely(psf != NULL)) {				state->im = im;				state->idev = idev;				break;			}			spin_unlock_bh(&im->mca_lock);		}		read_unlock_bh(&idev->lock);		in6_dev_put(idev);	}	return psf;}static struct ip6_sf_list *igmp6_mcf_get_next(struct seq_file *seq, struct ip6_sf_list *psf){	struct igmp6_mcf_iter_state *state = igmp6_mcf_seq_private(seq);	psf = psf->sf_next;	while (!psf) {		spin_unlock_bh(&state->im->mca_lock);		state->im = state->im->next;		while (!state->im) {			if (likely(state->idev != NULL)) {				read_unlock_bh(&state->idev->lock);				in6_dev_put(state->idev);			}			state->dev = next_net_device(state->dev);			if (!state->dev) {				state->idev = NULL;				goto out;			}			state->idev = in6_dev_get(state->dev);			if (!state->idev)				continue;			read_lock_bh(&state->idev->lock);			state->im = state->idev->mc_list;		}		if (!state->im)			break;		spin_lock_bh(&state->im->mca_lock);		psf = state->im->mca_sources;	}out:	return psf;}static struct ip6_sf_list *igmp6_mcf_get_idx(struct seq_file *seq, loff_t pos){	struct ip6_sf_list *psf = igmp6_mcf_get_first(seq);	if (psf)		while (pos && (psf = igmp6_mcf_get_next(seq, psf)) != NULL)			--pos;	return pos ? NULL : psf;}static void *igmp6_mcf_seq_start(struct seq_file *seq, loff_t *pos){	read_lock(&dev_base_lock);	return *pos ? igmp6_mcf_get_idx(seq, *pos - 1) : SEQ_START_TOKEN;}static void *igmp6_mcf_seq_next(struct seq_file *seq, void *v, loff_t *pos){	struct ip6_sf_list *psf;	if (v == SEQ_START_TOKEN)		psf = igmp6_mcf_get_first(seq);	else		psf = igmp6_mcf_get_next(seq, v);	++*pos;	return psf;}static void igmp6_mcf_seq_stop(struct seq_file *seq, void *v){	struct igmp6_mcf_iter_state *state = igmp6_mcf_seq_private(seq);	if (likely(state->im != NULL)) {		spin_unlock_bh(&state->im->mca_lock);		state->im = NULL;	}	if (likely(state->idev != NULL)) {		read_unlock_bh(&state->idev->lock);		in6_dev_put(state->idev);		state->idev = NULL;	}	state->dev = NULL;	read_unlock(&dev_base_lock);}static int igmp6_mcf_seq_show(struct seq_file *seq, void *v){	struct ip6_sf_list *psf = (struct ip6_sf_list *)v;	struct igmp6_mcf_iter_state *state = igmp6_mcf_seq_private(seq);	if (v == SEQ_START_TOKEN) {		seq_printf(seq,			   "%3s %6s "			   "%32s %32s %6s %6s\n", "Idx",			   "Device", "Multicast Address",			   "Source Address", "INC", "EXC");	} else {		seq_printf(seq,			   "%3d %6.6s " NIP6_SEQFMT " " NIP6_SEQFMT " %6lu %6lu\n",			   state->dev->ifindex, state->dev->name,			   NIP6(state->im->mca_addr),			   NIP6(psf->sf_addr),			   psf->sf_count[MCAST_INCLUDE],			   psf->sf_count[MCAST_EXCLUDE]);	}	return 0;}static const struct seq_operations igmp6_mcf_seq_ops = {	.start	=	igmp6_mcf_seq_start,	.next	=	igmp6_mcf_seq_next,	.stop	=	igmp6_mcf_seq_stop,	.show	=	igmp6_mcf_seq_show,};static int igmp6_mcf_seq_open(struct inode *inode, struct file *file){	return seq_open_private(file, &igmp6_mcf_seq_ops,			sizeof(struct igmp6_mcf_iter_state));}static const struct file_operations igmp6_mcf_seq_fops = {	.owner		=	THIS_MODULE,	.open		=	igmp6_mcf_seq_open,	.read		=	seq_read,	.llseek		=	seq_lseek,	.release	=	seq_release_private,};#endifint __init igmp6_init(struct net_proto_family *ops){	struct ipv6_pinfo *np;	struct sock *sk;	int err;	err = sock_create_kern(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6, &igmp6_socket);	if (err < 0) {		printk(KERN_ERR		       "Failed to initialize the IGMP6 control socket (err %d).\n",		       err);		igmp6_socket = NULL; /* For safety. */		return err;	}	sk = igmp6_socket->sk;	sk->sk_allocation = GFP_ATOMIC;	sk->sk_prot->unhash(sk);	np = inet6_sk(sk);	np->hop_limit = 1;#ifdef CONFIG_PROC_FS	proc_net_fops_create(&init_net, "igmp6", S_IRUGO, &igmp6_mc_seq_fops);	proc_net_fops_create(&init_net, "mcfilter6", S_IRUGO, &igmp6_mcf_seq_fops);#endif	return 0;}void igmp6_cleanup(void){	sock_release(igmp6_socket);	igmp6_socket = NULL; /* for safety */#ifdef CONFIG_PROC_FS	proc_net_remove(&init_net, "mcfilter6");	proc_net_remove(&init_net, "igmp6");#endif}

⌨️ 快捷键说明

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