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) == 0)
521 {
522 struct ip_mc_list *tmp= *i;
523 igmp_group_dropped(tmp);
524 *i=(*i)->next;
525 kfree_s(tmp,sizeof(*tmp));
526 }
527 return;
528 }
529 }
530 }
531
532
533
534
535
536 void ip_mc_drop_device(struct device *dev)
537 {
538 struct ip_mc_list *i;
539 struct ip_mc_list *j;
540 for(i=dev->ip_mc_list;i!=NULL;i=j)
541 {
542 j=i->next;
543 kfree_s(i,sizeof(*i));
544 }
545 dev->ip_mc_list=NULL;
546 }
547
548
549
550
551
552 void ip_mc_allhost(struct device *dev)
553 {
554 struct ip_mc_list *i;
555 for(i=dev->ip_mc_list;i!=NULL;i=i->next)
556 if(i->multiaddr==IGMP_ALL_HOSTS)
557 return;
558 i=(struct ip_mc_list *)kmalloc(sizeof(*i), GFP_KERNEL);
559 if(!i)
560 return;
561 i->users=1;
562 i->interface=dev;
563 i->multiaddr=IGMP_ALL_HOSTS;
564 i->tm_running=0;
565 i->next=dev->ip_mc_list;
566 dev->ip_mc_list=i;
567 ip_mc_filter_add(i->interface, i->multiaddr);
568
569 }
570
571
572
573
574
575 int ip_mc_join_group(struct sock *sk , struct device *dev, unsigned long addr)
576 {
577 int unused= -1;
578 int i;
579 if(!MULTICAST(addr))
580 return -EINVAL;
581 if(!(dev->flags&IFF_MULTICAST))
582 return -EADDRNOTAVAIL;
583 if(sk->ip_mc_list==NULL)
584 {
585 if((sk->ip_mc_list=(struct ip_mc_socklist *)kmalloc(sizeof(*sk->ip_mc_list), GFP_KERNEL))==NULL)
586 return -ENOMEM;
587 memset(sk->ip_mc_list,'\0',sizeof(*sk->ip_mc_list));
588 }
589 for(i=0;i<IP_MAX_MEMBERSHIPS;i++)
590 {
591 if(sk->ip_mc_list->multiaddr[i]==addr && sk->ip_mc_list->multidev[i]==dev)
592 return -EADDRINUSE;
593 if(sk->ip_mc_list->multidev[i]==NULL)
594 unused=i;
595 }
596
597 if(unused==-1)
598 return -ENOBUFS;
599 sk->ip_mc_list->multiaddr[unused]=addr;
600 sk->ip_mc_list->multidev[unused]=dev;
601 ip_mc_inc_group(dev,addr);
602 return 0;
603 }
604
605
606
607
608
609 int ip_mc_leave_group(struct sock *sk, struct device *dev, unsigned long addr)
610 {
611 int i;
612 if(!MULTICAST(addr))
613 return -EINVAL;
614 if(!(dev->flags&IFF_MULTICAST))
615 return -EADDRNOTAVAIL;
616 if(sk->ip_mc_list==NULL)
617 return -EADDRNOTAVAIL;
618
619 for(i=0;i<IP_MAX_MEMBERSHIPS;i++)
620 {
621 if(sk->ip_mc_list->multiaddr[i]==addr && sk->ip_mc_list->multidev[i]==dev)
622 {
623 sk->ip_mc_list->multidev[i]=NULL;
624 ip_mc_dec_group(dev,addr);
625 return 0;
626 }
627 }
628 return -EADDRNOTAVAIL;
629 }
630
631
632
633
634
635 void ip_mc_drop_socket(struct sock *sk)
636 {
637 int i;
638
639 if(sk->ip_mc_list==NULL)
640 return;
641
642 for(i=0;i<IP_MAX_MEMBERSHIPS;i++)
643 {
644 if(sk->ip_mc_list->multidev[i])
645 {
646 ip_mc_dec_group(sk->ip_mc_list->multidev[i], sk->ip_mc_list->multiaddr[i]);
647 sk->ip_mc_list->multidev[i]=NULL;
648 }
649 }
650 kfree_s(sk->ip_mc_list,sizeof(*sk->ip_mc_list));
651 sk->ip_mc_list=NULL;
652 }
653
654 #endif