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

📄 route.c

📁 Linux Kernel 2.6.9 for OMAP1710
💻 C
📖 第 1 页 / 共 4 页
字号:
	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_hold(&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.	 */	neigh_update(neigh, lladdr, NUD_STALE, 		     NEIGH_UPDATE_F_WEAK_OVERRIDE|		     NEIGH_UPDATE_F_OVERRIDE|		     (on_link ? 0 : (NEIGH_UPDATE_F_OVERRIDE_ISROUTER|				     NEIGH_UPDATE_F_ISROUTER))		     );	/*	 * 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;	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.metrics[RTAX_MTU-1] = ipv6_get_mtu(neigh->dev);	nrt->u.dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(dst_pmtu(&nrt->u.dst));	if (ip6_ins_rt(nrt, NULL, NULL))		goto out;	if (rt->rt6i_flags&RTF_CACHE) {		ip6_del_rt(rt, NULL, NULL);		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);		/* According to RFC1981, the PMTU is set to the IPv6 minimum		   link MTU if the node receives a Packet Too Big message		   reporting next-hop MTU that is less than the IPv6 minimum MTU.		   */		pmtu = IPV6_MIN_MTU;	}	rt = rt6_lookup(daddr, saddr, dev->ifindex, 0);	if (rt == NULL)		return;	if (pmtu >= dst_pmtu(&rt->u.dst))		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.metrics[RTAX_MTU-1] = 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.metrics[RTAX_MTU-1] = pmtu;			/* According to RFC 1981, detecting PMTU increase shouldn't be			   happened within 5 mins, the recommended timer is 10 mins.			   Here this route expiration time is set to ip6_rt_mtu_expires			   which is 10 mins. After 10 mins the decreased pmtu is expired			   and detecting PMTU increase will be automatically happened.			 */			dst_set_expires(&nrt->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(&nrt->u.dst, ip6_rt_mtu_expires);		nrt->rt6i_flags |= RTF_DYNAMIC|RTF_CACHE|RTF_EXPIRES;		nrt->u.dst.metrics[RTAX_MTU-1] = pmtu;		ip6_ins_rt(nrt, NULL, NULL);	}out:	dst_release(&rt->u.dst);}/* *	Misc support functions */static struct rt6_info * ip6_rt_copy(struct rt6_info *ort){	struct rt6_info *rt = ip6_dst_alloc();	if (rt) {		rt->u.dst.input = ort->u.dst.input;		rt->u.dst.output = ort->u.dst.output;		memcpy(rt->u.dst.metrics, ort->u.dst.metrics, RTAX_MAX*sizeof(u32));		rt->u.dst.dev = ort->u.dst.dev;		if (rt->u.dst.dev)			dev_hold(rt->u.dst.dev);		rt->rt6i_idev = ort->rt6i_idev;		if (rt->rt6i_idev)			in6_dev_hold(rt->rt6i_idev);		rt->u.dst.lastuse = jiffies;		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_hold(&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 | RTF_EXPIRES;	rtmsg.rtmsg_ifindex = dev->ifindex;	ip6_route_add(&rtmsg, NULL, NULL);	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);			rt6_reset_dflt_pointer(NULL);			read_unlock_bh(&rt6_lock);			ip6_del_rt(rt, NULL, NULL);			goto restart;		}	}	read_unlock_bh(&rt6_lock);}int ipv6_route_ioctl(unsigned int cmd, void __user *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, NULL, NULL);			break;		case SIOCDELRT:			err = ip6_route_del(&rtmsg, NULL, NULL);			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(IPSTATS_MIB_OUTNOROUTES);	icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_NOROUTE, 0, skb->dev);	kfree_skb(skb);	return 0;}int ip6_pkt_discard_out(struct sk_buff **pskb){	(*pskb)->dev = (*pskb)->dst->dev;	BUG_ON(!(*pskb)->dev);	return ip6_pkt_discard(*pskb);}/* *	Allocate a dst for local (unicast / anycast) address. */struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev,				    const struct in6_addr *addr,				    int anycast){	struct rt6_info *rt = ip6_dst_alloc();	if (rt == NULL)		return ERR_PTR(-ENOMEM);	dev_hold(&loopback_dev);	in6_dev_hold(idev);	rt->u.dst.flags = DST_HOST;	rt->u.dst.input = ip6_input;	rt->u.dst.output = ip6_output;	rt->rt6i_dev = &loopback_dev;	rt->rt6i_idev = idev;	rt->u.dst.metrics[RTAX_MTU-1] = ipv6_get_mtu(rt->rt6i_dev);	rt->u.dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(dst_pmtu(&rt->u.dst));	rt->u.dst.metrics[RTAX_HOPLIMIT-1] = ipv6_get_hoplimit(rt->rt6i_dev);	rt->u.dst.obsolete = -1;	rt->rt6i_flags = RTF_UP | RTF_NONEXTHOP;	if (!anycast)		rt->rt6i_flags |= RTF_LOCAL;	rt->rt6i_nexthop = ndisc_get_neigh(rt->rt6i_dev, &rt->rt6i_gateway);	if (rt->rt6i_nexthop == NULL) {		dst_free((struct dst_entry *) rt);		return ERR_PTR(-ENOMEM);	}	ipv6_addr_copy(&rt->rt6i_dst.addr, addr);	rt->rt6i_dst.plen = 128;	atomic_set(&rt->u.dst.__refcnt, 1);	return rt;}static int fib6_ifdown(struct rt6_info *rt, void *arg){	if (((void*)rt->rt6i_dev == arg || arg == NULL) &&	    rt != &ip6_null_entry) {		RT6_TRACE("deleted by ifdown %p\n", rt);		return -1;	}	return 0;}void rt6_ifdown(struct net_device *dev){	write_lock_bh(&rt6_lock);	fib6_clean_tree(&ip6_routing_table, fib6_ifdown, 0, dev);	write_unlock_bh(&rt6_lock);}struct rt6_mtu_change_arg{	struct net_device *dev;	unsigned mtu;};static int rt6_mtu_change_route(struct rt6_info *rt, void *p_arg){	struct rt6_mtu_change_arg *arg = (struct rt6_mtu_change_arg *) p_arg;	struct inet6_dev *idev;	/* In IPv6 pmtu discovery is not optional,	   so that RTAX_MTU lock cannot disable it.	   We still use this lock to block changes	   caused by addrconf/ndisc.	*/	idev = __in6_dev_get(arg->dev);	if (idev == NULL)		return 0;	/* For administrative MTU increase, there is no way to discover	   IPv6 PMTU increase, so PMTU increase should be updated here.	   Since RFC 1981 doesn't include administrative MTU increase	   update PMTU increase is a MUST. (i.e. jumbo frame)	 */	/*	   If new MTU is less than route PMTU, this new MTU will be the	   lowest MTU in the path, update the route PMTU to reflect PMTU	   decreases; if new MTU is greater than route PMTU, and the	   old MTU is the lowest MTU in the path, update the route PMTU	   to reflect the increase. In this case if the other nodes' MTU	   also have the lowest MTU, TOO BIG MESSAGE will be lead to	   PMTU discouvery.	 */	if (rt->rt6i_dev == arg->dev &&	    !dst_metric_locked(&rt->u.dst, RTAX_MTU) &&            (dst_pmtu(&rt->u.dst) > arg->mtu ||             (dst_pmtu(&rt->u.dst) < arg->mtu &&	      dst_pmtu(&rt->u.dst) == idev->cnf.mtu6)))		rt->u.dst.metrics[RTAX_MTU-1] = arg->mtu;	rt->u.dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(arg->mtu);	return 0;}void rt6_mtu_change(struct net_device *dev, unsigned mtu){	struct rt6_mtu_change_arg arg;	arg.dev = dev;	arg.mtu = mtu;	read_lock_bh(&rt6_lock);	fib6_clean_tree(&ip6_routing_table, rt6_mtu_change_route, 0, &arg);	read_unlock_bh(&rt6_lock);}static int inet6_rtm_to_rtmsg(struct rtmsg *r, struct rtattr **rta,			      struct in6_rtmsg *rtmsg){	memset(rtmsg, 0, sizeof(*rtmsg));	rtmsg->rtmsg_dst_len = r->rtm_dst_len;	rtmsg->rtmsg_src_len = r->rtm_src_len;	rtmsg->rtmsg_flags = RTF_UP;	if (r->rtm_type == RTN_UNREACHABLE)		rtmsg->rtmsg_flags |= RTF_REJECT;	if (rta[RTA_GATEWAY-1]) {		if (rta[RTA_GATEWAY-1]->rta_len != RTA_LENGTH(16))			return -EINVAL;		memcpy(&rtmsg->rtmsg_gateway, RTA_DATA(rta[RTA_GATEWAY-1]), 16);		rtmsg->rtmsg_flags |= RTF_GATEWAY;	}	if (rta[RTA_DST-1]) {		if (RTA_PAYLOAD(rta[RTA_DST-1]) < ((r->rtm_dst_len+7)>>3))			return -EINVAL;		memcpy(&rtmsg->rtmsg_dst, RTA_DATA(rta[RTA_DST-1]), ((r->rtm_dst_len+7)>>3));	}	if (rta[RTA_SRC-1]) {		if (RTA_PAYLOAD(rta[RTA_SRC-1]) < ((r->rtm_src_len+7)>>3))			return -EINVAL;		memcpy(&rtmsg->rtmsg_src, RTA_DATA(rta[RTA_SRC-1]), ((r->rtm_src_len+7)>>3));	}	if (rta[RTA_OIF-1]) {		if (rta[RTA_OIF-1]->rta_len != RTA_LENGTH(sizeof(int)))			return -EINVAL;		memcpy(&rtmsg->rtmsg_ifindex, RTA_DATA(rta[RTA_OIF-1]), sizeof(int));	}	if (rta[RTA_PRIORITY-1]) {		if (rta[RTA_PRIORITY-1]->rta_len != RTA_LENGTH(4))			return -EINVAL;		memcpy(&rtmsg->rtmsg_metric, RTA_DATA(rta[RTA_PRIORITY-1]), 4);	}	return 0;}int inet6_rtm_delroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg){	struct rtmsg *r = NLMSG_DATA(nlh);	struct in6_rtmsg rtmsg;	if (inet6_rtm_to_rtmsg(r, arg, &rtmsg))		return -EINVAL;	return ip6_route_del(&rtmsg, nlh, arg);}int inet6_rtm_newroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg){	struct rtmsg *r = NLMSG_DATA(nlh);	struct in6_rtmsg rtmsg;	if (inet6_rtm_to_rtmsg(r, arg, &rtmsg))		return -EINVAL;	return ip6_route_add(&rtmsg, nlh, arg);}struct rt6_rtnl_dump_arg{	struct sk_buff *skb;	struct netlink_callback *cb;};static int rt6_fill_node(struct sk_buff *skb, struct rt6_info *rt,			 struct in6_addr *dst,			 struct in6_addr *src,			 int iif,			 int type, u32 pid, u32 seq,			 struct nlmsghdr *in_nlh, int prefix){	struct rtmsg *rtm;	struct nlmsghdr  *nlh;	unsigned char	 *b = skb->tail;	struct rta_cacheinfo ci;	if (prefix) {	/* user wants prefix routes only */		if (!(rt->rt6i_flags & RTF_PREFIX_RT)) {			/* success since this is not a prefix route */			return 1;		}	}	if (!pid && in_nlh) {		pid = in_nlh->nlmsg_pid;	}	nlh = NLMSG_PUT(skb, pid, seq, type, sizeof(*rtm));	rtm = NLMSG_DATA(nlh);	rtm->rtm_family = AF_INET6;	rtm->rtm_dst_len = rt->rt6i_dst.plen;	rtm->rtm_src_len = rt->rt6i_src.plen;	rtm->rtm_tos = 0;	rtm->rtm_table = RT_TABLE_MAIN;	if (rt->rt6i_flags&RTF_REJECT)		rtm->rtm_type = RTN_UNREACHABLE;

⌨️ 快捷键说明

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