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