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

📄 route.c

📁 嵌入式系统设计与实验教材二源码linux内核移植与编译
💻 C
📖 第 1 页 / 共 3 页
字号:
int ip6_route_add(struct in6_rtmsg *rtmsg){	int err;	struct rt6_info *rt;	struct net_device *dev = NULL;	int addr_type;	if (rtmsg->rtmsg_dst_len > 128 || rtmsg->rtmsg_src_len > 128)		return -EINVAL;#ifndef CONFIG_IPV6_SUBTREES	if (rtmsg->rtmsg_src_len)		return -EINVAL;#endif	if (rtmsg->rtmsg_metric == 0)		rtmsg->rtmsg_metric = IP6_RT_PRIO_USER;	rt = dst_alloc(&ip6_dst_ops);	if (rt == NULL)		return -ENOMEM;	rt->u.dst.obsolete = -1;	rt->rt6i_expires = rtmsg->rtmsg_info;	addr_type = ipv6_addr_type(&rtmsg->rtmsg_dst);	if (addr_type & IPV6_ADDR_MULTICAST)		rt->u.dst.input = ip6_mc_input;	else		rt->u.dst.input = ip6_forward;	rt->u.dst.output = ip6_output;	if (rtmsg->rtmsg_ifindex) {		dev = dev_get_by_index(rtmsg->rtmsg_ifindex);		err = -ENODEV;		if (dev == NULL)			goto out;	}	ipv6_addr_copy(&rt->rt6i_dst.addr, &rtmsg->rtmsg_dst);	rt->rt6i_dst.plen = rtmsg->rtmsg_dst_len;	if (rt->rt6i_dst.plen == 128)	       rt->u.dst.flags = DST_HOST;	ipv6_wash_prefix(&rt->rt6i_dst.addr, rt->rt6i_dst.plen);#ifdef CONFIG_IPV6_SUBTREES	ipv6_addr_copy(&rt->rt6i_src.addr, &rtmsg->rtmsg_src);	rt->rt6i_src.plen = rtmsg->rtmsg_src_len;	ipv6_wash_prefix(&rt->rt6i_src.addr, rt->rt6i_src.plen);#endif	rt->rt6i_metric = rtmsg->rtmsg_metric;	/* We cannot add true routes via loopback here,	   they would result in kernel looping; promote them to reject routes	 */	if ((rtmsg->rtmsg_flags&RTF_REJECT) ||	    (dev && (dev->flags&IFF_LOOPBACK) && !(addr_type&IPV6_ADDR_LOOPBACK))) {		if (dev)			dev_put(dev);		dev = &loopback_dev;		dev_hold(dev);		rt->u.dst.output = ip6_pkt_discard;		rt->u.dst.input = ip6_pkt_discard;		rt->u.dst.error = -ENETUNREACH;		rt->rt6i_flags = RTF_REJECT|RTF_NONEXTHOP;		goto install_route;	}	if (rtmsg->rtmsg_flags & RTF_GATEWAY) {		struct in6_addr *gw_addr;		int gwa_type;		gw_addr = &rtmsg->rtmsg_gateway;		ipv6_addr_copy(&rt->rt6i_gateway, &rtmsg->rtmsg_gateway);		gwa_type = ipv6_addr_type(gw_addr);		if (gwa_type != (IPV6_ADDR_LINKLOCAL|IPV6_ADDR_UNICAST)) {			struct rt6_info *grt;			/* IPv6 strictly inhibits using not link-local			   addresses as nexthop address.			   Otherwise, router will not able to send redirects.			   It is very good, but in some (rare!) curcumstances			   (SIT, PtP, NBMA NOARP links) it is handy to allow			   some exceptions. --ANK			 */			err = -EINVAL;			if (!(gwa_type&IPV6_ADDR_UNICAST))				goto out;			grt = rt6_lookup(gw_addr, NULL, rtmsg->rtmsg_ifindex, 1);			err = -EHOSTUNREACH;			if (grt == NULL)				goto out;			if (dev) {				if (dev != grt->rt6i_dev) {					dst_release(&grt->u.dst);					goto out;				}			} else {				dev = grt->rt6i_dev;				dev_hold(dev);			}			if (!(grt->rt6i_flags&RTF_GATEWAY))				err = 0;			dst_release(&grt->u.dst);			if (err)				goto out;		}		err = -EINVAL;		if (dev == NULL || (dev->flags&IFF_LOOPBACK))			goto out;	}	err = -ENODEV;	if (dev == NULL)		goto out;	if (rtmsg->rtmsg_flags & (RTF_GATEWAY|RTF_NONEXTHOP)) {		rt->rt6i_nexthop = __neigh_lookup_errno(&nd_tbl, &rt->rt6i_gateway, dev);		if (IS_ERR(rt->rt6i_nexthop)) {			err = PTR_ERR(rt->rt6i_nexthop);			rt->rt6i_nexthop = NULL;			goto out;		}	}	if (ipv6_addr_is_multicast(&rt->rt6i_dst.addr))		rt->rt6i_hoplimit = IPV6_DEFAULT_MCASTHOPS;	else		rt->rt6i_hoplimit = ipv6_get_hoplimit(dev);	rt->rt6i_flags = rtmsg->rtmsg_flags;install_route:	rt->u.dst.pmtu = ipv6_get_mtu(dev);	rt->u.dst.advmss = max_t(unsigned int, rt->u.dst.pmtu - 60, ip6_rt_min_advmss);	/* Maximal non-jumbo IPv6 payload is 65535 and corresponding	   MSS is 65535 - tcp_header_size. 65535 is also valid and	   means: "any MSS, rely only on pmtu discovery"	 */	if (rt->u.dst.advmss > 65535-20)		rt->u.dst.advmss = 65535;	rt->u.dst.dev = dev;	return rt6_ins(rt);out:	if (dev)		dev_put(dev);	dst_free((struct dst_entry *) rt);	return err;}int ip6_del_rt(struct rt6_info *rt){	int err;	write_lock_bh(&rt6_lock);	spin_lock_bh(&rt6_dflt_lock);	rt6_dflt_pointer = NULL;	spin_unlock_bh(&rt6_dflt_lock);	dst_release(&rt->u.dst);	err = fib6_del(rt);	write_unlock_bh(&rt6_lock);	return err;}int ip6_route_del(struct in6_rtmsg *rtmsg){	struct fib6_node *fn;	struct rt6_info *rt;	int err = -ESRCH;	read_lock_bh(&rt6_lock);	fn = fib6_locate(&ip6_routing_table,			 &rtmsg->rtmsg_dst, rtmsg->rtmsg_dst_len,			 &rtmsg->rtmsg_src, rtmsg->rtmsg_src_len);		if (fn) {		for (rt = fn->leaf; rt; rt = rt->u.next) {			if (rtmsg->rtmsg_ifindex &&			    (rt->rt6i_dev == NULL ||			     rt->rt6i_dev->ifindex != rtmsg->rtmsg_ifindex))				continue;			if (rtmsg->rtmsg_flags&RTF_GATEWAY &&			    ipv6_addr_cmp(&rtmsg->rtmsg_gateway, &rt->rt6i_gateway))				continue;			if (rtmsg->rtmsg_metric &&			    rtmsg->rtmsg_metric != rt->rt6i_metric)				continue;			dst_clone(&rt->u.dst);			read_unlock_bh(&rt6_lock);			return ip6_del_rt(rt);		}	}	read_unlock_bh(&rt6_lock);	return err;}/* *	Handle redirects */void rt6_redirect(struct in6_addr *dest, struct in6_addr *saddr,		  struct neighbour *neigh, int on_link){	struct rt6_info *rt, *nrt;	/* Locate old route to this destination. */	rt = rt6_lookup(dest, NULL, neigh->dev->ifindex, 1);	if (rt == NULL)		return;	if (neigh->dev != rt->rt6i_dev)		goto out;	/* Redirect received -> path was valid.	   Look, redirects are sent only in response to data packets,	   so that this nexthop apparently is reachable. --ANK	 */	dst_confirm(&rt->u.dst);	/* Duplicate redirect: silently ignore. */	if (neigh == rt->u.dst.neighbour)		goto out;	/* Current route is on-link; redirect is always invalid.	   	   Seems, previous statement is not true. It could	   be node, which looks for us as on-link (f.e. proxy ndisc)	   But then router serving it might decide, that we should	   know truth 8)8) --ANK (980726).	 */	if (!(rt->rt6i_flags&RTF_GATEWAY))		goto out;	/*	 *	RFC 1970 specifies that redirects should only be	 *	accepted if they come from the nexthop to the target.	 *	Due to the way default routers are chosen, this notion	 *	is a bit fuzzy and one might need to check all default	 *	routers.	 */	if (ipv6_addr_cmp(saddr, &rt->rt6i_gateway)) {		if (rt->rt6i_flags & RTF_DEFAULT) {			struct rt6_info *rt1;			read_lock(&rt6_lock);			for (rt1 = ip6_routing_table.leaf; rt1; rt1 = rt1->u.next) {				if (!ipv6_addr_cmp(saddr, &rt1->rt6i_gateway)) {					dst_clone(&rt1->u.dst);					dst_release(&rt->u.dst);					read_unlock(&rt6_lock);					rt = rt1;					goto source_ok;				}			}			read_unlock(&rt6_lock);		}		if (net_ratelimit())			printk(KERN_DEBUG "rt6_redirect: source isn't a valid nexthop "			       "for redirect target\n");		goto out;	}source_ok:	/*	 *	We have finally decided to accept it.	 */	nrt = ip6_rt_copy(rt);	if (nrt == NULL)		goto out;	nrt->rt6i_flags = RTF_GATEWAY|RTF_UP|RTF_DYNAMIC|RTF_CACHE;	if (on_link)		nrt->rt6i_flags &= ~RTF_GATEWAY;	ipv6_addr_copy(&nrt->rt6i_dst.addr, dest);	nrt->rt6i_dst.plen = 128;	nrt->u.dst.flags |= DST_HOST;	ipv6_addr_copy(&nrt->rt6i_gateway, (struct in6_addr*)neigh->primary_key);	nrt->rt6i_nexthop = neigh_clone(neigh);	/* Reset pmtu, it may be better */	nrt->u.dst.pmtu = ipv6_get_mtu(neigh->dev);	nrt->u.dst.advmss = max_t(unsigned int, nrt->u.dst.pmtu - 60, ip6_rt_min_advmss);	if (rt->u.dst.advmss > 65535-20)		rt->u.dst.advmss = 65535;	nrt->rt6i_hoplimit = ipv6_get_hoplimit(neigh->dev);	if (rt6_ins(nrt))		goto out;	if (rt->rt6i_flags&RTF_CACHE) {		ip6_del_rt(rt);		return;	}out:        dst_release(&rt->u.dst);	return;}/* *	Handle ICMP "packet too big" messages *	i.e. Path MTU discovery */void rt6_pmtu_discovery(struct in6_addr *daddr, struct in6_addr *saddr,			struct net_device *dev, u32 pmtu){	struct rt6_info *rt, *nrt;	if (pmtu < IPV6_MIN_MTU) {		if (net_ratelimit())			printk(KERN_DEBUG "rt6_pmtu_discovery: invalid MTU value %d\n",			       pmtu);		return;	}	rt = rt6_lookup(daddr, saddr, dev->ifindex, 0);	if (rt == NULL)		return;	if (pmtu >= rt->u.dst.pmtu)		goto out;	/* New mtu received -> path was valid.	   They are sent only in response to data packets,	   so that this nexthop apparently is reachable. --ANK	 */	dst_confirm(&rt->u.dst);	/* Host route. If it is static, it would be better	   not to override it, but add new one, so that	   when cache entry will expire old pmtu	   would return automatically.	 */	if (rt->rt6i_flags & RTF_CACHE) {		rt->u.dst.pmtu = pmtu;		dst_set_expires(&rt->u.dst, ip6_rt_mtu_expires);		rt->rt6i_flags |= RTF_MODIFIED|RTF_EXPIRES;		goto out;	}	/* Network route.	   Two cases are possible:	   1. It is connected route. Action: COW	   2. It is gatewayed route or NONEXTHOP route. Action: clone it.	 */	if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP)) {		nrt = rt6_cow(rt, daddr, saddr);		if (!nrt->u.dst.error) {			nrt->u.dst.pmtu = pmtu;			dst_set_expires(&rt->u.dst, ip6_rt_mtu_expires);			nrt->rt6i_flags |= RTF_DYNAMIC|RTF_EXPIRES;			dst_release(&nrt->u.dst);		}	} else {		nrt = ip6_rt_copy(rt);		if (nrt == NULL)			goto out;		ipv6_addr_copy(&nrt->rt6i_dst.addr, daddr);		nrt->rt6i_dst.plen = 128;		nrt->u.dst.flags |= DST_HOST;		nrt->rt6i_nexthop = neigh_clone(rt->rt6i_nexthop);		dst_set_expires(&rt->u.dst, ip6_rt_mtu_expires);		nrt->rt6i_flags |= RTF_DYNAMIC|RTF_CACHE|RTF_EXPIRES;		nrt->u.dst.pmtu = pmtu;		rt6_ins(nrt);	}out:	dst_release(&rt->u.dst);}/* *	Misc support functions */static struct rt6_info * ip6_rt_copy(struct rt6_info *ort){	struct rt6_info *rt;	rt = dst_alloc(&ip6_dst_ops);	if (rt) {		rt->u.dst.input = ort->u.dst.input;		rt->u.dst.output = ort->u.dst.output;		memcpy(&rt->u.dst.mxlock, &ort->u.dst.mxlock, RTAX_MAX*sizeof(unsigned));		rt->u.dst.dev = ort->u.dst.dev;		if (rt->u.dst.dev)			dev_hold(rt->u.dst.dev);		rt->u.dst.lastuse = jiffies;		rt->rt6i_hoplimit = ort->rt6i_hoplimit;		rt->rt6i_expires = 0;		ipv6_addr_copy(&rt->rt6i_gateway, &ort->rt6i_gateway);		rt->rt6i_flags = ort->rt6i_flags & ~RTF_EXPIRES;		rt->rt6i_metric = 0;		memcpy(&rt->rt6i_dst, &ort->rt6i_dst, sizeof(struct rt6key));#ifdef CONFIG_IPV6_SUBTREES		memcpy(&rt->rt6i_src, &ort->rt6i_src, sizeof(struct rt6key));#endif	}	return rt;}struct rt6_info *rt6_get_dflt_router(struct in6_addr *addr, struct net_device *dev){		struct rt6_info *rt;	struct fib6_node *fn;	fn = &ip6_routing_table;	write_lock_bh(&rt6_lock);	for (rt = fn->leaf; rt; rt=rt->u.next) {		if (dev == rt->rt6i_dev &&		    ipv6_addr_cmp(&rt->rt6i_gateway, addr) == 0)			break;	}	if (rt)		dst_clone(&rt->u.dst);	write_unlock_bh(&rt6_lock);	return rt;}struct rt6_info *rt6_add_dflt_router(struct in6_addr *gwaddr,				     struct net_device *dev){	struct in6_rtmsg rtmsg;	memset(&rtmsg, 0, sizeof(struct in6_rtmsg));	rtmsg.rtmsg_type = RTMSG_NEWROUTE;	ipv6_addr_copy(&rtmsg.rtmsg_gateway, gwaddr);	rtmsg.rtmsg_metric = 1024;	rtmsg.rtmsg_flags = RTF_GATEWAY | RTF_ADDRCONF | RTF_DEFAULT | RTF_UP;	rtmsg.rtmsg_ifindex = dev->ifindex;	ip6_route_add(&rtmsg);	return rt6_get_dflt_router(gwaddr, dev);}void rt6_purge_dflt_routers(int last_resort){	struct rt6_info *rt;	u32 flags;	if (last_resort)		flags = RTF_ALLONLINK;	else		flags = RTF_DEFAULT | RTF_ADDRCONF;	restart:	read_lock_bh(&rt6_lock);	for (rt = ip6_routing_table.leaf; rt; rt = rt->u.next) {		if (rt->rt6i_flags & flags) {			dst_hold(&rt->u.dst);			spin_lock_bh(&rt6_dflt_lock);			rt6_dflt_pointer = NULL;			spin_unlock_bh(&rt6_dflt_lock);			read_unlock_bh(&rt6_lock);			ip6_del_rt(rt);			goto restart;		}	}	read_unlock_bh(&rt6_lock);}int ipv6_route_ioctl(unsigned int cmd, void *arg){	struct in6_rtmsg rtmsg;	int err;	switch(cmd) {	case SIOCADDRT:		/* Add a route */	case SIOCDELRT:		/* Delete a route */		if (!capable(CAP_NET_ADMIN))			return -EPERM;		err = copy_from_user(&rtmsg, arg,				     sizeof(struct in6_rtmsg));		if (err)			return -EFAULT;					rtnl_lock();		switch (cmd) {		case SIOCADDRT:			err = ip6_route_add(&rtmsg);			break;		case SIOCDELRT:			err = ip6_route_del(&rtmsg);			break;		default:			err = -EINVAL;		}		rtnl_unlock();		return err;	};	return -EINVAL;}/* *	Drop the packet on the floor */int ip6_pkt_discard(struct sk_buff *skb){	IP6_INC_STATS(Ip6OutNoRoutes);	icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_ADDR_UNREACH, 0, skb->dev);	kfree_skb(skb);	return 0;}/* *	Add address */int ip6_rt_addr_add(struct in6_addr *addr, struct net_device *dev){	struct rt6_info *rt;	rt = dst_alloc(&ip6_dst_ops);	if (rt == NULL)		return -ENOMEM;	rt->u.dst.flags = DST_HOST;	rt->u.dst.input = ip6_input;	rt->u.dst.output = ip6_output;	rt->rt6i_dev = dev_get_by_name("lo");	rt->u.dst.pmtu = ipv6_get_mtu(rt->rt6i_dev);	rt->u.dst.advmss = max_t(unsigned int, rt->u.dst.pmtu - 60, ip6_rt_min_advmss);	if (rt->u.dst.advmss > 65535-20)		rt->u.dst.advmss = 65535;	rt->rt6i_hoplimit = ipv6_get_hoplimit(rt->rt6i_dev);	rt->u.dst.obsolete = -1;	rt->rt6i_flags = RTF_UP | RTF_NONEXTHOP;	rt->rt6i_nexthop = ndisc_get_neigh(rt->rt6i_dev, &rt->rt6i_gateway);	if (rt->rt6i_nexthop == NULL) {		dst_free((struct dst_entry *) rt);		return -ENOMEM;	}	ipv6_addr_copy(&rt->rt6i_dst.addr, addr);	rt->rt6i_dst.plen = 128;	rt6_ins(rt);	return 0;}/* Delete address. Warning: you should check that this address   disappeared before calling this function. */int ip6_rt_addr_del(struct in6_addr *addr, struct net_device *dev){	struct rt6_info *rt;	int err = -ENOENT;	rt = rt6_lookup(addr, NULL, loopback_dev.ifindex, 1);	if (rt) {		if (rt->rt6i_dst.plen == 128)			err = ip6_del_rt(rt);		else			dst_release(&rt->u.dst);	}	return err;}#ifdef CONFIG_RT6_POLICYstatic int rt6_flow_match_in(struct rt6_info *rt, struct sk_buff *skb){	struct flow_filter *frule;	struct pkt_filter *filter;	int res = 1;	if ((frule = rt->rt6i_filter) == NULL)		goto out;	if (frule->type != FLR_INPUT) {		res = 0;		goto out;	}	for (filter = frule->u.filter; filter; filter = filter->next) {		__u32 *word;		word = (__u32 *) skb->h.raw;		word += filter->offset;		if ((*word ^ filter->value) & filter->mask) {			res = 0;			break;		}	}out:	return res;}static int rt6_flow_match_out(struct rt6_info *rt, struct sock *sk){	struct flow_filter *frule;	int res = 1;	if ((frule = rt->rt6i_filter) == NULL)		goto out;	if (frule->type != FLR_INPUT) {		res = 0;		goto out;	}	if (frule->u.sk != sk)		res = 0;out:	return res;}static struct rt6_info *rt6_flow_lookup(struct rt6_info *rt,					struct in6_addr *daddr,					struct in6_addr *saddr,					struct fl_acc_args *args)

⌨️ 快捷键说明

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