2 * Linux NET3: Internet Group Management Protocol [IGMP]
4 * This code implements the IGMP protocol as defined in RFC1112. There has
5 * been a further revision of this protocol since which is now supported.
7 * If you have trouble with this module be careful what gcc you have used,
8 * the older version didn't come out right using gcc 2.5.8, the newer one
9 * seems to fall out with gcc 2.6.2.
11 * Version: $Id: igmp.c,v 1.1.1.1 2005/04/11 02:51:13 jack Exp $
14 * Alan Cox <Alan.Cox@linux.org>
16 * This program is free software; you can redistribute it and/or
17 * modify it under the terms of the GNU General Public License
18 * as published by the Free Software Foundation; either version
19 * 2 of the License, or (at your option) any later version.
23 * Alan Cox : Added lots of __inline__ to optimise
24 * the memory usage of all the tiny little
26 * Alan Cox : Dumped the header building experiment.
27 * Alan Cox : Minor tweaks ready for multicast routing
28 * and extended IGMP protocol.
29 * Alan Cox : Removed a load of inline directives. Gcc 2.5.8
30 * writes utterly bogus code otherwise (sigh)
31 * fixed IGMP loopback to behave in the manner
32 * desired by mrouted, fixed the fact it has been
33 * broken since 1.3.6 and cleaned up a few minor
36 * Chih-Jen Chang : Tried to revise IGMP to Version 2
37 * Tsu-Sheng Tsao E-mail: chihjenc@scf.usc.edu and tsusheng@scf.usc.edu
38 * The enhancements are mainly based on Steve Deering's
39 * ipmulti-3.5 source code.
40 * Chih-Jen Chang : Added the igmp_get_mrouter_info and
41 * Tsu-Sheng Tsao igmp_set_mrouter_info to keep track of
42 * the mrouted version on that device.
43 * Chih-Jen Chang : Added the max_resp_time parameter to
44 * Tsu-Sheng Tsao igmp_heard_query(). Using this parameter
45 * to identify the multicast router version
46 * and do what the IGMP version 2 specified.
47 * Chih-Jen Chang : Added a timer to revert to IGMP V2 router
48 * Tsu-Sheng Tsao if the specified time expired.
49 * Alan Cox : Stop IGMP from 0.0.0.0 being accepted.
50 * Alan Cox : Use GFP_ATOMIC in the right places.
51 * Christian Daudt : igmp timer wasn't set for local group
52 * memberships but was being deleted,
53 * which caused a "del_timer() called
54 * from %p with timer not initialized\n"
56 * Christian Daudt : removed del_timer from
57 * igmp_timer_expire function (960205).
58 * Christian Daudt : igmp_heard_report now only calls
59 * igmp_timer_expire if tm->running is
61 * Malcolm Beattie : ttl comparison wrong in igmp_rcv made
62 * igmp_heard_query never trigger. Expiry
63 * miscalculation fixed in igmp_heard_query
64 * and random() made to return unsigned to
65 * prevent negative expiry times.
66 * Alexey Kuznetsov: Wrong group leaving behaviour, backport
67 * fix from pending 2.1.x patches.
68 * Alan Cox: Forget to enable FDDI support earlier.
69 * Alexey Kuznetsov: Fixed leaving groups on device down.
70 * Alexey Kuznetsov: Accordance to igmp-v2-06 draft.
74 #include <linux/config.h>
75 #include <asm/uaccess.h>
76 #include <asm/system.h>
77 #include <linux/types.h>
78 #include <linux/kernel.h>
79 #include <linux/sched.h>
80 #include <linux/string.h>
81 #include <linux/socket.h>
82 #include <linux/sockios.h>
84 #include <linux/inet.h>
85 #include <linux/netdevice.h>
86 #include <linux/skbuff.h>
87 #include <linux/inetdevice.h>
88 #include <linux/igmp.h>
89 #include <linux/if_arp.h>
90 #include <linux/rtnetlink.h>
92 #include <net/protocol.h>
93 #include <net/route.h>
95 #include <net/checksum.h>
96 #include <linux/netfilter_ipv4.h>
97 #ifdef CONFIG_IP_MROUTE
98 #include <linux/mroute.h>
102 #define IP_MAX_MEMBERSHIPS 20
104 #ifdef CONFIG_IP_MULTICAST
107 /* Parameter names and values are taken from igmp-v2-06 draft */
109 #define IGMP_V1_Router_Present_Timeout (400*HZ)
110 #define IGMP_Unsolicited_Report_Interval (10*HZ)
111 #define IGMP_Query_Response_Interval (10*HZ)
112 #define IGMP_Unsolicited_Report_Count 2
115 #define IGMP_Initial_Report_Delay (1)
117 /* IGMP_Initial_Report_Delay is not from IGMP specs!
118 * IGMP specs require to report membership immediately after
119 * joining a group, but we delay the first report by a
120 * small interval. It seems more natural and still does not
121 * contradict to specs provided this delay is small enough.
124 #define IGMP_V1_SEEN(in_dev) ((in_dev)->mr_v1_seen && (long)(jiffies - (in_dev)->mr_v1_seen) < 0)
128 static void ip_ma_put(struct ip_mc_list *im)
130 if (atomic_dec_and_test(&im->refcnt)) {
131 in_dev_put(im->interface);
136 #ifdef CONFIG_IP_MULTICAST
142 static __inline__ void igmp_stop_timer(struct ip_mc_list *im)
144 spin_lock_bh(&im->lock);
145 if (del_timer(&im->timer))
146 atomic_dec(&im->refcnt);
149 im->unsolicit_count = 0;
150 spin_unlock_bh(&im->lock);
153 /* It must be called with locked im->lock */
154 static void igmp_start_timer(struct ip_mc_list *im, int max_delay)
156 int tv=net_random() % max_delay;
159 if (!mod_timer(&im->timer, jiffies+tv+2))
160 atomic_inc(&im->refcnt);
163 static void igmp_mod_timer(struct ip_mc_list *im, int max_delay)
165 spin_lock_bh(&im->lock);
166 im->unsolicit_count = 0;
167 if (del_timer(&im->timer)) {
168 if ((long)(im->timer.expires-jiffies) < max_delay) {
169 add_timer(&im->timer);
171 spin_unlock_bh(&im->lock);
174 atomic_dec(&im->refcnt);
176 igmp_start_timer(im, max_delay);
177 spin_unlock_bh(&im->lock);
182 * Send an IGMP report.
185 #define IGMP_SIZE (sizeof(struct igmphdr)+sizeof(struct iphdr)+4)
187 /* Don't just hand NF_HOOK skb->dst->output, in case netfilter hook
190 output_maybe_reroute(struct sk_buff *skb)
192 return skb->dst->output(skb);
195 static int igmp_send_report(struct net_device *dev, u32 group, int type)
203 /* According to IGMPv2 specs, LEAVE messages are
204 * sent to all-routers group.
207 if (type == IGMP_HOST_LEAVE_MESSAGE)
208 dst = IGMP_ALL_ROUTER;
210 if (ip_route_output(&rt, dst, 0, 0, dev->ifindex))
212 if (rt->rt_src == 0) {
217 skb=alloc_skb(IGMP_SIZE+dev->hard_header_len+15, GFP_ATOMIC);
223 skb->dst = &rt->u.dst;
225 skb_reserve(skb, (dev->hard_header_len+15)&~15);
227 skb->nh.iph = iph = (struct iphdr *)skb_put(skb, sizeof(struct iphdr)+4);
230 iph->ihl = (sizeof(struct iphdr)+4)>>2;
232 iph->frag_off = htons(IP_DF);
235 iph->saddr = rt->rt_src;
236 iph->protocol = IPPROTO_IGMP;
237 iph->tot_len = htons(IGMP_SIZE);
238 ip_select_ident(iph, &rt->u.dst, NULL);
239 ((u8*)&iph[1])[0] = IPOPT_RA;
240 ((u8*)&iph[1])[1] = 4;
241 ((u8*)&iph[1])[2] = 0;
242 ((u8*)&iph[1])[3] = 0;
245 ih = (struct igmphdr *)skb_put(skb, sizeof(struct igmphdr));
250 ih->csum=ip_compute_csum((void *)ih, sizeof(struct igmphdr));
252 return NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, skb, NULL, rt->u.dst.dev,
253 output_maybe_reroute);
257 static void igmp_timer_expire(unsigned long data)
259 struct ip_mc_list *im=(struct ip_mc_list *)data;
260 struct in_device *in_dev = im->interface;
263 spin_lock(&im->lock);
266 if (IGMP_V1_SEEN(in_dev))
267 err = igmp_send_report(in_dev->dev, im->multiaddr, IGMP_HOST_MEMBERSHIP_REPORT);
269 err = igmp_send_report(in_dev->dev, im->multiaddr, IGMP_HOST_NEW_MEMBERSHIP_REPORT);
271 /* Failed. Retry later. */
274 igmp_start_timer(im, IGMP_Unsolicited_Report_Interval);
278 if (im->unsolicit_count) {
279 im->unsolicit_count--;
280 igmp_start_timer(im, IGMP_Unsolicited_Report_Interval);
284 spin_unlock(&im->lock);
288 static void igmp_heard_report(struct in_device *in_dev, u32 group)
290 struct ip_mc_list *im;
292 /* Timers are only set for non-local groups */
294 if (group == IGMP_ALL_HOSTS)
297 read_lock(&in_dev->lock);
298 for (im=in_dev->mc_list; im!=NULL; im=im->next) {
299 if (im->multiaddr == group) {
304 read_unlock(&in_dev->lock);
307 static void igmp_heard_query(struct in_device *in_dev, unsigned char max_resp_time,
310 struct ip_mc_list *im;
313 max_delay = max_resp_time*(HZ/IGMP_TIMER_SCALE);
315 if (max_resp_time == 0) {
316 /* Alas, old v1 router presents here. */
318 max_delay = IGMP_Query_Response_Interval;
319 in_dev->mr_v1_seen = jiffies + IGMP_V1_Router_Present_Timeout;
324 * - Start the timers in all of our membership records
325 * that the query applies to for the interface on
326 * which the query arrived excl. those that belong
327 * to a "local" group (224.0.0.X)
328 * - For timers already running check if they need to
330 * - Use the igmp->igmp_code field as the maximum
333 read_lock(&in_dev->lock);
334 for (im=in_dev->mc_list; im!=NULL; im=im->next) {
335 if (group && group != im->multiaddr)
337 if (im->multiaddr == IGMP_ALL_HOSTS)
339 igmp_mod_timer(im, max_delay);
341 read_unlock(&in_dev->lock);
344 int igmp_rcv(struct sk_buff *skb)
346 /* This basically follows the spec line by line -- see RFC1112 */
347 struct igmphdr *ih = skb->h.igmph;
348 struct in_device *in_dev = in_dev_get(skb->dev);
356 if (skb_is_nonlinear(skb)) {
357 if (skb_linearize(skb, GFP_ATOMIC) != 0) {
364 if (len < sizeof(struct igmphdr) || ip_compute_csum((void *)ih, len)) {
371 case IGMP_HOST_MEMBERSHIP_QUERY:
372 igmp_heard_query(in_dev, ih->code, ih->group);
374 case IGMP_HOST_MEMBERSHIP_REPORT:
375 case IGMP_HOST_NEW_MEMBERSHIP_REPORT:
376 /* Is it our report looped back? */
377 if (((struct rtable*)skb->dst)->key.iif == 0)
379 igmp_heard_report(in_dev, ih->group);
382 #ifdef CONFIG_IP_PIMSM_V1
384 return pim_rcv_v1(skb);
388 case IGMP_HOST_LEAVE_MESSAGE:
390 case IGMP_MTRACE_RESP:
393 NETDEBUG(printk(KERN_DEBUG "New IGMP type=%d, why we do not know about it?\n", ih->type));
404 * Add a filter to a device
407 static void ip_mc_filter_add(struct in_device *in_dev, u32 addr)
409 char buf[MAX_ADDR_LEN];
410 struct net_device *dev = in_dev->dev;
412 /* Checking for IFF_MULTICAST here is WRONG-WRONG-WRONG.
413 We will get multicast token leakage, when IFF_MULTICAST
414 is changed. This check should be done in dev->set_multicast_list
415 routine. Something sort of:
416 if (dev->mc_list && dev->flags&IFF_MULTICAST) { do it; }
419 if (arp_mc_map(addr, buf, dev, 0) == 0)
420 dev_mc_add(dev,buf,dev->addr_len,0);
424 * Remove a filter from a device
427 static void ip_mc_filter_del(struct in_device *in_dev, u32 addr)
429 char buf[MAX_ADDR_LEN];
430 struct net_device *dev = in_dev->dev;
432 if (arp_mc_map(addr, buf, dev, 0) == 0)
433 dev_mc_delete(dev,buf,dev->addr_len,0);
436 static void igmp_group_dropped(struct ip_mc_list *im)
438 #ifdef CONFIG_IP_MULTICAST
444 ip_mc_filter_del(im->interface, im->multiaddr);
447 #ifdef CONFIG_IP_MULTICAST
448 if (im->multiaddr == IGMP_ALL_HOSTS)
451 reporter = im->reporter;
454 if (reporter && !IGMP_V1_SEEN(im->interface))
455 igmp_send_report(im->interface->dev, im->multiaddr, IGMP_HOST_LEAVE_MESSAGE);
459 static void igmp_group_added(struct ip_mc_list *im)
461 if (im->loaded == 0) {
463 ip_mc_filter_add(im->interface, im->multiaddr);
466 #ifdef CONFIG_IP_MULTICAST
467 if (im->multiaddr == IGMP_ALL_HOSTS)
470 spin_lock_bh(&im->lock);
471 igmp_start_timer(im, IGMP_Initial_Report_Delay);
472 spin_unlock_bh(&im->lock);
478 * Multicast list managers
483 * A socket has joined a multicast group on device dev.
486 void ip_mc_inc_group(struct in_device *in_dev, u32 addr)
488 struct ip_mc_list *im;
492 for (im=in_dev->mc_list; im; im=im->next) {
493 if (im->multiaddr == addr) {
499 im = (struct ip_mc_list *)kmalloc(sizeof(*im), GFP_KERNEL);
504 im->interface=in_dev;
507 atomic_set(&im->refcnt, 1);
508 spin_lock_init(&im->lock);
509 #ifdef CONFIG_IP_MULTICAST
511 init_timer(&im->timer);
512 im->timer.data=(unsigned long)im;
513 im->timer.function=&igmp_timer_expire;
514 im->unsolicit_count = IGMP_Unsolicited_Report_Count;
518 write_lock_bh(&in_dev->lock);
519 im->next=in_dev->mc_list;
521 write_unlock_bh(&in_dev->lock);
522 igmp_group_added(im);
523 if (in_dev->dev->flags & IFF_UP)
524 ip_rt_multicast_event(in_dev);
530 * A socket has left a multicast group on device dev
533 void ip_mc_dec_group(struct in_device *in_dev, u32 addr)
535 struct ip_mc_list *i, **ip;
539 for (ip=&in_dev->mc_list; (i=*ip)!=NULL; ip=&i->next) {
540 if (i->multiaddr==addr) {
541 if (--i->users == 0) {
542 write_lock_bh(&in_dev->lock);
544 write_unlock_bh(&in_dev->lock);
545 igmp_group_dropped(i);
547 if (in_dev->dev->flags & IFF_UP)
548 ip_rt_multicast_event(in_dev);
558 /* Device going down */
560 void ip_mc_down(struct in_device *in_dev)
562 struct ip_mc_list *i;
566 for (i=in_dev->mc_list; i; i=i->next)
567 igmp_group_dropped(i);
569 ip_mc_dec_group(in_dev, IGMP_ALL_HOSTS);
572 /* Device going up */
574 void ip_mc_up(struct in_device *in_dev)
576 struct ip_mc_list *i;
580 ip_mc_inc_group(in_dev, IGMP_ALL_HOSTS);
582 for (i=in_dev->mc_list; i; i=i->next)
587 * Device is about to be destroyed: clean up.
590 void ip_mc_destroy_dev(struct in_device *in_dev)
592 struct ip_mc_list *i;
596 write_lock_bh(&in_dev->lock);
597 while ((i = in_dev->mc_list) != NULL) {
598 in_dev->mc_list = i->next;
599 write_unlock_bh(&in_dev->lock);
601 igmp_group_dropped(i);
604 write_lock_bh(&in_dev->lock);
606 write_unlock_bh(&in_dev->lock);
609 static struct in_device * ip_mc_find_dev(struct ip_mreqn *imr)
612 struct net_device *dev = NULL;
613 struct in_device *idev = NULL;
615 if (imr->imr_address.s_addr) {
616 dev = ip_dev_find(imr->imr_address.s_addr);
622 if (!dev && !ip_route_output(&rt, imr->imr_multiaddr.s_addr, 0, 0, 0)) {
627 imr->imr_ifindex = dev->ifindex;
628 idev = __in_dev_get(dev);
634 * Join a socket to a group
636 int sysctl_igmp_max_memberships = IP_MAX_MEMBERSHIPS;
638 int ip_mc_join_group(struct sock *sk , struct ip_mreqn *imr)
641 u32 addr = imr->imr_multiaddr.s_addr;
642 struct ip_mc_socklist *iml, *i;
643 struct in_device *in_dev;
646 if (!MULTICAST(addr))
651 if (!imr->imr_ifindex)
652 in_dev = ip_mc_find_dev(imr);
654 in_dev = inetdev_by_index(imr->imr_ifindex);
656 __in_dev_put(in_dev);
665 iml = (struct ip_mc_socklist *)sock_kmalloc(sk, sizeof(*iml), GFP_KERNEL);
668 for (i=sk->protinfo.af_inet.mc_list; i; i=i->next) {
669 if (memcmp(&i->multi, imr, sizeof(*imr)) == 0) {
670 /* New style additions are reference counted */
671 if (imr->imr_address.s_addr == 0) {
680 if (iml == NULL || count >= sysctl_igmp_max_memberships)
682 memcpy(&iml->multi, imr, sizeof(*imr));
683 iml->next = sk->protinfo.af_inet.mc_list;
685 sk->protinfo.af_inet.mc_list = iml;
686 ip_mc_inc_group(in_dev, addr);
693 sock_kfree_s(sk, iml, sizeof(*iml));
698 * Ask a socket to leave a group.
701 int ip_mc_leave_group(struct sock *sk, struct ip_mreqn *imr)
703 struct ip_mc_socklist *iml, **imlp;
706 for (imlp=&sk->protinfo.af_inet.mc_list; (iml=*imlp)!=NULL; imlp=&iml->next) {
707 if (iml->multi.imr_multiaddr.s_addr==imr->imr_multiaddr.s_addr &&
708 iml->multi.imr_address.s_addr==imr->imr_address.s_addr &&
709 (!imr->imr_ifindex || iml->multi.imr_ifindex==imr->imr_ifindex)) {
710 struct in_device *in_dev;
718 in_dev = inetdev_by_index(iml->multi.imr_ifindex);
720 ip_mc_dec_group(in_dev, imr->imr_multiaddr.s_addr);
724 sock_kfree_s(sk, iml, sizeof(*iml));
729 return -EADDRNOTAVAIL;
733 * A socket is closing.
736 void ip_mc_drop_socket(struct sock *sk)
738 struct ip_mc_socklist *iml;
740 if (sk->protinfo.af_inet.mc_list == NULL)
744 while ((iml=sk->protinfo.af_inet.mc_list) != NULL) {
745 struct in_device *in_dev;
746 sk->protinfo.af_inet.mc_list = iml->next;
748 if ((in_dev = inetdev_by_index(iml->multi.imr_ifindex)) != NULL) {
749 ip_mc_dec_group(in_dev, iml->multi.imr_multiaddr.s_addr);
752 sock_kfree_s(sk, iml, sizeof(*iml));
758 int ip_check_mc(struct in_device *in_dev, u32 mc_addr)
760 struct ip_mc_list *im;
762 read_lock(&in_dev->lock);
763 for (im=in_dev->mc_list; im; im=im->next) {
764 if (im->multiaddr == mc_addr) {
765 read_unlock(&in_dev->lock);
769 read_unlock(&in_dev->lock);
774 #ifdef CONFIG_IP_MULTICAST
776 int ip_mc_procinfo(char *buffer, char **start, off_t offset, int length)
778 off_t pos=0, begin=0;
779 struct ip_mc_list *im;
781 struct net_device *dev;
783 len=sprintf(buffer,"Idx\tDevice : Count Querier\tGroup Users Timer\tReporter\n");
785 read_lock(&dev_base_lock);
786 for(dev = dev_base; dev; dev = dev->next) {
787 struct in_device *in_dev = in_dev_get(dev);
788 char *querier = "NONE";
793 querier = IGMP_V1_SEEN(in_dev) ? "V1" : "V2";
795 len+=sprintf(buffer+len,"%d\t%-10s: %5d %7s\n",
796 dev->ifindex, dev->name, dev->mc_count, querier);
798 read_lock(&in_dev->lock);
799 for (im = in_dev->mc_list; im; im = im->next) {
800 len+=sprintf(buffer+len,
801 "\t\t\t\t%08lX %5d %d:%08lX\t\t%d\n",
802 im->multiaddr, im->users,
803 im->tm_running, im->timer.expires-jiffies, im->reporter);
811 if(pos>offset+length) {
812 read_unlock(&in_dev->lock);
817 read_unlock(&in_dev->lock);
821 read_unlock(&dev_base_lock);
823 *start=buffer+(offset-begin);