int ip6_route_add(struct in6_rtmsg *rtmsg, struct nlmsghdr *nlh, void *_rtattr) 
int ip6_route_add(struct in6_rtmsg *rtmsg, struct nlmsghdr *nlh, void *_rtattr, struct netlink_skb_parms *req) 
int ip6_route_add(struct in6_rtmsg *rtmsg, struct nlmsghdr *nlh, void *_rtattr){	int err;	struct rtmsg *r;	struct rtattr **rta;	struct rt6_info *rt = NULL;	struct net_device *dev = NULL;	struct inet6_dev *idev = NULL;	int addr_type;	rta = (struct rtattr **) _rtattr;	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_ifindex) {		err = -ENODEV;		dev = dev_get_by_index(rtmsg->rtmsg_ifindex);		if (!dev)			goto out;		idev = in6_dev_get(dev);		if (!idev)			goto out;	}	if (rtmsg->rtmsg_metric == 0)		rtmsg->rtmsg_metric = IP6_RT_PRIO_USER;	rt = ip6_dst_alloc();	if (rt == NULL) {		err = -ENOMEM;		goto out;	}	rt->u.dst.obsolete = -1;	rt->rt6i_expires = clock_t_to_jiffies(rtmsg->rtmsg_info);	if (nlh && (r = NLMSG_DATA(nlh))) {		rt->rt6i_protocol = r->rtm_protocol;	} else {		rt->rt6i_protocol = RTPROT_BOOT;	}	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;	ipv6_addr_prefix(&rt->rt6i_dst.addr, 			 &rtmsg->rtmsg_dst, rtmsg->rtmsg_dst_len);	rt->rt6i_dst.plen = rtmsg->rtmsg_dst_len;	if (rt->rt6i_dst.plen == 128)	       rt->u.dst.flags = DST_HOST;#ifdef CONFIG_IPV6_SUBTREES	ipv6_addr_prefix(&rt->rt6i_src.addr, 			 &rtmsg->rtmsg_src, rtmsg->rtmsg_src_len);	rt->rt6i_src.plen = rtmsg->rtmsg_src_len;#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))) {		/* hold loopback dev/idev if we haven't done so. */		if (dev != &loopback_dev) {			if (dev) {				dev_put(dev);				in6_dev_put(idev);			}			dev = &loopback_dev;			dev_hold(dev);			idev = in6_dev_get(dev);			if (!idev) {				err = -ENODEV;				goto out;			}		}		rt->u.dst.output = ip6_pkt_discard_out;		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!) circumstances			   (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;				idev = grt->rt6i_idev;				dev_hold(dev);				in6_dev_hold(grt->rt6i_idev);			}			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;		}	}	rt->rt6i_flags = rtmsg->rtmsg_flags;install_route:	if (rta && rta[RTA_METRICS-1]) {		int attrlen = RTA_PAYLOAD(rta[RTA_METRICS-1]);		struct rtattr *attr = RTA_DATA(rta[RTA_METRICS-1]);		while (RTA_OK(attr, attrlen)) {			unsigned flavor = attr->rta_type;			if (flavor) {				if (flavor > RTAX_MAX) {					err = -EINVAL;					goto out;				}				rt->u.dst.metrics[flavor-1] =					*(u32 *)RTA_DATA(attr);			}			attr = RTA_NEXT(attr, attrlen);		}	}	if (rt->u.dst.metrics[RTAX_HOPLIMIT-1] == 0)		rt->u.dst.metrics[RTAX_HOPLIMIT-1] = -1;	if (!rt->u.dst.metrics[RTAX_MTU-1])		rt->u.dst.metrics[RTAX_MTU-1] = ipv6_get_mtu(dev);	if (!rt->u.dst.metrics[RTAX_ADVMSS-1])		rt->u.dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(dst_mtu(&rt->u.dst));	rt->u.dst.dev = dev;	rt->rt6i_idev = idev;	return ip6_ins_rt(rt, nlh, _rtattr);out:	if (dev)		dev_put(dev);	if (idev)		in6_dev_put(idev);	if (rt)		dst_free((struct dst_entry *) rt);	return err;}
10457	/local/tlutelli/issta_data/temp/c/2005_temp/2005/10457/0d51aa80a9b1db43920c0770c3bb842dd823c005/route.c/buggy/net/ipv6/route.c