* added 0.99 linux version
[mascara-docs.git] / i386 / linux / linux-2.3.21 / net / ipv6 / mcast.c
blob324c37e9d89d20557bd295451e2c7fbe21c41a43
1 /*
2 * Multicast support for IPv6
3 * Linux INET6 implementation
5 * Authors:
6 * Pedro Roque <roque@di.fc.ul.pt>
8 * $Id: mcast.c,v 1.26 1999/08/31 07:04:08 davem Exp $
10 * Based on linux/ipv4/igmp.c and linux/ipv4/ip_sockglue.c
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.
18 #define __NO_VERSION__
19 #include <linux/config.h>
20 #include <linux/module.h>
21 #include <linux/errno.h>
22 #include <linux/types.h>
23 #include <linux/string.h>
24 #include <linux/socket.h>
25 #include <linux/sockios.h>
26 #include <linux/sched.h>
27 #include <linux/net.h>
28 #include <linux/in6.h>
29 #include <linux/netdevice.h>
30 #include <linux/if_arp.h>
31 #include <linux/route.h>
32 #include <linux/init.h>
33 #include <linux/proc_fs.h>
35 #include <net/sock.h>
36 #include <net/snmp.h>
38 #include <net/ipv6.h>
39 #include <net/protocol.h>
40 #include <net/if_inet6.h>
41 #include <net/ndisc.h>
42 #include <net/addrconf.h>
43 #include <net/ip6_route.h>
45 #include <net/checksum.h>
47 /* Set to 3 to get tracing... */
48 #define MCAST_DEBUG 2
50 #if MCAST_DEBUG >= 3
51 #define MDBG(x) printk x
52 #else
53 #define MDBG(x)
54 #endif
56 /* Big mc list lock for all the sockets */
57 static rwlock_t ipv6_sk_mc_lock = RW_LOCK_UNLOCKED;
59 static struct socket *igmp6_socket;
61 static void igmp6_join_group(struct ifmcaddr6 *ma);
62 static void igmp6_leave_group(struct ifmcaddr6 *ma);
63 void igmp6_timer_handler(unsigned long data);
65 #define IGMP6_UNSOLICITED_IVAL (10*HZ)
68 * socket join on multicast group
71 int ipv6_sock_mc_join(struct sock *sk, int ifindex, struct in6_addr *addr)
73 struct net_device *dev = NULL;
74 struct ipv6_mc_socklist *mc_lst;
75 struct ipv6_pinfo *np = &sk->net_pinfo.af_inet6;
76 int err;
78 if (!(ipv6_addr_type(addr) & IPV6_ADDR_MULTICAST))
79 return -EINVAL;
81 mc_lst = sock_kmalloc(sk, sizeof(struct ipv6_mc_socklist), GFP_KERNEL);
83 if (mc_lst == NULL)
84 return -ENOMEM;
86 mc_lst->next = NULL;
87 memcpy(&mc_lst->addr, addr, sizeof(struct in6_addr));
88 mc_lst->ifindex = ifindex;
90 if (ifindex == 0) {
91 struct rt6_info *rt;
92 rt = rt6_lookup(addr, NULL, 0, 0);
93 if (rt) {
94 dev = rt->rt6i_dev;
95 dev_hold(dev);
96 dst_release(&rt->u.dst);
98 } else
99 dev = dev_get_by_index(ifindex);
101 if (dev == NULL) {
102 sock_kfree_s(sk, mc_lst, sizeof(*mc_lst));
103 return -ENODEV;
107 * now add/increase the group membership on the device
110 err = ipv6_dev_mc_inc(dev, addr);
112 if (err) {
113 sock_kfree_s(sk, mc_lst, sizeof(*mc_lst));
114 dev_put(dev);
115 return err;
118 write_lock_bh(&ipv6_sk_mc_lock);
119 mc_lst->next = np->ipv6_mc_list;
120 np->ipv6_mc_list = mc_lst;
121 write_unlock_bh(&ipv6_sk_mc_lock);
123 dev_put(dev);
125 return 0;
129 * socket leave on multicast group
131 int ipv6_sock_mc_drop(struct sock *sk, int ifindex, struct in6_addr *addr)
133 struct ipv6_pinfo *np = &sk->net_pinfo.af_inet6;
134 struct ipv6_mc_socklist *mc_lst, **lnk;
136 write_lock_bh(&ipv6_sk_mc_lock);
137 for (lnk = &np->ipv6_mc_list; (mc_lst = *lnk) !=NULL ; lnk = &mc_lst->next) {
138 if (mc_lst->ifindex == ifindex &&
139 ipv6_addr_cmp(&mc_lst->addr, addr) == 0) {
140 struct net_device *dev;
142 *lnk = mc_lst->next;
143 write_unlock_bh(&ipv6_sk_mc_lock);
145 if ((dev = dev_get_by_index(ifindex)) != NULL) {
146 ipv6_dev_mc_dec(dev, &mc_lst->addr);
147 dev_put(dev);
149 sock_kfree_s(sk, mc_lst, sizeof(*mc_lst));
150 return 0;
153 write_unlock_bh(&ipv6_sk_mc_lock);
155 return -ENOENT;
158 void ipv6_sock_mc_close(struct sock *sk)
160 struct ipv6_pinfo *np = &sk->net_pinfo.af_inet6;
161 struct ipv6_mc_socklist *mc_lst;
163 write_lock_bh(&ipv6_sk_mc_lock);
164 while ((mc_lst = np->ipv6_mc_list) != NULL) {
165 struct net_device *dev;
167 np->ipv6_mc_list = mc_lst->next;
168 write_unlock_bh(&ipv6_sk_mc_lock);
170 dev = dev_get_by_index(mc_lst->ifindex);
171 if (dev) {
172 ipv6_dev_mc_dec(dev, &mc_lst->addr);
173 dev_put(dev);
176 sock_kfree_s(sk, mc_lst, sizeof(*mc_lst));
178 write_lock_bh(&ipv6_sk_mc_lock);
180 write_unlock_bh(&ipv6_sk_mc_lock);
183 int inet6_mc_check(struct sock *sk, struct in6_addr *addr)
185 struct ipv6_mc_socklist *mc;
187 read_lock(&ipv6_sk_mc_lock);
188 for (mc = sk->net_pinfo.af_inet6.ipv6_mc_list; mc; mc=mc->next) {
189 if (ipv6_addr_cmp(&mc->addr, addr) == 0) {
190 read_unlock(&ipv6_sk_mc_lock);
191 return 1;
194 read_unlock(&ipv6_sk_mc_lock);
196 return 0;
199 static int igmp6_group_added(struct ifmcaddr6 *mc)
201 struct net_device *dev = mc->idev->dev;
202 char buf[MAX_ADDR_LEN];
204 if (!(mc->mca_flags&MAF_LOADED)) {
205 mc->mca_flags |= MAF_LOADED;
206 if (ndisc_mc_map(&mc->mca_addr, buf, dev, 0) == 0)
207 dev_mc_add(dev, buf, dev->addr_len, 0);
210 if (dev->flags&IFF_UP)
211 igmp6_join_group(mc);
212 return 0;
215 static int igmp6_group_dropped(struct ifmcaddr6 *mc)
217 struct net_device *dev = mc->idev->dev;
218 char buf[MAX_ADDR_LEN];
220 if (mc->mca_flags&MAF_LOADED) {
221 mc->mca_flags &= ~MAF_LOADED;
222 if (ndisc_mc_map(&mc->mca_addr, buf, dev, 0) == 0)
223 dev_mc_delete(dev, buf, dev->addr_len, 0);
226 if (dev->flags&IFF_UP)
227 igmp6_leave_group(mc);
228 return 0;
233 * device multicast group inc (add if not found)
235 int ipv6_dev_mc_inc(struct net_device *dev, struct in6_addr *addr)
237 struct ifmcaddr6 *mc;
238 struct inet6_dev *idev;
240 idev = in6_dev_get(dev);
242 if (idev == NULL)
243 return -EINVAL;
245 write_lock_bh(&idev->lock);
246 if (idev->dead) {
247 write_unlock_bh(&idev->lock);
248 in6_dev_put(idev);
249 return -ENODEV;
252 for (mc = idev->mc_list; mc; mc = mc->next) {
253 if (ipv6_addr_cmp(&mc->mca_addr, addr) == 0) {
254 atomic_inc(&mc->mca_users);
255 write_unlock_bh(&idev->lock);
256 in6_dev_put(idev);
257 return 0;
262 * not found: create a new one.
265 mc = kmalloc(sizeof(struct ifmcaddr6), GFP_ATOMIC);
267 if (mc == NULL) {
268 write_unlock_bh(&idev->lock);
269 in6_dev_put(idev);
270 return -ENOMEM;
273 memset(mc, 0, sizeof(struct ifmcaddr6));
274 mc->mca_timer.function = igmp6_timer_handler;
275 mc->mca_timer.data = (unsigned long) mc;
277 memcpy(&mc->mca_addr, addr, sizeof(struct in6_addr));
278 mc->idev = idev;
279 atomic_set(&mc->mca_users, 1);
281 mc->next = idev->mc_list;
282 idev->mc_list = mc;
284 igmp6_group_added(mc);
286 write_unlock_bh(&idev->lock);
288 return 0;
292 * device multicast group del
294 int ipv6_dev_mc_dec(struct net_device *dev, struct in6_addr *addr)
296 struct inet6_dev *idev;
297 struct ifmcaddr6 *ma, **map;
299 idev = in6_dev_get(dev);
300 if (idev == NULL)
301 return -ENODEV;
303 write_lock_bh(&idev->lock);
304 for (map = &idev->mc_list; (ma=*map) != NULL; map = &ma->next) {
305 if (ipv6_addr_cmp(&ma->mca_addr, addr) == 0) {
306 if (atomic_dec_and_test(&ma->mca_users)) {
307 *map = ma->next;
308 write_unlock_bh(&idev->lock);
310 igmp6_group_dropped(ma);
312 if (ma->idev)
313 __in6_dev_put(ma->idev);
315 kfree(ma);
316 in6_dev_put(idev);
317 return 0;
319 write_unlock_bh(&idev->lock);
320 in6_dev_put(idev);
321 return 0;
324 write_unlock_bh(&idev->lock);
325 in6_dev_put(idev);
327 return -ENOENT;
331 * check if the interface/address pair is valid
333 int ipv6_chk_mcast_addr(struct net_device *dev, struct in6_addr *addr)
335 struct inet6_dev *idev;
336 struct ifmcaddr6 *mc;
338 idev = in6_dev_get(dev);
339 if (idev) {
340 read_lock_bh(&idev->lock);
341 for (mc = idev->mc_list; mc; mc=mc->next) {
342 if (ipv6_addr_cmp(&mc->mca_addr, addr) == 0) {
343 read_unlock_bh(&idev->lock);
344 in6_dev_put(idev);
345 return 1;
348 read_unlock_bh(&idev->lock);
350 in6_dev_put(idev);
351 return 0;
355 * IGMP handling (alias multicast ICMPv6 messages)
358 static void igmp6_group_queried(struct ifmcaddr6 *ma, unsigned long resptime)
360 unsigned long delay = resptime;
362 /* Do not start timer for addresses with link/host scope */
363 if (ipv6_addr_type(&ma->mca_addr)&(IPV6_ADDR_LINKLOCAL|IPV6_ADDR_LOOPBACK))
364 return;
366 if (del_timer(&ma->mca_timer))
367 delay = ma->mca_timer.expires - jiffies;
369 if (delay >= resptime) {
370 if (resptime)
371 delay = net_random() % resptime;
372 else
373 delay = 1;
376 ma->mca_flags |= MAF_TIMER_RUNNING;
377 ma->mca_timer.expires = jiffies + delay;
378 add_timer(&ma->mca_timer);
381 int igmp6_event_query(struct sk_buff *skb, struct icmp6hdr *hdr, int len)
383 struct ifmcaddr6 *ma;
384 struct in6_addr *addrp;
385 unsigned long resptime;
386 struct inet6_dev *idev;
389 if (len < sizeof(struct icmp6hdr) + sizeof(struct in6_addr))
390 return -EINVAL;
392 /* Drop queries with not link local source */
393 if (!(ipv6_addr_type(&skb->nh.ipv6h->saddr)&IPV6_ADDR_LINKLOCAL))
394 return -EINVAL;
396 resptime = ntohs(hdr->icmp6_maxdelay);
397 /* Translate milliseconds to jiffies */
398 resptime = (resptime<<10)/(1024000/HZ);
400 addrp = (struct in6_addr *) (hdr + 1);
402 idev = in6_dev_get(skb->dev);
404 if (idev == NULL)
405 return 0;
407 read_lock(&idev->lock);
408 if (ipv6_addr_any(addrp)) {
409 for (ma = idev->mc_list; ma; ma=ma->next)
410 igmp6_group_queried(ma, resptime);
411 } else {
412 for (ma = idev->mc_list; ma; ma=ma->next) {
413 if (ipv6_addr_cmp(addrp, &ma->mca_addr) == 0) {
414 igmp6_group_queried(ma, resptime);
415 break;
419 read_unlock(&idev->lock);
420 in6_dev_put(idev);
422 return 0;
426 int igmp6_event_report(struct sk_buff *skb, struct icmp6hdr *hdr, int len)
428 struct ifmcaddr6 *ma;
429 struct in6_addr *addrp;
430 struct inet6_dev *idev;
432 /* Our own report looped back. Ignore it. */
433 if (skb->pkt_type == PACKET_LOOPBACK)
434 return 0;
436 if (len < sizeof(struct icmp6hdr) + sizeof(struct in6_addr))
437 return -EINVAL;
439 /* Drop reports with not link local source */
440 if (!(ipv6_addr_type(&skb->nh.ipv6h->saddr)&IPV6_ADDR_LINKLOCAL))
441 return -EINVAL;
443 addrp = (struct in6_addr *) (hdr + 1);
445 idev = in6_dev_get(skb->dev);
446 if (idev == NULL)
447 return -ENODEV;
450 * Cancel the timer for this group
453 read_lock(&idev->lock);
454 for (ma = idev->mc_list; ma; ma=ma->next) {
455 if (ipv6_addr_cmp(&ma->mca_addr, addrp) == 0) {
456 if (ma->mca_flags & MAF_TIMER_RUNNING) {
457 del_timer(&ma->mca_timer);
458 ma->mca_flags &= ~MAF_TIMER_RUNNING;
461 ma->mca_flags &= ~MAF_LAST_REPORTER;
462 break;
465 read_unlock(&idev->lock);
466 in6_dev_put(idev);
467 return 0;
470 void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type)
472 struct sock *sk = igmp6_socket->sk;
473 struct sk_buff *skb;
474 struct icmp6hdr *hdr;
475 struct in6_addr *snd_addr;
476 struct in6_addr *addrp;
477 struct in6_addr addr_buf;
478 struct in6_addr all_routers;
479 int err, len, payload_len, full_len;
480 u8 ra[8] = { IPPROTO_ICMPV6, 0,
481 IPV6_TLV_ROUTERALERT, 0, 0, 0,
482 IPV6_TLV_PADN, 0 };
484 snd_addr = addr;
485 if (type == ICMPV6_MGM_REDUCTION) {
486 snd_addr = &all_routers;
487 ipv6_addr_all_routers(&all_routers);
490 len = sizeof(struct icmp6hdr) + sizeof(struct in6_addr);
491 payload_len = len + sizeof(ra);
492 full_len = sizeof(struct ipv6hdr) + payload_len;
494 skb = sock_alloc_send_skb(sk, dev->hard_header_len + full_len + 15, 0, 0, &err);
496 if (skb == NULL)
497 return;
499 skb_reserve(skb, (dev->hard_header_len + 15) & ~15);
500 if (dev->hard_header) {
501 unsigned char ha[MAX_ADDR_LEN];
502 ndisc_mc_map(snd_addr, ha, dev, 1);
503 dev->hard_header(skb, dev, ETH_P_IPV6, ha, NULL, full_len);
506 if (ipv6_get_lladdr(dev, &addr_buf)) {
507 #if MCAST_DEBUG >= 1
508 printk(KERN_DEBUG "igmp6: %s no linklocal address\n",
509 dev->name);
510 #endif
511 return;
514 ip6_nd_hdr(sk, skb, dev, &addr_buf, snd_addr, NEXTHDR_HOP, payload_len);
516 memcpy(skb_put(skb, sizeof(ra)), ra, sizeof(ra));
518 hdr = (struct icmp6hdr *) skb_put(skb, sizeof(struct icmp6hdr));
519 memset(hdr, 0, sizeof(struct icmp6hdr));
520 hdr->icmp6_type = type;
522 addrp = (struct in6_addr *) skb_put(skb, sizeof(struct in6_addr));
523 ipv6_addr_copy(addrp, addr);
525 hdr->icmp6_cksum = csum_ipv6_magic(&addr_buf, snd_addr, len,
526 IPPROTO_ICMPV6,
527 csum_partial((__u8 *) hdr, len, 0));
529 dev_queue_xmit(skb);
530 if (type == ICMPV6_MGM_REDUCTION)
531 icmpv6_statistics.Icmp6OutGroupMembReductions++;
532 else
533 icmpv6_statistics.Icmp6OutGroupMembResponses++;
534 icmpv6_statistics.Icmp6OutMsgs++;
537 static void igmp6_join_group(struct ifmcaddr6 *ma)
539 unsigned long delay;
540 int addr_type;
542 addr_type = ipv6_addr_type(&ma->mca_addr);
544 if ((addr_type & (IPV6_ADDR_LINKLOCAL|IPV6_ADDR_LOOPBACK)))
545 return;
547 igmp6_send(&ma->mca_addr, ma->idev->dev, ICMPV6_MGM_REPORT);
549 delay = net_random() % IGMP6_UNSOLICITED_IVAL;
550 if (del_timer(&ma->mca_timer))
551 delay = ma->mca_timer.expires - jiffies;
553 ma->mca_timer.expires = jiffies + delay;
555 add_timer(&ma->mca_timer);
556 ma->mca_flags |= MAF_TIMER_RUNNING | MAF_LAST_REPORTER;
559 static void igmp6_leave_group(struct ifmcaddr6 *ma)
561 int addr_type;
563 addr_type = ipv6_addr_type(&ma->mca_addr);
565 if ((addr_type & IPV6_ADDR_LINKLOCAL))
566 return;
568 if (ma->mca_flags & MAF_LAST_REPORTER)
569 igmp6_send(&ma->mca_addr, ma->idev->dev, ICMPV6_MGM_REDUCTION);
571 if (ma->mca_flags & MAF_TIMER_RUNNING)
572 del_timer(&ma->mca_timer);
575 void igmp6_timer_handler(unsigned long data)
577 struct ifmcaddr6 *ma = (struct ifmcaddr6 *) data;
579 ma->mca_flags |= MAF_LAST_REPORTER;
580 igmp6_send(&ma->mca_addr, ma->idev->dev, ICMPV6_MGM_REPORT);
581 ma->mca_flags &= ~MAF_TIMER_RUNNING;
584 /* Device going down */
586 void ipv6_mc_down(struct inet6_dev *idev)
588 struct ifmcaddr6 *i;
589 struct in6_addr maddr;
591 /* Withdraw multicast list */
593 read_lock_bh(&idev->lock);
594 for (i = idev->mc_list; i; i=i->next)
595 igmp6_group_dropped(i);
596 read_unlock_bh(&idev->lock);
598 /* Delete all-nodes address. */
600 ipv6_addr_all_nodes(&maddr);
601 ipv6_dev_mc_dec(idev->dev, &maddr);
604 /* Device going up */
606 void ipv6_mc_up(struct inet6_dev *idev)
608 struct ifmcaddr6 *i;
609 struct in6_addr maddr;
611 /* Add all-nodes address. */
613 ipv6_addr_all_nodes(&maddr);
614 ipv6_dev_mc_inc(idev->dev, &maddr);
616 /* Install multicast list, except for all-nodes (already installed) */
618 read_lock_bh(&idev->lock);
619 for (i = idev->mc_list; i; i=i->next)
620 igmp6_group_added(i);
621 read_unlock_bh(&idev->lock);
625 * Device is about to be destroyed: clean up.
628 void ipv6_mc_destroy_dev(struct inet6_dev *idev)
630 struct ifmcaddr6 *i;
632 write_lock_bh(&idev->lock);
633 while ((i = idev->mc_list) != NULL) {
634 idev->mc_list = i->next;
635 write_unlock_bh(&idev->lock);
637 igmp6_group_dropped(i);
639 if (i->idev)
640 in6_dev_put(i->idev);
641 kfree(i);
643 write_lock_bh(&idev->lock);
645 write_unlock_bh(&idev->lock);
648 #ifdef CONFIG_PROC_FS
649 static int igmp6_read_proc(char *buffer, char **start, off_t offset,
650 int length, int *eof, void *data)
652 off_t pos=0, begin=0;
653 struct ifmcaddr6 *im;
654 int len=0;
655 struct net_device *dev;
657 read_lock(&dev_base_lock);
658 for (dev = dev_base; dev; dev = dev->next) {
659 struct inet6_dev *idev;
661 if ((idev = in6_dev_get(dev)) == NULL)
662 continue;
664 read_lock_bh(&idev->lock);
665 for (im = idev->mc_list; im; im = im->next) {
666 int i;
668 len += sprintf(buffer+len,"%-4d %-15s ", dev->ifindex, dev->name);
670 for (i=0; i<16; i++)
671 len += sprintf(buffer+len, "%02x", im->mca_addr.s6_addr[i]);
673 len+=sprintf(buffer+len,
674 " %5d %08X %ld\n",
675 atomic_read(&im->mca_users),
676 im->mca_flags,
677 (im->mca_flags&MAF_TIMER_RUNNING) ? im->mca_timer.expires-jiffies : 0);
679 pos=begin+len;
680 if (pos < offset) {
681 len=0;
682 begin=pos;
684 if (pos > offset+length) {
685 read_unlock_bh(&idev->lock);
686 in6_dev_put(idev);
687 goto done;
690 read_unlock_bh(&idev->lock);
691 in6_dev_put(idev);
693 *eof = 1;
695 done:
696 read_unlock(&dev_base_lock);
698 *start=buffer+(offset-begin);
699 len-=(offset-begin);
700 if(len>length)
701 len=length;
702 if (len<0)
703 len=0;
704 return len;
706 #endif
708 int __init igmp6_init(struct net_proto_family *ops)
710 #ifdef CONFIG_PROC_FS
711 struct proc_dir_entry *ent;
712 #endif
713 struct sock *sk;
714 int err;
716 igmp6_socket = sock_alloc();
717 if (igmp6_socket == NULL) {
718 printk(KERN_ERR
719 "Failed to create the IGMP6 control socket.\n");
720 return -1;
722 igmp6_socket->inode->i_uid = 0;
723 igmp6_socket->inode->i_gid = 0;
724 igmp6_socket->type = SOCK_RAW;
726 if((err = ops->create(igmp6_socket, IPPROTO_ICMPV6)) < 0) {
727 printk(KERN_DEBUG
728 "Failed to initialize the IGMP6 control socket (err %d).\n",
729 err);
730 sock_release(igmp6_socket);
731 igmp6_socket = NULL; /* For safety. */
732 return err;
735 sk = igmp6_socket->sk;
736 sk->allocation = GFP_ATOMIC;
737 sk->prot->unhash(sk);
739 sk->net_pinfo.af_inet6.hop_limit = 1;
740 #ifdef CONFIG_PROC_FS
741 ent = create_proc_entry("net/igmp6", 0, 0);
742 ent->read_proc = igmp6_read_proc;
743 #endif
745 return 0;
748 #ifdef MODULE
749 void igmp6_cleanup(void)
751 sock_release(igmp6_socket);
752 igmp6_socket = NULL; /* for safety */
753 #ifdef CONFIG_PROC_FS
754 remove_proc_entry("net/igmp6", 0);
755 #endif
757 #endif