📄 mcast.c
字号:
spin_unlock(&ma->mca_lock);}int igmp6_event_query(struct sk_buff *skb){ struct ifmcaddr6 *ma; struct in6_addr *addrp; unsigned long resptime; struct inet6_dev *idev; struct icmp6hdr *hdr; if (!pskb_may_pull(skb, sizeof(struct in6_addr))) return -EINVAL; hdr = (struct icmp6hdr*) skb->h.raw; /* Drop queries with not link local source */ if (!(ipv6_addr_type(&skb->nh.ipv6h->saddr)&IPV6_ADDR_LINKLOCAL)) return -EINVAL; resptime = ntohs(hdr->icmp6_maxdelay); /* Translate milliseconds to jiffies */ resptime = (resptime<<10)/(1024000/HZ); addrp = (struct in6_addr *) (hdr + 1); idev = in6_dev_get(skb->dev); if (idev == NULL) return 0; read_lock(&idev->lock); if (ipv6_addr_any(addrp)) { for (ma = idev->mc_list; ma; ma=ma->next) igmp6_group_queried(ma, resptime); } else { for (ma = idev->mc_list; ma; ma=ma->next) { if (ipv6_addr_cmp(addrp, &ma->mca_addr) == 0) { igmp6_group_queried(ma, resptime); break; } } } read_unlock(&idev->lock); in6_dev_put(idev); return 0;}int igmp6_event_report(struct sk_buff *skb){ struct ifmcaddr6 *ma; struct in6_addr *addrp; struct inet6_dev *idev; struct icmp6hdr *hdr; /* Our own report looped back. Ignore it. */ if (skb->pkt_type == PACKET_LOOPBACK) return 0; if (!pskb_may_pull(skb, sizeof(struct in6_addr))) return -EINVAL; hdr = (struct icmp6hdr*) skb->h.raw; /* Drop reports with not link local source */ if (!(ipv6_addr_type(&skb->nh.ipv6h->saddr)&IPV6_ADDR_LINKLOCAL)) return -EINVAL; addrp = (struct in6_addr *) (hdr + 1); idev = in6_dev_get(skb->dev); if (idev == NULL) return -ENODEV; /* * Cancel the timer for this group */ read_lock(&idev->lock); for (ma = idev->mc_list; ma; ma=ma->next) { if (ipv6_addr_cmp(&ma->mca_addr, addrp) == 0) { spin_lock(&ma->mca_lock); if (del_timer(&ma->mca_timer)) atomic_dec(&ma->mca_refcnt); ma->mca_flags &= ~(MAF_LAST_REPORTER|MAF_TIMER_RUNNING); spin_unlock(&ma->mca_lock); break; } } read_unlock(&idev->lock); in6_dev_put(idev); return 0;}void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type){ struct sock *sk = igmp6_socket->sk; struct sk_buff *skb; struct icmp6hdr *hdr; struct in6_addr *snd_addr; struct in6_addr *addrp; struct in6_addr addr_buf; struct in6_addr all_routers; int err, len, payload_len, full_len; u8 ra[8] = { IPPROTO_ICMPV6, 0, IPV6_TLV_ROUTERALERT, 2, 0, 0, IPV6_TLV_PADN, 0 }; snd_addr = addr; if (type == ICMPV6_MGM_REDUCTION) { snd_addr = &all_routers; ipv6_addr_all_routers(&all_routers); } len = sizeof(struct icmp6hdr) + sizeof(struct in6_addr); payload_len = len + sizeof(ra); full_len = sizeof(struct ipv6hdr) + payload_len; skb = sock_alloc_send_skb(sk, dev->hard_header_len + full_len + 15, 0, &err); if (skb == NULL) return; skb_reserve(skb, (dev->hard_header_len + 15) & ~15); if (dev->hard_header) { unsigned char ha[MAX_ADDR_LEN]; ndisc_mc_map(snd_addr, ha, dev, 1); if (dev->hard_header(skb, dev, ETH_P_IPV6, ha, NULL, full_len) < 0) goto out; } if (ipv6_get_lladdr(dev, &addr_buf)) {#if MCAST_DEBUG >= 1 printk(KERN_DEBUG "igmp6: %s no linklocal address\n", dev->name);#endif goto out; } ip6_nd_hdr(sk, skb, dev, &addr_buf, snd_addr, NEXTHDR_HOP, payload_len); memcpy(skb_put(skb, sizeof(ra)), ra, sizeof(ra)); hdr = (struct icmp6hdr *) skb_put(skb, sizeof(struct icmp6hdr)); memset(hdr, 0, sizeof(struct icmp6hdr)); hdr->icmp6_type = type; addrp = (struct in6_addr *) skb_put(skb, sizeof(struct in6_addr)); ipv6_addr_copy(addrp, addr); hdr->icmp6_cksum = csum_ipv6_magic(&addr_buf, snd_addr, len, IPPROTO_ICMPV6, csum_partial((__u8 *) hdr, len, 0)); dev_queue_xmit(skb); if (type == ICMPV6_MGM_REDUCTION) ICMP6_INC_STATS(Icmp6OutGroupMembReductions); else ICMP6_INC_STATS(Icmp6OutGroupMembResponses); ICMP6_INC_STATS(Icmp6OutMsgs); return;out: kfree_skb(skb);}static void igmp6_join_group(struct ifmcaddr6 *ma){ unsigned long delay; int addr_type; addr_type = ipv6_addr_type(&ma->mca_addr); if ((addr_type & (IPV6_ADDR_LINKLOCAL|IPV6_ADDR_LOOPBACK))) 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 void igmp6_leave_group(struct ifmcaddr6 *ma){ int addr_type; addr_type = ipv6_addr_type(&ma->mca_addr); if ((addr_type & IPV6_ADDR_LINKLOCAL)) return; if (ma->mca_flags & MAF_LAST_REPORTER) igmp6_send(&ma->mca_addr, ma->idev->dev, ICMPV6_MGM_REDUCTION); spin_lock_bh(&ma->mca_lock); if (del_timer(&ma->mca_timer)) atomic_dec(&ma->mca_refcnt); spin_unlock_bh(&ma->mca_lock);}void igmp6_timer_handler(unsigned long data){ struct ifmcaddr6 *ma = (struct ifmcaddr6 *) data; igmp6_send(&ma->mca_addr, ma->idev->dev, ICMPV6_MGM_REPORT); 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); for (i = idev->mc_list; i; i=i->next) igmp6_group_dropped(i); read_unlock_bh(&idev->lock);}/* 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; /* 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; /* Delete all-nodes address. */ ipv6_addr_all_nodes(&maddr); ipv6_dev_mc_dec(idev->dev, &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_FSstatic int igmp6_read_proc(char *buffer, char **start, off_t offset, int length, int *eof, void *data){ off_t pos=0, begin=0; struct ifmcaddr6 *im; int len=0; struct net_device *dev; read_lock(&dev_base_lock); for (dev = dev_base; dev; dev = dev->next) { struct inet6_dev *idev; if ((idev = in6_dev_get(dev)) == NULL) continue; read_lock_bh(&idev->lock); for (im = idev->mc_list; im; im = im->next) { int i; len += sprintf(buffer+len,"%-4d %-15s ", dev->ifindex, dev->name); for (i=0; i<16; i++) len += sprintf(buffer+len, "%02x", im->mca_addr.s6_addr[i]); len+=sprintf(buffer+len, " %5d %08X %ld\n", im->mca_users, im->mca_flags, (im->mca_flags&MAF_TIMER_RUNNING) ? im->mca_timer.expires-jiffies : 0); pos=begin+len; if (pos < offset) { len=0; begin=pos; } if (pos > offset+length) { read_unlock_bh(&idev->lock); in6_dev_put(idev); goto done; } } read_unlock_bh(&idev->lock); in6_dev_put(idev); } *eof = 1;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;}#endifint __init igmp6_init(struct net_proto_family *ops){ struct sock *sk; int err; igmp6_socket = sock_alloc(); if (igmp6_socket == NULL) { printk(KERN_ERR "Failed to create the IGMP6 control socket.\n"); return -1; } igmp6_socket->inode->i_uid = 0; igmp6_socket->inode->i_gid = 0; igmp6_socket->type = SOCK_RAW; if((err = ops->create(igmp6_socket, IPPROTO_ICMPV6)) < 0) { printk(KERN_DEBUG "Failed to initialize the IGMP6 control socket (err %d).\n", err); sock_release(igmp6_socket); igmp6_socket = NULL; /* For safety. */ return err; } sk = igmp6_socket->sk; sk->allocation = GFP_ATOMIC; sk->prot->unhash(sk); sk->net_pinfo.af_inet6.hop_limit = 1;#ifdef CONFIG_PROC_FS create_proc_read_entry("net/igmp6", 0, 0, igmp6_read_proc, NULL);#endif return 0;}void igmp6_cleanup(void){ sock_release(igmp6_socket); igmp6_socket = NULL; /* for safety */#ifdef CONFIG_PROC_FS remove_proc_entry("net/igmp6", 0);#endif}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -