#include <linux/skbuff.h>
 #include <linux/rcupdate.h>
 #include <linux/seq_file.h>
+#include <linux/bitmap.h>
 
 #include <linux/err.h>
 #include <linux/sysctl.h>
 
        int     reachable_time;
        int     data[NEIGH_VAR_DATA_MAX];
+       DECLARE_BITMAP(data_state, NEIGH_VAR_DATA_MAX);
 };
 
 static inline void neigh_var_set(struct neigh_parms *p, int index, int val)
 {
+       set_bit(index, p->data_state);
        p->data[index] = val;
 }
 
 #define NEIGH_VAR(p, attr) ((p)->data[NEIGH_VAR_ ## attr])
 #define NEIGH_VAR_SET(p, attr, val) neigh_var_set(p, NEIGH_VAR_ ## attr, val)
 
+static inline void neigh_parms_data_state_setall(struct neigh_parms *p)
+{
+       bitmap_fill(p->data_state, NEIGH_VAR_DATA_MAX);
+}
+
+static inline void neigh_parms_data_state_cleanall(struct neigh_parms *p)
+{
+       bitmap_zero(p->data_state, NEIGH_VAR_DATA_MAX);
+}
+
 struct neigh_statistics {
        unsigned long allocs;           /* number of allocated neighs */
        unsigned long destroys;         /* number of destroyed neighs */
 
 #include <linux/random.h>
 #include <linux/string.h>
 #include <linux/log2.h>
+#include <linux/inetdevice.h>
 
 #define DEBUG
 #define NEIGH_DEBUG 1
                p->next         = tbl->parms.next;
                tbl->parms.next = p;
                write_unlock_bh(&tbl->lock);
+
+               neigh_parms_data_state_cleanall(p);
        }
        return p;
 }
        return ret;
 }
 
+static struct neigh_parms *neigh_get_dev_parms_rcu(struct net_device *dev,
+                                                  int family)
+{
+       if (family == AF_INET)
+               return __in_dev_arp_parms_get_rcu(dev);
+       return NULL;
+}
+
+static void neigh_copy_dflt_parms(struct net *net, struct neigh_parms *p,
+                                 int index)
+{
+       struct net_device *dev;
+       int family = neigh_parms_family(p);
+
+       rcu_read_lock();
+       for_each_netdev_rcu(net, dev) {
+               struct neigh_parms *dst_p =
+                               neigh_get_dev_parms_rcu(dev, family);
+
+               if (dst_p && !test_bit(index, dst_p->data_state))
+                       dst_p->data[index] = p->data[index];
+       }
+       rcu_read_unlock();
+}
+
+static void neigh_proc_update(struct ctl_table *ctl, int write)
+{
+       struct net_device *dev = ctl->extra1;
+       struct neigh_parms *p = ctl->extra2;
+       struct net *net = p->net;
+       int index = (int *) ctl->data - p->data;
+
+       if (!write)
+               return;
+
+       set_bit(index, p->data_state);
+       if (!dev) /* NULL dev means this is default value */
+               neigh_copy_dflt_parms(net, p, index);
+}
+
 static int neigh_proc_dointvec_zero_intmax(struct ctl_table *ctl, int write,
                                           void __user *buffer,
                                           size_t *lenp, loff_t *ppos)
 {
        struct ctl_table tmp = *ctl;
+       int ret;
 
        tmp.extra1 = &zero;
        tmp.extra2 = &int_max;
 
-       return proc_dointvec_minmax(&tmp, write, buffer, lenp, ppos);
+       ret = proc_dointvec_minmax(&tmp, write, buffer, lenp, ppos);
+       neigh_proc_update(ctl, write);
+       return ret;
 }
 
 int neigh_proc_dointvec(struct ctl_table *ctl, int write,
                        void __user *buffer, size_t *lenp, loff_t *ppos)
 {
-       return proc_dointvec(ctl, write, buffer, lenp, ppos);
+       int ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
+
+       neigh_proc_update(ctl, write);
+       return ret;
 }
 EXPORT_SYMBOL(neigh_proc_dointvec);
 
                                void __user *buffer,
                                size_t *lenp, loff_t *ppos)
 {
-       return proc_dointvec_jiffies(ctl, write, buffer, lenp, ppos);
+       int ret = proc_dointvec_jiffies(ctl, write, buffer, lenp, ppos);
+
+       neigh_proc_update(ctl, write);
+       return ret;
 }
 EXPORT_SYMBOL(neigh_proc_dointvec_jiffies);
 
                                              void __user *buffer,
                                              size_t *lenp, loff_t *ppos)
 {
-       return proc_dointvec_userhz_jiffies(ctl, write, buffer, lenp, ppos);
+       int ret = proc_dointvec_userhz_jiffies(ctl, write, buffer, lenp, ppos);
+
+       neigh_proc_update(ctl, write);
+       return ret;
 }
 
 int neigh_proc_dointvec_ms_jiffies(struct ctl_table *ctl, int write,
                                   void __user *buffer,
                                   size_t *lenp, loff_t *ppos)
 {
-       return proc_dointvec_ms_jiffies(ctl, write, buffer, lenp, ppos);
+       int ret = proc_dointvec_ms_jiffies(ctl, write, buffer, lenp, ppos);
+
+       neigh_proc_update(ctl, write);
+       return ret;
 }
 EXPORT_SYMBOL(neigh_proc_dointvec_ms_jiffies);
 
                                          void __user *buffer,
                                          size_t *lenp, loff_t *ppos)
 {
-       return proc_unres_qlen(ctl, write, buffer, lenp, ppos);
+       int ret = proc_unres_qlen(ctl, write, buffer, lenp, ppos);
+
+       neigh_proc_update(ctl, write);
+       return ret;
 }
 
 #define NEIGH_PARMS_DATA_OFFSET(index) \
        for (i = 0; i < ARRAY_SIZE(t->neigh_vars); i++) {
                t->neigh_vars[i].data += (long) p;
                t->neigh_vars[i].extra1 = dev;
+               t->neigh_vars[i].extra2 = p;
        }
 
        if (dev) {