]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - net/ipv6/addrconf.c
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
[karo-tx-linux.git] / net / ipv6 / addrconf.c
index e7780d72067c00862d7978bad16be72ef261aff2..2d6d1793bbfed73fc001ccfbff9485601ea527d7 100644 (file)
@@ -99,9 +99,9 @@
 #define ACONF_DEBUG 2
 
 #if ACONF_DEBUG >= 3
-#define ADBG(x) printk x
+#define ADBG(fmt, ...) printk(fmt, ##__VA_ARGS__)
 #else
-#define ADBG(x)
+#define ADBG(fmt, ...) do { if (0) printk(fmt, ##__VA_ARGS__); } while (0)
 #endif
 
 #define        INFINITY_LIFE_TIME      0xFFFFFFFF
@@ -177,6 +177,8 @@ static struct ipv6_devconf ipv6_devconf __read_mostly = {
        .accept_redirects       = 1,
        .autoconf               = 1,
        .force_mld_version      = 0,
+       .mldv1_unsolicited_report_interval = 10 * HZ,
+       .mldv2_unsolicited_report_interval = HZ,
        .dad_transmits          = 1,
        .rtr_solicits           = MAX_RTR_SOLICITATIONS,
        .rtr_solicit_interval   = RTR_SOLICITATION_INTERVAL,
@@ -211,6 +213,9 @@ static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = {
        .accept_ra              = 1,
        .accept_redirects       = 1,
        .autoconf               = 1,
+       .force_mld_version      = 0,
+       .mldv1_unsolicited_report_interval = 10 * HZ,
+       .mldv2_unsolicited_report_interval = HZ,
        .dad_transmits          = 1,
        .rtr_solicits           = MAX_RTR_SOLICITATIONS,
        .rtr_solicit_interval   = RTR_SOLICITATION_INTERVAL,
@@ -369,9 +374,9 @@ static struct inet6_dev *ipv6_add_dev(struct net_device *dev)
        dev_hold(dev);
 
        if (snmp6_alloc_dev(ndev) < 0) {
-               ADBG((KERN_WARNING
+               ADBG(KERN_WARNING
                        "%s: cannot allocate memory for statistics; dev=%s.\n",
-                       __func__, dev->name));
+                       __func__, dev->name);
                neigh_parms_release(&nd_tbl, ndev->nd_parms);
                dev_put(dev);
                kfree(ndev);
@@ -379,9 +384,9 @@ static struct inet6_dev *ipv6_add_dev(struct net_device *dev)
        }
 
        if (snmp6_register_dev(ndev) < 0) {
-               ADBG((KERN_WARNING
+               ADBG(KERN_WARNING
                        "%s: cannot create /proc/net/dev_snmp6/%s\n",
-                       __func__, dev->name));
+                       __func__, dev->name);
                neigh_parms_release(&nd_tbl, ndev->nd_parms);
                ndev->dead = 1;
                in6_dev_finish_destroy(ndev);
@@ -813,8 +818,9 @@ static u32 inet6_addr_hash(const struct in6_addr *addr)
 /* On success it returns ifp with increased reference count */
 
 static struct inet6_ifaddr *
-ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen,
-             int scope, u32 flags)
+ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr,
+             const struct in6_addr *peer_addr, int pfxlen,
+             int scope, u32 flags, u32 valid_lft, u32 prefered_lft)
 {
        struct inet6_ifaddr *ifa = NULL;
        struct rt6_info *rt;
@@ -843,7 +849,7 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen,
 
        /* Ignore adding duplicate addresses on an interface */
        if (ipv6_chk_same_addr(dev_net(idev->dev), addr, idev->dev)) {
-               ADBG(("ipv6_add_addr: already assigned\n"));
+               ADBG("ipv6_add_addr: already assigned\n");
                err = -EEXIST;
                goto out;
        }
@@ -851,7 +857,7 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen,
        ifa = kzalloc(sizeof(struct inet6_ifaddr), GFP_ATOMIC);
 
        if (ifa == NULL) {
-               ADBG(("ipv6_add_addr: malloc failed\n"));
+               ADBG("ipv6_add_addr: malloc failed\n");
                err = -ENOBUFS;
                goto out;
        }
@@ -863,6 +869,8 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen,
        }
 
        ifa->addr = *addr;
+       if (peer_addr)
+               ifa->peer_addr = *peer_addr;
 
        spin_lock_init(&ifa->lock);
        spin_lock_init(&ifa->state_lock);
@@ -872,6 +880,8 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen,
        ifa->scope = scope;
        ifa->prefix_len = pfxlen;
        ifa->flags = flags | IFA_F_TENTATIVE;
+       ifa->valid_lft = valid_lft;
+       ifa->prefered_lft = prefered_lft;
        ifa->cstamp = ifa->tstamp = jiffies;
        ifa->tokenized = false;
 
@@ -1121,11 +1131,10 @@ retry:
        if (ifp->flags & IFA_F_OPTIMISTIC)
                addr_flags |= IFA_F_OPTIMISTIC;
 
-       ift = !max_addresses ||
-             ipv6_count_addresses(idev) < max_addresses ?
-               ipv6_add_addr(idev, &addr, tmp_plen, ipv6_addr_scope(&addr),
-                             addr_flags) : NULL;
-       if (IS_ERR_OR_NULL(ift)) {
+       ift = ipv6_add_addr(idev, &addr, NULL, tmp_plen,
+                           ipv6_addr_scope(&addr), addr_flags,
+                           tmp_valid_lft, tmp_prefered_lft);
+       if (IS_ERR(ift)) {
                in6_ifa_put(ifp);
                in6_dev_put(idev);
                pr_info("%s: retry temporary address regeneration\n", __func__);
@@ -1136,8 +1145,6 @@ retry:
 
        spin_lock_bh(&ift->lock);
        ift->ifpub = ifp;
-       ift->valid_lft = tmp_valid_lft;
-       ift->prefered_lft = tmp_prefered_lft;
        ift->cstamp = now;
        ift->tstamp = tmp_tstamp;
        spin_unlock_bh(&ift->lock);
@@ -1805,6 +1812,16 @@ static int addrconf_ifid_gre(u8 *eui, struct net_device *dev)
        return __ipv6_isatap_ifid(eui, *(__be32 *)dev->dev_addr);
 }
 
+static int addrconf_ifid_ip6tnl(u8 *eui, struct net_device *dev)
+{
+       memcpy(eui, dev->perm_addr, 3);
+       memcpy(eui + 5, dev->perm_addr + 3, 3);
+       eui[3] = 0xFF;
+       eui[4] = 0xFE;
+       eui[0] ^= 2;
+       return 0;
+}
+
 static int ipv6_generate_eui64(u8 *eui, struct net_device *dev)
 {
        switch (dev->type) {
@@ -1823,6 +1840,8 @@ static int ipv6_generate_eui64(u8 *eui, struct net_device *dev)
                return addrconf_ifid_eui64(eui, dev);
        case ARPHRD_IEEE1394:
                return addrconf_ifid_ieee1394(eui, dev);
+       case ARPHRD_TUNNEL6:
+               return addrconf_ifid_ip6tnl(eui, dev);
        }
        return -1;
 }
@@ -2048,7 +2067,7 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len, bool sllao)
        pinfo = (struct prefix_info *) opt;
 
        if (len < sizeof(struct prefix_info)) {
-               ADBG(("addrconf: prefix option too short\n"));
+               ADBG("addrconf: prefix option too short\n");
                return;
        }
 
@@ -2179,16 +2198,19 @@ ok:
                         */
                        if (!max_addresses ||
                            ipv6_count_addresses(in6_dev) < max_addresses)
-                               ifp = ipv6_add_addr(in6_dev, &addr, pinfo->prefix_len,
+                               ifp = ipv6_add_addr(in6_dev, &addr, NULL,
+                                                   pinfo->prefix_len,
                                                    addr_type&IPV6_ADDR_SCOPE_MASK,
-                                                   addr_flags);
+                                                   addr_flags, valid_lft,
+                                                   prefered_lft);
 
                        if (IS_ERR_OR_NULL(ifp)) {
                                in6_dev_put(in6_dev);
                                return;
                        }
 
-                       update_lft = create = 1;
+                       update_lft = 0;
+                       create = 1;
                        ifp->cstamp = jiffies;
                        ifp->tokenized = tokenized;
                        addrconf_dad_start(ifp);
@@ -2209,7 +2231,7 @@ ok:
                                stored_lft = ifp->valid_lft - (now - ifp->tstamp) / HZ;
                        else
                                stored_lft = 0;
-                       if (!update_lft && stored_lft) {
+                       if (!update_lft && !create && stored_lft) {
                                if (valid_lft > MIN_VALID_LIFETIME ||
                                    valid_lft > stored_lft)
                                        update_lft = 1;
@@ -2455,17 +2477,10 @@ static int inet6_addr_add(struct net *net, int ifindex, const struct in6_addr *p
                prefered_lft = timeout;
        }
 
-       ifp = ipv6_add_addr(idev, pfx, plen, scope, ifa_flags);
+       ifp = ipv6_add_addr(idev, pfx, peer_pfx, plen, scope, ifa_flags,
+                           valid_lft, prefered_lft);
 
        if (!IS_ERR(ifp)) {
-               spin_lock_bh(&ifp->lock);
-               ifp->valid_lft = valid_lft;
-               ifp->prefered_lft = prefered_lft;
-               ifp->tstamp = jiffies;
-               if (peer_pfx)
-                       ifp->peer_addr = *peer_pfx;
-               spin_unlock_bh(&ifp->lock);
-
                addrconf_prefix_route(&ifp->addr, ifp->prefix_len, dev,
                                      expires, flags);
                /*
@@ -2557,7 +2572,8 @@ static void add_addr(struct inet6_dev *idev, const struct in6_addr *addr,
 {
        struct inet6_ifaddr *ifp;
 
-       ifp = ipv6_add_addr(idev, addr, plen, scope, IFA_F_PERMANENT);
+       ifp = ipv6_add_addr(idev, addr, NULL, plen,
+                           scope, IFA_F_PERMANENT, 0, 0);
        if (!IS_ERR(ifp)) {
                spin_lock_bh(&ifp->lock);
                ifp->flags &= ~IFA_F_TENTATIVE;
@@ -2683,7 +2699,7 @@ static void addrconf_add_linklocal(struct inet6_dev *idev, const struct in6_addr
 #endif
 
 
-       ifp = ipv6_add_addr(idev, addr, 64, IFA_LINK, addr_flags);
+       ifp = ipv6_add_addr(idev, addr, NULL, 64, IFA_LINK, addr_flags, 0, 0);
        if (!IS_ERR(ifp)) {
                addrconf_prefix_route(&ifp->addr, ifp->prefix_len, idev->dev, 0, 0);
                addrconf_dad_start(ifp);
@@ -2703,7 +2719,8 @@ static void addrconf_dev_config(struct net_device *dev)
            (dev->type != ARPHRD_ARCNET) &&
            (dev->type != ARPHRD_INFINIBAND) &&
            (dev->type != ARPHRD_IEEE802154) &&
-           (dev->type != ARPHRD_IEEE1394)) {
+           (dev->type != ARPHRD_IEEE1394) &&
+           (dev->type != ARPHRD_TUNNEL6)) {
                /* Alas, we support only Ethernet autoconfiguration. */
                return;
        }
@@ -2789,44 +2806,6 @@ ipv6_inherit_linklocal(struct inet6_dev *idev, struct net_device *link_dev)
        return -1;
 }
 
-static void ip6_tnl_add_linklocal(struct inet6_dev *idev)
-{
-       struct net_device *link_dev;
-       struct net *net = dev_net(idev->dev);
-
-       /* first try to inherit the link-local address from the link device */
-       if (idev->dev->iflink &&
-           (link_dev = __dev_get_by_index(net, idev->dev->iflink))) {
-               if (!ipv6_inherit_linklocal(idev, link_dev))
-                       return;
-       }
-       /* then try to inherit it from any device */
-       for_each_netdev(net, link_dev) {
-               if (!ipv6_inherit_linklocal(idev, link_dev))
-                       return;
-       }
-       pr_debug("init ip6-ip6: add_linklocal failed\n");
-}
-
-/*
- * Autoconfigure tunnel with a link-local address so routing protocols,
- * DHCPv6, MLD etc. can be run over the virtual link
- */
-
-static void addrconf_ip6_tnl_config(struct net_device *dev)
-{
-       struct inet6_dev *idev;
-
-       ASSERT_RTNL();
-
-       idev = addrconf_add_dev(dev);
-       if (IS_ERR(idev)) {
-               pr_debug("init ip6-ip6: add_dev failed\n");
-               return;
-       }
-       ip6_tnl_add_linklocal(idev);
-}
-
 static int addrconf_notify(struct notifier_block *this, unsigned long event,
                           void *ptr)
 {
@@ -2894,9 +2873,6 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event,
                        addrconf_gre_config(dev);
                        break;
 #endif
-               case ARPHRD_TUNNEL6:
-                       addrconf_ip6_tnl_config(dev);
-                       break;
                case ARPHRD_LOOPBACK:
                        init_loopback(dev);
                        break;
@@ -3631,8 +3607,8 @@ restart:
        if (time_before(next_sched, jiffies + ADDRCONF_TIMER_FUZZ_MAX))
                next_sched = jiffies + ADDRCONF_TIMER_FUZZ_MAX;
 
-       ADBG((KERN_DEBUG "now = %lu, schedule = %lu, rounded schedule = %lu => %lu\n",
-             now, next, next_sec, next_sched));
+       ADBG(KERN_DEBUG "now = %lu, schedule = %lu, rounded schedule = %lu => %lu\n",
+             now, next, next_sec, next_sched);
 
        addr_chk_timer.expires = next_sched;
        add_timer(&addr_chk_timer);
@@ -4178,6 +4154,10 @@ static inline void ipv6_store_devconf(struct ipv6_devconf *cnf,
        array[DEVCONF_RTR_SOLICIT_DELAY] =
                jiffies_to_msecs(cnf->rtr_solicit_delay);
        array[DEVCONF_FORCE_MLD_VERSION] = cnf->force_mld_version;
+       array[DEVCONF_MLDV1_UNSOLICITED_REPORT_INTERVAL] =
+               jiffies_to_msecs(cnf->mldv1_unsolicited_report_interval);
+       array[DEVCONF_MLDV2_UNSOLICITED_REPORT_INTERVAL] =
+               jiffies_to_msecs(cnf->mldv2_unsolicited_report_interval);
 #ifdef CONFIG_IPV6_PRIVACY
        array[DEVCONF_USE_TEMPADDR] = cnf->use_tempaddr;
        array[DEVCONF_TEMP_VALID_LFT] = cnf->temp_valid_lft;
@@ -4861,6 +4841,22 @@ static struct addrconf_sysctl_table
                        .mode           = 0644,
                        .proc_handler   = proc_dointvec,
                },
+               {
+                       .procname       = "mldv1_unsolicited_report_interval",
+                       .data           =
+                               &ipv6_devconf.mldv1_unsolicited_report_interval,
+                       .maxlen         = sizeof(int),
+                       .mode           = 0644,
+                       .proc_handler   = proc_dointvec_ms_jiffies,
+               },
+               {
+                       .procname       = "mldv2_unsolicited_report_interval",
+                       .data           =
+                               &ipv6_devconf.mldv2_unsolicited_report_interval,
+                       .maxlen         = sizeof(int),
+                       .mode           = 0644,
+                       .proc_handler   = proc_dointvec_ms_jiffies,
+               },
 #ifdef CONFIG_IPV6_PRIVACY
                {
                        .procname       = "use_tempaddr",