pre-2.3.4..
[davej-history.git] / net / ipv4 / igmp.c
blob0c7ac7324bcf53486e0617eac3e12c90984b3a86
1 /*
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 $
13 * Authors:
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.
21 * Fixes:
23 * Alan Cox : Added lots of __inline__ to optimise
24 * the memory usage of all the tiny little
25 * functions.
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
34 * points.
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"
55 * message (960131).
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
60 * true (960216).
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>
83 #include <linux/in.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>
91 #include <net/ip.h>
92 #include <net/protocol.h>
93 #include <net/route.h>
94 #include <net/sock.h>
95 #include <net/checksum.h>
96 #ifdef CONFIG_IP_MROUTE
97 #include <linux/mroute.h>
98 #endif
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)
124 * Timer management
127 static __inline__ void igmp_stop_timer(struct ip_mc_list *im)
129 if (im->tm_running) {
130 del_timer(&im->timer);
131 im->tm_running=0;
135 static __inline__ void igmp_start_timer(struct ip_mc_list *im, int max_delay)
137 int tv;
138 if (im->tm_running)
139 return;
140 tv=net_random() % max_delay;
141 im->timer.expires=jiffies+tv+2;
142 im->tm_running=1;
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)
154 struct sk_buff *skb;
155 struct iphdr *iph;
156 struct igmphdr *ih;
157 struct rtable *rt;
158 u32 dst;
160 /* According to IGMPv2 specs, LEAVE messages are
161 * sent to all-routers group.
163 dst = group;
164 if (type == IGMP_HOST_LEAVE_MESSAGE)
165 dst = IGMP_ALL_ROUTER;
167 if (ip_route_output(&rt, dst, 0, 0, dev->ifindex))
168 return -1;
169 if (rt->rt_src == 0) {
170 ip_rt_put(rt);
171 return -1;
174 skb=alloc_skb(IGMP_SIZE+dev->hard_header_len+15, GFP_ATOMIC);
175 if (skb == NULL) {
176 ip_rt_put(rt);
177 return -1;
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);
186 iph->version = 4;
187 iph->ihl = (sizeof(struct iphdr)+4)>>2;
188 iph->tos = 0;
189 iph->frag_off = 0;
190 iph->ttl = 1;
191 iph->daddr = dst;
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;
200 ip_send_check(iph);
202 ih = (struct igmphdr *)skb_put(skb, sizeof(struct igmphdr));
203 ih->type=type;
204 ih->code=0;
205 ih->csum=0;
206 ih->group=group;
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;
217 int err;
219 im->tm_running=0;
221 if (IGMP_V1_SEEN(in_dev))
222 err = igmp_send_report(in_dev->dev, im->multiaddr, IGMP_HOST_MEMBERSHIP_REPORT);
223 else
224 err = igmp_send_report(in_dev->dev, im->multiaddr, IGMP_HOST_NEW_MEMBERSHIP_REPORT);
226 /* Failed. Retry later. */
227 if (err) {
228 igmp_start_timer(im, IGMP_Unsolicited_Report_Interval);
229 return;
232 if (im->unsolicit_count) {
233 im->unsolicit_count--;
234 igmp_start_timer(im, IGMP_Unsolicited_Report_Interval);
236 im->reporter = 1;
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))
246 return;
248 for (im=in_dev->mc_list; im!=NULL; im=im->next) {
249 if (im->multiaddr == group) {
250 igmp_stop_timer(im);
251 im->reporter = 0;
252 im->unsolicit_count = 0;
253 return;
258 static void igmp_heard_query(struct in_device *in_dev, unsigned char max_resp_time,
259 u32 group)
261 struct ip_mc_list *im;
262 int max_delay;
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;
271 group = 0;
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
280 * be reset.
281 * - Use the igmp->igmp_code field as the maximum
282 * delay possible
284 for (im=in_dev->mc_list; im!=NULL; im=im->next) {
285 if (group && group != im->multiaddr)
286 continue;
287 if (LOCAL_MCAST(im->multiaddr))
288 continue;
289 im->unsolicit_count = 0;
290 if (im->tm_running && (long)(im->timer.expires-jiffies) > max_delay)
291 igmp_stop_timer(im);
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)
303 || in_dev==NULL) {
304 kfree_skb(skb);
305 return 0;
308 switch (ih->type) {
309 case IGMP_HOST_MEMBERSHIP_QUERY:
310 igmp_heard_query(in_dev, ih->code, ih->group);
311 break;
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)
316 break;
317 igmp_heard_report(in_dev, ih->group);
318 break;
319 case IGMP_PIM:
320 #ifdef CONFIG_IP_PIMSM_V1
321 return pim_rcv_v1(skb, len);
322 #endif
323 case IGMP_DVMRP:
324 case IGMP_TRACE:
325 case IGMP_HOST_LEAVE_MESSAGE:
326 case IGMP_MTRACE:
327 case IGMP_MTRACE_RESP:
328 break;
329 default:
330 NETDEBUG(printk(KERN_DEBUG "New IGMP type=%d, why we do not know about it?\n", ih->type));
332 kfree_skb(skb);
333 return 0;
336 #endif
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; }
353 --ANK
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)
374 if (im->loaded) {
375 im->loaded = 0;
376 ip_mc_filter_del(im->interface, im->multiaddr);
379 #ifdef CONFIG_IP_MULTICAST
380 if (LOCAL_MCAST(im->multiaddr))
381 return;
383 start_bh_atomic();
384 igmp_stop_timer(im);
385 end_bh_atomic();
387 if (im->reporter && !IGMP_V1_SEEN(im->interface))
388 igmp_send_report(im->interface->dev, im->multiaddr, IGMP_HOST_LEAVE_MESSAGE);
389 #endif
392 static void igmp_group_added(struct ip_mc_list *im)
394 if (im->loaded == 0) {
395 im->loaded = 1;
396 ip_mc_filter_add(im->interface, im->multiaddr);
399 #ifdef CONFIG_IP_MULTICAST
400 if (LOCAL_MCAST(im->multiaddr))
401 return;
403 start_bh_atomic();
404 igmp_start_timer(im, IGMP_Initial_Report_Delay);
405 end_bh_atomic();
406 #endif
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) {
427 i->users++;
428 if (im)
429 kfree(im);
430 return;
433 if (!im)
434 return;
435 im->users=1;
436 im->interface=in_dev;
437 im->multiaddr=addr;
438 #ifdef CONFIG_IP_MULTICAST
439 im->tm_running=0;
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;
444 im->reporter = 0;
445 im->loaded = 0;
446 #endif
447 im->next=in_dev->mc_list;
448 in_dev->mc_list=im;
449 igmp_group_added(im);
450 if (in_dev->dev->flags & IFF_UP)
451 ip_rt_multicast_event(in_dev);
452 return;
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) {
466 *ip = i->next;
467 synchronize_bh();
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));
474 return 0;
477 return -ESRCH;
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)
501 igmp_group_added(i);
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)
521 struct rtable *rt;
522 struct device *dev = NULL;
524 if (imr->imr_address.s_addr) {
525 dev = ip_dev_find(imr->imr_address.s_addr);
526 if (!dev)
527 return NULL;
530 if (!dev && !ip_route_output(&rt, imr->imr_multiaddr.s_addr, 0, 0, 0)) {
531 dev = rt->u.dst.dev;
532 ip_rt_put(rt);
534 if (dev) {
535 imr->imr_ifindex = dev->ifindex;
536 return dev->ip_ptr;
538 return NULL;
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)
548 int err;
549 u32 addr = imr->imr_multiaddr.s_addr;
550 struct ip_mc_socklist *iml, *i;
551 struct in_device *in_dev;
552 int count = 0;
554 if (!MULTICAST(addr))
555 return -EINVAL;
557 rtnl_shlock();
559 if (!imr->imr_ifindex)
560 in_dev = ip_mc_find_dev(imr);
561 else
562 in_dev = inetdev_by_index(imr->imr_ifindex);
564 if (!in_dev) {
565 iml = NULL;
566 err = -ENODEV;
567 goto done;
570 iml = (struct ip_mc_socklist *)sock_kmalloc(sk, sizeof(*iml), GFP_KERNEL);
572 err = -EADDRINUSE;
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) {
577 i->count++;
578 err = 0;
580 goto done;
582 count++;
584 err = -ENOBUFS;
585 if (iml == NULL || count >= sysctl_igmp_max_memberships)
586 goto done;
587 memcpy(&iml->multi, imr, sizeof(*imr));
588 iml->next = sk->ip_mc_list;
589 iml->count = 1;
590 sk->ip_mc_list = iml;
591 ip_mc_inc_group(in_dev, addr);
592 iml = NULL;
593 err = 0;
594 done:
595 rtnl_shunlock();
596 if (iml)
597 sock_kfree_s(sk, iml, sizeof(*iml));
598 return err;
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;
614 if (--iml->count)
615 return 0;
617 *imlp = iml->next;
618 synchronize_bh();
620 in_dev = inetdev_by_index(iml->multi.imr_ifindex);
621 if (in_dev)
622 ip_mc_dec_group(in_dev, imr->imr_multiaddr.s_addr);
623 sock_kfree_s(sk, iml, sizeof(*iml));
624 return 0;
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;
654 int len=0;
655 struct device *dev;
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";
664 if (in_dev == NULL)
665 continue;
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);
678 pos=begin+len;
679 if(pos<offset)
681 len=0;
682 begin=pos;
684 if(pos>offset+length)
685 goto done;
688 done:
689 read_unlock_bh(&dev_base_lock);
691 *start=buffer+(offset-begin);
692 len-=(offset-begin);
693 if(len>length)
694 len=length;
695 if(len<0)
696 len=0;
697 return len;
699 #endif