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