📄 igmp.c
字号:
struct ip_sf_socklist *psl; if (!MULTICAST(addr)) return -EINVAL; rtnl_lock(); imr.imr_multiaddr.s_addr = msf->imsf_multiaddr; imr.imr_address.s_addr = msf->imsf_interface; imr.imr_ifindex = 0; 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 == msf->imsf_multiaddr && pmc->multi.imr_ifindex == imr.imr_ifindex) break; } if (!pmc) /* must have a prior join */ goto done; msf->imsf_fmode = pmc->sfmode; psl = pmc->sflist; rtnl_unlock(); if (!psl) { len = 0; count = 0; } else { count = psl->sl_count; } copycount = count < msf->imsf_numsrc ? count : msf->imsf_numsrc; len = copycount * sizeof(psl->sl_addr[0]); msf->imsf_numsrc = count; if (put_user(IP_MSFILTER_SIZE(copycount), optlen) || copy_to_user(optval, msf, IP_MSFILTER_SIZE(0))) { return -EFAULT; } if (len && copy_to_user(&optval->imsf_slist[0], psl->sl_addr, len)) return -EFAULT; return 0;done: rtnl_unlock(); return err;}int ip_mc_gsfget(struct sock *sk, struct group_filter *gsf, struct group_filter __user *optval, int __user *optlen){ int err, i, count, copycount; struct sockaddr_in *psin; __be32 addr; struct ip_mc_socklist *pmc; struct inet_sock *inet = inet_sk(sk); struct ip_sf_socklist *psl; psin = (struct sockaddr_in *)&gsf->gf_group; if (psin->sin_family != AF_INET) return -EINVAL; addr = psin->sin_addr.s_addr; if (!MULTICAST(addr)) return -EINVAL; rtnl_lock(); err = -EADDRNOTAVAIL; for (pmc=inet->mc_list; pmc; pmc=pmc->next) { if (pmc->multi.imr_multiaddr.s_addr == addr && pmc->multi.imr_ifindex == gsf->gf_interface) break; } if (!pmc) /* must have a prior join */ goto done; gsf->gf_fmode = pmc->sfmode; psl = pmc->sflist; rtnl_unlock(); count = psl ? psl->sl_count : 0; copycount = count < gsf->gf_numsrc ? count : gsf->gf_numsrc; gsf->gf_numsrc = count; if (put_user(GROUP_FILTER_SIZE(copycount), optlen) || copy_to_user(optval, gsf, GROUP_FILTER_SIZE(0))) { return -EFAULT; } for (i=0; i<copycount; i++) { struct sockaddr_storage ss; psin = (struct sockaddr_in *)&ss; memset(&ss, 0, sizeof(ss)); psin->sin_family = AF_INET; psin->sin_addr.s_addr = psl->sl_addr[i]; if (copy_to_user(&optval->gf_slist[i], &ss, sizeof(ss))) return -EFAULT; } return 0;done: rtnl_unlock(); return err;}/* * check if a multicast source filter allows delivery for a given <src,dst,intf> */int ip_mc_sf_allow(struct sock *sk, __be32 loc_addr, __be32 rmt_addr, int dif){ struct inet_sock *inet = inet_sk(sk); struct ip_mc_socklist *pmc; struct ip_sf_socklist *psl; int i; if (!MULTICAST(loc_addr)) return 1; for (pmc=inet->mc_list; pmc; pmc=pmc->next) { if (pmc->multi.imr_multiaddr.s_addr == loc_addr && pmc->multi.imr_ifindex == dif) break; } if (!pmc) return 1; psl = pmc->sflist; if (!psl) return pmc->sfmode == MCAST_EXCLUDE; for (i=0; i<psl->sl_count; i++) { if (psl->sl_addr[i] == rmt_addr) break; } if (pmc->sfmode == MCAST_INCLUDE && i >= psl->sl_count) return 0; if (pmc->sfmode == MCAST_EXCLUDE && i < psl->sl_count) return 0; return 1;}/* * A socket is closing. */void ip_mc_drop_socket(struct sock *sk){ struct inet_sock *inet = inet_sk(sk); struct ip_mc_socklist *iml; if (inet->mc_list == NULL) return; rtnl_lock(); while ((iml = inet->mc_list) != NULL) { struct in_device *in_dev; inet->mc_list = iml->next; in_dev = inetdev_by_index(iml->multi.imr_ifindex); (void) ip_mc_leave_src(sk, iml, in_dev); if (in_dev != NULL) { ip_mc_dec_group(in_dev, iml->multi.imr_multiaddr.s_addr); in_dev_put(in_dev); } sock_kfree_s(sk, iml, sizeof(*iml)); } rtnl_unlock();}int ip_check_mc(struct in_device *in_dev, __be32 mc_addr, __be32 src_addr, u16 proto){ struct ip_mc_list *im; struct ip_sf_list *psf; int rv = 0; read_lock(&in_dev->mc_list_lock); for (im=in_dev->mc_list; im; im=im->next) { if (im->multiaddr == mc_addr) break; } if (im && proto == IPPROTO_IGMP) { rv = 1; } else if (im) { if (src_addr) { for (psf=im->sources; psf; psf=psf->sf_next) { if (psf->sf_inaddr == src_addr) break; } if (psf) rv = psf->sf_count[MCAST_INCLUDE] || psf->sf_count[MCAST_EXCLUDE] != im->sfcount[MCAST_EXCLUDE]; else rv = im->sfcount[MCAST_EXCLUDE] != 0; } else rv = 1; /* unspecified source; tentatively allow */ } read_unlock(&in_dev->mc_list_lock); return rv;}#if defined(CONFIG_PROC_FS)struct igmp_mc_iter_state { struct net_device *dev; struct in_device *in_dev;};#define igmp_mc_seq_private(seq) ((struct igmp_mc_iter_state *)(seq)->private)static inline struct ip_mc_list *igmp_mc_get_first(struct seq_file *seq){ struct ip_mc_list *im = NULL; struct igmp_mc_iter_state *state = igmp_mc_seq_private(seq); state->in_dev = NULL; for_each_netdev(&init_net, state->dev) { struct in_device *in_dev; in_dev = in_dev_get(state->dev); if (!in_dev) continue; read_lock(&in_dev->mc_list_lock); im = in_dev->mc_list; if (im) { state->in_dev = in_dev; break; } read_unlock(&in_dev->mc_list_lock); in_dev_put(in_dev); } return im;}static struct ip_mc_list *igmp_mc_get_next(struct seq_file *seq, struct ip_mc_list *im){ struct igmp_mc_iter_state *state = igmp_mc_seq_private(seq); im = im->next; while (!im) { if (likely(state->in_dev != NULL)) { read_unlock(&state->in_dev->mc_list_lock); in_dev_put(state->in_dev); } state->dev = next_net_device(state->dev); if (!state->dev) { state->in_dev = NULL; break; } state->in_dev = in_dev_get(state->dev); if (!state->in_dev) continue; read_lock(&state->in_dev->mc_list_lock); im = state->in_dev->mc_list; } return im;}static struct ip_mc_list *igmp_mc_get_idx(struct seq_file *seq, loff_t pos){ struct ip_mc_list *im = igmp_mc_get_first(seq); if (im) while (pos && (im = igmp_mc_get_next(seq, im)) != NULL) --pos; return pos ? NULL : im;}static void *igmp_mc_seq_start(struct seq_file *seq, loff_t *pos){ read_lock(&dev_base_lock); return *pos ? igmp_mc_get_idx(seq, *pos - 1) : SEQ_START_TOKEN;}static void *igmp_mc_seq_next(struct seq_file *seq, void *v, loff_t *pos){ struct ip_mc_list *im; if (v == SEQ_START_TOKEN) im = igmp_mc_get_first(seq); else im = igmp_mc_get_next(seq, v); ++*pos; return im;}static void igmp_mc_seq_stop(struct seq_file *seq, void *v){ struct igmp_mc_iter_state *state = igmp_mc_seq_private(seq); if (likely(state->in_dev != NULL)) { read_unlock(&state->in_dev->mc_list_lock); in_dev_put(state->in_dev); state->in_dev = NULL; } state->dev = NULL; read_unlock(&dev_base_lock);}static int igmp_mc_seq_show(struct seq_file *seq, void *v){ if (v == SEQ_START_TOKEN) seq_puts(seq, "Idx\tDevice : Count Querier\tGroup Users Timer\tReporter\n"); else { struct ip_mc_list *im = (struct ip_mc_list *)v; struct igmp_mc_iter_state *state = igmp_mc_seq_private(seq); char *querier;#ifdef CONFIG_IP_MULTICAST querier = IGMP_V1_SEEN(state->in_dev) ? "V1" : IGMP_V2_SEEN(state->in_dev) ? "V2" : "V3";#else querier = "NONE";#endif if (state->in_dev->mc_list == im) { seq_printf(seq, "%d\t%-10s: %5d %7s\n", state->dev->ifindex, state->dev->name, state->dev->mc_count, querier); } seq_printf(seq, "\t\t\t\t%08X %5d %d:%08lX\t\t%d\n", im->multiaddr, im->users, im->tm_running, im->tm_running ? jiffies_to_clock_t(im->timer.expires-jiffies) : 0, im->reporter); } return 0;}static const struct seq_operations igmp_mc_seq_ops = { .start = igmp_mc_seq_start, .next = igmp_mc_seq_next, .stop = igmp_mc_seq_stop, .show = igmp_mc_seq_show,};static int igmp_mc_seq_open(struct inode *inode, struct file *file){ return seq_open_private(file, &igmp_mc_seq_ops, sizeof(struct igmp_mc_iter_state));}static const struct file_operations igmp_mc_seq_fops = { .owner = THIS_MODULE, .open = igmp_mc_seq_open, .read = seq_read, .llseek = seq_lseek, .release = seq_release_private,};struct igmp_mcf_iter_state { struct net_device *dev; struct in_device *idev; struct ip_mc_list *im;};#define igmp_mcf_seq_private(seq) ((struct igmp_mcf_iter_state *)(seq)->private)static inline struct ip_sf_list *igmp_mcf_get_first(struct seq_file *seq){ struct ip_sf_list *psf = NULL; struct ip_mc_list *im = NULL; struct igmp_mcf_iter_state *state = igmp_mcf_seq_private(seq); state->idev = NULL; state->im = NULL; for_each_netdev(&init_net, state->dev) { struct in_device *idev; idev = in_dev_get(state->dev); if (unlikely(idev == NULL)) continue; read_lock(&idev->mc_list_lock); im = idev->mc_list; if (likely(im != NULL)) { spin_lock_bh(&im->lock); psf = im->sources; if (likely(psf != NULL)) { state->im = im; state->idev = idev; break; } spin_unlock_bh(&im->lock); } read_unlock(&idev->mc_list_lock); in_dev_put(idev); } return psf;}static struct ip_sf_list *igmp_mcf_get_next(struct seq_file *seq, struct ip_sf_list *psf){ struct igmp_mcf_iter_state *state = igmp_mcf_seq_private(seq); psf = psf->sf_next; while (!psf) { spin_unlock_bh(&state->im->lock); state->im = state->im->next; while (!state->im) { if (likely(state->idev != NULL)) { read_unlock(&state->idev->mc_list_lock); in_dev_put(state->idev); } state->dev = next_net_device(state->dev); if (!state->dev) { state->idev = NULL; goto out; } state->idev = in_dev_get(state->dev); if (!state->idev) continue; read_lock(&state->idev->mc_list_lock); state->im = state->idev->mc_list; } if (!state->im) break; spin_lock_bh(&state->im->lock); psf = state->im->sources; }out: return psf;}static struct ip_sf_list *igmp_mcf_get_idx(struct seq_file *seq, loff_t pos){ struct ip_sf_list *psf = igmp_mcf_get_first(seq); if (psf) while (pos && (psf = igmp_mcf_get_next(seq, psf)) != NULL) --pos; return pos ? NULL : psf;}static void *igmp_mcf_seq_start(struct seq_file *seq, loff_t *pos){ read_lock(&dev_base_lock); return *pos ? igmp_mcf_get_idx(seq, *pos - 1) : SEQ_START_TOKEN;}static void *igmp_mcf_seq_next(struct seq_file *seq, void *v, loff_t *pos){ struct ip_sf_list *psf; if (v == SEQ_START_TOKEN) psf = igmp_mcf_get_first(seq); else psf = igmp_mcf_get_next(seq, v); ++*pos; return psf;}static void igmp_mcf_seq_stop(struct seq_file *seq, void *v){ struct igmp_mcf_iter_state *state = igmp_mcf_seq_private(seq); if (likely(state->im != NULL)) { spin_unlock_bh(&state->im->lock); state->im = NULL; } if (likely(state->idev != NULL)) { read_unlock(&state->idev->mc_list_lock); in_dev_put(state->idev); state->idev = NULL; } state->dev = NULL; read_unlock(&dev_base_lock);}static int igmp_mcf_seq_show(struct seq_file *seq, void *v){ struct ip_sf_list *psf = (struct ip_sf_list *)v; struct igmp_mcf_iter_state *state = igmp_mcf_seq_private(seq); if (v == SEQ_START_TOKEN) { seq_printf(seq, "%3s %6s " "%10s %10s %6s %6s\n", "Idx", "Device", "MCA", "SRC", "INC", "EXC"); } else { seq_printf(seq, "%3d %6.6s 0x%08x " "0x%08x %6lu %6lu\n", state->dev->ifindex, state->dev->name, ntohl(state->im->multiaddr), ntohl(psf->sf_inaddr), psf->sf_count[MCAST_INCLUDE], psf->sf_count[MCAST_EXCLUDE]); } return 0;}static const struct seq_operations igmp_mcf_seq_ops = { .start = igmp_mcf_seq_start, .next = igmp_mcf_seq_next, .stop = igmp_mcf_seq_stop, .show = igmp_mcf_seq_show,};static int igmp_mcf_seq_open(struct inode *inode, struct file *file){ return seq_open_private(file, &igmp_mcf_seq_ops, sizeof(struct igmp_mcf_iter_state));}static const struct file_operations igmp_mcf_seq_fops = { .owner = THIS_MODULE, .open = igmp_mcf_seq_open, .read = seq_read, .llseek = seq_lseek, .release = seq_release_private,};int __init igmp_mc_proc_init(void){ proc_net_fops_create(&init_net, "igmp", S_IRUGO, &igmp_mc_seq_fops); proc_net_fops_create(&init_net, "mcfilter", S_IRUGO, &igmp_mcf_seq_fops); return 0;}#endifEXPORT_SYMBOL(ip_mc_dec_group);EXPORT_SYMBOL(ip_mc_inc_group);EXPORT_SYMBOL(ip_mc_join_group);EXPORT_SYMBOL(ip_mc_rejoin_group);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -