Beispiel #1
0
int inet_addr_onlink(struct in_device *in_dev, __be32 a, __be32 b)
{
	rcu_read_lock();
	for_primary_ifa(in_dev) {
		if (inet_ifa_match(a, ifa)) {
			if (!b || inet_ifa_match(b, ifa)) {
				rcu_read_unlock();
				return 1;
			}
		}
	} endfor_ifa(in_dev);
	rcu_read_unlock();
	return 0;
}
Beispiel #2
0
int
inet_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
{
	struct rtattr  **rta = arg;
	struct in_device *in_dev;
	struct ifaddrmsg *ifm = NLMSG_DATA(nlh);
	struct in_ifaddr *ifa, **ifap;

	ASSERT_RTNL();

	if ((in_dev = inetdev_by_index(ifm->ifa_index)) == NULL)
		return -EADDRNOTAVAIL;
	__in_dev_put(in_dev);

	for (ifap=&in_dev->ifa_list; (ifa=*ifap)!=NULL; ifap=&ifa->ifa_next) {
		if ((rta[IFA_LOCAL-1] && memcmp(RTA_DATA(rta[IFA_LOCAL-1]), &ifa->ifa_local, 4)) ||
		    (rta[IFA_LABEL-1] && strcmp(RTA_DATA(rta[IFA_LABEL-1]), ifa->ifa_label)) ||
		    (rta[IFA_ADDRESS-1] &&
		     (ifm->ifa_prefixlen != ifa->ifa_prefixlen ||
		      !inet_ifa_match(*(u32*)RTA_DATA(rta[IFA_ADDRESS-1]), ifa))))
			continue;
		inet_del_ifa(in_dev, ifap, 1);
		return 0;
	}

	return -EADDRNOTAVAIL;
}
u32 inet_select_addr(const struct net_device *dev, u32 dst, int scope)
{
	u32 addr = 0;
	struct in_device *in_dev;

	read_lock(&inetdev_lock);
	in_dev = __in_dev_get(dev);
	if (!in_dev)
		goto out_unlock_inetdev;

	read_lock(&in_dev->lock);
	for_primary_ifa(in_dev) {
		if (ifa->ifa_scope > scope)
			continue;
		if (!dst || inet_ifa_match(dst, ifa)) {
			addr = ifa->ifa_local;
			break;
		}
		if (!addr)
			addr = ifa->ifa_local;
	} endfor_ifa(in_dev);
	read_unlock(&in_dev->lock);
	read_unlock(&inetdev_lock);

	if (addr)
		goto out;

	/* Not loopback addresses on loopback should be preferred
	   in this case. It is importnat that lo is the first interface
	   in dev_base list.
	 */
	read_lock(&dev_base_lock);
	read_lock(&inetdev_lock);
	for (dev = dev_base; dev; dev = dev->next) {
		if ((in_dev = __in_dev_get(dev)) == NULL)
			continue;

		read_lock(&in_dev->lock);
		for_primary_ifa(in_dev) {
			if (ifa->ifa_scope != RT_SCOPE_LINK &&
			    ifa->ifa_scope <= scope) {
				read_unlock(&in_dev->lock);
				addr = ifa->ifa_local;
				goto out_unlock_both;
			}
		} endfor_ifa(in_dev);
		read_unlock(&in_dev->lock);
	}
out_unlock_both:
	read_unlock(&inetdev_lock);
	read_unlock(&dev_base_lock);
out:
	return addr;
out_unlock_inetdev:
	read_unlock(&inetdev_lock);
	goto out;
}
Beispiel #4
0
struct in_ifaddr *inet_ifa_byprefix(struct in_device *in_dev, u32 prefix, u32 mask)
{
	ASSERT_RTNL();

	for_primary_ifa(in_dev) {
		if (ifa->ifa_mask == mask && inet_ifa_match(prefix, ifa))
			return ifa;
	} endfor_ifa(in_dev);
	return NULL;
}
Beispiel #5
0
static void
inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap, int destroy)
{
	struct in_ifaddr *ifa1 = *ifap;

	ASSERT_RTNL();

	/* 1. Deleting primary ifaddr forces deletion all secondaries */

	if (!(ifa1->ifa_flags&IFA_F_SECONDARY)) {
		struct in_ifaddr *ifa;
		struct in_ifaddr **ifap1 = &ifa1->ifa_next;

		while ((ifa=*ifap1) != NULL) {
			if (!(ifa->ifa_flags&IFA_F_SECONDARY) ||
			    ifa1->ifa_mask != ifa->ifa_mask ||
			    !inet_ifa_match(ifa1->ifa_address, ifa)) {
				ifap1 = &ifa->ifa_next;
				continue;
			}
			write_lock_bh(&in_dev->lock);
			*ifap1 = ifa->ifa_next;
			write_unlock_bh(&in_dev->lock);

			rtmsg_ifa(RTM_DELADDR, ifa);
			notifier_call_chain(&inetaddr_chain, NETDEV_DOWN, ifa);
			inet_free_ifa(ifa);
		}
	}

	/* 2. Unlink it */

	write_lock_bh(&in_dev->lock);
	*ifap = ifa1->ifa_next;
	write_unlock_bh(&in_dev->lock);

	/* 3. Announce address deletion */

	/* Send message first, then call notifier.
	   At first sight, FIB update triggered by notifier
	   will refer to already deleted ifaddr, that could confuse
	   netlink listeners. It is not true: look, gated sees
	   that route deleted and if it still thinks that ifaddr
	   is valid, it will try to restore deleted routes... Grr.
	   So that, this order is correct.
	 */
	rtmsg_ifa(RTM_DELADDR, ifa1);
	notifier_call_chain(&inetaddr_chain, NETDEV_DOWN, ifa1);
	if (destroy) {
		inet_free_ifa(ifa1);

		if (in_dev->ifa_list == NULL)
			inetdev_destroy(in_dev);
	}
}
static int __inet_insert_ifa(struct in_ifaddr *ifa, struct nlmsghdr *nlh,
			     u32 pid)
{
	struct in_device *in_dev = ifa->ifa_dev;
	struct in_ifaddr *ifa1, **ifap, **last_primary;

	ASSERT_RTNL();

	if (!ifa->ifa_local) {
		inet_free_ifa(ifa);
		return 0;
	}

	ifa->ifa_flags &= ~IFA_F_SECONDARY;
	last_primary = &in_dev->ifa_list;

	for (ifap = &in_dev->ifa_list; (ifa1 = *ifap) != NULL;
	     ifap = &ifa1->ifa_next) {
		if (!(ifa1->ifa_flags & IFA_F_SECONDARY) &&
		    ifa->ifa_scope <= ifa1->ifa_scope)
			last_primary = &ifa1->ifa_next;
		if (ifa1->ifa_mask == ifa->ifa_mask &&
		    inet_ifa_match(ifa1->ifa_address, ifa)) {
			if (ifa1->ifa_local == ifa->ifa_local) {
				inet_free_ifa(ifa);
				return -EEXIST;
			}
			if (ifa1->ifa_scope != ifa->ifa_scope) {
				inet_free_ifa(ifa);
				return -EINVAL;
			}
			ifa->ifa_flags |= IFA_F_SECONDARY;
		}
		trace_mark(net_insert_ifa_ipv4, "label %s address #4u%lu",
			ifa->ifa_label,
			(unsigned long)ifa->ifa_address);
	}

	if (!(ifa->ifa_flags & IFA_F_SECONDARY)) {
		net_srandom(ifa->ifa_local);
		ifap = last_primary;
	}

	ifa->ifa_next = *ifap;
	*ifap = ifa;

	/* Send message first, then call notifier.
	   Notifier will trigger FIB update, so that
	   listeners of netlink will know about new ifaddr */
	rtmsg_ifa(RTM_NEWADDR, ifa, nlh, pid);
	blocking_notifier_call_chain(&inetaddr_chain, NETDEV_UP, ifa);

	return 0;
}
static int inet_insert_ifa(struct in_ifaddr *ifa)
{
	struct in_device *in_dev = ifa->ifa_dev;
	struct in_ifaddr *ifa1, **ifap, **last_primary;

	ASSERT_RTNL();

	if (!ifa->ifa_local) {
		inet_free_ifa(ifa);
		return 0;
	}

	ifa->ifa_flags &= ~IFA_F_SECONDARY;
	last_primary = &in_dev->ifa_list;

	for (ifap = &in_dev->ifa_list; (ifa1 = *ifap) != NULL;
	     ifap = &ifa1->ifa_next) {
		if (!(ifa1->ifa_flags & IFA_F_SECONDARY) &&
		    ifa->ifa_scope <= ifa1->ifa_scope)
			last_primary = &ifa1->ifa_next;
		if (ifa1->ifa_mask == ifa->ifa_mask &&
		    inet_ifa_match(ifa1->ifa_address, ifa)) {
			if (ifa1->ifa_local == ifa->ifa_local) {
				inet_free_ifa(ifa);
				return -EEXIST;
			}
			if (ifa1->ifa_scope != ifa->ifa_scope) {
				inet_free_ifa(ifa);
				return -EINVAL;
			}
			ifa->ifa_flags |= IFA_F_SECONDARY;
		}
	}

	if (!(ifa->ifa_flags & IFA_F_SECONDARY)) {
		net_srandom(ifa->ifa_local);
		ifap = last_primary;
	}

	ifa->ifa_next = *ifap;
	write_lock_bh(&in_dev->lock);
	*ifap = ifa;
	write_unlock_bh(&in_dev->lock);

	/* Send message first, then call notifier.
	   Notifier will trigger FIB update, so that
	   listeners of netlink will know about new ifaddr */
	rtmsg_ifa(RTM_NEWADDR, ifa);
	notifier_call_chain(&inetaddr_chain, NETDEV_UP, ifa);

	return 0;
}
Beispiel #8
0
static u32 confirm_addr_indev(struct in_device *in_dev, u32 dst,
                              u32 local, int scope)
{
    int same = 0;
    u32 addr = 0;

    for_ifa(in_dev) {
        if (!addr &&
                (local == ifa->ifa_local || !local) &&
                ifa->ifa_scope <= scope) {
            addr = ifa->ifa_local;
            if (same)
                break;
        }
        if (!same) {
            same = (!local || inet_ifa_match(local, ifa)) &&
                   (!dst || inet_ifa_match(dst, ifa));
            if (same && addr) {
                if (local || !dst)
                    break;
                /* Is the selected addr into dst subnet? */
                if (inet_ifa_match(addr, ifa))
                    break;
                /* No, then can we use new local src? */
                if (ifa->ifa_scope <= scope) {
                    addr = ifa->ifa_local;
                    break;
                }
                /* search for large dst subnet for addr */
                same = 0;
            }
        }
    }
    endfor_ifa(in_dev);

    return same? addr : 0;
}
Beispiel #9
0
static int inet_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
{
	struct net *net = sock_net(skb->sk);
	struct nlattr *tb[IFA_MAX+1];
	struct in_device *in_dev;
	struct ifaddrmsg *ifm;
	struct in_ifaddr *ifa, **ifap;
	int err = -EINVAL;

	ASSERT_RTNL();

	err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv4_policy);
	if (err < 0)
		goto errout;

	ifm = nlmsg_data(nlh);
	in_dev = inetdev_by_index(net, ifm->ifa_index);
	if (in_dev == NULL) {
		err = -ENODEV;
		goto errout;
	}

	__in_dev_put(in_dev);

	for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
	     ifap = &ifa->ifa_next) {
		if (tb[IFA_LOCAL] &&
		    ifa->ifa_local != nla_get_be32(tb[IFA_LOCAL]))
			continue;

		if (tb[IFA_LABEL] && nla_strcmp(tb[IFA_LABEL], ifa->ifa_label))
			continue;

		if (tb[IFA_ADDRESS] &&
		    (ifm->ifa_prefixlen != ifa->ifa_prefixlen ||
		    !inet_ifa_match(nla_get_be32(tb[IFA_ADDRESS]), ifa)))
			continue;

		__inet_del_ifa(in_dev, ifap, 1, nlh, NETLINK_CB(skb).pid);
		return 0;
	}

	err = -EADDRNOTAVAIL;
errout:
	return err;
}
Beispiel #10
0
__be32 inet_select_addr(const struct net_device *dev, __be32 dst, int scope)
{
	__be32 addr = 0;
	struct in_device *in_dev;
	struct net *net = dev_net(dev);

	rcu_read_lock();
	in_dev = __in_dev_get_rcu(dev);
	if (!in_dev)
		goto no_in_dev;

	for_primary_ifa(in_dev) {
		if (ifa->ifa_scope > scope)
			continue;
		if (!dst || inet_ifa_match(dst, ifa)) {
			addr = ifa->ifa_local;
			break;
		}
		if (!addr)
			addr = ifa->ifa_local;
	} endfor_ifa(in_dev);

	if (addr)
		goto out_unlock;
no_in_dev:

	/* Not loopback addresses on loopback should be preferred
	   in this case. It is importnat that lo is the first interface
	   in dev_base list.
	 */
	for_each_netdev_rcu(net, dev) {
		in_dev = __in_dev_get_rcu(dev);
		if (!in_dev)
			continue;

		for_primary_ifa(in_dev) {
			if (ifa->ifa_scope != RT_SCOPE_LINK &&
			    ifa->ifa_scope <= scope) {
				addr = ifa->ifa_local;
				goto out_unlock;
			}
		} endfor_ifa(in_dev);
	}
Beispiel #11
0
static void icmp_address_reply(struct icmphdr *icmph, struct sk_buff *skb, int len)
{
	struct rtable *rt = (struct rtable*)skb->dst;
	struct device *dev = skb->dev;
	struct in_device *in_dev = dev->ip_ptr;
	struct in_ifaddr *ifa;
	u32 mask;

	if (!in_dev || !in_dev->ifa_list ||
	    !IN_DEV_LOG_MARTIANS(in_dev) ||
	    !IN_DEV_FORWARD(in_dev) ||
	    len < 4 ||
	    !(rt->rt_flags&RTCF_DIRECTSRC))
		return;

	mask = *(u32*)&icmph[1];
	for (ifa=in_dev->ifa_list; ifa; ifa = ifa->ifa_next) {
		if (mask == ifa->ifa_mask && inet_ifa_match(rt->rt_src, ifa))
			return;
	}
	if (sysctl_ip_always_defrag == 0 && net_ratelimit())
		printk(KERN_INFO "Wrong address mask %08lX from %08lX/%s\n",
		       ntohl(mask), ntohl(rt->rt_src), dev->name);
}
Beispiel #12
0
static void __inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
			 int destroy, struct nlmsghdr *nlh, u32 pid)
{
	struct in_ifaddr *promote = NULL;
	struct in_ifaddr *ifa, *ifa1 = *ifap;
	struct in_ifaddr *last_prim = in_dev->ifa_list;
	struct in_ifaddr *prev_prom = NULL;
	int do_promote = IN_DEV_PROMOTE_SECONDARIES(in_dev);

	ASSERT_RTNL();

	/* 1. Deleting primary ifaddr forces deletion all secondaries
	 * unless alias promotion is set
	 **/

	if (!(ifa1->ifa_flags & IFA_F_SECONDARY)) {
		struct in_ifaddr **ifap1 = &ifa1->ifa_next;

		while ((ifa = *ifap1) != NULL) {
			if (!(ifa->ifa_flags & IFA_F_SECONDARY) &&
			    ifa1->ifa_scope <= ifa->ifa_scope)
				last_prim = ifa;

			if (!(ifa->ifa_flags & IFA_F_SECONDARY) ||
			    ifa1->ifa_mask != ifa->ifa_mask ||
			    !inet_ifa_match(ifa1->ifa_address, ifa)) {
				ifap1 = &ifa->ifa_next;
				prev_prom = ifa;
				continue;
			}

			if (!do_promote) {
				*ifap1 = ifa->ifa_next;

				rtmsg_ifa(RTM_DELADDR, ifa, nlh, pid);
				blocking_notifier_call_chain(&inetaddr_chain,
						NETDEV_DOWN, ifa);
				inet_free_ifa(ifa);
			} else {
				promote = ifa;
				break;
			}
		}
	}

	/* 2. Unlink it */

	*ifap = ifa1->ifa_next;

	/* 3. Announce address deletion */

	/* Send message first, then call notifier.
	   At first sight, FIB update triggered by notifier
	   will refer to already deleted ifaddr, that could confuse
	   netlink listeners. It is not true: look, gated sees
	   that route deleted and if it still thinks that ifaddr
	   is valid, it will try to restore deleted routes... Grr.
	   So that, this order is correct.
	 */
	rtmsg_ifa(RTM_DELADDR, ifa1, nlh, pid);
	blocking_notifier_call_chain(&inetaddr_chain, NETDEV_DOWN, ifa1);

	if (promote) {

		if (prev_prom) {
			prev_prom->ifa_next = promote->ifa_next;
			promote->ifa_next = last_prim->ifa_next;
			last_prim->ifa_next = promote;
		}

		promote->ifa_flags &= ~IFA_F_SECONDARY;
		rtmsg_ifa(RTM_NEWADDR, promote, nlh, pid);
		blocking_notifier_call_chain(&inetaddr_chain,
				NETDEV_UP, promote);
		for (ifa = promote->ifa_next; ifa; ifa = ifa->ifa_next) {
			if (ifa1->ifa_mask != ifa->ifa_mask ||
			    !inet_ifa_match(ifa1->ifa_address, ifa))
					continue;
			fib_add_ifaddr(ifa);
		}

	}
	if (destroy)
		inet_free_ifa(ifa1);
}
Beispiel #13
0
static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap,
                         int destroy)
{
    struct in_ifaddr *promote = NULL;
    struct in_ifaddr *ifa1 = *ifap;

    ASSERT_RTNL();

    /* 1. Deleting primary ifaddr forces deletion all secondaries
     * unless alias promotion is set
     **/

    if (!(ifa1->ifa_flags & IFA_F_SECONDARY)) {
        struct in_ifaddr *ifa;
        struct in_ifaddr **ifap1 = &ifa1->ifa_next;

        while ((ifa = *ifap1) != NULL) {
            if (!(ifa->ifa_flags & IFA_F_SECONDARY) ||
                    ifa1->ifa_mask != ifa->ifa_mask ||
                    !inet_ifa_match(ifa1->ifa_address, ifa)) {
                ifap1 = &ifa->ifa_next;
                continue;
            }

            if (!IN_DEV_PROMOTE_SECONDARIES(in_dev)) {
                *ifap1 = ifa->ifa_next;

                rtmsg_ifa(RTM_DELADDR, ifa);
                notifier_call_chain(&inetaddr_chain, NETDEV_DOWN, ifa);
                inet_free_ifa(ifa);
            } else {
                promote = ifa;
                break;
            }
        }
    }

    /* 2. Unlink it */

    *ifap = ifa1->ifa_next;

    /* 3. Announce address deletion */

    /* Send message first, then call notifier.
       At first sight, FIB update triggered by notifier
       will refer to already deleted ifaddr, that could confuse
       netlink listeners. It is not true: look, gated sees
       that route deleted and if it still thinks that ifaddr
       is valid, it will try to restore deleted routes... Grr.
       So that, this order is correct.
     */
    rtmsg_ifa(RTM_DELADDR, ifa1);
    notifier_call_chain(&inetaddr_chain, NETDEV_DOWN, ifa1);
    if (destroy) {
        inet_free_ifa(ifa1);

        if (!in_dev->ifa_list)
            inetdev_destroy(in_dev);
    }

    if (promote && IN_DEV_PROMOTE_SECONDARIES(in_dev)) {
        /* not sure if we should send a delete notify first? */
        promote->ifa_flags &= ~IFA_F_SECONDARY;
        rtmsg_ifa(RTM_NEWADDR, promote);
        notifier_call_chain(&inetaddr_chain, NETDEV_UP, promote);
    }
}