mcast.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 2,496 行 · 第 1/4 页
C
2,496 行
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; 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_EXCLUDE] = 0; pmc->mca_sfcount[MCAST_EXCLUDE] = 1;}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);}int ip6_mc_leave_src(struct sock *sk, struct ipv6_mc_socklist *iml, struct inet6_dev *idev){ int err; if (iml->sflist == 0) { /* 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){ struct in6_addr maddr; write_lock_bh(&idev->lock); idev->mc_lock = RW_LOCK_UNLOCKED; 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); /* Add all-nodes address. */ ipv6_addr_all_nodes(&maddr); ipv6_dev_mc_inc(idev->dev, &maddr);}/* * 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); for (state->dev = dev_base, state->idev = NULL; state->dev; state->dev = state->dev->next) { 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 = state->dev->next; 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 %04x%04x%04x%04x%04x%04x%04x%04x %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 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){ struct seq_file *seq; int rc = -ENOMEM; struct igmp6_mc_iter_state *s = kmalloc(sizeof(*s), GFP_KERNEL); if (!s) goto out; rc = seq_open(file, &igmp6_mc_seq_ops); if (rc) goto out_kfree; seq = file->private_data; seq->private = s; memset(s, 0, sizeof(*s));out: return rc;out_kfree: kfree(s); goto out;}static 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); for (state->dev = dev_base, state->idev = NULL, state->im = NULL; state->dev; state->dev = state->dev->next) { 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 = state->dev->next; 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 " "%04x%04x%04x%04x%04x%04x%04x%04x " "%04x%04x%04x%04x%04x%04x%04x%04x " "%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 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){ struct seq_file *seq; int rc = -ENOMEM; struct igmp6_mcf_iter_state *s = kmalloc(sizeof(*s), GFP_KERNEL); if (!s) goto out; rc = seq_open(file, &igmp6_mcf_seq_ops); if (rc) goto out_kfree; seq = file->private_data; seq->private = s; memset(s, 0, sizeof(*s));out: return rc;out_kfree: kfree(s); goto out;}static 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("igmp6", S_IRUGO, &igmp6_mc_seq_fops); proc_net_fops_create("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("mcfilter6"); proc_net_remove("igmp6");#endif}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?