This source file includes following definitions.
- 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 #include <asm/segment.h>
22 #include <asm/system.h>
23 #include <linux/types.h>
24 #include <linux/kernel.h>
25 #include <linux/sched.h>
26 #include <linux/string.h>
27 #include <linux/config.h>
28 #include <linux/socket.h>
29 #include <linux/sockios.h>
30 #include <linux/in.h>
31 #include <linux/inet.h>
32 #include <linux/netdevice.h>
33 #include <net/ip.h>
34 #include <net/protocol.h>
35 #include <net/route.h>
36 #include <linux/skbuff.h>
37 #include <net/sock.h>
38 #include <linux/igmp.h>
39 #include <net/checksum.h>
40
41 #ifdef CONFIG_IP_MULTICAST
42
43
44
45
46
47
48
49 extern __inline__ void igmp_stop_timer(struct ip_mc_list *im)
50 {
51 del_timer(&im->timer);
52 im->tm_running=0;
53 }
54
55 extern __inline__ int random(void)
56 {
57 static unsigned long seed=152L;
58 seed=seed*69069L+1;
59 return seed^jiffies;
60 }
61
62
63
64
65
66 extern __inline__ void igmp_start_timer(struct ip_mc_list *im)
67 {
68 int tv;
69 if(im->tm_running)
70 return;
71 tv=random()%(10*HZ);
72 im->timer.expires=jiffies+tv;
73 im->tm_running=1;
74 add_timer(&im->timer);
75 }
76
77
78
79
80
81 #define MAX_IGMP_SIZE (sizeof(struct igmphdr)+sizeof(struct iphdr)+64)
82
83 static void igmp_send_report(struct device *dev, unsigned long address, int type)
84 {
85 struct sk_buff *skb=alloc_skb(MAX_IGMP_SIZE, GFP_ATOMIC);
86 int tmp;
87 struct igmphdr *ih;
88
89 if(skb==NULL)
90 return;
91 tmp=ip_build_header(skb, INADDR_ANY, address, &dev, IPPROTO_IGMP, NULL,
92 skb->truesize, 0, 1);
93 if(tmp<0)
94 {
95 kfree_skb(skb, FREE_WRITE);
96 return;
97 }
98 ih=(struct igmphdr *)skb_put(skb,sizeof(struct igmphdr));
99 ih->type=IGMP_HOST_MEMBERSHIP_REPORT;
100 ih->unused=0;
101 ih->csum=0;
102 ih->group=address;
103 ih->csum=ip_compute_csum((void *)ih,sizeof(struct igmphdr));
104 ip_queue_xmit(NULL,dev,skb,1);
105 }
106
107
108 static void igmp_timer_expire(unsigned long data)
109 {
110 struct ip_mc_list *im=(struct ip_mc_list *)data;
111 igmp_stop_timer(im);
112 igmp_send_report(im->interface, im->multiaddr, IGMP_HOST_MEMBERSHIP_REPORT);
113 }
114
115 extern __inline__ void igmp_init_timer(struct ip_mc_list *im)
116 {
117 im->tm_running=0;
118 init_timer(&im->timer);
119 im->timer.data=(unsigned long)im;
120 im->timer.function=&igmp_timer_expire;
121 }
122
123
124 extern __inline__ void igmp_heard_report(struct device *dev, unsigned long address)
125 {
126 struct ip_mc_list *im;
127 for(im=dev->ip_mc_list;im!=NULL;im=im->next)
128 if(im->multiaddr==address)
129 igmp_stop_timer(im);
130 }
131
132 extern __inline__ void igmp_heard_query(struct device *dev)
133 {
134 struct ip_mc_list *im;
135 for(im=dev->ip_mc_list;im!=NULL;im=im->next)
136 if(!im->tm_running && im->multiaddr!=IGMP_ALL_HOSTS)
137 igmp_start_timer(im);
138 }
139
140
141
142
143
144 extern __inline__ void ip_mc_map(unsigned long addr, char *buf)
145 {
146 addr=ntohl(addr);
147 buf[0]=0x01;
148 buf[1]=0x00;
149 buf[2]=0x5e;
150 buf[5]=addr&0xFF;
151 addr>>=8;
152 buf[4]=addr&0xFF;
153 addr>>=8;
154 buf[3]=addr&0x7F;
155 }
156
157
158
159
160
161 void ip_mc_filter_add(struct device *dev, unsigned long addr)
162 {
163 char buf[6];
164 if(dev->type!=ARPHRD_ETHER)
165 return;
166 ip_mc_map(addr,buf);
167 dev_mc_add(dev,buf,ETH_ALEN,0);
168 }
169
170
171
172
173
174 void ip_mc_filter_del(struct device *dev, unsigned long addr)
175 {
176 char buf[6];
177 if(dev->type!=ARPHRD_ETHER)
178 return;
179 ip_mc_map(addr,buf);
180 dev_mc_delete(dev,buf,ETH_ALEN,0);
181 }
182
183 extern __inline__ void igmp_group_dropped(struct ip_mc_list *im)
184 {
185 del_timer(&im->timer);
186 igmp_send_report(im->interface, im->multiaddr, IGMP_HOST_LEAVE_MESSAGE);
187 ip_mc_filter_del(im->interface, im->multiaddr);
188
189 }
190
191 extern __inline__ void igmp_group_added(struct ip_mc_list *im)
192 {
193 igmp_init_timer(im);
194 igmp_send_report(im->interface, im->multiaddr, IGMP_HOST_MEMBERSHIP_REPORT);
195 ip_mc_filter_add(im->interface, im->multiaddr);
196
197 }
198
199 int igmp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
200 unsigned long daddr, unsigned short len, unsigned long saddr, int redo,
201 struct inet_protocol *protocol)
202 {
203
204 struct igmphdr *ih;
205
206 ih=(struct igmphdr *)skb->data;
207
208 if(skb->len <sizeof(struct igmphdr) || skb->ip_hdr->ttl!=1 || ip_compute_csum((void *)skb->h.raw,sizeof(struct igmphdr)))
209 {
210 kfree_skb(skb, FREE_READ);
211 return 0;
212 }
213
214 if(ih->type==IGMP_HOST_MEMBERSHIP_QUERY && daddr==IGMP_ALL_HOSTS)
215 igmp_heard_query(dev);
216 if(ih->type==IGMP_HOST_MEMBERSHIP_REPORT && daddr==ih->group)
217 igmp_heard_report(dev,ih->group);
218 kfree_skb(skb, FREE_READ);
219 return 0;
220 }
221
222
223
224
225
226
227
228
229
230
231 static void ip_mc_inc_group(struct device *dev, unsigned long addr)
232 {
233 struct ip_mc_list *i;
234 for(i=dev->ip_mc_list;i!=NULL;i=i->next)
235 {
236 if(i->multiaddr==addr)
237 {
238 i->users++;
239 return;
240 }
241 }
242 i=(struct ip_mc_list *)kmalloc(sizeof(*i), GFP_KERNEL);
243 if(!i)
244 return;
245 i->users=1;
246 i->interface=dev;
247 i->multiaddr=addr;
248 i->next=dev->ip_mc_list;
249 igmp_group_added(i);
250 dev->ip_mc_list=i;
251 }
252
253
254
255
256
257 static void ip_mc_dec_group(struct device *dev, unsigned long addr)
258 {
259 struct ip_mc_list **i;
260 for(i=&(dev->ip_mc_list);(*i)!=NULL;i=&(*i)->next)
261 {
262 if((*i)->multiaddr==addr)
263 {
264 if(--((*i)->users))
265 return;
266 else
267 {
268 struct ip_mc_list *tmp= *i;
269 igmp_group_dropped(tmp);
270 *i=(*i)->next;
271 kfree_s(tmp,sizeof(*tmp));
272 }
273 }
274 }
275 }
276
277
278
279
280
281 void ip_mc_drop_device(struct device *dev)
282 {
283 struct ip_mc_list *i;
284 struct ip_mc_list *j;
285 for(i=dev->ip_mc_list;i!=NULL;i=j)
286 {
287 j=i->next;
288 kfree_s(i,sizeof(*i));
289 }
290 dev->ip_mc_list=NULL;
291 }
292
293
294
295
296
297 void ip_mc_allhost(struct device *dev)
298 {
299 struct ip_mc_list *i;
300 for(i=dev->ip_mc_list;i!=NULL;i=i->next)
301 if(i->multiaddr==IGMP_ALL_HOSTS)
302 return;
303 i=(struct ip_mc_list *)kmalloc(sizeof(*i), GFP_KERNEL);
304 if(!i)
305 return;
306 i->users=1;
307 i->interface=dev;
308 i->multiaddr=IGMP_ALL_HOSTS;
309 i->next=dev->ip_mc_list;
310 dev->ip_mc_list=i;
311 ip_mc_filter_add(i->interface, i->multiaddr);
312
313 }
314
315
316
317
318
319 int ip_mc_join_group(struct sock *sk , struct device *dev, unsigned long addr)
320 {
321 int unused= -1;
322 int i;
323 if(!MULTICAST(addr))
324 return -EINVAL;
325 if(!(dev->flags&IFF_MULTICAST))
326 return -EADDRNOTAVAIL;
327 if(sk->ip_mc_list==NULL)
328 {
329 if((sk->ip_mc_list=(struct ip_mc_socklist *)kmalloc(sizeof(*sk->ip_mc_list), GFP_KERNEL))==NULL)
330 return -ENOMEM;
331 memset(sk->ip_mc_list,'\0',sizeof(*sk->ip_mc_list));
332 }
333 for(i=0;i<IP_MAX_MEMBERSHIPS;i++)
334 {
335 if(sk->ip_mc_list->multiaddr[i]==addr && sk->ip_mc_list->multidev[i]==dev)
336 return -EADDRINUSE;
337 if(sk->ip_mc_list->multidev[i]==NULL)
338 unused=i;
339 }
340
341 if(unused==-1)
342 return -ENOBUFS;
343 sk->ip_mc_list->multiaddr[unused]=addr;
344 sk->ip_mc_list->multidev[unused]=dev;
345 ip_mc_inc_group(dev,addr);
346 return 0;
347 }
348
349
350
351
352
353 int ip_mc_leave_group(struct sock *sk, struct device *dev, unsigned long addr)
354 {
355 int i;
356 if(!MULTICAST(addr))
357 return -EINVAL;
358 if(!(dev->flags&IFF_MULTICAST))
359 return -EADDRNOTAVAIL;
360 if(sk->ip_mc_list==NULL)
361 return -EADDRNOTAVAIL;
362
363 for(i=0;i<IP_MAX_MEMBERSHIPS;i++)
364 {
365 if(sk->ip_mc_list->multiaddr[i]==addr && sk->ip_mc_list->multidev[i]==dev)
366 {
367 sk->ip_mc_list->multidev[i]=NULL;
368 ip_mc_dec_group(dev,addr);
369 return 0;
370 }
371 }
372 return -EADDRNOTAVAIL;
373 }
374
375
376
377
378
379 void ip_mc_drop_socket(struct sock *sk)
380 {
381 int i;
382
383 if(sk->ip_mc_list==NULL)
384 return;
385
386 for(i=0;i<IP_MAX_MEMBERSHIPS;i++)
387 {
388 if(sk->ip_mc_list->multidev[i])
389 {
390 ip_mc_dec_group(sk->ip_mc_list->multidev[i], sk->ip_mc_list->multiaddr[i]);
391 sk->ip_mc_list->multidev[i]=NULL;
392 }
393 }
394 kfree_s(sk->ip_mc_list,sizeof(*sk->ip_mc_list));
395 sk->ip_mc_list=NULL;
396 }
397
398 #endif