* 2 of the License, or (at your option) any later version.
*
* Derived from the IP parts of dev.c 1.0.19
- * Authors: Ross Biro, <bir7@leland.Stanford.Edu>
+ * Authors: Ross Biro
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
* Mark Evans, <evansmp@uhura.aston.ac.uk>
*
dev_hold(dev);
#ifdef CONFIG_SYSCTL
neigh_sysctl_register(dev, in_dev->arp_parms, NET_IPV4,
- NET_IPV4_NEIGH, "ipv4", NULL);
+ NET_IPV4_NEIGH, "ipv4", NULL, NULL);
#endif
/* Account for reference dev->ip_ptr */
ASSERT_RTNL();
+ dev = in_dev->dev;
+ if (dev == &loopback_dev)
+ return;
+
in_dev->dead = 1;
ip_mc_destroy_dev(in_dev);
devinet_sysctl_unregister(&in_dev->cnf);
#endif
- dev = in_dev->dev;
dev->ip_ptr = NULL;
#ifdef CONFIG_SYSCTL
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 */
+ /* 1. Deleting primary ifaddr forces deletion all secondaries
+ * unless alias promotion is set
+ **/
if (!(ifa1->ifa_flags & IFA_F_SECONDARY)) {
struct in_ifaddr *ifa;
continue;
}
- *ifap1 = ifa->ifa_next;
+ 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);
+ rtmsg_ifa(RTM_DELADDR, ifa);
+ notifier_call_chain(&inetaddr_chain, NETDEV_DOWN, ifa);
+ inet_free_ifa(ifa);
+ } else {
+ promote = ifa;
+ break;
+ }
}
}
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);
+ }
}
static int inet_insert_ifa(struct in_ifaddr *ifa)
return NULL;
}
-int inet_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
+static int inet_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
{
struct rtattr **rta = arg;
struct in_device *in_dev;
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)) ||
+ rtattr_strcmp(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]),
return -EADDRNOTAVAIL;
}
-int inet_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
+static int inet_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
{
struct rtattr **rta = arg;
struct net_device *dev;
in_dev_hold(in_dev);
ifa->ifa_dev = in_dev;
if (rta[IFA_LABEL - 1])
- memcpy(ifa->ifa_label, RTA_DATA(rta[IFA_LABEL - 1]), IFNAMSIZ);
+ rtattr_strlcpy(ifa->ifa_label, rta[IFA_LABEL - 1], IFNAMSIZ);
else
memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
return rc;
}
+/*
+ Check that a device is not member of the ipv4root assigned to the process
+ Return true if this is the case
+
+ If the process is not bound to specific IP, then it returns 0 (all
+ interface are fine).
+*/
+static inline int devinet_notiproot (struct in_ifaddr *ifa)
+{
+ int ret = 0;
+ struct nx_info *nxi;
+
+ if ((nxi = current->nx_info)) {
+ int i;
+ int nbip = nxi->nbipv4;
+ __u32 addr = ifa->ifa_local;
+ ret = 1;
+ for (i=0; i<nbip; i++) {
+ if(nxi->ipv4[i] == addr) {
+ ret = 0;
+ break;
+ }
+ }
+ }
+ return ret;
+}
+
int devinet_ioctl(unsigned int cmd, void __user *arg)
{
ret = -EADDRNOTAVAIL;
if (!ifa && cmd != SIOCSIFADDR && cmd != SIOCSIFFLAGS)
goto done;
+ if (vx_flags(VXF_HIDE_NETIF, 0) &&
+ !ifa_in_nx_info(ifa, current->nx_info))
+ goto done;
switch(cmd) {
case SIOCGIFADDR: /* Get interface address */
goto out;
for (; ifa; ifa = ifa->ifa_next) {
+ if (vx_flags(VXF_HIDE_NETIF, 0) &&
+ !ifa_in_nx_info(ifa, current->nx_info))
+ continue;
if (!buf) {
done += sizeof(ifr);
continue;
ASSERT_RTNL();
- if (!in_dev)
+ if (!in_dev) {
+ if (event == NETDEV_REGISTER && dev == &loopback_dev) {
+ in_dev = inetdev_init(dev);
+ if (!in_dev)
+ panic("devinet: Failed to create loopback\n");
+ in_dev->cnf.no_xfrm = 1;
+ in_dev->cnf.no_policy = 1;
+ }
goto out;
+ }
switch (event) {
case NETDEV_REGISTER:
memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
inet_insert_ifa(ifa);
}
- in_dev->cnf.no_xfrm = 1;
- in_dev->cnf.no_policy = 1;
}
ip_mc_up(in_dev);
break;
devinet_sysctl_unregister(&in_dev->cnf);
neigh_sysctl_unregister(in_dev->arp_parms);
neigh_sysctl_register(dev, in_dev->arp_parms, NET_IPV4,
- NET_IPV4_NEIGH, "ipv4", NULL);
+ NET_IPV4_NEIGH, "ipv4", NULL, NULL);
devinet_sysctl_register(in_dev, &in_dev->cnf);
#endif
break;
struct net_device *dev;
struct in_device *in_dev;
struct in_ifaddr *ifa;
+ struct sock *sk = skb->sk;
int s_ip_idx, s_idx = cb->args[0];
s_ip_idx = ip_idx = cb->args[1];
for (ifa = in_dev->ifa_list, ip_idx = 0; ifa;
ifa = ifa->ifa_next, ip_idx++) {
+ if (sk && vx_info_flags(sk->sk_vx_info, VXF_HIDE_NETIF, 0) &&
+ !ifa_in_nx_info(ifa, sk->sk_nx_info))
+ continue;
if (ip_idx < s_ip_idx)
continue;
if (inet_fill_ifaddr(skb, ifa, NETLINK_CB(cb->skb).pid,
}
}
-static struct rtnetlink_link inet_rtnetlink_table[RTM_MAX - RTM_BASE + 1] = {
- [4] = { .doit = inet_rtm_newaddr, },
- [5] = { .doit = inet_rtm_deladdr, },
- [6] = { .dumpit = inet_dump_ifaddr, },
- [8] = { .doit = inet_rtm_newroute, },
- [9] = { .doit = inet_rtm_delroute, },
- [10] = { .doit = inet_rtm_getroute, .dumpit = inet_dump_fib, },
+static struct rtnetlink_link inet_rtnetlink_table[RTM_NR_MSGTYPES] = {
+ [RTM_NEWADDR - RTM_BASE] = { .doit = inet_rtm_newaddr, },
+ [RTM_DELADDR - RTM_BASE] = { .doit = inet_rtm_deladdr, },
+ [RTM_GETADDR - RTM_BASE] = { .dumpit = inet_dump_ifaddr, },
+ [RTM_NEWROUTE - RTM_BASE] = { .doit = inet_rtm_newroute, },
+ [RTM_DELROUTE - RTM_BASE] = { .doit = inet_rtm_delroute, },
+ [RTM_GETROUTE - RTM_BASE] = { .doit = inet_rtm_getroute,
+ .dumpit = inet_dump_fib, },
#ifdef CONFIG_IP_MULTIPLE_TABLES
- [16] = { .doit = inet_rtm_newrule, },
- [17] = { .doit = inet_rtm_delrule, },
- [18] = { .dumpit = inet_dump_rules, },
+ [RTM_NEWRULE - RTM_BASE] = { .doit = inet_rtm_newrule, },
+ [RTM_DELRULE - RTM_BASE] = { .doit = inet_rtm_delrule, },
+ [RTM_GETRULE - RTM_BASE] = { .dumpit = inet_dump_rules, },
#endif
};
static struct devinet_sysctl_table {
struct ctl_table_header *sysctl_header;
- ctl_table devinet_vars[20];
+ ctl_table devinet_vars[__NET_IPV4_CONF_MAX];
ctl_table devinet_dev[2];
ctl_table devinet_conf_dir[2];
ctl_table devinet_proto_dir[2];
.proc_handler = &ipv4_doint_and_flush,
.strategy = &ipv4_doint_and_flush_strategy,
},
+ {
+ .ctl_name = NET_IPV4_CONF_PROMOTE_SECONDARIES,
+ .procname = "promote_secondaries",
+ .data = &ipv4_devconf.promote_secondaries,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = &ipv4_doint_and_flush,
+ .strategy = &ipv4_doint_and_flush_strategy,
+ },
},
.devinet_dev = {
{