1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
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
99
100#define IP_MAX_MEMBERSHIPS 20
101
102#ifdef CONFIG_IP_MULTICAST
103
104
105
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
110
111
112#define IGMP_Initial_Report_Delay (1*HZ)
113
114
115
116
117
118
119
120
121#define IGMP_V1_SEEN(in_dev) ((in_dev)->mr_v1_seen && (long)(jiffies - (in_dev)->mr_v1_seen) < 0)
122
123
124
125
126
127static __inline__ void igmp_stop_timer(struct ip_mc_list *im)
128{
129 if (im->tm_running) {
130 del_timer(&im->timer);
131 im->tm_running=0;
132 }
133}
134
135static __inline__ void igmp_start_timer(struct ip_mc_list *im, int max_delay)
136{
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);
144}
145
146
147
148
149
150#define IGMP_SIZE (sizeof(struct igmphdr)+sizeof(struct iphdr)+4)
151
152static int igmp_send_report(struct device *dev, u32 group, int type)
153{
154 struct sk_buff *skb;
155 struct iphdr *iph;
156 struct igmphdr *ih;
157 struct rtable *rt;
158 u32 dst;
159
160
161
162
163 dst = group;
164 if (type == IGMP_HOST_LEAVE_MESSAGE)
165 dst = IGMP_ALL_ROUTER;
166
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;
172 }
173
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;
178 }
179
180 skb->dst = &rt->u.dst;
181
182 skb_reserve(skb, (dev->hard_header_len+15)&~15);
183
184 skb->nh.iph = iph = (struct iphdr *)skb_put(skb, sizeof(struct iphdr)+4);
185
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);
201
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));
208
209 return skb->dst->output(skb);
210}
211
212
213static void igmp_timer_expire(unsigned long data)
214{
215 struct ip_mc_list *im=(struct ip_mc_list *)data;
216 struct in_device *in_dev = im->interface;
217 int err;
218
219 im->tm_running=0;
220
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);
225
226
227 if (err) {
228 igmp_start_timer(im, IGMP_Unsolicited_Report_Interval);
229 return;
230 }
231
232 if (im->unsolicit_count) {
233 im->unsolicit_count--;
234 igmp_start_timer(im, IGMP_Unsolicited_Report_Interval);
235 }
236 im->reporter = 1;
237}
238
239static void igmp_heard_report(struct in_device *in_dev, u32 group)
240{
241 struct ip_mc_list *im;
242
243
244
245 if (LOCAL_MCAST(group))
246 return;
247
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;
254 }
255 }
256}
257
258static void igmp_heard_query(struct in_device *in_dev, unsigned char max_resp_time,
259 u32 group)
260{
261 struct ip_mc_list *im;
262 int max_delay;
263
264 max_delay = max_resp_time*(HZ/IGMP_TIMER_SCALE);
265
266 if (max_resp_time == 0) {
267
268
269 max_delay = IGMP_Query_Response_Interval;
270 in_dev->mr_v1_seen = jiffies + IGMP_V1_Router_Present_Timeout;
271 group = 0;
272 }
273
274
275
276
277
278
279
280
281
282
283
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);
293 }
294}
295
296int igmp_rcv(struct sk_buff *skb, unsigned short len)
297{
298
299 struct igmphdr *ih = skb->h.igmph;
300 struct in_device *in_dev = skb->dev->ip_ptr;
301
302 if (len < sizeof(struct igmphdr) || ip_compute_csum((void *)ih, len)
303 || in_dev==NULL) {
304 kfree_skb(skb);
305 return 0;
306 }
307
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
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));
331 }
332 kfree_skb(skb);
333 return 0;
334}
335
336#endif
337
338
339
340
341
342
343static void ip_mc_filter_add(struct in_device *in_dev, u32 addr)
344{
345 char buf[MAX_ADDR_LEN];
346 struct device *dev = in_dev->dev;
347
348
349
350
351
352
353
354
355 if (arp_mc_map(addr, buf, dev, 0) == 0)
356 dev_mc_add(dev,buf,dev->addr_len,0);
357}
358
359
360
361
362
363static void ip_mc_filter_del(struct in_device *in_dev, u32 addr)
364{
365 char buf[MAX_ADDR_LEN];
366 struct device *dev = in_dev->dev;
367
368 if (arp_mc_map(addr, buf, dev, 0) == 0)
369 dev_mc_delete(dev,buf,dev->addr_len,0);
370}
371
372static void igmp_group_dropped(struct ip_mc_list *im)
373{
374 if (im->loaded) {
375 im->loaded = 0;
376 ip_mc_filter_del(im->interface, im->multiaddr);
377 }
378
379#ifdef CONFIG_IP_MULTICAST
380 if (LOCAL_MCAST(im->multiaddr))
381 return;
382
383 start_bh_atomic();
384 igmp_stop_timer(im);
385 end_bh_atomic();
386
387 if (im->reporter && !IGMP_V1_SEEN(im->interface))
388 igmp_send_report(im->interface->dev, im->multiaddr, IGMP_HOST_LEAVE_MESSAGE);
389#endif
390}
391
392static void igmp_group_added(struct ip_mc_list *im)
393{
394 if (im->loaded == 0) {
395 im->loaded = 1;
396 ip_mc_filter_add(im->interface, im->multiaddr);
397 }
398
399#ifdef CONFIG_IP_MULTICAST
400 if (LOCAL_MCAST(im->multiaddr))
401 return;
402
403 start_bh_atomic();
404 igmp_start_timer(im, IGMP_Initial_Report_Delay);
405 end_bh_atomic();
406#endif
407}
408
409
410
411
412
413
414
415
416
417
418
419void ip_mc_inc_group(struct in_device *in_dev, u32 addr)
420{
421 struct ip_mc_list *i, *im;
422
423 im = (struct ip_mc_list *)kmalloc(sizeof(*im), GFP_KERNEL);
424
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;
431 }
432 }
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;
453}
454
455
456
457
458
459int ip_mc_dec_group(struct in_device *in_dev, u32 addr)
460{
461 struct ip_mc_list *i, **ip;
462
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();
468
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));
473 }
474 return 0;
475 }
476 }
477 return -ESRCH;
478}
479
480
481
482void ip_mc_down(struct in_device *in_dev)
483{
484 struct ip_mc_list *i;
485
486 for (i=in_dev->mc_list; i; i=i->next)
487 igmp_group_dropped(i);
488
489 ip_mc_dec_group(in_dev, IGMP_ALL_HOSTS);
490}
491
492
493
494void ip_mc_up(struct in_device *in_dev)
495{
496 struct ip_mc_list *i;
497
498 ip_mc_inc_group(in_dev, IGMP_ALL_HOSTS);
499
500 for (i=in_dev->mc_list; i; i=i->next)
501 igmp_group_added(i);
502}
503
504
505
506
507
508void ip_mc_destroy_dev(struct in_device *in_dev)
509{
510 struct ip_mc_list *i;
511
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));
516 }
517}
518
519static struct in_device * ip_mc_find_dev(struct ip_mreqn *imr)
520{
521 struct rtable *rt;
522 struct device *dev = NULL;
523
524 if (imr->imr_address.s_addr) {
525 dev = ip_dev_find(imr->imr_address.s_addr);
526 if (!dev)
527 return NULL;
528 }
529
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);
533 }
534 if (dev) {
535 imr->imr_ifindex = dev->ifindex;
536 return dev->ip_ptr;
537 }
538 return NULL;
539}
540
541
542
543
544int sysctl_igmp_max_memberships = IP_MAX_MEMBERSHIPS;
545
546int ip_mc_join_group(struct sock *sk , struct ip_mreqn *imr)
547{
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;
553
554 if (!MULTICAST(addr))
555 return -EINVAL;
556
557 rtnl_shlock();
558
559 if (!imr->imr_ifindex)
560 in_dev = ip_mc_find_dev(imr);
561 else
562 in_dev = inetdev_by_index(imr->imr_ifindex);
563
564 if (!in_dev) {
565 iml = NULL;
566 err = -ENODEV;
567 goto done;
568 }
569
570 iml = (struct ip_mc_socklist *)sock_kmalloc(sk, sizeof(*iml), GFP_KERNEL);
571
572 err = -EADDRINUSE;
573 for (i=sk->ip_mc_list; i; i=i->next) {
574 if (memcmp(&i->multi, imr, sizeof(*imr)) == 0) {
575
576 if (imr->imr_address.s_addr == 0) {
577 i->count++;
578 err = 0;
579 }
580 goto done;
581 }
582 count++;
583 }
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;
594done:
595 rtnl_shunlock();
596 if (iml)
597 sock_kfree_s(sk, iml, sizeof(*iml));
598 return err;
599}
600
601
602
603
604
605int ip_mc_leave_group(struct sock *sk, struct ip_mreqn *imr)
606{
607 struct ip_mc_socklist *iml, **imlp;
608
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;
616
617 *imlp = iml->next;
618 synchronize_bh();
619
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;
625 }
626 }
627 return -EADDRNOTAVAIL;
628}
629
630
631
632
633
634void ip_mc_drop_socket(struct sock *sk)
635{
636 struct ip_mc_socklist *iml;
637
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));
644 }
645}
646
647
648#ifdef CONFIG_IP_MULTICAST
649
650int ip_mc_procinfo(char *buffer, char **start, off_t offset, int length, int dummy)
651{
652 off_t pos=0, begin=0;
653 struct ip_mc_list *im;
654 int len=0;
655 struct device *dev;
656
657 len=sprintf(buffer,"Idx\tDevice : Count Querier\tGroup Users Timer\tReporter\n");
658
659 for(dev = dev_base; dev; dev = dev->next)
660 {
661 struct in_device *in_dev = dev->ip_ptr;
662 char *querier = "NONE";
663
664 if (in_dev == NULL)
665 continue;
666
667 querier = IGMP_V1_SEEN(in_dev) ? "V1" : "V2";
668
669 len+=sprintf(buffer+len,"%d\t%-10s: %5d %7s\n",
670 dev->ifindex, dev->name, dev->mc_count, querier);
671
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);
677
678 pos=begin+len;
679 if(pos<offset)
680 {
681 len=0;
682 begin=pos;
683 }
684 if(pos>offset+length)
685 goto done;
686 }
687 }
688done:
689 *start=buffer+(offset-begin);
690 len-=(offset-begin);
691 if(len>length)
692 len=length;
693 if(len<0)
694 len=0;
695 return len;
696}
697#endif
698
699