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