cleanup
[linux-2.4.21-pre4.git] / net / ipv6 / mcast.c
1 /*
2  *      Multicast support for IPv6
3  *      Linux INET6 implementation 
4  *
5  *      Authors:
6  *      Pedro Roque             <roque@di.fc.ul.pt>     
7  *
8  *      $Id: mcast.c,v 1.1.1.1 2005/04/11 02:51:13 jack Exp $
9  *
10  *      Based on linux/ipv4/igmp.c and linux/ipv4/ip_sockglue.c 
11  *
12  *      This program is free software; you can redistribute it and/or
13  *      modify it under the terms of the GNU General Public License
14  *      as published by the Free Software Foundation; either version
15  *      2 of the License, or (at your option) any later version.
16  */
17
18 /* Changes:
19  *
20  *      yoshfuji        : fix format of router-alert option
21  *      YOSHIFUJI Hideaki @USAGI:
22  *              Fixed source address for MLD message based on
23  *              <draft-ietf-magma-mld-source-02.txt>.
24  *      YOSHIFUJI Hideaki @USAGI:
25  *              - Ignore Queries for invalid addresses.
26  *              - MLD for link-local addresses.
27  */
28
29 #define __NO_VERSION__
30 #include <linux/config.h>
31 #include <linux/module.h>
32 #include <linux/errno.h>
33 #include <linux/types.h>
34 #include <linux/string.h>
35 #include <linux/socket.h>
36 #include <linux/sockios.h>
37 #include <linux/sched.h>
38 #include <linux/net.h>
39 #include <linux/in6.h>
40 #include <linux/netdevice.h>
41 #include <linux/if_arp.h>
42 #include <linux/route.h>
43 #include <linux/init.h>
44 #include <linux/proc_fs.h>
45
46 #include <net/sock.h>
47 #include <net/snmp.h>
48
49 #include <net/ipv6.h>
50 #include <net/protocol.h>
51 #include <net/if_inet6.h>
52 #include <net/ndisc.h>
53 #include <net/addrconf.h>
54 #include <net/ip6_route.h>
55
56 #include <net/checksum.h>
57
58 /* Set to 3 to get tracing... */
59 #define MCAST_DEBUG 2
60
61 #if MCAST_DEBUG >= 3
62 #define MDBG(x) printk x
63 #else
64 #define MDBG(x)
65 #endif
66
67 /* Big mc list lock for all the sockets */
68 static rwlock_t ipv6_sk_mc_lock = RW_LOCK_UNLOCKED;
69
70 static struct socket *igmp6_socket;
71
72 static void igmp6_join_group(struct ifmcaddr6 *ma);
73 static void igmp6_leave_group(struct ifmcaddr6 *ma);
74 void igmp6_timer_handler(unsigned long data);
75
76 #define IGMP6_UNSOLICITED_IVAL  (10*HZ)
77
78 /*
79  *      socket join on multicast group
80  */
81
82 int ipv6_sock_mc_join(struct sock *sk, int ifindex, struct in6_addr *addr)
83 {
84         struct net_device *dev = NULL;
85         struct ipv6_mc_socklist *mc_lst;
86         struct ipv6_pinfo *np = &sk->net_pinfo.af_inet6;
87         int err;
88
89         if (!(ipv6_addr_type(addr) & IPV6_ADDR_MULTICAST))
90                 return -EINVAL;
91
92         mc_lst = sock_kmalloc(sk, sizeof(struct ipv6_mc_socklist), GFP_KERNEL);
93
94         if (mc_lst == NULL)
95                 return -ENOMEM;
96
97         mc_lst->next = NULL;
98         memcpy(&mc_lst->addr, addr, sizeof(struct in6_addr));
99
100         if (ifindex == 0) {
101                 struct rt6_info *rt;
102                 rt = rt6_lookup(addr, NULL, 0, 0);
103                 if (rt) {
104                         dev = rt->rt6i_dev;
105                         dev_hold(dev);
106                         dst_release(&rt->u.dst);
107                 }
108         } else
109                 dev = dev_get_by_index(ifindex);
110
111         if (dev == NULL) {
112                 sock_kfree_s(sk, mc_lst, sizeof(*mc_lst));
113                 return -ENODEV;
114         }
115
116         mc_lst->ifindex = dev->ifindex;
117
118         /*
119          *      now add/increase the group membership on the device
120          */
121
122         err = ipv6_dev_mc_inc(dev, addr);
123
124         if (err) {
125                 sock_kfree_s(sk, mc_lst, sizeof(*mc_lst));
126                 dev_put(dev);
127                 return err;
128         }
129
130         write_lock_bh(&ipv6_sk_mc_lock);
131         mc_lst->next = np->ipv6_mc_list;
132         np->ipv6_mc_list = mc_lst;
133         write_unlock_bh(&ipv6_sk_mc_lock);
134
135         dev_put(dev);
136
137         return 0;
138 }
139
140 /*
141  *      socket leave on multicast group
142  */
143 int ipv6_sock_mc_drop(struct sock *sk, int ifindex, struct in6_addr *addr)
144 {
145         struct ipv6_pinfo *np = &sk->net_pinfo.af_inet6;
146         struct ipv6_mc_socklist *mc_lst, **lnk;
147
148         write_lock_bh(&ipv6_sk_mc_lock);
149         for (lnk = &np->ipv6_mc_list; (mc_lst = *lnk) !=NULL ; lnk = &mc_lst->next) {
150                 if (mc_lst->ifindex == ifindex &&
151                     ipv6_addr_cmp(&mc_lst->addr, addr) == 0) {
152                         struct net_device *dev;
153
154                         *lnk = mc_lst->next;
155                         write_unlock_bh(&ipv6_sk_mc_lock);
156
157                         if ((dev = dev_get_by_index(ifindex)) != NULL) {
158                                 ipv6_dev_mc_dec(dev, &mc_lst->addr);
159                                 dev_put(dev);
160                         }
161                         sock_kfree_s(sk, mc_lst, sizeof(*mc_lst));
162                         return 0;
163                 }
164         }
165         write_unlock_bh(&ipv6_sk_mc_lock);
166
167         return -ENOENT;
168 }
169
170 void ipv6_sock_mc_close(struct sock *sk)
171 {
172         struct ipv6_pinfo *np = &sk->net_pinfo.af_inet6;
173         struct ipv6_mc_socklist *mc_lst;
174
175         write_lock_bh(&ipv6_sk_mc_lock);
176         while ((mc_lst = np->ipv6_mc_list) != NULL) {
177                 struct net_device *dev;
178
179                 np->ipv6_mc_list = mc_lst->next;
180                 write_unlock_bh(&ipv6_sk_mc_lock);
181
182                 dev = dev_get_by_index(mc_lst->ifindex);
183                 if (dev) {
184                         ipv6_dev_mc_dec(dev, &mc_lst->addr);
185                         dev_put(dev);
186                 }
187
188                 sock_kfree_s(sk, mc_lst, sizeof(*mc_lst));
189
190                 write_lock_bh(&ipv6_sk_mc_lock);
191         }
192         write_unlock_bh(&ipv6_sk_mc_lock);
193 }
194
195 int inet6_mc_check(struct sock *sk, struct in6_addr *addr)
196 {
197         struct ipv6_mc_socklist *mc;
198
199         read_lock(&ipv6_sk_mc_lock);
200         for (mc = sk->net_pinfo.af_inet6.ipv6_mc_list; mc; mc=mc->next) {
201                 if (ipv6_addr_cmp(&mc->addr, addr) == 0) {
202                         read_unlock(&ipv6_sk_mc_lock);
203                         return 1;
204                 }
205         }
206         read_unlock(&ipv6_sk_mc_lock);
207
208         return 0;
209 }
210
211 static void ma_put(struct ifmcaddr6 *mc)
212 {
213         if (atomic_dec_and_test(&mc->mca_refcnt)) {
214                 in6_dev_put(mc->idev);
215                 kfree(mc);
216         }
217 }
218
219 static int igmp6_group_added(struct ifmcaddr6 *mc)
220 {
221         struct net_device *dev = mc->idev->dev;
222         char buf[MAX_ADDR_LEN];
223
224         spin_lock_bh(&mc->mca_lock);
225         if (!(mc->mca_flags&MAF_LOADED)) {
226                 mc->mca_flags |= MAF_LOADED;
227                 if (ndisc_mc_map(&mc->mca_addr, buf, dev, 0) == 0)
228                         dev_mc_add(dev, buf, dev->addr_len, 0);
229         }
230         spin_unlock_bh(&mc->mca_lock);
231
232         if (dev->flags&IFF_UP)
233                 igmp6_join_group(mc);
234         return 0;
235 }
236
237 static int igmp6_group_dropped(struct ifmcaddr6 *mc)
238 {
239         struct net_device *dev = mc->idev->dev;
240         char buf[MAX_ADDR_LEN];
241
242         spin_lock_bh(&mc->mca_lock);
243         if (mc->mca_flags&MAF_LOADED) {
244                 mc->mca_flags &= ~MAF_LOADED;
245                 if (ndisc_mc_map(&mc->mca_addr, buf, dev, 0) == 0)
246                         dev_mc_delete(dev, buf, dev->addr_len, 0);
247         }
248         spin_unlock_bh(&mc->mca_lock);
249
250         if (dev->flags&IFF_UP)
251                 igmp6_leave_group(mc);
252         return 0;
253 }
254
255
256 /*
257  *      device multicast group inc (add if not found)
258  */
259 int ipv6_dev_mc_inc(struct net_device *dev, struct in6_addr *addr)
260 {
261         struct ifmcaddr6 *mc;
262         struct inet6_dev *idev;
263
264         idev = in6_dev_get(dev);
265
266         if (idev == NULL)
267                 return -EINVAL;
268
269         write_lock_bh(&idev->lock);
270         if (idev->dead) {
271                 write_unlock_bh(&idev->lock);
272                 in6_dev_put(idev);
273                 return -ENODEV;
274         }
275
276         for (mc = idev->mc_list; mc; mc = mc->next) {
277                 if (ipv6_addr_cmp(&mc->mca_addr, addr) == 0) {
278                         mc->mca_users++;
279                         write_unlock_bh(&idev->lock);
280                         in6_dev_put(idev);
281                         return 0;
282                 }
283         }
284
285         /*
286          *      not found: create a new one.
287          */
288
289         mc = kmalloc(sizeof(struct ifmcaddr6), GFP_ATOMIC);
290
291         if (mc == NULL) {
292                 write_unlock_bh(&idev->lock);
293                 in6_dev_put(idev);
294                 return -ENOMEM;
295         }
296
297         memset(mc, 0, sizeof(struct ifmcaddr6));
298         mc->mca_timer.function = igmp6_timer_handler;
299         mc->mca_timer.data = (unsigned long) mc;
300
301         memcpy(&mc->mca_addr, addr, sizeof(struct in6_addr));
302         mc->idev = idev;
303         mc->mca_users = 1;
304         atomic_set(&mc->mca_refcnt, 2);
305         mc->mca_lock = SPIN_LOCK_UNLOCKED;
306
307         mc->next = idev->mc_list;
308         idev->mc_list = mc;
309         write_unlock_bh(&idev->lock);
310
311         igmp6_group_added(mc);
312         ma_put(mc);
313         return 0;
314 }
315
316 /*
317  *      device multicast group del
318  */
319 int ipv6_dev_mc_dec(struct net_device *dev, struct in6_addr *addr)
320 {
321         struct inet6_dev *idev;
322         struct ifmcaddr6 *ma, **map;
323
324         idev = in6_dev_get(dev);
325         if (idev == NULL)
326                 return -ENODEV;
327
328         write_lock_bh(&idev->lock);
329         for (map = &idev->mc_list; (ma=*map) != NULL; map = &ma->next) {
330                 if (ipv6_addr_cmp(&ma->mca_addr, addr) == 0) {
331                         if (--ma->mca_users == 0) {
332                                 *map = ma->next;
333                                 write_unlock_bh(&idev->lock);
334
335                                 igmp6_group_dropped(ma);
336
337                                 ma_put(ma);
338                                 in6_dev_put(idev);
339                                 return 0;
340                         }
341                         write_unlock_bh(&idev->lock);
342                         in6_dev_put(idev);
343                         return 0;
344                 }
345         }
346         write_unlock_bh(&idev->lock);
347         in6_dev_put(idev);
348
349         return -ENOENT;
350 }
351
352 /*
353  *      check if the interface/address pair is valid
354  */
355 int ipv6_chk_mcast_addr(struct net_device *dev, struct in6_addr *addr)
356 {
357         struct inet6_dev *idev;
358         struct ifmcaddr6 *mc;
359
360         idev = in6_dev_get(dev);
361         if (idev) {
362                 read_lock_bh(&idev->lock);
363                 for (mc = idev->mc_list; mc; mc=mc->next) {
364                         if (ipv6_addr_cmp(&mc->mca_addr, addr) == 0) {
365                                 read_unlock_bh(&idev->lock);
366                                 in6_dev_put(idev);
367                                 return 1;
368                         }
369                 }
370                 read_unlock_bh(&idev->lock);
371                 in6_dev_put(idev);
372         }
373         return 0;
374 }
375
376 /*
377  *      IGMP handling (alias multicast ICMPv6 messages)
378  */
379
380 static void igmp6_group_queried(struct ifmcaddr6 *ma, unsigned long resptime)
381 {
382         unsigned long delay = resptime;
383
384         /* Do not start timer for addresses with link/host scope */
385         if (ipv6_addr_type(&ma->mca_addr)&(IPV6_ADDR_LINKLOCAL|IPV6_ADDR_LOOPBACK))
386                 return;
387
388         spin_lock(&ma->mca_lock);
389         if (del_timer(&ma->mca_timer)) {
390                 atomic_dec(&ma->mca_refcnt);
391                 delay = ma->mca_timer.expires - jiffies;
392         }
393
394         if (delay >= resptime) {
395                 if (resptime)
396                         delay = net_random() % resptime;
397                 else
398                         delay = 1;
399         }
400
401         ma->mca_timer.expires = jiffies + delay;
402         if (!mod_timer(&ma->mca_timer, jiffies + delay))
403                 atomic_inc(&ma->mca_refcnt);
404         spin_unlock(&ma->mca_lock);
405 }
406
407 int igmp6_event_query(struct sk_buff *skb)
408 {
409         struct ifmcaddr6 *ma;
410         struct in6_addr *addrp;
411         unsigned long resptime;
412         struct inet6_dev *idev;
413         struct icmp6hdr *hdr;
414         int addr_type;
415
416         if (!pskb_may_pull(skb, sizeof(struct in6_addr)))
417                 return -EINVAL;
418
419         hdr = (struct icmp6hdr*) skb->h.raw;
420
421         /* Drop queries with not link local source */
422         if (!(ipv6_addr_type(&skb->nh.ipv6h->saddr)&IPV6_ADDR_LINKLOCAL))
423                 return -EINVAL;
424
425         resptime = ntohs(hdr->icmp6_maxdelay);
426         /* Translate milliseconds to jiffies */
427         resptime = (resptime<<10)/(1024000/HZ);
428
429         addrp = (struct in6_addr *) (hdr + 1);
430         addr_type = ipv6_addr_type(addrp);
431
432         if (addr_type != IPV6_ADDR_ANY &&
433             !(addr_type&IPV6_ADDR_MULTICAST))
434                 return -EINVAL;
435
436         idev = in6_dev_get(skb->dev);
437
438         if (idev == NULL)
439                 return 0;
440
441         read_lock(&idev->lock);
442         if (addr_type == IPV6_ADDR_ANY) {
443                 for (ma = idev->mc_list; ma; ma=ma->next)
444                         igmp6_group_queried(ma, resptime);
445         } else {
446                 for (ma = idev->mc_list; ma; ma=ma->next) {
447                         if (ipv6_addr_cmp(addrp, &ma->mca_addr) == 0) {
448                                 igmp6_group_queried(ma, resptime);
449                                 break;
450                         }
451                 }
452         }
453         read_unlock(&idev->lock);
454         in6_dev_put(idev);
455
456         return 0;
457 }
458
459
460 int igmp6_event_report(struct sk_buff *skb)
461 {
462         struct ifmcaddr6 *ma;
463         struct in6_addr *addrp;
464         struct inet6_dev *idev;
465         struct icmp6hdr *hdr;
466         int addr_type;
467
468         /* Our own report looped back. Ignore it. */
469         if (skb->pkt_type == PACKET_LOOPBACK)
470                 return 0;
471
472         if (!pskb_may_pull(skb, sizeof(struct in6_addr)))
473                 return -EINVAL;
474
475         hdr = (struct icmp6hdr*) skb->h.raw;
476
477         /* Drop reports with not link local source */
478         addr_type = ipv6_addr_type(&skb->nh.ipv6h->saddr);
479         if (addr_type != IPV6_ADDR_ANY && 
480             !(addr_type&IPV6_ADDR_LINKLOCAL))
481                 return -EINVAL;
482
483         addrp = (struct in6_addr *) (hdr + 1);
484
485         idev = in6_dev_get(skb->dev);
486         if (idev == NULL)
487                 return -ENODEV;
488
489         /*
490          *      Cancel the timer for this group
491          */
492
493         read_lock(&idev->lock);
494         for (ma = idev->mc_list; ma; ma=ma->next) {
495                 if (ipv6_addr_cmp(&ma->mca_addr, addrp) == 0) {
496                         spin_lock(&ma->mca_lock);
497                         if (del_timer(&ma->mca_timer))
498                                 atomic_dec(&ma->mca_refcnt);
499                         ma->mca_flags &= ~(MAF_LAST_REPORTER|MAF_TIMER_RUNNING);
500                         spin_unlock(&ma->mca_lock);
501                         break;
502                 }
503         }
504         read_unlock(&idev->lock);
505         in6_dev_put(idev);
506         return 0;
507 }
508
509 void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type)
510 {
511         struct sock *sk = igmp6_socket->sk;
512         struct sk_buff *skb;
513         struct icmp6hdr *hdr;
514         struct in6_addr *snd_addr;
515         struct in6_addr *addrp;
516         struct in6_addr addr_buf;
517         struct in6_addr all_routers;
518         int err, len, payload_len, full_len;
519         u8 ra[8] = { IPPROTO_ICMPV6, 0,
520                      IPV6_TLV_ROUTERALERT, 2, 0, 0,
521                      IPV6_TLV_PADN, 0 };
522
523         snd_addr = addr;
524         if (type == ICMPV6_MGM_REDUCTION) {
525                 snd_addr = &all_routers;
526                 ipv6_addr_all_routers(&all_routers);
527         }
528
529         len = sizeof(struct icmp6hdr) + sizeof(struct in6_addr);
530         payload_len = len + sizeof(ra);
531         full_len = sizeof(struct ipv6hdr) + payload_len;
532
533         skb = sock_alloc_send_skb(sk, dev->hard_header_len + full_len + 15, 0, &err);
534
535         if (skb == NULL)
536                 return;
537
538         skb_reserve(skb, (dev->hard_header_len + 15) & ~15);
539         if (dev->hard_header) {
540                 unsigned char ha[MAX_ADDR_LEN];
541                 ndisc_mc_map(snd_addr, ha, dev, 1);
542                 if (dev->hard_header(skb, dev, ETH_P_IPV6, ha, NULL, full_len) < 0)
543                         goto out;
544         }
545
546         if (ipv6_get_lladdr(dev, &addr_buf)) {
547                 /* <draft-ietf-magma-mld-source-02.txt>:
548                  * use unspecified address as the source address 
549                  * when a valid link-local address is not available.
550                  */
551                 memset(&addr_buf, 0, sizeof(addr_buf));
552         }
553
554         ip6_nd_hdr(sk, skb, dev, &addr_buf, snd_addr, NEXTHDR_HOP, payload_len);
555
556         memcpy(skb_put(skb, sizeof(ra)), ra, sizeof(ra));
557
558         hdr = (struct icmp6hdr *) skb_put(skb, sizeof(struct icmp6hdr));
559         memset(hdr, 0, sizeof(struct icmp6hdr));
560         hdr->icmp6_type = type;
561
562         addrp = (struct in6_addr *) skb_put(skb, sizeof(struct in6_addr));
563         ipv6_addr_copy(addrp, addr);
564
565         hdr->icmp6_cksum = csum_ipv6_magic(&addr_buf, snd_addr, len,
566                                            IPPROTO_ICMPV6,
567                                            csum_partial((__u8 *) hdr, len, 0));
568
569         dev_queue_xmit(skb);
570         if (type == ICMPV6_MGM_REDUCTION)
571                 ICMP6_INC_STATS(Icmp6OutGroupMembReductions);
572         else
573                 ICMP6_INC_STATS(Icmp6OutGroupMembResponses);
574         ICMP6_INC_STATS(Icmp6OutMsgs);
575         return;
576
577 out:
578         kfree_skb(skb);
579 }
580
581 static void igmp6_join_group(struct ifmcaddr6 *ma)
582 {
583         unsigned long delay;
584
585         if (IPV6_ADDR_MC_SCOPE(&ma->mca_addr) < IPV6_ADDR_SCOPE_LINKLOCAL ||
586             ipv6_addr_is_ll_all_nodes(&ma->mca_addr))
587                 return;
588
589         igmp6_send(&ma->mca_addr, ma->idev->dev, ICMPV6_MGM_REPORT);
590
591         delay = net_random() % IGMP6_UNSOLICITED_IVAL;
592
593         spin_lock_bh(&ma->mca_lock);
594         if (del_timer(&ma->mca_timer)) {
595                 atomic_dec(&ma->mca_refcnt);
596                 delay = ma->mca_timer.expires - jiffies;
597         }
598
599         if (!mod_timer(&ma->mca_timer, jiffies + delay))
600                 atomic_inc(&ma->mca_refcnt);
601         ma->mca_flags |= MAF_TIMER_RUNNING | MAF_LAST_REPORTER;
602         spin_unlock_bh(&ma->mca_lock);
603 }
604
605 static void igmp6_leave_group(struct ifmcaddr6 *ma)
606 {
607         if (IPV6_ADDR_MC_SCOPE(&ma->mca_addr) < IPV6_ADDR_SCOPE_LINKLOCAL ||
608             ipv6_addr_is_ll_all_nodes(&ma->mca_addr))
609                 return;
610
611         if (ma->mca_flags & MAF_LAST_REPORTER)
612                 igmp6_send(&ma->mca_addr, ma->idev->dev, ICMPV6_MGM_REDUCTION);
613
614         spin_lock_bh(&ma->mca_lock);
615         if (del_timer(&ma->mca_timer))
616                 atomic_dec(&ma->mca_refcnt);
617         spin_unlock_bh(&ma->mca_lock);
618 }
619
620 void igmp6_timer_handler(unsigned long data)
621 {
622         struct ifmcaddr6 *ma = (struct ifmcaddr6 *) data;
623
624         igmp6_send(&ma->mca_addr, ma->idev->dev, ICMPV6_MGM_REPORT);
625
626         spin_lock(&ma->mca_lock);
627         ma->mca_flags |=  MAF_LAST_REPORTER;
628         ma->mca_flags &= ~MAF_TIMER_RUNNING;
629         spin_unlock(&ma->mca_lock);
630         ma_put(ma);
631 }
632
633 /* Device going down */
634
635 void ipv6_mc_down(struct inet6_dev *idev)
636 {
637         struct ifmcaddr6 *i;
638
639         /* Withdraw multicast list */
640
641         read_lock_bh(&idev->lock);
642         for (i = idev->mc_list; i; i=i->next)
643                 igmp6_group_dropped(i);
644         read_unlock_bh(&idev->lock);
645 }
646
647
648 /* Device going up */
649
650 void ipv6_mc_up(struct inet6_dev *idev)
651 {
652         struct ifmcaddr6 *i;
653
654         /* Install multicast list, except for all-nodes (already installed) */
655
656         read_lock_bh(&idev->lock);
657         for (i = idev->mc_list; i; i=i->next)
658                 igmp6_group_added(i);
659         read_unlock_bh(&idev->lock);
660 }
661
662 /* IPv6 device initialization. */
663
664 void ipv6_mc_init_dev(struct inet6_dev *idev)
665 {
666         struct in6_addr maddr;
667
668         /* Add all-nodes address. */
669         ipv6_addr_all_nodes(&maddr);
670         ipv6_dev_mc_inc(idev->dev, &maddr);
671 }
672
673 /*
674  *      Device is about to be destroyed: clean up.
675  */
676
677 void ipv6_mc_destroy_dev(struct inet6_dev *idev)
678 {
679         struct ifmcaddr6 *i;
680         struct in6_addr maddr;
681
682         /* Delete all-nodes address. */
683         ipv6_addr_all_nodes(&maddr);
684         ipv6_dev_mc_dec(idev->dev, &maddr);
685
686         write_lock_bh(&idev->lock);
687         while ((i = idev->mc_list) != NULL) {
688                 idev->mc_list = i->next;
689                 write_unlock_bh(&idev->lock);
690
691                 igmp6_group_dropped(i);
692                 ma_put(i);
693
694                 write_lock_bh(&idev->lock);
695         }
696         write_unlock_bh(&idev->lock);
697 }
698
699 #ifdef CONFIG_PROC_FS
700 static int igmp6_read_proc(char *buffer, char **start, off_t offset,
701                            int length, int *eof, void *data)
702 {
703         off_t pos=0, begin=0;
704         struct ifmcaddr6 *im;
705         int len=0;
706         struct net_device *dev;
707         
708         read_lock(&dev_base_lock);
709         for (dev = dev_base; dev; dev = dev->next) {
710                 struct inet6_dev *idev;
711
712                 if ((idev = in6_dev_get(dev)) == NULL)
713                         continue;
714
715                 read_lock_bh(&idev->lock);
716                 for (im = idev->mc_list; im; im = im->next) {
717                         int i;
718
719                         len += sprintf(buffer+len,"%-4d %-15s ", dev->ifindex, dev->name);
720
721                         for (i=0; i<16; i++)
722                                 len += sprintf(buffer+len, "%02x", im->mca_addr.s6_addr[i]);
723
724                         len+=sprintf(buffer+len,
725                                      " %5d %08X %ld\n",
726                                      im->mca_users,
727                                      im->mca_flags,
728                                      (im->mca_flags&MAF_TIMER_RUNNING) ? im->mca_timer.expires-jiffies : 0);
729
730                         pos=begin+len;
731                         if (pos < offset) {
732                                 len=0;
733                                 begin=pos;
734                         }
735                         if (pos > offset+length) {
736                                 read_unlock_bh(&idev->lock);
737                                 in6_dev_put(idev);
738                                 goto done;
739                         }
740                 }
741                 read_unlock_bh(&idev->lock);
742                 in6_dev_put(idev);
743         }
744         *eof = 1;
745
746 done:
747         read_unlock(&dev_base_lock);
748
749         *start=buffer+(offset-begin);
750         len-=(offset-begin);
751         if(len>length)
752                 len=length;
753         if (len<0)
754                 len=0;
755         return len;
756 }
757 #endif
758
759 int __init igmp6_init(struct net_proto_family *ops)
760 {
761         struct sock *sk;
762         int err;
763
764         igmp6_socket = sock_alloc();
765         if (igmp6_socket == NULL) {
766                 printk(KERN_ERR
767                        "Failed to create the IGMP6 control socket.\n");
768                 return -1;
769         }
770         igmp6_socket->inode->i_uid = 0;
771         igmp6_socket->inode->i_gid = 0;
772         igmp6_socket->type = SOCK_RAW;
773
774         if((err = ops->create(igmp6_socket, IPPROTO_ICMPV6)) < 0) {
775                 printk(KERN_DEBUG 
776                        "Failed to initialize the IGMP6 control socket (err %d).\n",
777                        err);
778                 sock_release(igmp6_socket);
779                 igmp6_socket = NULL; /* For safety. */
780                 return err;
781         }
782
783         sk = igmp6_socket->sk;
784         sk->allocation = GFP_ATOMIC;
785         sk->prot->unhash(sk);
786
787         sk->net_pinfo.af_inet6.hop_limit = 1;
788 #ifdef CONFIG_PROC_FS
789         create_proc_read_entry("net/igmp6", 0, 0, igmp6_read_proc, NULL);
790 #endif
791
792         return 0;
793 }
794
795 void igmp6_cleanup(void)
796 {
797         sock_release(igmp6_socket);
798         igmp6_socket = NULL; /* for safety */
799 #ifdef CONFIG_PROC_FS
800         remove_proc_entry("net/igmp6", 0);
801 #endif
802 }