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