📄 igmp.c
字号:
routine. Something sort of: if (dev->mc_list && dev->flags&IFF_MULTICAST) { do it; } --ANK */ 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 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){ 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; start_bh_atomic(); igmp_stop_timer(im); end_bh_atomic(); if (im->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; start_bh_atomic(); igmp_start_timer(im, IGMP_Initial_Report_Delay); end_bh_atomic();#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 *i, *im; im = (struct ip_mc_list *)kmalloc(sizeof(*im), GFP_KERNEL); for (i=in_dev->mc_list; i; i=i->next) { if (i->multiaddr == addr) { i->users++; if (im) kfree(im); return; } } if (!im) return; im->users=1; im->interface=in_dev; im->multiaddr=addr;#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; im->loaded = 0;#endif im->next=in_dev->mc_list; in_dev->mc_list=im; igmp_group_added(im); if (in_dev->dev->flags & IFF_UP) ip_rt_multicast_event(in_dev); return;}/* * A socket has left a multicast group on device dev */int ip_mc_dec_group(struct in_device *in_dev, u32 addr){ struct ip_mc_list *i, **ip; for (ip=&in_dev->mc_list; (i=*ip)!=NULL; ip=&i->next) { if (i->multiaddr==addr) { if (--i->users == 0) { *ip = i->next; synchronize_bh(); igmp_group_dropped(i); if (in_dev->dev->flags & IFF_UP) ip_rt_multicast_event(in_dev); kfree_s(i, sizeof(*i)); } return 0; } } return -ESRCH;}/* Device going down */void ip_mc_down(struct in_device *in_dev){ struct ip_mc_list *i; 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; 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; while ((i = in_dev->mc_list) != NULL) { in_dev->mc_list = i->next; igmp_group_dropped(i); kfree_s(i, sizeof(*i)); }}static struct in_device * ip_mc_find_dev(struct ip_mreqn *imr){ struct rtable *rt; struct device *dev = NULL; if (imr->imr_address.s_addr) { dev = ip_dev_find(imr->imr_address.s_addr); if (!dev) return NULL; } 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; return dev->ip_ptr; } return NULL;}/* * 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) { iml = NULL; err = -ENODEV; goto done; } iml = (struct ip_mc_socklist *)sock_kmalloc(sk, sizeof(*iml), GFP_KERNEL); err = -EADDRINUSE; for (i=sk->ip_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->ip_mc_list; iml->count = 1; sk->ip_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; for (imlp=&sk->ip_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) return 0; *imlp = iml->next; synchronize_bh(); in_dev = inetdev_by_index(iml->multi.imr_ifindex); if (in_dev) ip_mc_dec_group(in_dev, imr->imr_multiaddr.s_addr); sock_kfree_s(sk, iml, sizeof(*iml)); return 0; } } return -EADDRNOTAVAIL;}/* * A socket is closing. */void ip_mc_drop_socket(struct sock *sk){ struct ip_mc_socklist *iml; while ((iml=sk->ip_mc_list) != NULL) { struct in_device *in_dev; sk->ip_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); sock_kfree_s(sk, iml, sizeof(*iml)); }}#ifdef CONFIG_IP_MULTICAST int ip_mc_procinfo(char *buffer, char **start, off_t offset, int length, int dummy){ off_t pos=0, begin=0; struct ip_mc_list *im; int len=0; struct device *dev; len=sprintf(buffer,"Idx\tDevice : Count Querier\tGroup Users Timer\tReporter\n"); for(dev = dev_base; dev; dev = dev->next) { struct in_device *in_dev = dev->ip_ptr; 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); 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) goto done; } }done: *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 + -