📄 mcast.c
字号:
}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 + -