📄 igmp.c
字号:
if (arp_mc_map(addr, buf, dev, 0) == 0) dev_mc_add(dev,buf,dev->addr_len,0);}/* * Remove a filter from a device */static void ip_mc_filter_del(struct in_device *in_dev, u32 addr){ char buf[MAX_ADDR_LEN]; struct net_device *dev = in_dev->dev; if (arp_mc_map(addr, buf, dev, 0) == 0) dev_mc_delete(dev,buf,dev->addr_len,0);}static void igmp_group_dropped(struct ip_mc_list *im){#ifdef CONFIG_IP_MULTICAST int reporter;#endif if (im->loaded) { im->loaded = 0; ip_mc_filter_del(im->interface, im->multiaddr); }#ifdef CONFIG_IP_MULTICAST if (im->multiaddr == IGMP_ALL_HOSTS) return; reporter = im->reporter; igmp_stop_timer(im); if (reporter && !IGMP_V1_SEEN(im->interface)) igmp_send_report(im->interface->dev, im->multiaddr, IGMP_HOST_LEAVE_MESSAGE);#endif}static void igmp_group_added(struct ip_mc_list *im){ if (im->loaded == 0) { im->loaded = 1; ip_mc_filter_add(im->interface, im->multiaddr); }#ifdef CONFIG_IP_MULTICAST if (im->multiaddr == IGMP_ALL_HOSTS) return; spin_lock_bh(&im->lock); igmp_start_timer(im, IGMP_Initial_Report_Delay); spin_unlock_bh(&im->lock);#endif}/* * Multicast list managers *//* * A socket has joined a multicast group on device dev. */void ip_mc_inc_group(struct in_device *in_dev, u32 addr){ struct ip_mc_list *im; ASSERT_RTNL(); for (im=in_dev->mc_list; im; im=im->next) { if (im->multiaddr == addr) { im->users++; goto out; } } im = (struct ip_mc_list *)kmalloc(sizeof(*im), GFP_KERNEL); if (!im) goto out; im->users=1; im->interface=in_dev; in_dev_hold(in_dev); im->multiaddr=addr; atomic_set(&im->refcnt, 1); spin_lock_init(&im->lock);#ifdef CONFIG_IP_MULTICAST im->tm_running=0; init_timer(&im->timer); im->timer.data=(unsigned long)im; im->timer.function=&igmp_timer_expire; im->unsolicit_count = IGMP_Unsolicited_Report_Count; im->reporter = 0;#endif im->loaded = 0; write_lock_bh(&in_dev->lock); im->next=in_dev->mc_list; in_dev->mc_list=im; write_unlock_bh(&in_dev->lock); igmp_group_added(im); if (in_dev->dev->flags & IFF_UP) ip_rt_multicast_event(in_dev);out: return;}/* * A socket has left a multicast group on device dev */int ip_mc_dec_group(struct in_device *in_dev, u32 addr){ int err = -ESRCH; struct ip_mc_list *i, **ip; ASSERT_RTNL(); for (ip=&in_dev->mc_list; (i=*ip)!=NULL; ip=&i->next) { if (i->multiaddr==addr) { if (--i->users == 0) { write_lock_bh(&in_dev->lock); *ip = i->next; write_unlock_bh(&in_dev->lock); igmp_group_dropped(i); if (in_dev->dev->flags & IFF_UP) ip_rt_multicast_event(in_dev); ip_ma_put(i); return 0; } err = 0; break; } } return -ESRCH;}/* Device going down */void ip_mc_down(struct in_device *in_dev){ struct ip_mc_list *i; ASSERT_RTNL(); for (i=in_dev->mc_list; i; i=i->next) igmp_group_dropped(i); ip_mc_dec_group(in_dev, IGMP_ALL_HOSTS);}/* Device going up */void ip_mc_up(struct in_device *in_dev){ struct ip_mc_list *i; ASSERT_RTNL(); ip_mc_inc_group(in_dev, IGMP_ALL_HOSTS); for (i=in_dev->mc_list; i; i=i->next) igmp_group_added(i);}/* * Device is about to be destroyed: clean up. */void ip_mc_destroy_dev(struct in_device *in_dev){ struct ip_mc_list *i; ASSERT_RTNL(); write_lock_bh(&in_dev->lock); while ((i = in_dev->mc_list) != NULL) { in_dev->mc_list = i->next; write_unlock_bh(&in_dev->lock); igmp_group_dropped(i); ip_ma_put(i); write_lock_bh(&in_dev->lock); } write_unlock_bh(&in_dev->lock);}static struct in_device * ip_mc_find_dev(struct ip_mreqn *imr){ struct rtable *rt; struct net_device *dev = NULL; struct in_device *idev = NULL; if (imr->imr_address.s_addr) { dev = ip_dev_find(imr->imr_address.s_addr); if (!dev) return NULL; __dev_put(dev); } if (!dev && !ip_route_output(&rt, imr->imr_multiaddr.s_addr, 0, 0, 0)) { dev = rt->u.dst.dev; ip_rt_put(rt); } if (dev) { imr->imr_ifindex = dev->ifindex; idev = __in_dev_get(dev); } return idev;}/* * Join a socket to a group */int sysctl_igmp_max_memberships = IP_MAX_MEMBERSHIPS;int ip_mc_join_group(struct sock *sk , struct ip_mreqn *imr){ int err; u32 addr = imr->imr_multiaddr.s_addr; struct ip_mc_socklist *iml, *i; struct in_device *in_dev; int count = 0; if (!MULTICAST(addr)) return -EINVAL; rtnl_shlock(); if (!imr->imr_ifindex) in_dev = ip_mc_find_dev(imr); else { in_dev = inetdev_by_index(imr->imr_ifindex); if (in_dev) __in_dev_put(in_dev); } if (!in_dev) { iml = NULL; err = -ENODEV; goto done; } iml = (struct ip_mc_socklist *)sock_kmalloc(sk, sizeof(*iml), GFP_KERNEL); err = -EADDRINUSE; for (i=sk->protinfo.af_inet.mc_list; i; i=i->next) { if (memcmp(&i->multi, imr, sizeof(*imr)) == 0) { /* New style additions are reference counted */ if (imr->imr_address.s_addr == 0) { i->count++; err = 0; } goto done; } count++; } err = -ENOBUFS; if (iml == NULL || count >= sysctl_igmp_max_memberships) goto done; memcpy(&iml->multi, imr, sizeof(*imr)); iml->next = sk->protinfo.af_inet.mc_list; iml->count = 1; sk->protinfo.af_inet.mc_list = iml; ip_mc_inc_group(in_dev, addr); iml = NULL; err = 0;done: rtnl_shunlock(); if (iml) sock_kfree_s(sk, iml, sizeof(*iml)); return err;}/* * Ask a socket to leave a group. */int ip_mc_leave_group(struct sock *sk, struct ip_mreqn *imr){ struct ip_mc_socklist *iml, **imlp; rtnl_lock(); for (imlp=&sk->protinfo.af_inet.mc_list; (iml=*imlp)!=NULL; imlp=&iml->next) { if (iml->multi.imr_multiaddr.s_addr==imr->imr_multiaddr.s_addr && iml->multi.imr_address.s_addr==imr->imr_address.s_addr && (!imr->imr_ifindex || iml->multi.imr_ifindex==imr->imr_ifindex)) { struct in_device *in_dev; if (--iml->count) { rtnl_unlock(); return 0; } *imlp = iml->next; in_dev = inetdev_by_index(iml->multi.imr_ifindex); if (in_dev) { ip_mc_dec_group(in_dev, imr->imr_multiaddr.s_addr); in_dev_put(in_dev); } rtnl_unlock(); sock_kfree_s(sk, iml, sizeof(*iml)); return 0; } } rtnl_unlock(); return -EADDRNOTAVAIL;}/* * A socket is closing. */void ip_mc_drop_socket(struct sock *sk){ struct ip_mc_socklist *iml; if (sk->protinfo.af_inet.mc_list == NULL) return; rtnl_lock(); while ((iml=sk->protinfo.af_inet.mc_list) != NULL) { struct in_device *in_dev; sk->protinfo.af_inet.mc_list = iml->next; if ((in_dev = inetdev_by_index(iml->multi.imr_ifindex)) != 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, u32 mc_addr){ struct ip_mc_list *im; read_lock(&in_dev->lock); for (im=in_dev->mc_list; im; im=im->next) { if (im->multiaddr == mc_addr) { read_unlock(&in_dev->lock); return 1; } } read_unlock(&in_dev->lock); return 0;}#ifdef CONFIG_IP_MULTICAST int ip_mc_procinfo(char *buffer, char **start, off_t offset, int length){ off_t pos=0, begin=0; struct ip_mc_list *im; int len=0; struct net_device *dev; len=sprintf(buffer,"Idx\tDevice : Count Querier\tGroup Users Timer\tReporter\n"); read_lock(&dev_base_lock); for(dev = dev_base; dev; dev = dev->next) { struct in_device *in_dev = in_dev_get(dev); char *querier = "NONE"; if (in_dev == NULL) continue; querier = IGMP_V1_SEEN(in_dev) ? "V1" : "V2"; len+=sprintf(buffer+len,"%d\t%-10s: %5d %7s\n", dev->ifindex, dev->name, dev->mc_count, querier); read_lock(&in_dev->lock); for (im = in_dev->mc_list; im; im = im->next) { len+=sprintf(buffer+len, "\t\t\t\t%08lX %5d %d:%08lX\t\t%d\n", im->multiaddr, im->users, im->tm_running, im->timer.expires-jiffies, im->reporter); pos=begin+len; if(pos<offset) { len=0; begin=pos; } if(pos>offset+length) { read_unlock(&in_dev->lock); in_dev_put(in_dev); goto done; } } read_unlock(&in_dev->lock); in_dev_put(in_dev); }done: read_unlock(&dev_base_lock); *start=buffer+(offset-begin); len-=(offset-begin); if(len>length) len=length; if(len<0) len=0; return len;}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -