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.30 1999/03/25 10:04:10 davem 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 #ifdef CONFIG_IP_MROUTE
97 #include <linux/mroute.h>
100 #define IP_MAX_MEMBERSHIPS 20
102 #ifdef CONFIG_IP_MULTICAST
104 /* Parameter names and values are taken from igmp-v2-06 draft */
106 #define IGMP_V1_Router_Present_Timeout (400*HZ)
107 #define IGMP_Unsolicited_Report_Interval (10*HZ)
108 #define IGMP_Query_Response_Interval (10*HZ)
109 #define IGMP_Unsolicited_Report_Count 2
112 #define IGMP_Initial_Report_Delay (1*HZ)
114 /* IGMP_Initial_Report_Delay is not from IGMP specs!
115 * IGMP specs require to report membership immediately after
116 * joining a group, but we delay the first report by a
117 * small interval. It seems more natural and still does not
118 * contradict to specs provided this delay is small enough.
121 #define IGMP_V1_SEEN(in_dev) ((in_dev)->mr_v1_seen && (long)(jiffies - (in_dev)->mr_v1_seen) < 0)
127 static __inline__
void igmp_stop_timer(struct ip_mc_list
*im
)
129 if (im
->tm_running
) {
130 del_timer(&im
->timer
);
135 static __inline__
void igmp_start_timer(struct ip_mc_list
*im
, int max_delay
)
140 tv
=net_random() % max_delay
;
141 im
->timer
.expires
=jiffies
+tv
+2;
143 add_timer(&im
->timer
);
147 * Send an IGMP report.
150 #define IGMP_SIZE (sizeof(struct igmphdr)+sizeof(struct iphdr)+4)
152 static int igmp_send_report(struct device
*dev
, u32 group
, int type
)
160 /* According to IGMPv2 specs, LEAVE messages are
161 * sent to all-routers group.
164 if (type
== IGMP_HOST_LEAVE_MESSAGE
)
165 dst
= IGMP_ALL_ROUTER
;
167 if (ip_route_output(&rt
, dst
, 0, 0, dev
->ifindex
))
169 if (rt
->rt_src
== 0) {
174 skb
=alloc_skb(IGMP_SIZE
+dev
->hard_header_len
+15, GFP_ATOMIC
);
180 skb
->dst
= &rt
->u
.dst
;
182 skb_reserve(skb
, (dev
->hard_header_len
+15)&~15);
184 skb
->nh
.iph
= iph
= (struct iphdr
*)skb_put(skb
, sizeof(struct iphdr
)+4);
187 iph
->ihl
= (sizeof(struct iphdr
)+4)>>2;
192 iph
->saddr
= rt
->rt_src
;
193 iph
->protocol
= IPPROTO_IGMP
;
194 iph
->tot_len
= htons(IGMP_SIZE
);
195 iph
->id
= htons(ip_id_count
++);
196 ((u8
*)&iph
[1])[0] = IPOPT_RA
;
197 ((u8
*)&iph
[1])[1] = 4;
198 ((u8
*)&iph
[1])[2] = 0;
199 ((u8
*)&iph
[1])[3] = 0;
202 ih
= (struct igmphdr
*)skb_put(skb
, sizeof(struct igmphdr
));
207 ih
->csum
=ip_compute_csum((void *)ih
, sizeof(struct igmphdr
));
209 return skb
->dst
->output(skb
);
213 static void igmp_timer_expire(unsigned long data
)
215 struct ip_mc_list
*im
=(struct ip_mc_list
*)data
;
216 struct in_device
*in_dev
= im
->interface
;
221 if (IGMP_V1_SEEN(in_dev
))
222 err
= igmp_send_report(in_dev
->dev
, im
->multiaddr
, IGMP_HOST_MEMBERSHIP_REPORT
);
224 err
= igmp_send_report(in_dev
->dev
, im
->multiaddr
, IGMP_HOST_NEW_MEMBERSHIP_REPORT
);
226 /* Failed. Retry later. */
228 igmp_start_timer(im
, IGMP_Unsolicited_Report_Interval
);
232 if (im
->unsolicit_count
) {
233 im
->unsolicit_count
--;
234 igmp_start_timer(im
, IGMP_Unsolicited_Report_Interval
);
239 static void igmp_heard_report(struct in_device
*in_dev
, u32 group
)
241 struct ip_mc_list
*im
;
243 /* Timers are only set for non-local groups */
245 if (LOCAL_MCAST(group
))
248 for (im
=in_dev
->mc_list
; im
!=NULL
; im
=im
->next
) {
249 if (im
->multiaddr
== group
) {
252 im
->unsolicit_count
= 0;
258 static void igmp_heard_query(struct in_device
*in_dev
, unsigned char max_resp_time
,
261 struct ip_mc_list
*im
;
264 max_delay
= max_resp_time
*(HZ
/IGMP_TIMER_SCALE
);
266 if (max_resp_time
== 0) {
267 /* Alas, old v1 router presents here. */
269 max_delay
= IGMP_Query_Response_Interval
;
270 in_dev
->mr_v1_seen
= jiffies
+ IGMP_V1_Router_Present_Timeout
;
275 * - Start the timers in all of our membership records
276 * that the query applies to for the interface on
277 * which the query arrived excl. those that belong
278 * to a "local" group (224.0.0.X)
279 * - For timers already running check if they need to
281 * - Use the igmp->igmp_code field as the maximum
284 for (im
=in_dev
->mc_list
; im
!=NULL
; im
=im
->next
) {
285 if (group
&& group
!= im
->multiaddr
)
287 if (LOCAL_MCAST(im
->multiaddr
))
289 im
->unsolicit_count
= 0;
290 if (im
->tm_running
&& (long)(im
->timer
.expires
-jiffies
) > max_delay
)
292 igmp_start_timer(im
, max_delay
);
296 int igmp_rcv(struct sk_buff
*skb
, unsigned short len
)
298 /* This basically follows the spec line by line -- see RFC1112 */
299 struct igmphdr
*ih
= skb
->h
.igmph
;
300 struct in_device
*in_dev
= skb
->dev
->ip_ptr
;
302 if (len
< sizeof(struct igmphdr
) || ip_compute_csum((void *)ih
, len
)
309 case IGMP_HOST_MEMBERSHIP_QUERY
:
310 igmp_heard_query(in_dev
, ih
->code
, ih
->group
);
312 case IGMP_HOST_MEMBERSHIP_REPORT
:
313 case IGMP_HOST_NEW_MEMBERSHIP_REPORT
:
314 /* Is it our report looped back? */
315 if (((struct rtable
*)skb
->dst
)->key
.iif
== 0)
317 igmp_heard_report(in_dev
, ih
->group
);
320 #ifdef CONFIG_IP_PIMSM_V1
321 return pim_rcv_v1(skb
, len
);
325 case IGMP_HOST_LEAVE_MESSAGE
:
327 case IGMP_MTRACE_RESP
:
330 NETDEBUG(printk(KERN_DEBUG
"New IGMP type=%d, why we do not know about it?\n", ih
->type
));
340 * Add a filter to a device
343 static void ip_mc_filter_add(struct in_device
*in_dev
, u32 addr
)
345 char buf
[MAX_ADDR_LEN
];
346 struct device
*dev
= in_dev
->dev
;
348 /* Checking for IFF_MULTICAST here is WRONG-WRONG-WRONG.
349 We will get multicast token leakage, when IFF_MULTICAST
350 is changed. This check should be done in dev->set_multicast_list
351 routine. Something sort of:
352 if (dev->mc_list && dev->flags&IFF_MULTICAST) { do it; }
355 if (arp_mc_map(addr
, buf
, dev
, 0) == 0)
356 dev_mc_add(dev
,buf
,dev
->addr_len
,0);
360 * Remove a filter from a device
363 static void ip_mc_filter_del(struct in_device
*in_dev
, u32 addr
)
365 char buf
[MAX_ADDR_LEN
];
366 struct device
*dev
= in_dev
->dev
;
368 if (arp_mc_map(addr
, buf
, dev
, 0) == 0)
369 dev_mc_delete(dev
,buf
,dev
->addr_len
,0);
372 static void igmp_group_dropped(struct ip_mc_list
*im
)
376 ip_mc_filter_del(im
->interface
, im
->multiaddr
);
379 #ifdef CONFIG_IP_MULTICAST
380 if (LOCAL_MCAST(im
->multiaddr
))
387 if (im
->reporter
&& !IGMP_V1_SEEN(im
->interface
))
388 igmp_send_report(im
->interface
->dev
, im
->multiaddr
, IGMP_HOST_LEAVE_MESSAGE
);
392 static void igmp_group_added(struct ip_mc_list
*im
)
394 if (im
->loaded
== 0) {
396 ip_mc_filter_add(im
->interface
, im
->multiaddr
);
399 #ifdef CONFIG_IP_MULTICAST
400 if (LOCAL_MCAST(im
->multiaddr
))
404 igmp_start_timer(im
, IGMP_Initial_Report_Delay
);
411 * Multicast list managers
416 * A socket has joined a multicast group on device dev.
419 void ip_mc_inc_group(struct in_device
*in_dev
, u32 addr
)
421 struct ip_mc_list
*i
, *im
;
423 im
= (struct ip_mc_list
*)kmalloc(sizeof(*im
), GFP_KERNEL
);
425 for (i
=in_dev
->mc_list
; i
; i
=i
->next
) {
426 if (i
->multiaddr
== addr
) {
436 im
->interface
=in_dev
;
438 #ifdef CONFIG_IP_MULTICAST
440 init_timer(&im
->timer
);
441 im
->timer
.data
=(unsigned long)im
;
442 im
->timer
.function
=&igmp_timer_expire
;
443 im
->unsolicit_count
= IGMP_Unsolicited_Report_Count
;
447 im
->next
=in_dev
->mc_list
;
449 igmp_group_added(im
);
450 if (in_dev
->dev
->flags
& IFF_UP
)
451 ip_rt_multicast_event(in_dev
);
456 * A socket has left a multicast group on device dev
459 int ip_mc_dec_group(struct in_device
*in_dev
, u32 addr
)
461 struct ip_mc_list
*i
, **ip
;
463 for (ip
=&in_dev
->mc_list
; (i
=*ip
)!=NULL
; ip
=&i
->next
) {
464 if (i
->multiaddr
==addr
) {
465 if (--i
->users
== 0) {
469 igmp_group_dropped(i
);
470 if (in_dev
->dev
->flags
& IFF_UP
)
471 ip_rt_multicast_event(in_dev
);
472 kfree_s(i
, sizeof(*i
));
480 /* Device going down */
482 void ip_mc_down(struct in_device
*in_dev
)
484 struct ip_mc_list
*i
;
486 for (i
=in_dev
->mc_list
; i
; i
=i
->next
)
487 igmp_group_dropped(i
);
489 ip_mc_dec_group(in_dev
, IGMP_ALL_HOSTS
);
492 /* Device going up */
494 void ip_mc_up(struct in_device
*in_dev
)
496 struct ip_mc_list
*i
;
498 ip_mc_inc_group(in_dev
, IGMP_ALL_HOSTS
);
500 for (i
=in_dev
->mc_list
; i
; i
=i
->next
)
505 * Device is about to be destroyed: clean up.
508 void ip_mc_destroy_dev(struct in_device
*in_dev
)
510 struct ip_mc_list
*i
;
512 while ((i
= in_dev
->mc_list
) != NULL
) {
513 in_dev
->mc_list
= i
->next
;
514 igmp_group_dropped(i
);
515 kfree_s(i
, sizeof(*i
));
519 static struct in_device
* ip_mc_find_dev(struct ip_mreqn
*imr
)
522 struct device
*dev
= NULL
;
524 if (imr
->imr_address
.s_addr
) {
525 dev
= ip_dev_find(imr
->imr_address
.s_addr
);
530 if (!dev
&& !ip_route_output(&rt
, imr
->imr_multiaddr
.s_addr
, 0, 0, 0)) {
535 imr
->imr_ifindex
= dev
->ifindex
;
542 * Join a socket to a group
544 int sysctl_igmp_max_memberships
= IP_MAX_MEMBERSHIPS
;
546 int ip_mc_join_group(struct sock
*sk
, struct ip_mreqn
*imr
)
549 u32 addr
= imr
->imr_multiaddr
.s_addr
;
550 struct ip_mc_socklist
*iml
, *i
;
551 struct in_device
*in_dev
;
554 if (!MULTICAST(addr
))
559 if (!imr
->imr_ifindex
)
560 in_dev
= ip_mc_find_dev(imr
);
562 in_dev
= inetdev_by_index(imr
->imr_ifindex
);
570 iml
= (struct ip_mc_socklist
*)sock_kmalloc(sk
, sizeof(*iml
), GFP_KERNEL
);
573 for (i
=sk
->ip_mc_list
; i
; i
=i
->next
) {
574 if (memcmp(&i
->multi
, imr
, sizeof(*imr
)) == 0) {
575 /* New style additions are reference counted */
576 if (imr
->imr_address
.s_addr
== 0) {
585 if (iml
== NULL
|| count
>= sysctl_igmp_max_memberships
)
587 memcpy(&iml
->multi
, imr
, sizeof(*imr
));
588 iml
->next
= sk
->ip_mc_list
;
590 sk
->ip_mc_list
= iml
;
591 ip_mc_inc_group(in_dev
, addr
);
597 sock_kfree_s(sk
, iml
, sizeof(*iml
));
602 * Ask a socket to leave a group.
605 int ip_mc_leave_group(struct sock
*sk
, struct ip_mreqn
*imr
)
607 struct ip_mc_socklist
*iml
, **imlp
;
609 for (imlp
=&sk
->ip_mc_list
; (iml
=*imlp
)!=NULL
; imlp
=&iml
->next
) {
610 if (iml
->multi
.imr_multiaddr
.s_addr
==imr
->imr_multiaddr
.s_addr
&&
611 iml
->multi
.imr_address
.s_addr
==imr
->imr_address
.s_addr
&&
612 (!imr
->imr_ifindex
|| iml
->multi
.imr_ifindex
==imr
->imr_ifindex
)) {
613 struct in_device
*in_dev
;
620 in_dev
= inetdev_by_index(iml
->multi
.imr_ifindex
);
622 ip_mc_dec_group(in_dev
, imr
->imr_multiaddr
.s_addr
);
623 sock_kfree_s(sk
, iml
, sizeof(*iml
));
627 return -EADDRNOTAVAIL
;
631 * A socket is closing.
634 void ip_mc_drop_socket(struct sock
*sk
)
636 struct ip_mc_socklist
*iml
;
638 while ((iml
=sk
->ip_mc_list
) != NULL
) {
639 struct in_device
*in_dev
;
640 sk
->ip_mc_list
= iml
->next
;
641 if ((in_dev
= inetdev_by_index(iml
->multi
.imr_ifindex
)) != NULL
)
642 ip_mc_dec_group(in_dev
, iml
->multi
.imr_multiaddr
.s_addr
);
643 sock_kfree_s(sk
, iml
, sizeof(*iml
));
648 #ifdef CONFIG_IP_MULTICAST
650 int ip_mc_procinfo(char *buffer
, char **start
, off_t offset
, int length
, int dummy
)
652 off_t pos
=0, begin
=0;
653 struct ip_mc_list
*im
;
657 len
=sprintf(buffer
,"Idx\tDevice : Count Querier\tGroup Users Timer\tReporter\n");
659 read_lock_bh(&dev_base_lock
);
660 for(dev
= dev_base
; dev
; dev
= dev
->next
) {
661 struct in_device
*in_dev
= dev
->ip_ptr
;
662 char *querier
= "NONE";
667 querier
= IGMP_V1_SEEN(in_dev
) ? "V1" : "V2";
669 len
+=sprintf(buffer
+len
,"%d\t%-10s: %5d %7s\n",
670 dev
->ifindex
, dev
->name
, dev
->mc_count
, querier
);
672 for (im
= in_dev
->mc_list
; im
; im
= im
->next
) {
673 len
+=sprintf(buffer
+len
,
674 "\t\t\t\t%08lX %5d %d:%08lX\t\t%d\n",
675 im
->multiaddr
, im
->users
,
676 im
->tm_running
, im
->timer
.expires
-jiffies
, im
->reporter
);
684 if(pos
>offset
+length
)
689 read_unlock_bh(&dev_base_lock
);
691 *start
=buffer
+(offset
-begin
);