OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [tags/] [before_ORP/] [uclinux/] [uClinux-2.0.x/] [net/] [ipv4/] [igmp.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 199 simons
/*
2
 *      Linux NET3:     Internet Group Management Protocol  [IGMP]
3
 *
4
 *      This code implements the IGMP protocol as defined in RFC1112. There has
5
 *      been a further revision of this protocol since which is now supported.
6
 *
7
 *      If you have trouble with this module be careful what gcc you have used,
8
 *      the older version didn't come out right using gcc 2.5.8, the newer one
9
 *      seems to fall out with gcc 2.6.2.
10
 *
11
 *      Authors:
12
 *              Alan Cox <Alan.Cox@linux.org>
13
 *
14
 *      This program is free software; you can redistribute it and/or
15
 *      modify it under the terms of the GNU General Public License
16
 *      as published by the Free Software Foundation; either version
17
 *      2 of the License, or (at your option) any later version.
18
 *
19
 *      Fixes:
20
 *
21
 *              Alan Cox        :       Added lots of __inline__ to optimise
22
 *                                      the memory usage of all the tiny little
23
 *                                      functions.
24
 *              Alan Cox        :       Dumped the header building experiment.
25
 *              Alan Cox        :       Minor tweaks ready for multicast routing
26
 *                                      and extended IGMP protocol.
27
 *              Alan Cox        :       Removed a load of inline directives. Gcc 2.5.8
28
 *                                      writes utterly bogus code otherwise (sigh)
29
 *                                      fixed IGMP loopback to behave in the manner
30
 *                                      desired by mrouted, fixed the fact it has been
31
 *                                      broken since 1.3.6 and cleaned up a few minor
32
 *                                      points.
33
 *
34
 *              Chih-Jen Chang  :       Tried to revise IGMP to Version 2
35
 *              Tsu-Sheng Tsao          E-mail: chihjenc@scf.usc.edu and tsusheng@scf.usc.edu
36
 *                                      The enhancements are mainly based on Steve Deering's
37
 *                                      ipmulti-3.5 source code.
38
 *              Chih-Jen Chang  :       Added the igmp_get_mrouter_info and
39
 *              Tsu-Sheng Tsao          igmp_set_mrouter_info to keep track of
40
 *                                      the mrouted version on that device.
41
 *              Chih-Jen Chang  :       Added the max_resp_time parameter to
42
 *              Tsu-Sheng Tsao          igmp_heard_query(). Using this parameter
43
 *                                      to identify the multicast router version
44
 *                                      and do what the IGMP version 2 specified.
45
 *              Chih-Jen Chang  :       Added a timer to revert to IGMP V2 router
46
 *              Tsu-Sheng Tsao          if the specified time expired.
47
 *              Alan Cox        :       Stop IGMP from 0.0.0.0 being accepted.
48
 *              Alan Cox        :       Use GFP_ATOMIC in the right places.
49
 *              Christian Daudt :       igmp timer wasn't set for local group
50
 *                                      memberships but was being deleted,
51
 *                                      which caused a "del_timer() called
52
 *                                      from %p with timer not initialized\n"
53
 *                                      message (960131).
54
 *              Christian Daudt :       removed del_timer from
55
 *                                      igmp_timer_expire function (960205).
56
 *             Christian Daudt :       igmp_heard_report now only calls
57
 *                                     igmp_timer_expire if tm->running is
58
 *                                     true (960216).
59
 *              Malcolm Beattie :       ttl comparison wrong in igmp_rcv made
60
 *                                      igmp_heard_query never trigger. Expiry
61
 *                                      miscalculation fixed in igmp_heard_query
62
 *                                      and random() made to return unsigned to
63
 *                                      prevent negative expiry times.
64
 *              Alexey Kuznetsov:       Wrong group leaving behaviour, backport
65
 *                                      fix from pending 2.1.x patches.
66
 *              Alan Cox:               Forget to enable FDDI support earlier.
67
 *     Elena Apolinario Fdez de Sousa,: IGMP Leave Messages must be sent to
68
 *     Juan-Mariano de Goyeneche        the "all routers" group, not the group
69
 *                                      group being left.
70
 */
71
 
72
 
73
#include <asm/segment.h>
74
#include <asm/system.h>
75
#include <linux/types.h>
76
#include <linux/kernel.h>
77
#include <linux/sched.h>
78
#include <linux/string.h>
79
#include <linux/config.h>
80
#include <linux/socket.h>
81
#include <linux/sockios.h>
82
#include <linux/in.h>
83
#include <linux/inet.h>
84
#include <linux/netdevice.h>
85
#include <linux/if_arp.h>
86
#include <net/ip.h>
87
#include <net/protocol.h>
88
#include <net/route.h>
89
#include <linux/skbuff.h>
90
#include <net/sock.h>
91
#include <linux/igmp.h>
92
#include <net/checksum.h>
93
 
94
#ifdef CONFIG_IP_MULTICAST
95
 
96
 
97
/*
98
 *      If time expired, change the router type to IGMP_NEW_ROUTER.
99
 */
100
 
101
static void ip_router_timer_expire(unsigned long data)
102
{
103
        struct ip_router_info *i=(struct ip_router_info *)data;
104
 
105
        del_timer(&i->timer);
106
        i->type=IGMP_NEW_ROUTER;        /* Revert to new multicast router */
107
        i->time=0;
108
}
109
 
110
/*
111
 *      Multicast router info manager
112
 */
113
 
114
struct  ip_router_info  *ip_router_info_head=(struct ip_router_info *)0;
115
 
116
/*
117
 *      Get the multicast router info on that device
118
 */
119
 
120
static  struct  ip_router_info  *igmp_get_mrouter_info(struct device *dev)
121
{
122
        register struct ip_router_info *i;
123
 
124
        for(i=ip_router_info_head;i!=NULL;i=i->next)
125
        {
126
                if (i->dev == dev)
127
                {
128
                        return i;
129
                }
130
        }
131
 
132
        /*
133
         *  Not found. Create a new entry. The default is IGMP V2 router
134
         */
135
 
136
        i=(struct ip_router_info *)kmalloc(sizeof(*i), GFP_ATOMIC);
137
        if(i==NULL)
138
                return NULL;
139
        i->dev = dev;
140
        i->type = IGMP_NEW_ROUTER;
141
        i->time = IGMP_AGE_THRESHOLD;
142
        i->next = ip_router_info_head;
143
        ip_router_info_head = i;
144
 
145
        init_timer(&i->timer);
146
        i->timer.data=(unsigned long)i;
147
        i->timer.function=&ip_router_timer_expire;
148
 
149
        return i;
150
}
151
 
152
/*
153
 *      Set the multicast router info on that device
154
 */
155
 
156
static  struct  ip_router_info  *igmp_set_mrouter_info(struct device *dev,int type,int time)
157
{
158
        register struct ip_router_info *i;
159
 
160
        for(i=ip_router_info_head;i!=NULL;i=i->next)
161
        {
162
                if (i->dev == dev)
163
                {
164
                        if(i->type==IGMP_OLD_ROUTER)
165
                        {
166
                                del_timer(&i->timer);
167
                        }
168
 
169
                        i->type = type;
170
                        i->time = time;
171
 
172
                        if(i->type==IGMP_OLD_ROUTER)
173
                        {
174
                                i->timer.expires=jiffies+i->time*HZ;
175
                                add_timer(&i->timer);
176
                        }
177
                        return i;
178
                }
179
        }
180
 
181
        /*
182
         *  Not found. Create a new entry.
183
         */
184
        i=(struct ip_router_info *)kmalloc(sizeof(*i), GFP_ATOMIC);
185
        if(i==NULL)
186
                return NULL;
187
        i->dev = dev;
188
        i->type = type;
189
        i->time = time;
190
        i->next = ip_router_info_head;
191
        ip_router_info_head = i;
192
 
193
        init_timer(&i->timer);
194
        i->timer.data=(unsigned long)i;
195
        i->timer.function=&ip_router_timer_expire;
196
        if(i->type==IGMP_OLD_ROUTER)
197
        {
198
                i->timer.expires=jiffies+i->time*HZ;
199
                add_timer(&i->timer);
200
        }
201
 
202
        return i;
203
}
204
 
205
 
206
/*
207
 *      Timer management
208
 */
209
 
210
static void igmp_stop_timer(struct ip_mc_list *im)
211
{
212
  if (im->tm_running) {
213
    del_timer(&im->timer);
214
    im->tm_running=0;
215
  }
216
  else {
217
    printk(KERN_ERR "igmp_stop_timer() called with timer not running by %p\n",__builtin_return_address(0));
218
  }
219
}
220
 
221
extern __inline__ unsigned int random(void)
222
{
223
        static unsigned long seed=152L;
224
        seed=seed*69069L+1;
225
        return seed^jiffies;
226
}
227
 
228
/*
229
 *      Inlined as it's only called once.
230
 */
231
 
232
static void igmp_start_timer(struct ip_mc_list *im,unsigned char max_resp_time)
233
{
234
        int tv;
235
        if(im->tm_running)
236
                return;
237
        tv=random()%(max_resp_time*HZ/IGMP_TIMER_SCALE); /* Pick a number any number 8) */
238
        im->timer.expires=jiffies+tv;
239
        im->tm_running=1;
240
        add_timer(&im->timer);
241
}
242
 
243
/*
244
 *      Send an IGMP report.
245
 */
246
 
247
#define MAX_IGMP_SIZE (sizeof(struct igmphdr)+sizeof(struct iphdr)+64)
248
 
249
static void igmp_send_report(struct device *dev, unsigned long address, int type)
250
{
251
        struct sk_buff *skb=alloc_skb(MAX_IGMP_SIZE, GFP_ATOMIC);
252
        int tmp;
253
        struct igmphdr *ih;
254
 
255
        if(skb==NULL)
256
                return;
257
        if (type != IGMP_HOST_LEAVE_MESSAGE)
258
                tmp=ip_build_header(skb, dev->pa_addr, address, &dev, IPPROTO_IGMP, NULL,
259
                        28 , 0, 1, NULL);
260
        else
261
                tmp=ip_build_header(skb, dev->pa_addr, IGMP_ALL_ROUTER, &dev, IPPROTO_IGMP, NULL,
262
                        28, 0, 1, NULL);
263
        if(tmp<0)
264
        {
265
                kfree_skb(skb, FREE_WRITE);
266
                return;
267
        }
268
        ih=(struct igmphdr *)skb_put(skb,sizeof(struct igmphdr));
269
        ih->type=type;
270
        ih->code=0;
271
        ih->csum=0;
272
        ih->group=address;
273
        ih->csum=ip_compute_csum((void *)ih,sizeof(struct igmphdr));    /* Checksum fill */
274
        ip_queue_xmit(NULL,dev,skb,1);
275
}
276
 
277
 
278
static void igmp_timer_expire(unsigned long data)
279
{
280
        struct ip_mc_list *im=(struct ip_mc_list *)data;
281
        struct ip_router_info *r;
282
 
283
        im->tm_running=0;
284
        r=igmp_get_mrouter_info(im->interface);
285
        if(r==NULL)
286
                return;
287
        if(r->type==IGMP_NEW_ROUTER)
288
                igmp_send_report(im->interface, im->multiaddr, IGMP_HOST_NEW_MEMBERSHIP_REPORT);
289
        else
290
                igmp_send_report(im->interface, im->multiaddr, IGMP_HOST_MEMBERSHIP_REPORT);
291
        im->reporter=1;
292
}
293
 
294
static void igmp_init_timer(struct ip_mc_list *im)
295
{
296
        im->tm_running=0;
297
        init_timer(&im->timer);
298
        im->timer.data=(unsigned long)im;
299
        im->timer.function=&igmp_timer_expire;
300
}
301
 
302
 
303
static void igmp_heard_report(struct device *dev, __u32 address, __u32 src)
304
{
305
        struct ip_mc_list *im;
306
 
307
        if ((address & IGMP_LOCAL_GROUP_MASK) != IGMP_LOCAL_GROUP)
308
        {
309
                /* Timers are only set for non-local groups */
310
                for(im=dev->ip_mc_list;im!=NULL;im=im->next)
311
                {
312
                        if(im->multiaddr==address)
313
                        {
314
                                if(im->tm_running)
315
                                        igmp_stop_timer(im);
316
                                if(src!=dev->pa_addr)
317
                                        im->reporter=0;
318
                                return;
319
                        }
320
                }
321
        }
322
}
323
 
324
static void igmp_heard_query(struct device *dev,unsigned char max_resp_time)
325
{
326
        struct ip_mc_list *im;
327
        int     mrouter_type;
328
 
329
        /*
330
         *      The max_resp_time is in units of 1/10 second.
331
         */
332
        if(max_resp_time>0)
333
        {
334
                mrouter_type=IGMP_NEW_ROUTER;
335
 
336
                if(igmp_set_mrouter_info(dev,mrouter_type,0)==NULL)
337
                        return;
338
                /*
339
                 * - Start the timers in all of our membership records
340
                 *   that the query applies to for the interface on
341
                 *   which the query arrived excl. those that belong
342
                 *   to a "local" group (224.0.0.X)
343
                 * - For timers already running check if they need to
344
                 *   be reset.
345
                 * - Use the igmp->igmp_code field as the maximum
346
                 *   delay possible
347
                 */
348
                for(im=dev->ip_mc_list;im!=NULL;im=im->next)
349
                {
350
                        if(im->tm_running)
351
                        {
352
                                if(im->timer.expires>jiffies+max_resp_time*HZ/IGMP_TIMER_SCALE)
353
                                {
354
                                        igmp_stop_timer(im);
355
                                        igmp_start_timer(im,max_resp_time);
356
                                }
357
                        }
358
                        else
359
                        {
360
                                if((im->multiaddr & IGMP_LOCAL_GROUP_MASK)!=IGMP_LOCAL_GROUP)
361
                                        igmp_start_timer(im,max_resp_time);
362
                        }
363
                }
364
        }
365
        else
366
        {
367
                mrouter_type=IGMP_OLD_ROUTER;
368
                max_resp_time=IGMP_MAX_HOST_REPORT_DELAY*IGMP_TIMER_SCALE;
369
 
370
                if(igmp_set_mrouter_info(dev,mrouter_type,IGMP_AGE_THRESHOLD)==NULL)
371
                        return;
372
 
373
                /*
374
                 * Start the timers in all of our membership records for
375
                 * the interface on which the query arrived, except those
376
                 * that are already running and those that belong to a
377
                 * "local" group (224.0.0.X).
378
                 */
379
 
380
                for(im=dev->ip_mc_list;im!=NULL;im=im->next)
381
                {
382
                        if(!im->tm_running && (im->multiaddr & IGMP_LOCAL_GROUP_MASK)!=IGMP_LOCAL_GROUP)
383
                                igmp_start_timer(im,max_resp_time);
384
                }
385
        }
386
}
387
 
388
/*
389
 *      Map a multicast IP onto multicast MAC for type ethernet.
390
 */
391
 
392
extern __inline__ void ip_mc_map(unsigned long addr, char *buf)
393
{
394
        addr=ntohl(addr);
395
        buf[0]=0x01;
396
        buf[1]=0x00;
397
        buf[2]=0x5e;
398
        buf[5]=addr&0xFF;
399
        addr>>=8;
400
        buf[4]=addr&0xFF;
401
        addr>>=8;
402
        buf[3]=addr&0x7F;
403
}
404
 
405
/*
406
 *      Add a filter to a device
407
 */
408
 
409
void ip_mc_filter_add(struct device *dev, unsigned long addr)
410
{
411
        char buf[6];
412
        if(dev->type!=ARPHRD_ETHER && dev->type!=ARPHRD_FDDI)
413
                return; /* Only do ethernet or FDDI for now */
414
        ip_mc_map(addr,buf);
415
        dev_mc_add(dev,buf,ETH_ALEN,0);
416
}
417
 
418
/*
419
 *      Remove a filter from a device
420
 */
421
 
422
void ip_mc_filter_del(struct device *dev, unsigned long addr)
423
{
424
        char buf[6];
425
        if(dev->type!=ARPHRD_ETHER && dev->type!=ARPHRD_FDDI)
426
                return; /* Only do ethernet or FDDI for now */
427
        ip_mc_map(addr,buf);
428
        dev_mc_delete(dev,buf,ETH_ALEN,0);
429
}
430
 
431
extern __inline__ void igmp_group_dropped(struct ip_mc_list *im)
432
{
433
        del_timer(&im->timer);
434
        /* It seems we have to send Leave Messages to 224.0.0.2 and not to
435
           the group itself, to remain RFC 2236 compliant... (jmel) */
436
        /*igmp_send_report(im->interface, IGMP_ALL_ROUTER, IGMP_HOST_LEAVE_MESSAGE);*/
437
        igmp_send_report(im->interface, im->multiaddr, IGMP_HOST_LEAVE_MESSAGE);
438
        ip_mc_filter_del(im->interface, im->multiaddr);
439
}
440
 
441
extern __inline__ void igmp_group_added(struct ip_mc_list *im)
442
{
443
        struct ip_router_info *r;
444
        igmp_init_timer(im);
445
        ip_mc_filter_add(im->interface, im->multiaddr);
446
        r=igmp_get_mrouter_info(im->interface);
447
        if(r==NULL)
448
                return;
449
        if(r->type==IGMP_NEW_ROUTER)
450
                igmp_send_report(im->interface, im->multiaddr, IGMP_HOST_NEW_MEMBERSHIP_REPORT);
451
        else
452
                igmp_send_report(im->interface, im->multiaddr, IGMP_HOST_MEMBERSHIP_REPORT);
453
}
454
 
455
int igmp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
456
        __u32 daddr, unsigned short len, __u32 saddr, int redo,
457
        struct inet_protocol *protocol)
458
{
459
        /* This basically follows the spec line by line -- see RFC1112 */
460
        struct igmphdr *ih;
461
 
462
        /*
463
         *      Mrouted needs to able to query local interfaces. So
464
         *      report for the device this was sent at. (Which can
465
         *      be the loopback this time)
466
         */
467
 
468
        if(dev->flags&IFF_LOOPBACK)
469
        {
470
                dev=ip_dev_find(saddr);
471
                if(dev==NULL)
472
                        dev=&loopback_dev;
473
        }
474
        ih=(struct igmphdr *)skb->h.raw;
475
 
476
        if(len <sizeof(struct igmphdr) || skb->ip_hdr->ttl<1 || ip_compute_csum((void *)skb->h.raw,sizeof(struct igmphdr)))
477
        {
478
                kfree_skb(skb, FREE_READ);
479
                return 0;
480
        }
481
 
482
        /*
483
         *      I have a report that someone does this!
484
         */
485
 
486
        if(saddr==0)
487
        {
488
                printk(KERN_INFO "Broken multicast host using 0.0.0.0 heard on %s\n",
489
                        dev->name);
490
                kfree_skb(skb, FREE_READ);
491
                return 0;
492
        }
493
 
494
        if(ih->type==IGMP_HOST_MEMBERSHIP_QUERY && daddr==IGMP_ALL_HOSTS)
495
                igmp_heard_query(dev,ih->code);
496
        if(ih->type==IGMP_HOST_MEMBERSHIP_REPORT && daddr==ih->group)
497
                igmp_heard_report(dev,ih->group, saddr);
498
        if(ih->type==IGMP_HOST_NEW_MEMBERSHIP_REPORT && daddr==ih->group)
499
                igmp_heard_report(dev,ih->group, saddr);
500
        kfree_skb(skb, FREE_READ);
501
        return 0;
502
}
503
 
504
/*
505
 *      Multicast list managers
506
 */
507
 
508
 
509
/*
510
 *      A socket has joined a multicast group on device dev.
511
 */
512
 
513
static void ip_mc_inc_group(struct device *dev, unsigned long addr)
514
{
515
        struct ip_mc_list *i;
516
        for(i=dev->ip_mc_list;i!=NULL;i=i->next)
517
        {
518
                if(i->multiaddr==addr)
519
                {
520
                        i->users++;
521
                        return;
522
                }
523
        }
524
        i=(struct ip_mc_list *)kmalloc(sizeof(*i), GFP_KERNEL);
525
        if(!i)
526
                return;
527
        i->users=1;
528
        i->interface=dev;
529
        i->multiaddr=addr;
530
        i->next=dev->ip_mc_list;
531
        igmp_group_added(i);
532
        dev->ip_mc_list=i;
533
}
534
 
535
/*
536
 *      A socket has left a multicast group on device dev
537
 */
538
 
539
static void ip_mc_dec_group(struct device *dev, unsigned long addr)
540
{
541
        struct ip_mc_list **i;
542
        for(i=&(dev->ip_mc_list);(*i)!=NULL;i=&(*i)->next)
543
        {
544
                if((*i)->multiaddr==addr)
545
                {
546
                        if(--((*i)->users) == 0)
547
                        {
548
                                struct ip_mc_list *tmp= *i;
549
                                igmp_group_dropped(tmp);
550
                                *i=(*i)->next;
551
                                kfree_s(tmp,sizeof(*tmp));
552
                        }
553
                        return;
554
                }
555
        }
556
}
557
 
558
/*
559
 *      Device going down: Clean up.
560
 */
561
 
562
void ip_mc_drop_device(struct device *dev)
563
{
564
        struct ip_mc_list *i;
565
        struct ip_mc_list *j;
566
        for(i=dev->ip_mc_list;i!=NULL;i=j)
567
        {
568
                j=i->next;
569
                kfree_s(i,sizeof(*i));
570
        }
571
        dev->ip_mc_list=NULL;
572
}
573
 
574
/*
575
 *      Device going up. Make sure it is in all hosts
576
 */
577
 
578
void ip_mc_allhost(struct device *dev)
579
{
580
        struct ip_mc_list *i;
581
        for(i=dev->ip_mc_list;i!=NULL;i=i->next)
582
                if(i->multiaddr==IGMP_ALL_HOSTS)
583
                        return;
584
        i=(struct ip_mc_list *)kmalloc(sizeof(*i), GFP_KERNEL);
585
        if(!i)
586
                return;
587
        i->users=1;
588
        i->interface=dev;
589
        i->multiaddr=IGMP_ALL_HOSTS;
590
        i->tm_running=0;
591
        i->next=dev->ip_mc_list;
592
        dev->ip_mc_list=i;
593
        ip_mc_filter_add(i->interface, i->multiaddr);
594
 
595
}
596
 
597
/*
598
 *      Join a socket to a group
599
 */
600
 
601
int ip_mc_join_group(struct sock *sk , struct device *dev, unsigned long addr)
602
{
603
        int unused= -1;
604
        int i;
605
        if(!MULTICAST(addr))
606
                return -EINVAL;
607
        if(!(dev->flags&IFF_MULTICAST))
608
                return -EADDRNOTAVAIL;
609
        if(sk->ip_mc_list==NULL)
610
        {
611
                if((sk->ip_mc_list=(struct ip_mc_socklist *)kmalloc(sizeof(*sk->ip_mc_list), GFP_KERNEL))==NULL)
612
                        return -ENOMEM;
613
                memset(sk->ip_mc_list,'\0',sizeof(*sk->ip_mc_list));
614
        }
615
        for(i=0;i<IP_MAX_MEMBERSHIPS;i++)
616
        {
617
                if(sk->ip_mc_list->multiaddr[i]==addr && sk->ip_mc_list->multidev[i]==dev)
618
                        return -EADDRINUSE;
619
                if(sk->ip_mc_list->multidev[i]==NULL)
620
                        unused=i;
621
        }
622
 
623
        if(unused==-1)
624
                return -ENOBUFS;
625
        sk->ip_mc_list->multiaddr[unused]=addr;
626
        sk->ip_mc_list->multidev[unused]=dev;
627
        ip_mc_inc_group(dev,addr);
628
        return 0;
629
}
630
 
631
/*
632
 *      Ask a socket to leave a group.
633
 */
634
 
635
int ip_mc_leave_group(struct sock *sk, struct device *dev, unsigned long addr)
636
{
637
        int i;
638
        if(!MULTICAST(addr))
639
                return -EINVAL;
640
        if(!(dev->flags&IFF_MULTICAST))
641
                return -EADDRNOTAVAIL;
642
        if(sk->ip_mc_list==NULL)
643
                return -EADDRNOTAVAIL;
644
 
645
        for(i=0;i<IP_MAX_MEMBERSHIPS;i++)
646
        {
647
                if(sk->ip_mc_list->multiaddr[i]==addr && sk->ip_mc_list->multidev[i]==dev)
648
                {
649
                        sk->ip_mc_list->multidev[i]=NULL;
650
                        ip_mc_dec_group(dev,addr);
651
                        return 0;
652
                }
653
        }
654
        return -EADDRNOTAVAIL;
655
}
656
 
657
/*
658
 *      A socket is closing.
659
 */
660
 
661
void ip_mc_drop_socket(struct sock *sk)
662
{
663
        int i;
664
 
665
        if(sk->ip_mc_list==NULL)
666
                return;
667
 
668
        for(i=0;i<IP_MAX_MEMBERSHIPS;i++)
669
        {
670
                if(sk->ip_mc_list->multidev[i])
671
                {
672
                        ip_mc_dec_group(sk->ip_mc_list->multidev[i], sk->ip_mc_list->multiaddr[i]);
673
                        sk->ip_mc_list->multidev[i]=NULL;
674
                }
675
        }
676
        kfree_s(sk->ip_mc_list,sizeof(*sk->ip_mc_list));
677
        sk->ip_mc_list=NULL;
678
}
679
 
680
#endif

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.