This source file includes following definitions.
- ip_router_timer_expire
- igmp_get_mrouter_info
- igmp_set_mrouter_info
- igmp_stop_timer
- random
- igmp_start_timer
- igmp_timer_expire
- igmp_init_timer
- igmp_heard_report
- igmp_heard_query
- ip_mc_map
- ip_mc_filter_add
- ip_mc_filter_del
- igmp_group_dropped
- igmp_group_added
- igmp_rcv
- ip_mc_inc_group
- ip_mc_dec_group
- ip_mc_drop_device
- ip_mc_allhost
- ip_mc_join_group
- ip_mc_leave_group
- ip_mc_drop_socket
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 #include <asm/segment.h>
58 #include <asm/system.h>
59 #include <linux/types.h>
60 #include <linux/kernel.h>
61 #include <linux/sched.h>
62 #include <linux/string.h>
63 #include <linux/config.h>
64 #include <linux/socket.h>
65 #include <linux/sockios.h>
66 #include <linux/in.h>
67 #include <linux/inet.h>
68 #include <linux/netdevice.h>
69 #include <linux/if_arp.h>
70 #include <net/ip.h>
71 #include <net/protocol.h>
72 #include <net/route.h>
73 #include <linux/skbuff.h>
74 #include <net/sock.h>
75 #include <linux/igmp.h>
76 #include <net/checksum.h>
77
78 #ifdef CONFIG_IP_MULTICAST
79
80
81
82
83
84
85 static void ip_router_timer_expire(unsigned long data)
86 {
87 struct ip_router_info *i=(struct ip_router_info *)data;
88
89 del_timer(&i->timer);
90 i->type=IGMP_NEW_ROUTER;
91 i->time=0;
92 }
93
94
95
96
97
98 struct ip_router_info *ip_router_info_head=(struct ip_router_info *)0;
99
100
101
102
103
104 static struct ip_router_info *igmp_get_mrouter_info(struct device *dev)
105 {
106 register struct ip_router_info *i;
107
108 for(i=ip_router_info_head;i!=NULL;i=i->next)
109 {
110 if (i->dev == dev)
111 {
112 return i;
113 }
114 }
115
116
117
118
119
120 i=(struct ip_router_info *)kmalloc(sizeof(*i), GFP_ATOMIC);
121 if(i==NULL)
122 return NULL;
123 i->dev = dev;
124 i->type = IGMP_NEW_ROUTER;
125 i->time = IGMP_AGE_THRESHOLD;
126 i->next = ip_router_info_head;
127 ip_router_info_head = i;
128
129 init_timer(&i->timer);
130 i->timer.data=(unsigned long)i;
131 i->timer.function=&ip_router_timer_expire;
132
133 return i;
134 }
135
136
137
138
139
140 static struct ip_router_info *igmp_set_mrouter_info(struct device *dev,int type,int time)
141 {
142 register struct ip_router_info *i;
143
144 for(i=ip_router_info_head;i!=NULL;i=i->next)
145 {
146 if (i->dev == dev)
147 {
148 if(i->type==IGMP_OLD_ROUTER)
149 {
150 del_timer(&i->timer);
151 }
152
153 i->type = type;
154 i->time = time;
155
156 if(i->type==IGMP_OLD_ROUTER)
157 {
158 i->timer.expires=jiffies+i->time*HZ;
159 add_timer(&i->timer);
160 }
161 return i;
162 }
163 }
164
165
166
167
168 i=(struct ip_router_info *)kmalloc(sizeof(*i), GFP_ATOMIC);
169 if(i==NULL)
170 return NULL;
171 i->dev = dev;
172 i->type = type;
173 i->time = time;
174 i->next = ip_router_info_head;
175 ip_router_info_head = i;
176
177 init_timer(&i->timer);
178 i->timer.data=(unsigned long)i;
179 i->timer.function=&ip_router_timer_expire;
180 if(i->type==IGMP_OLD_ROUTER)
181 {
182 i->timer.expires=jiffies+i->time*HZ;
183 add_timer(&i->timer);
184 }
185
186 return i;
187 }
188
189
190
191
192
193
194 static void igmp_stop_timer(struct ip_mc_list *im)
195 {
196 if (im->tm_running) {
197 del_timer(&im->timer);
198 im->tm_running=0;
199 }
200 else {
201 printk("igmp_stop_timer() called with timer not running by %p\n",__builtin_return_address(0));
202 }
203 }
204
205 extern __inline__ int random(void)
206 {
207 static unsigned long seed=152L;
208 seed=seed*69069L+1;
209 return seed^jiffies;
210 }
211
212
213
214
215
216 static void igmp_start_timer(struct ip_mc_list *im,unsigned char max_resp_time)
217 {
218 int tv;
219 if(im->tm_running)
220 return;
221 tv=random()%(max_resp_time*HZ/IGMP_TIMER_SCALE);
222 im->timer.expires=jiffies+tv;
223 im->tm_running=1;
224 add_timer(&im->timer);
225 }
226
227
228
229
230
231 #define MAX_IGMP_SIZE (sizeof(struct igmphdr)+sizeof(struct iphdr)+64)
232
233 static void igmp_send_report(struct device *dev, unsigned long address, int type)
234 {
235 struct sk_buff *skb=alloc_skb(MAX_IGMP_SIZE, GFP_ATOMIC);
236 int tmp;
237 struct igmphdr *ih;
238
239 if(skb==NULL)
240 return;
241 tmp=ip_build_header(skb, INADDR_ANY, address, &dev, IPPROTO_IGMP, NULL,
242 28 , 0, 1, NULL);
243 if(tmp<0)
244 {
245 kfree_skb(skb, FREE_WRITE);
246 return;
247 }
248 ih=(struct igmphdr *)skb_put(skb,sizeof(struct igmphdr));
249 ih->type=type;
250 ih->code=0;
251 ih->csum=0;
252 ih->group=address;
253 ih->csum=ip_compute_csum((void *)ih,sizeof(struct igmphdr));
254 ip_queue_xmit(NULL,dev,skb,1);
255 }
256
257
258 static void igmp_timer_expire(unsigned long data)
259 {
260 struct ip_mc_list *im=(struct ip_mc_list *)data;
261 struct ip_router_info *r;
262 igmp_stop_timer(im);
263 r=igmp_get_mrouter_info(im->interface);
264 if(r==NULL)
265 return;
266 if(r->type==IGMP_NEW_ROUTER)
267 igmp_send_report(im->interface, im->multiaddr, IGMP_HOST_NEW_MEMBERSHIP_REPORT);
268 else
269 igmp_send_report(im->interface, im->multiaddr, IGMP_HOST_MEMBERSHIP_REPORT);
270 }
271
272 static void igmp_init_timer(struct ip_mc_list *im)
273 {
274 im->tm_running=0;
275 init_timer(&im->timer);
276 im->timer.data=(unsigned long)im;
277 im->timer.function=&igmp_timer_expire;
278 }
279
280
281 static void igmp_heard_report(struct device *dev, unsigned long address)
282 {
283 struct ip_mc_list *im;
284
285 if ((address & IGMP_LOCAL_GROUP_MASK) != IGMP_LOCAL_GROUP) {
286
287 for(im=dev->ip_mc_list;im!=NULL;im=im->next) {
288 if(im->multiaddr==address) {
289 igmp_stop_timer(im);
290 }
291 }
292 }
293 }
294
295 static void igmp_heard_query(struct device *dev,unsigned char max_resp_time)
296 {
297 struct ip_mc_list *im;
298 int mrouter_type;
299
300
301
302
303 if(max_resp_time>0)
304 {
305 mrouter_type=IGMP_NEW_ROUTER;
306
307 if(igmp_set_mrouter_info(dev,mrouter_type,0)==NULL)
308 return;
309
310
311
312
313
314
315
316
317
318
319 for(im=dev->ip_mc_list;im!=NULL;im=im->next)
320 {
321 if(im->tm_running)
322 {
323 if(im->timer.expires>max_resp_time*HZ/IGMP_TIMER_SCALE)
324 {
325 igmp_stop_timer(im);
326 igmp_start_timer(im,max_resp_time);
327 }
328 }
329 else
330 {
331 if((im->multiaddr & IGMP_LOCAL_GROUP_MASK)!=IGMP_LOCAL_GROUP)
332 igmp_start_timer(im,max_resp_time);
333 }
334 }
335 }
336 else
337 {
338 mrouter_type=IGMP_OLD_ROUTER;
339 max_resp_time=IGMP_MAX_HOST_REPORT_DELAY*IGMP_TIMER_SCALE;
340
341 if(igmp_set_mrouter_info(dev,mrouter_type,IGMP_AGE_THRESHOLD)==NULL)
342 return;
343
344
345
346
347
348
349
350
351 for(im=dev->ip_mc_list;im!=NULL;im=im->next)
352 {
353 if(!im->tm_running && (im->multiaddr & IGMP_LOCAL_GROUP_MASK)!=IGMP_LOCAL_GROUP)
354 igmp_start_timer(im,max_resp_time);
355 }
356 }
357 }
358
359
360
361
362
363 extern __inline__ void ip_mc_map(unsigned long addr, char *buf)
364 {
365 addr=ntohl(addr);
366 buf[0]=0x01;
367 buf[1]=0x00;
368 buf[2]=0x5e;
369 buf[5]=addr&0xFF;
370 addr>>=8;
371 buf[4]=addr&0xFF;
372 addr>>=8;
373 buf[3]=addr&0x7F;
374 }
375
376
377
378
379
380 void ip_mc_filter_add(struct device *dev, unsigned long addr)
381 {
382 char buf[6];
383 if(dev->type!=ARPHRD_ETHER)
384 return;
385 ip_mc_map(addr,buf);
386 dev_mc_add(dev,buf,ETH_ALEN,0);
387 }
388
389
390
391
392
393 void ip_mc_filter_del(struct device *dev, unsigned long addr)
394 {
395 char buf[6];
396 if(dev->type!=ARPHRD_ETHER)
397 return;
398 ip_mc_map(addr,buf);
399 dev_mc_delete(dev,buf,ETH_ALEN,0);
400 }
401
402 extern __inline__ void igmp_group_dropped(struct ip_mc_list *im)
403 {
404 del_timer(&im->timer);
405 igmp_send_report(im->interface, im->multiaddr, IGMP_HOST_LEAVE_MESSAGE);
406 ip_mc_filter_del(im->interface, im->multiaddr);
407 }
408
409 extern __inline__ void igmp_group_added(struct ip_mc_list *im)
410 {
411 struct ip_router_info *r;
412 igmp_init_timer(im);
413 ip_mc_filter_add(im->interface, im->multiaddr);
414 r=igmp_get_mrouter_info(im->interface);
415 if(r==NULL)
416 return;
417 if(r->type==IGMP_NEW_ROUTER)
418 igmp_send_report(im->interface, im->multiaddr, IGMP_HOST_NEW_MEMBERSHIP_REPORT);
419 else
420 igmp_send_report(im->interface, im->multiaddr, IGMP_HOST_MEMBERSHIP_REPORT);
421 }
422
423 int igmp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
424 __u32 daddr, unsigned short len, __u32 saddr, int redo,
425 struct inet_protocol *protocol)
426 {
427
428 struct igmphdr *ih;
429
430
431
432
433
434
435
436 if(dev->flags&IFF_LOOPBACK)
437 {
438 dev=ip_dev_find(saddr);
439 if(dev==NULL)
440 dev=&loopback_dev;
441 }
442 ih=(struct igmphdr *)skb->h.raw;
443
444 if(skb->len <sizeof(struct igmphdr) || skb->ip_hdr->ttl>1 || ip_compute_csum((void *)skb->h.raw,sizeof(struct igmphdr)))
445 {
446 kfree_skb(skb, FREE_READ);
447 return 0;
448 }
449
450
451
452
453
454 if(saddr==0)
455 {
456 printk("Broken multicast host using 0.0.0.0 heard on %s\n",
457 dev->name);
458 kfree_skb(skb, FREE_READ);
459 return 0;
460 }
461
462 if(ih->type==IGMP_HOST_MEMBERSHIP_QUERY && daddr==IGMP_ALL_HOSTS)
463 igmp_heard_query(dev,ih->code);
464 if(ih->type==IGMP_HOST_MEMBERSHIP_REPORT && daddr==ih->group)
465 igmp_heard_report(dev,ih->group);
466 if(ih->type==IGMP_HOST_NEW_MEMBERSHIP_REPORT && daddr==ih->group)
467 igmp_heard_report(dev,ih->group);
468 kfree_skb(skb, FREE_READ);
469 return 0;
470 }
471
472
473
474
475
476
477
478
479
480
481 static void ip_mc_inc_group(struct device *dev, unsigned long addr)
482 {
483 struct ip_mc_list *i;
484 for(i=dev->ip_mc_list;i!=NULL;i=i->next)
485 {
486 if(i->multiaddr==addr)
487 {
488 i->users++;
489 return;
490 }
491 }
492 i=(struct ip_mc_list *)kmalloc(sizeof(*i), GFP_KERNEL);
493 if(!i)
494 return;
495 i->users=1;
496 i->interface=dev;
497 i->multiaddr=addr;
498 i->next=dev->ip_mc_list;
499 igmp_group_added(i);
500 dev->ip_mc_list=i;
501 }
502
503
504
505
506
507 static void ip_mc_dec_group(struct device *dev, unsigned long addr)
508 {
509 struct ip_mc_list **i;
510 for(i=&(dev->ip_mc_list);(*i)!=NULL;i=&(*i)->next)
511 {
512 if((*i)->multiaddr==addr)
513 {
514 if(--((*i)->users))
515 return;
516 else
517 {
518 struct ip_mc_list *tmp= *i;
519 igmp_group_dropped(tmp);
520 *i=(*i)->next;
521 kfree_s(tmp,sizeof(*tmp));
522 }
523 }
524 }
525 }
526
527
528
529
530
531 void ip_mc_drop_device(struct device *dev)
532 {
533 struct ip_mc_list *i;
534 struct ip_mc_list *j;
535 for(i=dev->ip_mc_list;i!=NULL;i=j)
536 {
537 j=i->next;
538 kfree_s(i,sizeof(*i));
539 }
540 dev->ip_mc_list=NULL;
541 }
542
543
544
545
546
547 void ip_mc_allhost(struct device *dev)
548 {
549 struct ip_mc_list *i;
550 for(i=dev->ip_mc_list;i!=NULL;i=i->next)
551 if(i->multiaddr==IGMP_ALL_HOSTS)
552 return;
553 i=(struct ip_mc_list *)kmalloc(sizeof(*i), GFP_KERNEL);
554 if(!i)
555 return;
556 i->users=1;
557 i->interface=dev;
558 i->multiaddr=IGMP_ALL_HOSTS;
559 i->tm_running=0;
560 i->next=dev->ip_mc_list;
561 dev->ip_mc_list=i;
562 ip_mc_filter_add(i->interface, i->multiaddr);
563
564 }
565
566
567
568
569
570 int ip_mc_join_group(struct sock *sk , struct device *dev, unsigned long addr)
571 {
572 int unused= -1;
573 int i;
574 if(!MULTICAST(addr))
575 return -EINVAL;
576 if(!(dev->flags&IFF_MULTICAST))
577 return -EADDRNOTAVAIL;
578 if(sk->ip_mc_list==NULL)
579 {
580 if((sk->ip_mc_list=(struct ip_mc_socklist *)kmalloc(sizeof(*sk->ip_mc_list), GFP_KERNEL))==NULL)
581 return -ENOMEM;
582 memset(sk->ip_mc_list,'\0',sizeof(*sk->ip_mc_list));
583 }
584 for(i=0;i<IP_MAX_MEMBERSHIPS;i++)
585 {
586 if(sk->ip_mc_list->multiaddr[i]==addr && sk->ip_mc_list->multidev[i]==dev)
587 return -EADDRINUSE;
588 if(sk->ip_mc_list->multidev[i]==NULL)
589 unused=i;
590 }
591
592 if(unused==-1)
593 return -ENOBUFS;
594 sk->ip_mc_list->multiaddr[unused]=addr;
595 sk->ip_mc_list->multidev[unused]=dev;
596 ip_mc_inc_group(dev,addr);
597 return 0;
598 }
599
600
601
602
603
604 int ip_mc_leave_group(struct sock *sk, struct device *dev, unsigned long addr)
605 {
606 int i;
607 if(!MULTICAST(addr))
608 return -EINVAL;
609 if(!(dev->flags&IFF_MULTICAST))
610 return -EADDRNOTAVAIL;
611 if(sk->ip_mc_list==NULL)
612 return -EADDRNOTAVAIL;
613
614 for(i=0;i<IP_MAX_MEMBERSHIPS;i++)
615 {
616 if(sk->ip_mc_list->multiaddr[i]==addr && sk->ip_mc_list->multidev[i]==dev)
617 {
618 sk->ip_mc_list->multidev[i]=NULL;
619 ip_mc_dec_group(dev,addr);
620 return 0;
621 }
622 }
623 return -EADDRNOTAVAIL;
624 }
625
626
627
628
629
630 void ip_mc_drop_socket(struct sock *sk)
631 {
632 int i;
633
634 if(sk->ip_mc_list==NULL)
635 return;
636
637 for(i=0;i<IP_MAX_MEMBERSHIPS;i++)
638 {
639 if(sk->ip_mc_list->multidev[i])
640 {
641 ip_mc_dec_group(sk->ip_mc_list->multidev[i], sk->ip_mc_list->multiaddr[i]);
642 sk->ip_mc_list->multidev[i]=NULL;
643 }
644 }
645 kfree_s(sk->ip_mc_list,sizeof(*sk->ip_mc_list));
646 sk->ip_mc_list=NULL;
647 }
648
649 #endif