⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mcast.c

📁 嵌入式系统设计与实例开发实验教材二源码 多线程应用程序设计 串行端口程序设计 AD接口实验 CAN总线通信实验 GPS通信实验 Linux内核移植与编译实验 IC卡读写实验 SD驱动使
💻 C
📖 第 1 页 / 共 2 页
字号:
/* *	Multicast support for IPv6 *	Linux INET6 implementation  * *	Authors: *	Pedro Roque		<roque@di.fc.ul.pt>	 * *	$Id: mcast.c,v 1.38 2001/08/15 07:36:31 davem Exp $ * *	Based on linux/ipv4/igmp.c and linux/ipv4/ip_sockglue.c  * *	This program is free software; you can redistribute it and/or *      modify it under the terms of the GNU General Public License *      as published by the Free Software Foundation; either version *      2 of the License, or (at your option) any later version. *//* Changes: * *	yoshfuji	: fix format of router-alert option */#define __NO_VERSION__#include <linux/config.h>#include <linux/module.h>#include <linux/errno.h>#include <linux/types.h>#include <linux/string.h>#include <linux/socket.h>#include <linux/sockios.h>#include <linux/sched.h>#include <linux/net.h>#include <linux/in6.h>#include <linux/netdevice.h>#include <linux/if_arp.h>#include <linux/route.h>#include <linux/init.h>#include <linux/proc_fs.h>#include <net/sock.h>#include <net/snmp.h>#include <net/ipv6.h>#include <net/protocol.h>#include <net/if_inet6.h>#include <net/ndisc.h>#include <net/addrconf.h>#include <net/ip6_route.h>#include <net/checksum.h>/* Set to 3 to get tracing... */#define MCAST_DEBUG 2#if MCAST_DEBUG >= 3#define MDBG(x) printk x#else#define MDBG(x)#endif/* Big mc list lock for all the sockets */static rwlock_t ipv6_sk_mc_lock = RW_LOCK_UNLOCKED;static struct socket *igmp6_socket;static void igmp6_join_group(struct ifmcaddr6 *ma);static void igmp6_leave_group(struct ifmcaddr6 *ma);void igmp6_timer_handler(unsigned long data);#define IGMP6_UNSOLICITED_IVAL	(10*HZ)/* *	socket join on multicast group */int ipv6_sock_mc_join(struct sock *sk, int ifindex, struct in6_addr *addr){	struct net_device *dev = NULL;	struct ipv6_mc_socklist *mc_lst;	struct ipv6_pinfo *np = &sk->net_pinfo.af_inet6;	int err;	if (!(ipv6_addr_type(addr) & IPV6_ADDR_MULTICAST))		return -EINVAL;	mc_lst = sock_kmalloc(sk, sizeof(struct ipv6_mc_socklist), GFP_KERNEL);	if (mc_lst == NULL)		return -ENOMEM;	mc_lst->next = NULL;	memcpy(&mc_lst->addr, addr, sizeof(struct in6_addr));	if (ifindex == 0) {		struct rt6_info *rt;		rt = rt6_lookup(addr, NULL, 0, 0);		if (rt) {			dev = rt->rt6i_dev;			dev_hold(dev);			dst_release(&rt->u.dst);		}	} else		dev = dev_get_by_index(ifindex);	if (dev == NULL) {		sock_kfree_s(sk, mc_lst, sizeof(*mc_lst));		return -ENODEV;	}	mc_lst->ifindex = dev->ifindex;	/*	 *	now add/increase the group membership on the device	 */	err = ipv6_dev_mc_inc(dev, addr);	if (err) {		sock_kfree_s(sk, mc_lst, sizeof(*mc_lst));		dev_put(dev);		return err;	}	write_lock_bh(&ipv6_sk_mc_lock);	mc_lst->next = np->ipv6_mc_list;	np->ipv6_mc_list = mc_lst;	write_unlock_bh(&ipv6_sk_mc_lock);	dev_put(dev);	return 0;}/* *	socket leave on multicast group */int ipv6_sock_mc_drop(struct sock *sk, int ifindex, struct in6_addr *addr){	struct ipv6_pinfo *np = &sk->net_pinfo.af_inet6;	struct ipv6_mc_socklist *mc_lst, **lnk;	write_lock_bh(&ipv6_sk_mc_lock);	for (lnk = &np->ipv6_mc_list; (mc_lst = *lnk) !=NULL ; lnk = &mc_lst->next) {		if (mc_lst->ifindex == ifindex &&		    ipv6_addr_cmp(&mc_lst->addr, addr) == 0) {			struct net_device *dev;			*lnk = mc_lst->next;			write_unlock_bh(&ipv6_sk_mc_lock);			if ((dev = dev_get_by_index(ifindex)) != NULL) {				ipv6_dev_mc_dec(dev, &mc_lst->addr);				dev_put(dev);			}			sock_kfree_s(sk, mc_lst, sizeof(*mc_lst));			return 0;		}	}	write_unlock_bh(&ipv6_sk_mc_lock);	return -ENOENT;}void ipv6_sock_mc_close(struct sock *sk){	struct ipv6_pinfo *np = &sk->net_pinfo.af_inet6;	struct ipv6_mc_socklist *mc_lst;	write_lock_bh(&ipv6_sk_mc_lock);	while ((mc_lst = np->ipv6_mc_list) != NULL) {		struct net_device *dev;		np->ipv6_mc_list = mc_lst->next;		write_unlock_bh(&ipv6_sk_mc_lock);		dev = dev_get_by_index(mc_lst->ifindex);		if (dev) {			ipv6_dev_mc_dec(dev, &mc_lst->addr);			dev_put(dev);		}		sock_kfree_s(sk, mc_lst, sizeof(*mc_lst));		write_lock_bh(&ipv6_sk_mc_lock);	}	write_unlock_bh(&ipv6_sk_mc_lock);}int inet6_mc_check(struct sock *sk, struct in6_addr *addr){	struct ipv6_mc_socklist *mc;	read_lock(&ipv6_sk_mc_lock);	for (mc = sk->net_pinfo.af_inet6.ipv6_mc_list; mc; mc=mc->next) {		if (ipv6_addr_cmp(&mc->addr, addr) == 0) {			read_unlock(&ipv6_sk_mc_lock);			return 1;		}	}	read_unlock(&ipv6_sk_mc_lock);	return 0;}static void ma_put(struct ifmcaddr6 *mc){	if (atomic_dec_and_test(&mc->mca_refcnt)) {		in6_dev_put(mc->idev);		kfree(mc);	}}static int igmp6_group_added(struct ifmcaddr6 *mc){	struct net_device *dev = mc->idev->dev;	char buf[MAX_ADDR_LEN];	spin_lock_bh(&mc->mca_lock);	if (!(mc->mca_flags&MAF_LOADED)) {		mc->mca_flags |= MAF_LOADED;		if (ndisc_mc_map(&mc->mca_addr, buf, dev, 0) == 0)			dev_mc_add(dev, buf, dev->addr_len, 0);	}	spin_unlock_bh(&mc->mca_lock);	if (dev->flags&IFF_UP)		igmp6_join_group(mc);	return 0;}static int igmp6_group_dropped(struct ifmcaddr6 *mc){	struct net_device *dev = mc->idev->dev;	char buf[MAX_ADDR_LEN];	spin_lock_bh(&mc->mca_lock);	if (mc->mca_flags&MAF_LOADED) {		mc->mca_flags &= ~MAF_LOADED;		if (ndisc_mc_map(&mc->mca_addr, buf, dev, 0) == 0)			dev_mc_delete(dev, buf, dev->addr_len, 0);	}	spin_unlock_bh(&mc->mca_lock);	if (dev->flags&IFF_UP)		igmp6_leave_group(mc);	return 0;}/* *	device multicast group inc (add if not found) */int ipv6_dev_mc_inc(struct net_device *dev, struct in6_addr *addr){	struct ifmcaddr6 *mc;	struct inet6_dev *idev;	idev = in6_dev_get(dev);	if (idev == NULL)		return -EINVAL;	write_lock_bh(&idev->lock);	if (idev->dead) {		write_unlock_bh(&idev->lock);		in6_dev_put(idev);		return -ENODEV;	}	for (mc = idev->mc_list; mc; mc = mc->next) {		if (ipv6_addr_cmp(&mc->mca_addr, addr) == 0) {			mc->mca_users++;			write_unlock_bh(&idev->lock);			in6_dev_put(idev);			return 0;		}	}	/*	 *	not found: create a new one.	 */	mc = kmalloc(sizeof(struct ifmcaddr6), GFP_ATOMIC);	if (mc == NULL) {		write_unlock_bh(&idev->lock);		in6_dev_put(idev);		return -ENOMEM;	}	memset(mc, 0, sizeof(struct ifmcaddr6));	mc->mca_timer.function = igmp6_timer_handler;	mc->mca_timer.data = (unsigned long) mc;	memcpy(&mc->mca_addr, addr, sizeof(struct in6_addr));	mc->idev = idev;	mc->mca_users = 1;	atomic_set(&mc->mca_refcnt, 2);	mc->mca_lock = SPIN_LOCK_UNLOCKED;	mc->next = idev->mc_list;	idev->mc_list = mc;	write_unlock_bh(&idev->lock);	igmp6_group_added(mc);	ma_put(mc);	return 0;}/* *	device multicast group del */int ipv6_dev_mc_dec(struct net_device *dev, struct in6_addr *addr){	struct inet6_dev *idev;	struct ifmcaddr6 *ma, **map;	idev = in6_dev_get(dev);	if (idev == NULL)		return -ENODEV;	write_lock_bh(&idev->lock);	for (map = &idev->mc_list; (ma=*map) != NULL; map = &ma->next) {		if (ipv6_addr_cmp(&ma->mca_addr, addr) == 0) {			if (--ma->mca_users == 0) {				*map = ma->next;				write_unlock_bh(&idev->lock);				igmp6_group_dropped(ma);				ma_put(ma);				in6_dev_put(idev);				return 0;			}			write_unlock_bh(&idev->lock);			in6_dev_put(idev);			return 0;		}	}	write_unlock_bh(&idev->lock);	in6_dev_put(idev);	return -ENOENT;}/* *	check if the interface/address pair is valid */int ipv6_chk_mcast_addr(struct net_device *dev, struct in6_addr *addr){	struct inet6_dev *idev;	struct ifmcaddr6 *mc;	idev = in6_dev_get(dev);	if (idev) {		read_lock_bh(&idev->lock);		for (mc = idev->mc_list; mc; mc=mc->next) {			if (ipv6_addr_cmp(&mc->mca_addr, addr) == 0) {				read_unlock_bh(&idev->lock);				in6_dev_put(idev);				return 1;			}		}		read_unlock_bh(&idev->lock);		in6_dev_put(idev);	}	return 0;}/* *	IGMP handling (alias multicast ICMPv6 messages) */static void igmp6_group_queried(struct ifmcaddr6 *ma, unsigned long resptime){	unsigned long delay = resptime;	/* Do not start timer for addresses with link/host scope */	if (ipv6_addr_type(&ma->mca_addr)&(IPV6_ADDR_LINKLOCAL|IPV6_ADDR_LOOPBACK))		return;	spin_lock(&ma->mca_lock);	if (del_timer(&ma->mca_timer)) {		atomic_dec(&ma->mca_refcnt);		delay = ma->mca_timer.expires - jiffies;	}	if (delay >= resptime) {		if (resptime)			delay = net_random() % resptime;		else			delay = 1;	}	ma->mca_timer.expires = jiffies + delay;	if (!mod_timer(&ma->mca_timer, jiffies + delay))		atomic_inc(&ma->mca_refcnt);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -