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