Example #1
0
static struct inet6_dev * ipv6_add_dev(struct device *dev)
{
	struct inet6_dev *ndev, **bptr, *iter;
	int hash;

	if (dev->mtu < IPV6_MIN_MTU)
		return NULL;

	ndev = kmalloc(sizeof(struct inet6_dev), GFP_KERNEL);

	if (ndev) {
		char name[64];
		memset(ndev, 0, sizeof(struct inet6_dev));

		ndev->dev = dev;
		memcpy(&ndev->cnf, &ipv6_devconf_dflt, sizeof(ndev->cnf));
		ndev->cnf.mtu6 = dev->mtu;
		ndev->cnf.sysctl = NULL;
		ndev->nd_parms = neigh_parms_alloc(dev, &nd_tbl);
		if (ndev->nd_parms == NULL) {
			kfree(ndev);
			return NULL;
		}

		ipv6_statistics.Ip6LastChange = timeticks(jiffies);
		ndev->stats.ipv6.Ip6LastChange = timeticks(jiffies);

#ifdef CONFIG_PROC_FS
		sprintf(name, "%d", dev->ifindex);
		ndev->stats.proc_dir_entry = create_proc_entry(name, 0, proc_net_devsnmp6);
		if (!ndev->stats.proc_dir_entry)
			printk(KERN_WARNING
				"addrconf_notify(): cannot create /proc/net/dev_snmp6/%s\n",name);
		ndev->stats.proc_dir_entry->read_proc = afinet6_read_devsnmp;
		ndev->stats.proc_dir_entry->data = ndev;
#endif

#ifdef CONFIG_SYSCTL
		neigh_sysctl_register(dev, ndev->nd_parms, NET_IPV6, NET_IPV6_NEIGH, "ipv6");
		addrconf_sysctl_register(ndev, &ndev->cnf);
#endif
		hash = ipv6_devindex_hash(dev->ifindex);
		bptr = &inet6_dev_lst[hash];
		iter = *bptr;

		for (; iter; iter = iter->next)
			bptr = &iter->next;

		*bptr = ndev;

	}
	return ndev;
}
Example #2
0
struct inet6_dev * ipv6_get_idev(struct device *dev)
{
    struct inet6_dev *idev;
    int hash;

    hash = ipv6_devindex_hash(dev->ifindex);

    for (idev = inet6_dev_lst[hash]; idev; idev = idev->next) {
        if (idev->dev == dev)
            return idev;
    }
    return NULL;
}
Example #3
0
struct inet6_ifaddr * ipv6_get_lladdr(struct device *dev)
{
    struct inet6_ifaddr *ifp;
    struct inet6_dev *idev;
    int hash;

    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 == IFA_LINK)
                    return ifp;
            }
            break;
        }
    }
    return NULL;
}
Example #4
0
static struct inet6_dev * ipv6_add_dev(struct device *dev)
{
    struct inet6_dev *ndev, **bptr, *iter;
    int hash;

    if (dev->mtu < IPV6_MIN_MTU)
        return NULL;

    ndev = kmalloc(sizeof(struct inet6_dev), gfp_any());

    if (ndev) {
        memset(ndev, 0, sizeof(struct inet6_dev));

        ndev->dev = dev;
        memcpy(&ndev->cnf, &ipv6_devconf_dflt, sizeof(ndev->cnf));
        ndev->cnf.mtu6 = dev->mtu;
        ndev->cnf.sysctl = NULL;
        ndev->nd_parms = neigh_parms_alloc(dev, &nd_tbl);
        if (ndev->nd_parms == NULL) {
            kfree(ndev);
            return NULL;
        }
#ifdef CONFIG_SYSCTL
        neigh_sysctl_register(dev, ndev->nd_parms, NET_IPV6, NET_IPV6_NEIGH, "ipv6");
        addrconf_sysctl_register(ndev, &ndev->cnf);
#endif
        hash = ipv6_devindex_hash(dev->ifindex);
        bptr = &inet6_dev_lst[hash];
        iter = *bptr;

        for (; iter; iter = iter->next)
            bptr = &iter->next;

        *bptr = ndev;

    }
    return ndev;
}
Example #5
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;
}
Example #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
 */
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;
}