Пример #1
0
static int inet6_addr_del(int ifindex, struct in6_addr *pfx, int plen)
{
    struct inet6_ifaddr *ifp;
    struct inet6_dev *idev;
    struct device *dev;
    int scope;

    if ((dev = dev_get_by_index(ifindex)) == NULL)
        return -ENODEV;

    if ((idev = ipv6_get_idev(dev)) == NULL)
        return -ENXIO;

    scope = ipv6_addr_scope(pfx);

    for (ifp = idev->addr_list; ifp; ifp=ifp->if_next) {
        if (ifp->scope == scope && ifp->prefix_len == plen &&
                (!memcmp(pfx, &ifp->addr, sizeof(struct in6_addr)))) {
            ipv6_del_addr(ifp);

            /* If the last address is deleted administratively,
               disable IPv6 on this interface.
             */

            if (idev->addr_list == NULL)
                addrconf_ifdown(idev->dev, 1);
            return 0;
        }
    }
    return -EADDRNOTAVAIL;
}
Пример #2
0
/*
 *	Manual configuration of address on an interface
 */
static int inet6_addr_add(int ifindex, struct in6_addr *pfx, int plen)
{
	struct inet6_ifaddr *ifp;
	struct inet6_dev *idev;
	struct net_device *dev;
	int scope;

	ASSERT_RTNL();
	
	if ((dev = __dev_get_by_index(ifindex)) == NULL)
		return -ENODEV;
	
	if (!(dev->flags&IFF_UP))
		return -ENETDOWN;

	if ((idev = addrconf_add_dev(dev)) == NULL)
		return -ENOBUFS;

	scope = ipv6_addr_scope(pfx);

	if ((ifp = ipv6_add_addr(idev, pfx, plen, scope, IFA_F_PERMANENT)) != NULL) {
		addrconf_dad_start(ifp);
		in6_ifa_put(ifp);
		return 0;
	}

	return -ENOBUFS;
}
Пример #3
0
/*
 *	Manual configuration of address on an interface
 */
static int inet6_addr_add(int ifindex, struct in6_addr *pfx, int plen)
{
    struct inet6_ifaddr *ifp;
    struct inet6_dev *idev;
    struct device *dev;
    int scope;

    if ((dev = dev_get_by_index(ifindex)) == NULL)
        return -ENODEV;

    if (!(dev->flags&IFF_UP))
        return -ENETDOWN;

    if ((idev = addrconf_add_dev(dev)) == NULL)
        return -ENOBUFS;

    scope = ipv6_addr_scope(pfx);

    if ((ifp = ipv6_add_addr(idev, pfx, scope)) == NULL)
        return -ENOMEM;

    ifp->prefix_len = plen;
    ifp->flags |= ADDR_PERMANENT;

    addrconf_dad_start(ifp);
    return 0;
}
Пример #4
0
/*
 *	Choose an apropriate source address
 *	should do:
 *	i)	get an address with an apropriate scope
 *	ii)	see if there is a specific route for the destination and use
 *		an address of the attached interface 
 *	iii)	don't use deprecated addresses
 */
int ipv6_get_saddr(struct dst_entry *dst,
		   struct in6_addr *daddr, struct in6_addr *saddr)
{
	int scope;
	struct inet6_ifaddr *ifp = NULL;
	struct inet6_ifaddr *match = NULL;
	struct net_device *dev = NULL;
	struct inet6_dev *idev;
	struct rt6_info *rt;
	int err;

	rt = (struct rt6_info *) dst;
	if (rt)
		dev = rt->rt6i_dev;

	scope = ipv6_addr_scope(daddr);
	if (rt && (rt->rt6i_flags & RTF_ALLONLINK)) {
		/*
		 *	route for the "all destinations on link" rule
		 *	when no routers are present
		 */
		scope = IFA_LINK;
	}

	/*
	 *	known dev
	 *	search dev and walk through dev addresses
	 */

	if (dev) {
		if (dev->flags & IFF_LOOPBACK)
			scope = IFA_HOST;

		read_lock(&addrconf_lock);
		idev = __in6_dev_get(dev);
		if (idev) {
			read_lock_bh(&idev->lock);
			for (ifp=idev->addr_list; ifp; ifp=ifp->if_next) {
				if (ifp->scope == scope) {
					if (!(ifp->flags & (IFA_F_DEPRECATED|IFA_F_TENTATIVE))) {
						in6_ifa_hold(ifp);
						read_unlock_bh(&idev->lock);
						read_unlock(&addrconf_lock);
						goto out;
					}

					if (!match && !(ifp->flags & IFA_F_TENTATIVE)) {
						match = ifp;
						in6_ifa_hold(ifp);
					}
				}
			}
			read_unlock_bh(&idev->lock);
		}
		read_unlock(&addrconf_lock);
	}

	if (scope == IFA_LINK)
		goto out;

	/*
	 *	dev == NULL or search failed for specified dev
	 */

	read_lock(&dev_base_lock);
	read_lock(&addrconf_lock);
	for (dev = dev_base; dev; dev=dev->next) {
		idev = __in6_dev_get(dev);
		if (idev) {
			read_lock_bh(&idev->lock);
			for (ifp=idev->addr_list; ifp; ifp=ifp->if_next) {
				if (ifp->scope == scope) {
					if (!(ifp->flags&(IFA_F_DEPRECATED|IFA_F_TENTATIVE))) {
						in6_ifa_hold(ifp);
						read_unlock_bh(&idev->lock);
						goto out_unlock_base;
					}

					if (!match && !(ifp->flags&IFA_F_TENTATIVE)) {
						match = ifp;
						in6_ifa_hold(ifp);
					}
				}
			}
			read_unlock_bh(&idev->lock);
		}
	}

out_unlock_base:
	read_unlock(&addrconf_lock);
	read_unlock(&dev_base_lock);

out:
	if (ifp == NULL) {
		ifp = match;
		match = NULL;
	}

	err = -EADDRNOTAVAIL;
	if (ifp) {
		ipv6_addr_copy(saddr, &ifp->addr);
		err = 0;
		in6_ifa_put(ifp);
	}
	if (match)
		in6_ifa_put(match);

	return err;
}
Пример #5
0
int getsock(char *tname, struct sockaddr_in6 *psin6_arg, int scope)
{
#ifdef HAVE_IFADDRS_H
	static struct ifaddrs *pifa_head;
	struct ifaddrs *pifa;
	struct sockaddr_in6 *psin6;
	char strbuf[128];
	int ifindex = 0;
	int s;

	if (!pifa_head && getifaddrs(&pifa_head)) {
		tst_resm(TBROK, "%s: getifaddrs failed", tname);
		return -1;
	}
	if (psin6_arg)
		ifindex = psin6_arg->sin6_scope_id;

	/* first, find a global address */
	for (pifa = pifa_head; pifa; pifa = pifa->ifa_next) {
		int this_scope;

		if (!(pifa->ifa_flags & IFF_UP))
			continue;
		if (pifa->ifa_addr->sa_family != AF_INET6)
			continue;
		psin6 = (struct sockaddr_in6 *)pifa->ifa_addr;
		this_scope = ipv6_addr_scope(&psin6->sin6_addr);
		if (this_scope &&
		    ((this_scope < 0 && -this_scope == scope) ||
		     (this_scope > 0 && this_scope != scope)))
			continue;
		psin6->sin6_scope_id = if_nametoindex(pifa->ifa_name);
		if ((ifindex < 0 && -ifindex == psin6->sin6_scope_id) ||
		    (ifindex > 0 && ifindex != psin6->sin6_scope_id))
			continue;
		s = socket(PF_INET6, SOCK_DGRAM, 0);
		if (s < 0) {
			tst_resm(TBROK, "%s: socket %s", tname,
				 strerror(errno));
			return -1;
		}
		if (bind(s, pifa->ifa_addr, sizeof(struct sockaddr_in6)) < 0) {
			tst_resm(TBROK, "%s: bind \"%s\": %s", tname,
				 inet_ntop(AF_INET6, &psin6->sin6_addr, strbuf,
					   sizeof(strbuf)), strerror(errno));
			return -1;
		}
		if (psin6_arg) {
			*psin6_arg = *psin6;
			psin6_arg->sin6_scope_id =
			    if_nametoindex(pifa->ifa_name);
		}
		return s;
	}
	{
		char *scopestr, *intfstr;

		switch (scope) {
		case IPV6_ADDR_NODE:
			scopestr = " node-local";
			break;
		case IPV6_ADDR_LINK:
			scopestr = " link-local";
			break;
		case IPV6_ADDR_GLOBAL:
			scopestr = " global";
			break;
		default:
			scopestr = "";
			break;
		}
		if (ifindex < 0) {
			intfstr = " not on ifindex";
			ifindex = -ifindex;
		} else if (ifindex)
			intfstr = " on ifindex";
		else
			intfstr = 0;

		if (intfstr)
			tst_resm(TBROK, "%s: getsock : no%s addresses%s %d",
				 tname, scopestr, intfstr, ifindex);
		else
			tst_resm(TBROK, "%s: getsock : no%s addresses",
				 tname, scopestr);
	}
	return -1;
#else /* HAVE_IFADDRS_H */
	return -1;
#endif
}
Пример #6
0
/*
 *	Choose an apropriate source address
 *	should do:
 *	i)	get an address with an apropriate scope
 *	ii)	see if there is a specific route for the destination and use
 *		an address of the attached interface
 *	iii)	don't use deprecated addresses
 *
 *	at the moment I believe only iii) is missing.
 */
struct inet6_ifaddr * ipv6_get_saddr(struct dst_entry *dst,
                                     struct in6_addr *daddr)
{
    int scope;
    struct inet6_ifaddr *ifp = NULL;
    struct inet6_ifaddr *match = NULL;
    struct device *dev = NULL;
    struct rt6_info *rt;
    int i;

    rt = (struct rt6_info *) dst;
    if (rt)
        dev = rt->rt6i_dev;

    atomic_inc(&addr_list_lock);

    scope = ipv6_addr_scope(daddr);
    if (rt && (rt->rt6i_flags & RTF_ALLONLINK)) {
        /*
         *	route for the "all destinations on link" rule
         *	when no routers are present
         */
        scope = IFA_LINK;
    }

    /*
     *	known dev
     *	search dev and walk through dev addresses
     */

    if (dev) {
        struct inet6_dev *idev;
        int hash;

        if (dev->flags & IFF_LOOPBACK)
            scope = IFA_HOST;

        hash = ipv6_devindex_hash(dev->ifindex);
        for (idev = inet6_dev_lst[hash]; idev; idev=idev->next) {
            if (idev->dev == dev) {
                for (ifp=idev->addr_list; ifp; ifp=ifp->if_next) {
                    if (ifp->scope == scope) {
                        if (!(ifp->flags & ADDR_STATUS))
                            goto out;

                        if (!(ifp->flags & ADDR_INVALID))
                            match = ifp;
                    }
                }
                break;
            }
        }
    }

    if (scope == IFA_LINK)
        goto out;

    /*
     *	dev == NULL or search failed for specified dev
     */

    for (i=0; i < IN6_ADDR_HSIZE; i++) {
        for (ifp=inet6_addr_lst[i]; ifp; ifp=ifp->lst_next) {
            if (ifp->scope == scope) {
                if (!(ifp->flags & ADDR_STATUS))
                    goto out;

                if (!(ifp->flags & ADDR_INVALID))
                    match = ifp;
            }
        }
    }

out:
    if (ifp == NULL)
        ifp = match;
    atomic_dec(&addr_list_lock);
    return ifp;
}
Пример #7
0
/*
 *	Choose an apropriate source address
 *	should do:
 *	i)	get an address with an apropriate scope
 *	ii)	see if there is a specific route for the destination and use
 *		an address of the attached interface 
 *	iii)	don't use deprecated addresses
 */
int ipv6_get_saddr(struct dst_entry *dst,
		   struct in6_addr *daddr, struct in6_addr *saddr)
{
	int scope;
	struct inet6_ifaddr *ifp = NULL;
	struct inet6_ifaddr *match = NULL;
	struct device *dev = NULL;
	struct rt6_info *rt;
	int deprecated = 1;
	int matchlen = 0;
	int err;
	int i;

	rt = (struct rt6_info *) dst;
	if (rt)
		dev = rt->rt6i_dev;
	
	addrconf_lock();

	scope = ipv6_addr_scope(daddr);
	if (rt && (rt->rt6i_flags & RTF_ALLONLINK)) {
		/*
		 *	route for the "all destinations on link" rule
		 *	when no routers are present
		 */
		scope = IFA_LINK;
	}

	/*
	 *	known dev
	 *	search dev and walk through dev addresses
	 */

	if (dev) {
		struct inet6_dev *idev;
		int hash;

		if (dev->flags & IFF_LOOPBACK)
			scope = IFA_HOST;

		hash = ipv6_devindex_hash(dev->ifindex);
		for (idev = inet6_dev_lst[hash]; idev; idev=idev->next) {
			if (idev->dev == dev) {
				for (ifp=idev->addr_list; ifp; ifp=ifp->if_next) {
					if (ifp->scope == scope) {
						int newlen = inet6_addr_diff(daddr, &ifp->addr);

						if (newlen < matchlen)
							continue;

						if (!(ifp->flags & (ADDR_STATUS|DAD_STATUS))) {
							match = ifp;
							matchlen = newlen;
							deprecated = 0;
							continue;
						}

						if(!deprecated)
							continue;

						if (!(ifp->flags & (ADDR_INVALID|DAD_STATUS))) {
							match = ifp;
							matchlen = newlen;
							continue;
						}
					}
				}
				break;
			}
		}
	}

	if (match != NULL && !deprecated)
		goto out;

	if (scope == IFA_LINK)
		goto out;

	/*
	 *	dev == NULL or search failed for specified dev
	 */

	for (i=0; i < IN6_ADDR_HSIZE; i++) {
		for (ifp=inet6_addr_lst[i]; ifp; ifp=ifp->lst_next) {
			if (ifp->scope == scope) {
				int newlen = inet6_addr_diff(daddr, &ifp->addr);

				if (newlen < matchlen)
					continue;

				if (!(ifp->flags & (ADDR_STATUS|DAD_STATUS))) {
					match = ifp;
					matchlen = newlen;
					deprecated = 0;
					continue;
				}

				if (!deprecated)
					continue;

				if (!(ifp->flags & (ADDR_INVALID|DAD_STATUS))) {
					match = ifp;
					matchlen = newlen;
					continue;
				}
			}
		}
	}

out:
	if (ifp == NULL)
		ifp = match;

	err = -ENETUNREACH;
	if (ifp) {
		memcpy(saddr, &ifp->addr, sizeof(struct in6_addr));
		err = 0;
	}
	addrconf_unlock();
	return err;
}