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

📄 dn_fib.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * DECnet       An implementation of the DECnet protocol suite for the LINUX *              operating system.  DECnet is implemented using the  BSD Socket *              interface as the means of communication with the user level. * *              DECnet Routing Forwarding Information Base (Glue/Info List) * * Author:      Steve Whitehouse <SteveW@ACM.org> * * * Changes: *              Alexey Kuznetsov : SMP locking changes *              Steve Whitehouse : Rewrote it... Well to be more correct, I *                                 copied most of it from the ipv4 fib code. * */#include <linux/config.h>#include <linux/string.h>#include <linux/net.h>#include <linux/socket.h>#include <linux/sockios.h>#include <linux/init.h>#include <linux/skbuff.h>#include <linux/netlink.h>#include <linux/rtnetlink.h>#include <linux/proc_fs.h>#include <linux/netdevice.h>#include <linux/timer.h>#include <linux/spinlock.h>#include <asm/atomic.h>#include <asm/uaccess.h>#include <net/neighbour.h>#include <net/dst.h>#include <net/dn.h>#include <net/dn_route.h>#include <net/dn_fib.h>#include <net/dn_neigh.h>#include <net/dn_dev.h>#define for_fib_info() { struct dn_fib_info *fi;\	for(fi = dn_fib_info_list; fi; fi = fi->fib_next)#define endfor_fib_info() }#define for_nexthops(fi) { int nhsel; const struct dn_fib_nh *nh;\	for(nhsel = 0, nh = (fi)->fib_nh; nhsel < (fi)->fib_nhs; nh++, nhsel++)#define change_nexthops(fi) { int nhsel; struct dn_fib_nh *nh;\	for(nhsel = 0, nh = (struct dn_fib_nh *)((fi)->fib_nh); nhsel < (fi)->fib_nhs; nh++, nhsel++)#define endfor_nexthops(fi) }#ifdef CONFIG_RTNETLINKextern int dn_cache_dump(struct sk_buff *skb, struct netlink_callback *cb);#endif /* CONFIG_RTNETLINK */static struct dn_fib_info *dn_fib_info_list = NULL;static rwlock_t dn_fib_info_lock = RW_LOCK_UNLOCKED;int dn_fib_info_cnt;static struct{	int error;	u8 scope;} dn_fib_props[RTA_MAX+1] = {	{ 0, RT_SCOPE_NOWHERE },		/* RTN_UNSPEC */	{ 0, RT_SCOPE_UNIVERSE },		/* RTN_UNICAST */	{ 0, RT_SCOPE_HOST },			/* RTN_LOCAL */	{ -EINVAL, RT_SCOPE_NOWHERE },		/* RTN_BROADCAST */	{ -EINVAL, RT_SCOPE_NOWHERE },		/* RTN_ANYCAST */	{ -EINVAL, RT_SCOPE_NOWHERE },		/* RTN_MULTICAST */	{ -EINVAL, RT_SCOPE_UNIVERSE },		/* RTN_BLACKHOLE */	{ -EHOSTUNREACH, RT_SCOPE_UNIVERSE },	/* RTN_UNREACHABLE */	{ -EACCES, RT_SCOPE_UNIVERSE },		/* RTN_PROHIBIT */	{ -EAGAIN, RT_SCOPE_UNIVERSE },		/* RTN_THROW */	{ -EINVAL, RT_SCOPE_NOWHERE },		/* RTN_NAT */	{ -EINVAL, RT_SCOPE_NOWHERE }		/* RTN_XRESOLVE */};void dn_fib_free_info(struct dn_fib_info *fi){	if (fi->fib_dead == 0) {		printk(KERN_DEBUG "DECnet: BUG! Attempt to free alive dn_fib_info\n");		return;	}	change_nexthops(fi) {		if (nh->nh_dev)			dev_put(nh->nh_dev);		nh->nh_dev = NULL;	} endfor_nexthops(fi);	dn_fib_info_cnt--;	kfree(fi);}void dn_fib_release_info(struct dn_fib_info *fi){	write_lock(&dn_fib_info_lock);	if (fi && --fi->fib_treeref == 0) {		if (fi->fib_next)			fi->fib_next->fib_prev = fi->fib_prev;		if (fi->fib_prev)			fi->fib_prev->fib_next = fi->fib_next;		if (fi == dn_fib_info_list)			dn_fib_info_list = fi->fib_next;		fi->fib_dead = 1;		dn_fib_info_put(fi);	}	write_unlock(&dn_fib_info_lock);}static __inline__ int dn_fib_nh_comp(const struct dn_fib_info *fi, const struct dn_fib_info *ofi){	const struct dn_fib_nh *onh = ofi->fib_nh;	for_nexthops(fi) {		if (nh->nh_oif != onh->nh_oif ||			nh->nh_gw != onh->nh_gw ||			nh->nh_scope != onh->nh_scope ||			nh->nh_weight != onh->nh_weight ||			((nh->nh_flags^onh->nh_flags)&~RTNH_F_DEAD))				return -1;		onh++;	} endfor_nexthops(fi);	return 0;}static __inline__ struct dn_fib_info *dn_fib_find_info(const struct dn_fib_info *nfi){	for_fib_info() {		if (fi->fib_nhs != nfi->fib_nhs)			continue;		if (nfi->fib_protocol == fi->fib_protocol &&			nfi->fib_prefsrc == fi->fib_prefsrc &&			nfi->fib_priority == fi->fib_priority &&			((nfi->fib_flags^fi->fib_flags)&~RTNH_F_DEAD) == 0 &&			(nfi->fib_nhs == 0 || dn_fib_nh_comp(fi, nfi) == 0))				return fi;	} endfor_fib_info();	return NULL;}u16 dn_fib_get_attr16(struct rtattr *attr, int attrlen, int type){	while(RTA_OK(attr,attrlen)) {		if (attr->rta_type == type)			return *(u16*)RTA_DATA(attr);		attr = RTA_NEXT(attr, attrlen);	}	return 0;}static int dn_fib_count_nhs(struct rtattr *rta){	int nhs = 0;	struct rtnexthop *nhp = RTA_DATA(rta);	int nhlen = RTA_PAYLOAD(rta);	while(nhlen >= (int)sizeof(struct rtnexthop)) {		if ((nhlen -= nhp->rtnh_len) < 0)			return 0;		nhs++;		nhp = RTNH_NEXT(nhp);	}	return nhs;}static int dn_fib_get_nhs(struct dn_fib_info *fi, const struct rtattr *rta, const struct rtmsg *r){	struct rtnexthop *nhp = RTA_DATA(rta);	int nhlen = RTA_PAYLOAD(rta);	change_nexthops(fi) {		int attrlen = nhlen - sizeof(struct rtnexthop);		if (attrlen < 0 || (nhlen -= nhp->rtnh_len) < 0)			return -EINVAL;		nh->nh_flags  = (r->rtm_flags&~0xFF) | nhp->rtnh_flags;		nh->nh_oif    = nhp->rtnh_ifindex;		nh->nh_weight = nhp->rtnh_hops + 1;		if (attrlen) {			nh->nh_gw = dn_fib_get_attr16(RTNH_DATA(nhp), attrlen, RTA_GATEWAY);		}		nhp = RTNH_NEXT(nhp);	} endfor_nexthops(fi);	return 0;}static int dn_fib_check_nh(const struct rtmsg *r, struct dn_fib_info *fi, struct dn_fib_nh *nh){	int err;	if (nh->nh_gw) {		struct dn_fib_key key;		struct dn_fib_res res;		if (nh->nh_flags&RTNH_F_ONLINK) {			struct net_device *dev;			if (r->rtm_scope >= RT_SCOPE_LINK)				return -EINVAL;			if ((dev = __dev_get_by_index(nh->nh_oif)) == NULL)				return -ENODEV;			if (!(dev->flags&IFF_UP))				return -ENETDOWN;			nh->nh_dev = dev;			atomic_inc(&dev->refcnt);			nh->nh_scope = RT_SCOPE_LINK;			return 0;		}		memset(&key, 0, sizeof(key));		key.dst = nh->nh_gw;		key.oif = nh->nh_oif;		key.scope = r->rtm_scope + 1;		if (key.scope < RT_SCOPE_LINK)			key.scope = RT_SCOPE_LINK;		if ((err = dn_fib_lookup(&key, &res)) != 0)			return err;		nh->nh_scope = res.scope;		nh->nh_oif = DN_FIB_RES_OIF(res);		nh->nh_dev = DN_FIB_RES_DEV(res);		if (nh->nh_dev)			atomic_inc(&nh->nh_dev->refcnt);		dn_fib_res_put(&res);	} else {		struct net_device *dev;		if (nh->nh_flags&(RTNH_F_PERVASIVE|RTNH_F_ONLINK))			return -EINVAL;		dev = __dev_get_by_index(nh->nh_oif);		if (dev == NULL || dev->dn_ptr == NULL)			return -ENODEV;		if (!(dev->flags&IFF_UP))			return -ENETDOWN;		nh->nh_dev = dev;		atomic_inc(&nh->nh_dev->refcnt);		nh->nh_scope = RT_SCOPE_HOST;	}	return 0;}struct dn_fib_info *dn_fib_create_info(const struct rtmsg *r, struct dn_kern_rta *rta, const struct nlmsghdr *nlh, int *errp){	int err;	struct dn_fib_info *fi = NULL;	struct dn_fib_info *ofi;	int nhs = 1;	if (dn_fib_props[r->rtm_type].scope > r->rtm_scope)		goto err_inval;	if (rta->rta_mp) {		nhs = dn_fib_count_nhs(rta->rta_mp);		if (nhs == 0)			goto err_inval;	}	fi = kmalloc(sizeof(*fi)+nhs*sizeof(struct dn_fib_nh), GFP_KERNEL);	err = -ENOBUFS;	if (fi == NULL)		goto failure;	memset(fi, 0, sizeof(*fi)+nhs*sizeof(struct dn_fib_nh));	fi->fib_protocol = r->rtm_protocol;	fi->fib_nhs = nhs;	fi->fib_flags = r->rtm_flags;	if (rta->rta_priority)		fi->fib_priority = *rta->rta_priority;	if (rta->rta_prefsrc)		memcpy(&fi->fib_prefsrc, rta->rta_prefsrc, 2);	if (rta->rta_mp) {		if ((err = dn_fib_get_nhs(fi, rta->rta_mp, r)) != 0)			goto failure;		if (rta->rta_oif && fi->fib_nh->nh_oif != *rta->rta_oif)			goto err_inval;		if (rta->rta_gw && memcmp(&fi->fib_nh->nh_gw, rta->rta_gw, 2))			goto err_inval;	} else {		struct dn_fib_nh *nh = fi->fib_nh;		if (rta->rta_oif)			nh->nh_oif = *rta->rta_oif;		if (rta->rta_gw)			memcpy(&nh->nh_gw, rta->rta_gw, 2);		nh->nh_flags = r->rtm_flags;		nh->nh_weight = 1;	}	if (dn_fib_props[r->rtm_type].error) {		if (rta->rta_gw || rta->rta_oif || rta->rta_mp)			goto err_inval;		goto link_it;	}	if (r->rtm_scope > RT_SCOPE_HOST)		goto err_inval;	if (r->rtm_scope == RT_SCOPE_HOST) {		struct dn_fib_nh *nh = fi->fib_nh;		/* Local address is added */		if (nhs != 1 || nh->nh_gw)			goto err_inval;		nh->nh_scope = RT_SCOPE_NOWHERE;		nh->nh_dev = dev_get_by_index(fi->fib_nh->nh_oif);		err = -ENODEV;		if (nh->nh_dev == NULL)			goto failure;	} else {		change_nexthops(fi) {			if ((err = dn_fib_check_nh(r, fi, nh)) != 0)				goto failure;		} endfor_nexthops(fi)	}#if I_GET_AROUND_TO_FIXING_PREFSRC	if (fi->fib_prefsrc) {		if (r->rtm_type != RTN_LOCAL || rta->rta_dst == NULL ||		    memcmp(&fi->fib_prefsrc, rta->rta_dst, 2))			if (dn_addr_type(fi->fib_prefsrc) != RTN_LOCAL)				goto err_inval;	}#endif

⌨️ 快捷键说明

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