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

📄 fib_frontend.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * INET		An implementation of the TCP/IP protocol suite for the LINUX *		operating system.  INET is implemented using the  BSD Socket *		interface as the means of communication with the user level. * *		IPv4 Forwarding Information Base: FIB frontend. * * Version:	$Id: fib_frontend.c,v 1.26 2001/10/31 21:55:54 davem Exp $ * * Authors:	Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> * *		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. */#include <linux/module.h>#include <asm/uaccess.h>#include <asm/system.h>#include <linux/bitops.h>#include <linux/capability.h>#include <linux/types.h>#include <linux/kernel.h>#include <linux/mm.h>#include <linux/string.h>#include <linux/socket.h>#include <linux/sockios.h>#include <linux/errno.h>#include <linux/in.h>#include <linux/inet.h>#include <linux/inetdevice.h>#include <linux/netdevice.h>#include <linux/if_addr.h>#include <linux/if_arp.h>#include <linux/skbuff.h>#include <linux/init.h>#include <linux/list.h>#include <net/ip.h>#include <net/protocol.h>#include <net/route.h>#include <net/tcp.h>#include <net/sock.h>#include <net/icmp.h>#include <net/arp.h>#include <net/ip_fib.h>#include <net/rtnetlink.h>#define FFprint(a...) printk(KERN_DEBUG a)static struct sock *fibnl;#ifndef CONFIG_IP_MULTIPLE_TABLESstruct fib_table *ip_fib_local_table;struct fib_table *ip_fib_main_table;#define FIB_TABLE_HASHSZ 1static struct hlist_head fib_table_hash[FIB_TABLE_HASHSZ];static void __init fib4_rules_init(void){	ip_fib_local_table = fib_hash_init(RT_TABLE_LOCAL);	hlist_add_head_rcu(&ip_fib_local_table->tb_hlist, &fib_table_hash[0]);	ip_fib_main_table  = fib_hash_init(RT_TABLE_MAIN);	hlist_add_head_rcu(&ip_fib_main_table->tb_hlist, &fib_table_hash[0]);}#else#define FIB_TABLE_HASHSZ 256static struct hlist_head fib_table_hash[FIB_TABLE_HASHSZ];struct fib_table *fib_new_table(u32 id){	struct fib_table *tb;	unsigned int h;	if (id == 0)		id = RT_TABLE_MAIN;	tb = fib_get_table(id);	if (tb)		return tb;	tb = fib_hash_init(id);	if (!tb)		return NULL;	h = id & (FIB_TABLE_HASHSZ - 1);	hlist_add_head_rcu(&tb->tb_hlist, &fib_table_hash[h]);	return tb;}struct fib_table *fib_get_table(u32 id){	struct fib_table *tb;	struct hlist_node *node;	unsigned int h;	if (id == 0)		id = RT_TABLE_MAIN;	h = id & (FIB_TABLE_HASHSZ - 1);	rcu_read_lock();	hlist_for_each_entry_rcu(tb, node, &fib_table_hash[h], tb_hlist) {		if (tb->tb_id == id) {			rcu_read_unlock();			return tb;		}	}	rcu_read_unlock();	return NULL;}#endif /* CONFIG_IP_MULTIPLE_TABLES */static void fib_flush(void){	int flushed = 0;	struct fib_table *tb;	struct hlist_node *node;	unsigned int h;	for (h = 0; h < FIB_TABLE_HASHSZ; h++) {		hlist_for_each_entry(tb, node, &fib_table_hash[h], tb_hlist)			flushed += tb->tb_flush(tb);	}	if (flushed)		rt_cache_flush(-1);}/* *	Find the first device with a given source address. */struct net_device * ip_dev_find(__be32 addr){	struct flowi fl = { .nl_u = { .ip4_u = { .daddr = addr } } };	struct fib_result res;	struct net_device *dev = NULL;	struct fib_table *local_table;#ifdef CONFIG_IP_MULTIPLE_TABLES	res.r = NULL;#endif	local_table = fib_get_table(RT_TABLE_LOCAL);	if (!local_table || local_table->tb_lookup(local_table, &fl, &res))		return NULL;	if (res.type != RTN_LOCAL)		goto out;	dev = FIB_RES_DEV(res);	if (dev)		dev_hold(dev);out:	fib_res_put(&res);	return dev;}unsigned inet_addr_type(__be32 addr){	struct flowi		fl = { .nl_u = { .ip4_u = { .daddr = addr } } };	struct fib_result	res;	unsigned ret = RTN_BROADCAST;	struct fib_table *local_table;	if (ZERONET(addr) || BADCLASS(addr))		return RTN_BROADCAST;	if (MULTICAST(addr))		return RTN_MULTICAST;#ifdef CONFIG_IP_MULTIPLE_TABLES	res.r = NULL;#endif	local_table = fib_get_table(RT_TABLE_LOCAL);	if (local_table) {		ret = RTN_UNICAST;		if (!local_table->tb_lookup(local_table, &fl, &res)) {			ret = res.type;			fib_res_put(&res);		}	}	return ret;}/* Given (packet source, input interface) and optional (dst, oif, tos):   - (main) check, that source is valid i.e. not broadcast or our local     address.   - figure out what "logical" interface this packet arrived     and calculate "specific destination" address.   - check, that packet arrived from expected physical interface. */int fib_validate_source(__be32 src, __be32 dst, u8 tos, int oif,			struct net_device *dev, __be32 *spec_dst, u32 *itag){	struct in_device *in_dev;	struct flowi fl = { .nl_u = { .ip4_u =				      { .daddr = src,					.saddr = dst,					.tos = tos } },			    .iif = oif };	struct fib_result res;	int no_addr, rpf;	int ret;	no_addr = rpf = 0;	rcu_read_lock();	in_dev = __in_dev_get_rcu(dev);	if (in_dev) {		no_addr = in_dev->ifa_list == NULL;		rpf = IN_DEV_RPFILTER(in_dev);	}	rcu_read_unlock();	if (in_dev == NULL)		goto e_inval;	if (fib_lookup(&fl, &res))		goto last_resort;	if (res.type != RTN_UNICAST)		goto e_inval_res;	*spec_dst = FIB_RES_PREFSRC(res);	fib_combine_itag(itag, &res);#ifdef CONFIG_IP_ROUTE_MULTIPATH	if (FIB_RES_DEV(res) == dev || res.fi->fib_nhs > 1)#else	if (FIB_RES_DEV(res) == dev)#endif	{		ret = FIB_RES_NH(res).nh_scope >= RT_SCOPE_HOST;		fib_res_put(&res);		return ret;	}	fib_res_put(&res);	if (no_addr)		goto last_resort;	if (rpf)		goto e_inval;	fl.oif = dev->ifindex;	ret = 0;	if (fib_lookup(&fl, &res) == 0) {		if (res.type == RTN_UNICAST) {			*spec_dst = FIB_RES_PREFSRC(res);			ret = FIB_RES_NH(res).nh_scope >= RT_SCOPE_HOST;		}		fib_res_put(&res);	}	return ret;last_resort:	if (rpf)		goto e_inval;	*spec_dst = inet_select_addr(dev, 0, RT_SCOPE_UNIVERSE);	*itag = 0;	return 0;e_inval_res:	fib_res_put(&res);e_inval:	return -EINVAL;}static inline __be32 sk_extract_addr(struct sockaddr *addr){	return ((struct sockaddr_in *) addr)->sin_addr.s_addr;}static int put_rtax(struct nlattr *mx, int len, int type, u32 value){	struct nlattr *nla;	nla = (struct nlattr *) ((char *) mx + len);	nla->nla_type = type;	nla->nla_len = nla_attr_size(4);	*(u32 *) nla_data(nla) = value;	return len + nla_total_size(4);}static int rtentry_to_fib_config(int cmd, struct rtentry *rt,				 struct fib_config *cfg){	__be32 addr;	int plen;	memset(cfg, 0, sizeof(*cfg));	if (rt->rt_dst.sa_family != AF_INET)		return -EAFNOSUPPORT;	/*	 * Check mask for validity:	 * a) it must be contiguous.	 * b) destination must have all host bits clear.	 * c) if application forgot to set correct family (AF_INET),	 *    reject request unless it is absolutely clear i.e.	 *    both family and mask are zero.	 */	plen = 32;	addr = sk_extract_addr(&rt->rt_dst);	if (!(rt->rt_flags & RTF_HOST)) {		__be32 mask = sk_extract_addr(&rt->rt_genmask);		if (rt->rt_genmask.sa_family != AF_INET) {			if (mask || rt->rt_genmask.sa_family)				return -EAFNOSUPPORT;		}		if (bad_mask(mask, addr))			return -EINVAL;		plen = inet_mask_len(mask);	}	cfg->fc_dst_len = plen;	cfg->fc_dst = addr;	if (cmd != SIOCDELRT) {		cfg->fc_nlflags = NLM_F_CREATE;		cfg->fc_protocol = RTPROT_BOOT;	}	if (rt->rt_metric)		cfg->fc_priority = rt->rt_metric - 1;	if (rt->rt_flags & RTF_REJECT) {		cfg->fc_scope = RT_SCOPE_HOST;		cfg->fc_type = RTN_UNREACHABLE;		return 0;	}	cfg->fc_scope = RT_SCOPE_NOWHERE;	cfg->fc_type = RTN_UNICAST;	if (rt->rt_dev) {		char *colon;		struct net_device *dev;		char devname[IFNAMSIZ];		if (copy_from_user(devname, rt->rt_dev, IFNAMSIZ-1))			return -EFAULT;		devname[IFNAMSIZ-1] = 0;		colon = strchr(devname, ':');		if (colon)			*colon = 0;		dev = __dev_get_by_name(&init_net, devname);		if (!dev)			return -ENODEV;		cfg->fc_oif = dev->ifindex;		if (colon) {			struct in_ifaddr *ifa;			struct in_device *in_dev = __in_dev_get_rtnl(dev);			if (!in_dev)				return -ENODEV;			*colon = ':';			for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next)				if (strcmp(ifa->ifa_label, devname) == 0)					break;			if (ifa == NULL)				return -ENODEV;			cfg->fc_prefsrc = ifa->ifa_local;		}	}	addr = sk_extract_addr(&rt->rt_gateway);	if (rt->rt_gateway.sa_family == AF_INET && addr) {		cfg->fc_gw = addr;		if (rt->rt_flags & RTF_GATEWAY &&		    inet_addr_type(addr) == RTN_UNICAST)			cfg->fc_scope = RT_SCOPE_UNIVERSE;	}	if (cmd == SIOCDELRT)		return 0;	if (rt->rt_flags & RTF_GATEWAY && !cfg->fc_gw)		return -EINVAL;	if (cfg->fc_scope == RT_SCOPE_NOWHERE)		cfg->fc_scope = RT_SCOPE_LINK;	if (rt->rt_flags & (RTF_MTU | RTF_WINDOW | RTF_IRTT)) {		struct nlattr *mx;		int len = 0;		mx = kzalloc(3 * nla_total_size(4), GFP_KERNEL);		if (mx == NULL)			return -ENOMEM;		if (rt->rt_flags & RTF_MTU)			len = put_rtax(mx, len, RTAX_ADVMSS, rt->rt_mtu - 40);		if (rt->rt_flags & RTF_WINDOW)			len = put_rtax(mx, len, RTAX_WINDOW, rt->rt_window);		if (rt->rt_flags & RTF_IRTT)			len = put_rtax(mx, len, RTAX_RTT, rt->rt_irtt << 3);		cfg->fc_mx = mx;		cfg->fc_mx_len = len;	}	return 0;}/* *	Handle IP routing ioctl calls. These are used to manipulate the routing tables */int ip_rt_ioctl(unsigned int cmd, void __user *arg){	struct fib_config cfg;	struct rtentry rt;	int err;	switch (cmd) {	case SIOCADDRT:		/* Add a route */	case SIOCDELRT:		/* Delete a route */		if (!capable(CAP_NET_ADMIN))			return -EPERM;		if (copy_from_user(&rt, arg, sizeof(rt)))			return -EFAULT;		rtnl_lock();		err = rtentry_to_fib_config(cmd, &rt, &cfg);		if (err == 0) {			struct fib_table *tb;			if (cmd == SIOCDELRT) {				tb = fib_get_table(cfg.fc_table);				if (tb)					err = tb->tb_delete(tb, &cfg);				else					err = -ESRCH;			} else {				tb = fib_new_table(cfg.fc_table);				if (tb)					err = tb->tb_insert(tb, &cfg);				else					err = -ENOBUFS;			}			/* allocated by rtentry_to_fib_config() */			kfree(cfg.fc_mx);		}		rtnl_unlock();		return err;	}	return -EINVAL;}const struct nla_policy rtm_ipv4_policy[RTA_MAX+1] = {	[RTA_DST]		= { .type = NLA_U32 },	[RTA_SRC]		= { .type = NLA_U32 },	[RTA_IIF]		= { .type = NLA_U32 },	[RTA_OIF]		= { .type = NLA_U32 },	[RTA_GATEWAY]		= { .type = NLA_U32 },	[RTA_PRIORITY]		= { .type = NLA_U32 },	[RTA_PREFSRC]		= { .type = NLA_U32 },	[RTA_METRICS]		= { .type = NLA_NESTED },	[RTA_MULTIPATH]		= { .len = sizeof(struct rtnexthop) },	[RTA_PROTOINFO]		= { .type = NLA_U32 },	[RTA_FLOW]		= { .type = NLA_U32 },

⌨️ 快捷键说明

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