mcast.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:17k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

  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.38 2001/08/15 07:36:31 davem 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. /* Changes:
  18.  *
  19.  * yoshfuji : fix format of router-alert option
  20.  */
  21. #define __NO_VERSION__
  22. #include <linux/config.h>
  23. #include <linux/module.h>
  24. #include <linux/errno.h>
  25. #include <linux/types.h>
  26. #include <linux/string.h>
  27. #include <linux/socket.h>
  28. #include <linux/sockios.h>
  29. #include <linux/sched.h>
  30. #include <linux/net.h>
  31. #include <linux/in6.h>
  32. #include <linux/netdevice.h>
  33. #include <linux/if_arp.h>
  34. #include <linux/route.h>
  35. #include <linux/init.h>
  36. #include <linux/proc_fs.h>
  37. #include <net/sock.h>
  38. #include <net/snmp.h>
  39. #include <net/ipv6.h>
  40. #include <net/protocol.h>
  41. #include <net/if_inet6.h>
  42. #include <net/ndisc.h>
  43. #include <net/addrconf.h>
  44. #include <net/ip6_route.h>
  45. #include <net/checksum.h>
  46. /* Set to 3 to get tracing... */
  47. #define MCAST_DEBUG 2
  48. #if MCAST_DEBUG >= 3
  49. #define MDBG(x) printk x
  50. #else
  51. #define MDBG(x)
  52. #endif
  53. /* Big mc list lock for all the sockets */
  54. static rwlock_t ipv6_sk_mc_lock = RW_LOCK_UNLOCKED;
  55. static struct socket *igmp6_socket;
  56. static void igmp6_join_group(struct ifmcaddr6 *ma);
  57. static void igmp6_leave_group(struct ifmcaddr6 *ma);
  58. void igmp6_timer_handler(unsigned long data);
  59. #define IGMP6_UNSOLICITED_IVAL (10*HZ)
  60. /*
  61.  * socket join on multicast group
  62.  */
  63. int ipv6_sock_mc_join(struct sock *sk, int ifindex, struct in6_addr *addr)
  64. {
  65. struct net_device *dev = NULL;
  66. struct ipv6_mc_socklist *mc_lst;
  67. struct ipv6_pinfo *np = &sk->net_pinfo.af_inet6;
  68. int err;
  69. if (!(ipv6_addr_type(addr) & IPV6_ADDR_MULTICAST))
  70. return -EINVAL;
  71. mc_lst = sock_kmalloc(sk, sizeof(struct ipv6_mc_socklist), GFP_KERNEL);
  72. if (mc_lst == NULL)
  73. return -ENOMEM;
  74. mc_lst->next = NULL;
  75. memcpy(&mc_lst->addr, addr, sizeof(struct in6_addr));
  76. if (ifindex == 0) {
  77. struct rt6_info *rt;
  78. rt = rt6_lookup(addr, NULL, 0, 0);
  79. if (rt) {
  80. dev = rt->rt6i_dev;
  81. dev_hold(dev);
  82. dst_release(&rt->u.dst);
  83. }
  84. } else
  85. dev = dev_get_by_index(ifindex);
  86. if (dev == NULL) {
  87. sock_kfree_s(sk, mc_lst, sizeof(*mc_lst));
  88. return -ENODEV;
  89. }
  90. mc_lst->ifindex = dev->ifindex;
  91. /*
  92.  * now add/increase the group membership on the device
  93.  */
  94. err = ipv6_dev_mc_inc(dev, addr);
  95. if (err) {
  96. sock_kfree_s(sk, mc_lst, sizeof(*mc_lst));
  97. dev_put(dev);
  98. return err;
  99. }
  100. write_lock_bh(&ipv6_sk_mc_lock);
  101. mc_lst->next = np->ipv6_mc_list;
  102. np->ipv6_mc_list = mc_lst;
  103. write_unlock_bh(&ipv6_sk_mc_lock);
  104. dev_put(dev);
  105. return 0;
  106. }
  107. /*
  108.  * socket leave on multicast group
  109.  */
  110. int ipv6_sock_mc_drop(struct sock *sk, int ifindex, struct in6_addr *addr)
  111. {
  112. struct ipv6_pinfo *np = &sk->net_pinfo.af_inet6;
  113. struct ipv6_mc_socklist *mc_lst, **lnk;
  114. write_lock_bh(&ipv6_sk_mc_lock);
  115. for (lnk = &np->ipv6_mc_list; (mc_lst = *lnk) !=NULL ; lnk = &mc_lst->next) {
  116. if (mc_lst->ifindex == ifindex &&
  117.     ipv6_addr_cmp(&mc_lst->addr, addr) == 0) {
  118. struct net_device *dev;
  119. *lnk = mc_lst->next;
  120. write_unlock_bh(&ipv6_sk_mc_lock);
  121. if ((dev = dev_get_by_index(ifindex)) != NULL) {
  122. ipv6_dev_mc_dec(dev, &mc_lst->addr);
  123. dev_put(dev);
  124. }
  125. sock_kfree_s(sk, mc_lst, sizeof(*mc_lst));
  126. return 0;
  127. }
  128. }
  129. write_unlock_bh(&ipv6_sk_mc_lock);
  130. return -ENOENT;
  131. }
  132. void ipv6_sock_mc_close(struct sock *sk)
  133. {
  134. struct ipv6_pinfo *np = &sk->net_pinfo.af_inet6;
  135. struct ipv6_mc_socklist *mc_lst;
  136. write_lock_bh(&ipv6_sk_mc_lock);
  137. while ((mc_lst = np->ipv6_mc_list) != NULL) {
  138. struct net_device *dev;
  139. np->ipv6_mc_list = mc_lst->next;
  140. write_unlock_bh(&ipv6_sk_mc_lock);
  141. dev = dev_get_by_index(mc_lst->ifindex);
  142. if (dev) {
  143. ipv6_dev_mc_dec(dev, &mc_lst->addr);
  144. dev_put(dev);
  145. }
  146. sock_kfree_s(sk, mc_lst, sizeof(*mc_lst));
  147. write_lock_bh(&ipv6_sk_mc_lock);
  148. }
  149. write_unlock_bh(&ipv6_sk_mc_lock);
  150. }
  151. int inet6_mc_check(struct sock *sk, struct in6_addr *addr)
  152. {
  153. struct ipv6_mc_socklist *mc;
  154. read_lock(&ipv6_sk_mc_lock);
  155. for (mc = sk->net_pinfo.af_inet6.ipv6_mc_list; mc; mc=mc->next) {
  156. if (ipv6_addr_cmp(&mc->addr, addr) == 0) {
  157. read_unlock(&ipv6_sk_mc_lock);
  158. return 1;
  159. }
  160. }
  161. read_unlock(&ipv6_sk_mc_lock);
  162. return 0;
  163. }
  164. static void ma_put(struct ifmcaddr6 *mc)
  165. {
  166. if (atomic_dec_and_test(&mc->mca_refcnt)) {
  167. in6_dev_put(mc->idev);
  168. kfree(mc);
  169. }
  170. }
  171. static int igmp6_group_added(struct ifmcaddr6 *mc)
  172. {
  173. struct net_device *dev = mc->idev->dev;
  174. char buf[MAX_ADDR_LEN];
  175. spin_lock_bh(&mc->mca_lock);
  176. if (!(mc->mca_flags&MAF_LOADED)) {
  177. mc->mca_flags |= MAF_LOADED;
  178. if (ndisc_mc_map(&mc->mca_addr, buf, dev, 0) == 0)
  179. dev_mc_add(dev, buf, dev->addr_len, 0);
  180. }
  181. spin_unlock_bh(&mc->mca_lock);
  182. if (dev->flags&IFF_UP)
  183. igmp6_join_group(mc);
  184. return 0;
  185. }
  186. static int igmp6_group_dropped(struct ifmcaddr6 *mc)
  187. {
  188. struct net_device *dev = mc->idev->dev;
  189. char buf[MAX_ADDR_LEN];
  190. spin_lock_bh(&mc->mca_lock);
  191. if (mc->mca_flags&MAF_LOADED) {
  192. mc->mca_flags &= ~MAF_LOADED;
  193. if (ndisc_mc_map(&mc->mca_addr, buf, dev, 0) == 0)
  194. dev_mc_delete(dev, buf, dev->addr_len, 0);
  195. }
  196. spin_unlock_bh(&mc->mca_lock);
  197. if (dev->flags&IFF_UP)
  198. igmp6_leave_group(mc);
  199. return 0;
  200. }
  201. /*
  202.  * device multicast group inc (add if not found)
  203.  */
  204. int ipv6_dev_mc_inc(struct net_device *dev, struct in6_addr *addr)
  205. {
  206. struct ifmcaddr6 *mc;
  207. struct inet6_dev *idev;
  208. idev = in6_dev_get(dev);
  209. if (idev == NULL)
  210. return -EINVAL;
  211. write_lock_bh(&idev->lock);
  212. if (idev->dead) {
  213. write_unlock_bh(&idev->lock);
  214. in6_dev_put(idev);
  215. return -ENODEV;
  216. }
  217. for (mc = idev->mc_list; mc; mc = mc->next) {
  218. if (ipv6_addr_cmp(&mc->mca_addr, addr) == 0) {
  219. mc->mca_users++;
  220. write_unlock_bh(&idev->lock);
  221. in6_dev_put(idev);
  222. return 0;
  223. }
  224. }
  225. /*
  226.  * not found: create a new one.
  227.  */
  228. mc = kmalloc(sizeof(struct ifmcaddr6), GFP_ATOMIC);
  229. if (mc == NULL) {
  230. write_unlock_bh(&idev->lock);
  231. in6_dev_put(idev);
  232. return -ENOMEM;
  233. }
  234. memset(mc, 0, sizeof(struct ifmcaddr6));
  235. mc->mca_timer.function = igmp6_timer_handler;
  236. mc->mca_timer.data = (unsigned long) mc;
  237. memcpy(&mc->mca_addr, addr, sizeof(struct in6_addr));
  238. mc->idev = idev;
  239. mc->mca_users = 1;
  240. atomic_set(&mc->mca_refcnt, 2);
  241. mc->mca_lock = SPIN_LOCK_UNLOCKED;
  242. mc->next = idev->mc_list;
  243. idev->mc_list = mc;
  244. write_unlock_bh(&idev->lock);
  245. igmp6_group_added(mc);
  246. ma_put(mc);
  247. return 0;
  248. }
  249. /*
  250.  * device multicast group del
  251.  */
  252. int ipv6_dev_mc_dec(struct net_device *dev, struct in6_addr *addr)
  253. {
  254. struct inet6_dev *idev;
  255. struct ifmcaddr6 *ma, **map;
  256. idev = in6_dev_get(dev);
  257. if (idev == NULL)
  258. return -ENODEV;
  259. write_lock_bh(&idev->lock);
  260. for (map = &idev->mc_list; (ma=*map) != NULL; map = &ma->next) {
  261. if (ipv6_addr_cmp(&ma->mca_addr, addr) == 0) {
  262. if (--ma->mca_users == 0) {
  263. *map = ma->next;
  264. write_unlock_bh(&idev->lock);
  265. igmp6_group_dropped(ma);
  266. ma_put(ma);
  267. in6_dev_put(idev);
  268. return 0;
  269. }
  270. write_unlock_bh(&idev->lock);
  271. in6_dev_put(idev);
  272. return 0;
  273. }
  274. }
  275. write_unlock_bh(&idev->lock);
  276. in6_dev_put(idev);
  277. return -ENOENT;
  278. }
  279. /*
  280.  * check if the interface/address pair is valid
  281.  */
  282. int ipv6_chk_mcast_addr(struct net_device *dev, struct in6_addr *addr)
  283. {
  284. struct inet6_dev *idev;
  285. struct ifmcaddr6 *mc;
  286. idev = in6_dev_get(dev);
  287. if (idev) {
  288. read_lock_bh(&idev->lock);
  289. for (mc = idev->mc_list; mc; mc=mc->next) {
  290. if (ipv6_addr_cmp(&mc->mca_addr, addr) == 0) {
  291. read_unlock_bh(&idev->lock);
  292. in6_dev_put(idev);
  293. return 1;
  294. }
  295. }
  296. read_unlock_bh(&idev->lock);
  297. in6_dev_put(idev);
  298. }
  299. return 0;
  300. }
  301. /*
  302.  * IGMP handling (alias multicast ICMPv6 messages)
  303.  */
  304. static void igmp6_group_queried(struct ifmcaddr6 *ma, unsigned long resptime)
  305. {
  306. unsigned long delay = resptime;
  307. /* Do not start timer for addresses with link/host scope */
  308. if (ipv6_addr_type(&ma->mca_addr)&(IPV6_ADDR_LINKLOCAL|IPV6_ADDR_LOOPBACK))
  309. return;
  310. spin_lock(&ma->mca_lock);
  311. if (del_timer(&ma->mca_timer)) {
  312. atomic_dec(&ma->mca_refcnt);
  313. delay = ma->mca_timer.expires - jiffies;
  314. }
  315. if (delay >= resptime) {
  316. if (resptime)
  317. delay = net_random() % resptime;
  318. else
  319. delay = 1;
  320. }
  321. ma->mca_timer.expires = jiffies + delay;
  322. if (!mod_timer(&ma->mca_timer, jiffies + delay))
  323. atomic_inc(&ma->mca_refcnt);
  324. spin_unlock(&ma->mca_lock);
  325. }
  326. int igmp6_event_query(struct sk_buff *skb)
  327. {
  328. struct ifmcaddr6 *ma;
  329. struct in6_addr *addrp;
  330. unsigned long resptime;
  331. struct inet6_dev *idev;
  332. struct icmp6hdr *hdr;
  333. if (!pskb_may_pull(skb, sizeof(struct in6_addr)))
  334. return -EINVAL;
  335. hdr = (struct icmp6hdr*) skb->h.raw;
  336. /* Drop queries with not link local source */
  337. if (!(ipv6_addr_type(&skb->nh.ipv6h->saddr)&IPV6_ADDR_LINKLOCAL))
  338. return -EINVAL;
  339. resptime = ntohs(hdr->icmp6_maxdelay);
  340. /* Translate milliseconds to jiffies */
  341. resptime = (resptime<<10)/(1024000/HZ);
  342. addrp = (struct in6_addr *) (hdr + 1);
  343. idev = in6_dev_get(skb->dev);
  344. if (idev == NULL)
  345. return 0;
  346. read_lock(&idev->lock);
  347. if (ipv6_addr_any(addrp)) {
  348. for (ma = idev->mc_list; ma; ma=ma->next)
  349. igmp6_group_queried(ma, resptime);
  350. } else {
  351. for (ma = idev->mc_list; ma; ma=ma->next) {
  352. if (ipv6_addr_cmp(addrp, &ma->mca_addr) == 0) {
  353. igmp6_group_queried(ma, resptime);
  354. break;
  355. }
  356. }
  357. }
  358. read_unlock(&idev->lock);
  359. in6_dev_put(idev);
  360. return 0;
  361. }
  362. int igmp6_event_report(struct sk_buff *skb)
  363. {
  364. struct ifmcaddr6 *ma;
  365. struct in6_addr *addrp;
  366. struct inet6_dev *idev;
  367. struct icmp6hdr *hdr;
  368. /* Our own report looped back. Ignore it. */
  369. if (skb->pkt_type == PACKET_LOOPBACK)
  370. return 0;
  371. if (!pskb_may_pull(skb, sizeof(struct in6_addr)))
  372. return -EINVAL;
  373. hdr = (struct icmp6hdr*) skb->h.raw;
  374. /* Drop reports with not link local source */
  375. if (!(ipv6_addr_type(&skb->nh.ipv6h->saddr)&IPV6_ADDR_LINKLOCAL))
  376. return -EINVAL;
  377. addrp = (struct in6_addr *) (hdr + 1);
  378. idev = in6_dev_get(skb->dev);
  379. if (idev == NULL)
  380. return -ENODEV;
  381. /*
  382.  * Cancel the timer for this group
  383.  */
  384. read_lock(&idev->lock);
  385. for (ma = idev->mc_list; ma; ma=ma->next) {
  386. if (ipv6_addr_cmp(&ma->mca_addr, addrp) == 0) {
  387. spin_lock(&ma->mca_lock);
  388. if (del_timer(&ma->mca_timer))
  389. atomic_dec(&ma->mca_refcnt);
  390. ma->mca_flags &= ~(MAF_LAST_REPORTER|MAF_TIMER_RUNNING);
  391. spin_unlock(&ma->mca_lock);
  392. break;
  393. }
  394. }
  395. read_unlock(&idev->lock);
  396. in6_dev_put(idev);
  397. return 0;
  398. }
  399. void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type)
  400. {
  401. struct sock *sk = igmp6_socket->sk;
  402.         struct sk_buff *skb;
  403.         struct icmp6hdr *hdr;
  404. struct in6_addr *snd_addr;
  405. struct in6_addr *addrp;
  406. struct in6_addr addr_buf;
  407. struct in6_addr all_routers;
  408. int err, len, payload_len, full_len;
  409. u8 ra[8] = { IPPROTO_ICMPV6, 0,
  410.      IPV6_TLV_ROUTERALERT, 2, 0, 0,
  411.      IPV6_TLV_PADN, 0 };
  412. snd_addr = addr;
  413. if (type == ICMPV6_MGM_REDUCTION) {
  414. snd_addr = &all_routers;
  415. ipv6_addr_all_routers(&all_routers);
  416. }
  417. len = sizeof(struct icmp6hdr) + sizeof(struct in6_addr);
  418. payload_len = len + sizeof(ra);
  419. full_len = sizeof(struct ipv6hdr) + payload_len;
  420. skb = sock_alloc_send_skb(sk, dev->hard_header_len + full_len + 15, 0, &err);
  421. if (skb == NULL)
  422. return;
  423. skb_reserve(skb, (dev->hard_header_len + 15) & ~15);
  424. if (dev->hard_header) {
  425. unsigned char ha[MAX_ADDR_LEN];
  426. ndisc_mc_map(snd_addr, ha, dev, 1);
  427. if (dev->hard_header(skb, dev, ETH_P_IPV6, ha, NULL, full_len) < 0)
  428. goto out;
  429. }
  430. if (ipv6_get_lladdr(dev, &addr_buf)) {
  431. #if MCAST_DEBUG >= 1
  432. printk(KERN_DEBUG "igmp6: %s no linklocal addressn",
  433.        dev->name);
  434. #endif
  435. goto out;
  436. }
  437. ip6_nd_hdr(sk, skb, dev, &addr_buf, snd_addr, NEXTHDR_HOP, payload_len);
  438. memcpy(skb_put(skb, sizeof(ra)), ra, sizeof(ra));
  439. hdr = (struct icmp6hdr *) skb_put(skb, sizeof(struct icmp6hdr));
  440. memset(hdr, 0, sizeof(struct icmp6hdr));
  441. hdr->icmp6_type = type;
  442. addrp = (struct in6_addr *) skb_put(skb, sizeof(struct in6_addr));
  443. ipv6_addr_copy(addrp, addr);
  444. hdr->icmp6_cksum = csum_ipv6_magic(&addr_buf, snd_addr, len,
  445.    IPPROTO_ICMPV6,
  446.    csum_partial((__u8 *) hdr, len, 0));
  447. dev_queue_xmit(skb);
  448. if (type == ICMPV6_MGM_REDUCTION)
  449. ICMP6_INC_STATS(Icmp6OutGroupMembReductions);
  450. else
  451. ICMP6_INC_STATS(Icmp6OutGroupMembResponses);
  452. ICMP6_INC_STATS(Icmp6OutMsgs);
  453. return;
  454. out:
  455. kfree_skb(skb);
  456. }
  457. static void igmp6_join_group(struct ifmcaddr6 *ma)
  458. {
  459. unsigned long delay;
  460. int addr_type;
  461. addr_type = ipv6_addr_type(&ma->mca_addr);
  462. if ((addr_type & (IPV6_ADDR_LINKLOCAL|IPV6_ADDR_LOOPBACK)))
  463. return;
  464. igmp6_send(&ma->mca_addr, ma->idev->dev, ICMPV6_MGM_REPORT);
  465. delay = net_random() % IGMP6_UNSOLICITED_IVAL;
  466. spin_lock_bh(&ma->mca_lock);
  467. if (del_timer(&ma->mca_timer)) {
  468. atomic_dec(&ma->mca_refcnt);
  469. delay = ma->mca_timer.expires - jiffies;
  470. }
  471. if (!mod_timer(&ma->mca_timer, jiffies + delay))
  472. atomic_inc(&ma->mca_refcnt);
  473. ma->mca_flags |= MAF_TIMER_RUNNING | MAF_LAST_REPORTER;
  474. spin_unlock_bh(&ma->mca_lock);
  475. }
  476. static void igmp6_leave_group(struct ifmcaddr6 *ma)
  477. {
  478. int addr_type;
  479. addr_type = ipv6_addr_type(&ma->mca_addr);
  480. if ((addr_type & IPV6_ADDR_LINKLOCAL))
  481. return;
  482. if (ma->mca_flags & MAF_LAST_REPORTER)
  483. igmp6_send(&ma->mca_addr, ma->idev->dev, ICMPV6_MGM_REDUCTION);
  484. spin_lock_bh(&ma->mca_lock);
  485. if (del_timer(&ma->mca_timer))
  486. atomic_dec(&ma->mca_refcnt);
  487. spin_unlock_bh(&ma->mca_lock);
  488. }
  489. void igmp6_timer_handler(unsigned long data)
  490. {
  491. struct ifmcaddr6 *ma = (struct ifmcaddr6 *) data;
  492. igmp6_send(&ma->mca_addr, ma->idev->dev, ICMPV6_MGM_REPORT);
  493. spin_lock(&ma->mca_lock);
  494. ma->mca_flags |=  MAF_LAST_REPORTER;
  495. ma->mca_flags &= ~MAF_TIMER_RUNNING;
  496. spin_unlock(&ma->mca_lock);
  497. ma_put(ma);
  498. }
  499. /* Device going down */
  500. void ipv6_mc_down(struct inet6_dev *idev)
  501. {
  502. struct ifmcaddr6 *i;
  503. /* Withdraw multicast list */
  504. read_lock_bh(&idev->lock);
  505. for (i = idev->mc_list; i; i=i->next)
  506. igmp6_group_dropped(i);
  507. read_unlock_bh(&idev->lock);
  508. }
  509. /* Device going up */
  510. void ipv6_mc_up(struct inet6_dev *idev)
  511. {
  512. struct ifmcaddr6 *i;
  513. /* Install multicast list, except for all-nodes (already installed) */
  514. read_lock_bh(&idev->lock);
  515. for (i = idev->mc_list; i; i=i->next)
  516. igmp6_group_added(i);
  517. read_unlock_bh(&idev->lock);
  518. }
  519. /* IPv6 device initialization. */
  520. void ipv6_mc_init_dev(struct inet6_dev *idev)
  521. {
  522. struct in6_addr maddr;
  523. /* Add all-nodes address. */
  524. ipv6_addr_all_nodes(&maddr);
  525. ipv6_dev_mc_inc(idev->dev, &maddr);
  526. }
  527. /*
  528.  * Device is about to be destroyed: clean up.
  529.  */
  530. void ipv6_mc_destroy_dev(struct inet6_dev *idev)
  531. {
  532. struct ifmcaddr6 *i;
  533. struct in6_addr maddr;
  534. /* Delete all-nodes address. */
  535. ipv6_addr_all_nodes(&maddr);
  536. ipv6_dev_mc_dec(idev->dev, &maddr);
  537. write_lock_bh(&idev->lock);
  538. while ((i = idev->mc_list) != NULL) {
  539. idev->mc_list = i->next;
  540. write_unlock_bh(&idev->lock);
  541. igmp6_group_dropped(i);
  542. ma_put(i);
  543. write_lock_bh(&idev->lock);
  544. }
  545. write_unlock_bh(&idev->lock);
  546. }
  547. #ifdef CONFIG_PROC_FS
  548. static int igmp6_read_proc(char *buffer, char **start, off_t offset,
  549.    int length, int *eof, void *data)
  550. {
  551. off_t pos=0, begin=0;
  552. struct ifmcaddr6 *im;
  553. int len=0;
  554. struct net_device *dev;
  555. read_lock(&dev_base_lock);
  556. for (dev = dev_base; dev; dev = dev->next) {
  557. struct inet6_dev *idev;
  558. if ((idev = in6_dev_get(dev)) == NULL)
  559. continue;
  560. read_lock_bh(&idev->lock);
  561. for (im = idev->mc_list; im; im = im->next) {
  562. int i;
  563. len += sprintf(buffer+len,"%-4d %-15s ", dev->ifindex, dev->name);
  564. for (i=0; i<16; i++)
  565. len += sprintf(buffer+len, "%02x", im->mca_addr.s6_addr[i]);
  566. len+=sprintf(buffer+len,
  567.      " %5d %08X %ldn",
  568.      im->mca_users,
  569.      im->mca_flags,
  570.      (im->mca_flags&MAF_TIMER_RUNNING) ? im->mca_timer.expires-jiffies : 0);
  571. pos=begin+len;
  572. if (pos < offset) {
  573. len=0;
  574. begin=pos;
  575. }
  576. if (pos > offset+length) {
  577. read_unlock_bh(&idev->lock);
  578. in6_dev_put(idev);
  579. goto done;
  580. }
  581. }
  582. read_unlock_bh(&idev->lock);
  583. in6_dev_put(idev);
  584. }
  585. *eof = 1;
  586. done:
  587. read_unlock(&dev_base_lock);
  588. *start=buffer+(offset-begin);
  589. len-=(offset-begin);
  590. if(len>length)
  591. len=length;
  592. if (len<0)
  593. len=0;
  594. return len;
  595. }
  596. #endif
  597. int __init igmp6_init(struct net_proto_family *ops)
  598. {
  599. struct sock *sk;
  600. int err;
  601. igmp6_socket = sock_alloc();
  602. if (igmp6_socket == NULL) {
  603. printk(KERN_ERR
  604.        "Failed to create the IGMP6 control socket.n");
  605. return -1;
  606. }
  607. igmp6_socket->inode->i_uid = 0;
  608. igmp6_socket->inode->i_gid = 0;
  609. igmp6_socket->type = SOCK_RAW;
  610. if((err = ops->create(igmp6_socket, IPPROTO_ICMPV6)) < 0) {
  611. printk(KERN_DEBUG 
  612.        "Failed to initialize the IGMP6 control socket (err %d).n",
  613.        err);
  614. sock_release(igmp6_socket);
  615. igmp6_socket = NULL; /* For safety. */
  616. return err;
  617. }
  618. sk = igmp6_socket->sk;
  619. sk->allocation = GFP_ATOMIC;
  620. sk->prot->unhash(sk);
  621. sk->net_pinfo.af_inet6.hop_limit = 1;
  622. #ifdef CONFIG_PROC_FS
  623. create_proc_read_entry("net/igmp6", 0, 0, igmp6_read_proc, NULL);
  624. #endif
  625. return 0;
  626. }
  627. void igmp6_cleanup(void)
  628. {
  629. sock_release(igmp6_socket);
  630. igmp6_socket = NULL; /* for safety */
  631. #ifdef CONFIG_PROC_FS
  632. remove_proc_entry("net/igmp6", 0);
  633. #endif
  634. }