* status etc.
*/
+#include <linux/config.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>
kfree(ifp);
}
-static void
-ipv6_link_dev_addr(struct inet6_dev *idev, struct inet6_ifaddr *ifp)
-{
- struct inet6_ifaddr *ifa, **ifap;
- int ifp_scope = ipv6_addr_src_scope(&ifp->addr);
-
- /*
- * Each device address list is sorted in order of scope -
- * global before linklocal.
- */
- for (ifap = &idev->addr_list; (ifa = *ifap) != NULL;
- ifap = &ifa->if_next) {
- if (ifp_scope >= ipv6_addr_src_scope(&ifa->addr))
- break;
- }
-
- ifp->if_next = *ifap;
- *ifap = ifp;
-}
-
/* On success it returns ifp with increased reference count */
static struct inet6_ifaddr *
ifa->flags = flags | IFA_F_TENTATIVE;
ifa->cstamp = ifa->tstamp = jiffies;
- ifa->rt = rt;
-
ifa->idev = idev;
in6_dev_hold(idev);
/* For caller */
write_lock(&idev->lock);
/* Add to inet6_dev unicast addr list. */
- ipv6_link_dev_addr(idev, ifa);
+ ifa->if_next = idev->addr_list;
+ idev->addr_list = ifa;
#ifdef CONFIG_IPV6_PRIVACY
if (ifa->flags&IFA_F_TEMPORARY) {
}
#endif
+ ifa->rt = rt;
+
in6_ifa_hold(ifa);
write_unlock(&idev->lock);
out2:
continue;
} else if (score.scope < hiscore.scope) {
if (score.scope < daddr_scope)
- break; /* addresses sorted by scope */
+ continue;
else {
score.rule = 2;
goto record_it;
/*
* Manual configuration of address on an interface
*/
-static int inet6_addr_add(int ifindex, struct in6_addr *pfx, int plen,
- __u32 prefered_lft, __u32 valid_lft)
+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;
- __u8 ifa_flags = 0;
int scope;
ASSERT_RTNL();
- /* check the lifetime */
- if (!valid_lft || prefered_lft > valid_lft)
- return -EINVAL;
-
if ((dev = __dev_get_by_index(ifindex)) == NULL)
return -ENODEV;
scope = ipv6_addr_scope(pfx);
- if (valid_lft == INFINITY_LIFE_TIME)
- ifa_flags |= IFA_F_PERMANENT;
- else if (valid_lft >= 0x7FFFFFFF/HZ)
- valid_lft = 0x7FFFFFFF/HZ;
-
- if (prefered_lft == 0)
- ifa_flags |= IFA_F_DEPRECATED;
- else if ((prefered_lft >= 0x7FFFFFFF/HZ) &&
- (prefered_lft != INFINITY_LIFE_TIME))
- prefered_lft = 0x7FFFFFFF/HZ;
-
- ifp = ipv6_add_addr(idev, pfx, plen, scope, ifa_flags);
-
+ ifp = ipv6_add_addr(idev, pfx, plen, scope, IFA_F_PERMANENT);
if (!IS_ERR(ifp)) {
- spin_lock_bh(&ifp->lock);
- ifp->valid_lft = valid_lft;
- ifp->prefered_lft = prefered_lft;
- ifp->tstamp = jiffies;
- spin_unlock_bh(&ifp->lock);
-
addrconf_dad_start(ifp, 0);
in6_ifa_put(ifp);
- addrconf_verify(0);
return 0;
}
return -EFAULT;
rtnl_lock();
- err = inet6_addr_add(ireq.ifr6_ifindex, &ireq.ifr6_addr, ireq.ifr6_prefixlen,
- INFINITY_LIFE_TIME, INFINITY_LIFE_TIME);
+ err = inet6_addr_add(ireq.ifr6_ifindex, &ireq.ifr6_addr, ireq.ifr6_prefixlen);
rtnl_unlock();
return err;
}
ifp->idev->nd_parms->retrans_time / HZ;
#endif
- if (ifp->valid_lft != INFINITY_LIFE_TIME &&
- age >= ifp->valid_lft) {
+ if (age >= ifp->valid_lft) {
spin_unlock(&ifp->lock);
in6_ifa_hold(ifp);
read_unlock(&addrconf_hash_lock);
ipv6_del_addr(ifp);
goto restart;
- } else if (ifp->prefered_lft == INFINITY_LIFE_TIME) {
- spin_unlock(&ifp->lock);
- continue;
} else if (age >= ifp->prefered_lft) {
/* jiffies - ifp->tsamp > age >= ifp->prefered_lft */
int deprecate = 0;
pfx = RTA_DATA(rta[IFA_ADDRESS-1]);
}
if (rta[IFA_LOCAL-1]) {
- if (RTA_PAYLOAD(rta[IFA_LOCAL-1]) < sizeof(*pfx) ||
- (pfx && memcmp(pfx, RTA_DATA(rta[IFA_LOCAL-1]), sizeof(*pfx))))
+ if (pfx && memcmp(pfx, RTA_DATA(rta[IFA_LOCAL-1]), sizeof(*pfx)))
return -EINVAL;
pfx = RTA_DATA(rta[IFA_LOCAL-1]);
}
return inet6_addr_del(ifm->ifa_index, pfx, ifm->ifa_prefixlen);
}
-static int
-inet6_addr_modify(int ifindex, struct in6_addr *pfx,
- __u32 prefered_lft, __u32 valid_lft)
-{
- struct inet6_ifaddr *ifp = NULL;
- struct net_device *dev;
- int ifa_flags = 0;
-
- if ((dev = __dev_get_by_index(ifindex)) == NULL)
- return -ENODEV;
-
- if (!(dev->flags&IFF_UP))
- return -ENETDOWN;
-
- if (!valid_lft || (prefered_lft > valid_lft))
- return -EINVAL;
-
- ifp = ipv6_get_ifaddr(pfx, dev, 1);
- if (ifp == NULL)
- return -ENOENT;
-
- if (valid_lft == INFINITY_LIFE_TIME)
- ifa_flags = IFA_F_PERMANENT;
- else if (valid_lft >= 0x7FFFFFFF/HZ)
- valid_lft = 0x7FFFFFFF/HZ;
-
- if (prefered_lft == 0)
- ifa_flags = IFA_F_DEPRECATED;
- else if ((prefered_lft >= 0x7FFFFFFF/HZ) &&
- (prefered_lft != INFINITY_LIFE_TIME))
- prefered_lft = 0x7FFFFFFF/HZ;
-
- spin_lock_bh(&ifp->lock);
- ifp->flags = (ifp->flags & ~(IFA_F_DEPRECATED|IFA_F_PERMANENT)) | ifa_flags;
-
- ifp->tstamp = jiffies;
- ifp->valid_lft = valid_lft;
- ifp->prefered_lft = prefered_lft;
-
- spin_unlock_bh(&ifp->lock);
- if (!(ifp->flags&IFA_F_TENTATIVE))
- ipv6_ifa_notify(0, ifp);
- in6_ifa_put(ifp);
-
- addrconf_verify(0);
-
- return 0;
-}
-
static int
inet6_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
{
struct rtattr **rta = arg;
struct ifaddrmsg *ifm = NLMSG_DATA(nlh);
struct in6_addr *pfx;
- __u32 valid_lft = INFINITY_LIFE_TIME, prefered_lft = INFINITY_LIFE_TIME;
pfx = NULL;
if (rta[IFA_ADDRESS-1]) {
pfx = RTA_DATA(rta[IFA_ADDRESS-1]);
}
if (rta[IFA_LOCAL-1]) {
- if (RTA_PAYLOAD(rta[IFA_LOCAL-1]) < sizeof(*pfx) ||
- (pfx && memcmp(pfx, RTA_DATA(rta[IFA_LOCAL-1]), sizeof(*pfx))))
+ if (pfx && memcmp(pfx, RTA_DATA(rta[IFA_LOCAL-1]), sizeof(*pfx)))
return -EINVAL;
pfx = RTA_DATA(rta[IFA_LOCAL-1]);
}
if (pfx == NULL)
return -EINVAL;
- if (rta[IFA_CACHEINFO-1]) {
- struct ifa_cacheinfo *ci;
- if (RTA_PAYLOAD(rta[IFA_CACHEINFO-1]) < sizeof(*ci))
- return -EINVAL;
- ci = RTA_DATA(rta[IFA_CACHEINFO-1]);
- valid_lft = ci->ifa_valid;
- prefered_lft = ci->ifa_prefered;
- }
-
- if (nlh->nlmsg_flags & NLM_F_REPLACE) {
- int ret;
- ret = inet6_addr_modify(ifm->ifa_index, pfx,
- prefered_lft, valid_lft);
- if (ret == 0 || !(nlh->nlmsg_flags & NLM_F_CREATE))
- return ret;
- }
-
- return inet6_addr_add(ifm->ifa_index, pfx, ifm->ifa_prefixlen,
- prefered_lft, valid_lft);
-
+ return inet6_addr_add(ifm->ifa_index, pfx, ifm->ifa_prefixlen);
}
/* Maximum length of ifa_cacheinfo attributes */
return inet6_dump_addr(skb, cb, type);
}
-static int inet6_rtm_getaddr(struct sk_buff *in_skb,
- struct nlmsghdr* nlh, void *arg)
-{
- struct rtattr **rta = arg;
- struct ifaddrmsg *ifm = NLMSG_DATA(nlh);
- struct in6_addr *addr = NULL;
- struct net_device *dev = NULL;
- struct inet6_ifaddr *ifa;
- struct sk_buff *skb;
- int size = NLMSG_SPACE(sizeof(struct ifaddrmsg) + INET6_IFADDR_RTA_SPACE);
- int err;
-
- if (rta[IFA_ADDRESS-1]) {
- if (RTA_PAYLOAD(rta[IFA_ADDRESS-1]) < sizeof(*addr))
- return -EINVAL;
- addr = RTA_DATA(rta[IFA_ADDRESS-1]);
- }
- if (rta[IFA_LOCAL-1]) {
- if (RTA_PAYLOAD(rta[IFA_LOCAL-1]) < sizeof(*addr) ||
- (addr && memcmp(addr, RTA_DATA(rta[IFA_LOCAL-1]), sizeof(*addr))))
- return -EINVAL;
- addr = RTA_DATA(rta[IFA_LOCAL-1]);
- }
- if (addr == NULL)
- return -EINVAL;
-
- if (ifm->ifa_index)
- dev = __dev_get_by_index(ifm->ifa_index);
-
- if ((ifa = ipv6_get_ifaddr(addr, dev, 1)) == NULL)
- return -EADDRNOTAVAIL;
-
- if ((skb = alloc_skb(size, GFP_KERNEL)) == NULL) {
- err = -ENOBUFS;
- goto out;
- }
-
- NETLINK_CB(skb).dst_pid = NETLINK_CB(in_skb).pid;
- err = inet6_fill_ifaddr(skb, ifa, NETLINK_CB(in_skb).pid,
- nlh->nlmsg_seq, RTM_NEWADDR, 0);
- if (err < 0) {
- err = -EMSGSIZE;
- goto out_free;
- }
-
- err = netlink_unicast(rtnl, skb, NETLINK_CB(in_skb).pid, MSG_DONTWAIT);
- if (err > 0)
- err = 0;
-out:
- in6_ifa_put(ifa);
- return err;
-out_free:
- kfree_skb(skb);
- goto out;
-}
-
static void inet6_ifa_notify(int event, struct inet6_ifaddr *ifa)
{
struct sk_buff *skb;
[RTM_GETLINK - RTM_BASE] = { .dumpit = inet6_dump_ifinfo, },
[RTM_NEWADDR - RTM_BASE] = { .doit = inet6_rtm_newaddr, },
[RTM_DELADDR - RTM_BASE] = { .doit = inet6_rtm_deladdr, },
- [RTM_GETADDR - RTM_BASE] = { .doit = inet6_rtm_getaddr,
- .dumpit = inet6_dump_ifaddr, },
+ [RTM_GETADDR - RTM_BASE] = { .dumpit = inet6_dump_ifaddr, },
[RTM_GETMULTICAST - RTM_BASE] = { .dumpit = inet6_dump_ifmcaddr, },
[RTM_GETANYCAST - RTM_BASE] = { .dumpit = inet6_dump_ifacaddr, },
[RTM_NEWROUTE - RTM_BASE] = { .doit = inet6_rtm_newroute, },