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