return skb->len;
 }
 
-/* Create new static fdb entry */
+/* Update (create or replace) forwarding database entry */
 static int fdb_add_entry(struct net_bridge_port *source, const __u8 *addr,
                         __u16 state, __u16 flags)
 {
        } else {
                if (flags & NLM_F_EXCL)
                        return -EEXIST;
+       }
+
+       if (fdb_to_nud(fdb) != state) {
+               if (state & NUD_PERMANENT)
+                       fdb->is_local = fdb->is_static = 1;
+               else if (state & NUD_NOARP) {
+                       fdb->is_local = 0;
+                       fdb->is_static = 1;
+               } else
+                       fdb->is_local = fdb->is_static = 0;
 
-               if (flags & NLM_F_REPLACE)
-                       fdb->updated = fdb->used = jiffies;
-               fdb->is_local = fdb->is_static = 0;
+               fdb->updated = fdb->used = jiffies;
+               fdb_notify(fdb, RTM_NEWNEIGH);
        }
 
-       if (state & NUD_PERMANENT)
-               fdb->is_local = fdb->is_static = 1;
-       else if (state & NUD_NOARP)
-               fdb->is_static = 1;
        return 0;
 }
 
                return -EINVAL;
        }
 
+       if (!(ndm->ndm_state & (NUD_PERMANENT|NUD_NOARP|NUD_REACHABLE))) {
+               pr_info("bridge: RTM_NEWNEIGH with invalid state %#x\n", ndm->ndm_state);
+               return -EINVAL;
+       }
+
        p = br_port_get_rtnl(dev);
        if (p == NULL) {
                pr_info("bridge: RTM_NEWNEIGH %s not a bridge port\n",
                return -EINVAL;
        }
 
-       spin_lock_bh(&p->br->hash_lock);
-       err = fdb_add_entry(p, addr, ndm->ndm_state, nlh->nlmsg_flags);
-       spin_unlock_bh(&p->br->hash_lock);
+       if (ndm->ndm_flags & NTF_USE) {
+               rcu_read_lock();
+               br_fdb_update(p->br, p, addr);
+               rcu_read_unlock();
+       } else {
+               spin_lock_bh(&p->br->hash_lock);
+               err = fdb_add_entry(p, addr, ndm->ndm_state, nlh->nlmsg_flags);
+               spin_unlock_bh(&p->br->hash_lock);
+       }
 
        return err;
 }