From: Roopa Prabhu <ro...@cumulusnetworks.com>

neigh notifications today carry pid 0 for nlmsg_pid
in all cases. This patch fixes it to carry calling process
pid when available. Applications (eg. quagga) rely on
nlmsg_pid to ignore notifications generated by their own
netlink operations. This patch follows the routing subsystem
which already sets this correctly.

Reported-by: Vivek Venkatraman <vi...@cumulusnetworks.com>
Signed-off-by: Roopa Prabhu <ro...@cumulusnetworks.com>
---
 include/net/neighbour.h |  3 ++-
 net/atm/clip.c          |  4 ++--
 net/core/neighbour.c    | 32 ++++++++++++++++++--------------
 net/ipv4/arp.c          |  6 +++---
 net/ipv6/ndisc.c        |  2 +-
 5 files changed, 26 insertions(+), 21 deletions(-)

diff --git a/include/net/neighbour.h b/include/net/neighbour.h
index 5ebf694..9496179 100644
--- a/include/net/neighbour.h
+++ b/include/net/neighbour.h
@@ -314,7 +314,8 @@ static inline struct neighbour *neigh_create(struct 
neigh_table *tbl,
 }
 void neigh_destroy(struct neighbour *neigh);
 int __neigh_event_send(struct neighbour *neigh, struct sk_buff *skb);
-int neigh_update(struct neighbour *neigh, const u8 *lladdr, u8 new, u32 flags);
+int neigh_update(struct neighbour *neigh, const u8 *lladdr, u8 new, u32 flags,
+                u32 nlmsg_pid);
 void __neigh_set_probe_once(struct neighbour *neigh);
 void neigh_changeaddr(struct neigh_table *tbl, struct net_device *dev);
 int neigh_ifdown(struct neigh_table *tbl, struct net_device *dev);
diff --git a/net/atm/clip.c b/net/atm/clip.c
index 53b4ac0..ec527b6 100644
--- a/net/atm/clip.c
+++ b/net/atm/clip.c
@@ -106,7 +106,7 @@ static void unlink_clip_vcc(struct clip_vcc *clip_vcc)
                        entry->expires = jiffies - 1;
                        /* force resolution or expiration */
                        error = neigh_update(entry->neigh, NULL, NUD_NONE,
-                                            NEIGH_UPDATE_F_ADMIN);
+                                            NEIGH_UPDATE_F_ADMIN, 0);
                        if (error)
                                pr_crit("neigh_update failed with %d\n", error);
                        goto out;
@@ -481,7 +481,7 @@ static int clip_setentry(struct atm_vcc *vcc, __be32 ip)
                link_vcc(clip_vcc, entry);
        }
        error = neigh_update(neigh, llc_oui, NUD_PERMANENT,
-                            NEIGH_UPDATE_F_OVERRIDE | NEIGH_UPDATE_F_ADMIN);
+                            NEIGH_UPDATE_F_OVERRIDE | NEIGH_UPDATE_F_ADMIN, 0);
        neigh_release(neigh);
        return error;
 }
diff --git a/net/core/neighbour.c b/net/core/neighbour.c
index e7c12ca..7069f5e 100644
--- a/net/core/neighbour.c
+++ b/net/core/neighbour.c
@@ -52,8 +52,9 @@
 #define PNEIGH_HASHMASK                0xF
 
 static void neigh_timer_handler(unsigned long arg);
-static void __neigh_notify(struct neighbour *n, int type, int flags);
-static void neigh_update_notify(struct neighbour *neigh);
+static void __neigh_notify(struct neighbour *n, int type, int flags,
+                          u32 pid);
+static void neigh_update_notify(struct neighbour *neigh, u32 nlmsg_pid);
 static int pneigh_ifdown(struct neigh_table *tbl, struct net_device *dev);
 
 #ifdef CONFIG_PROC_FS
@@ -99,7 +100,7 @@ static void neigh_cleanup_and_release(struct neighbour 
*neigh)
        if (neigh->parms->neigh_cleanup)
                neigh->parms->neigh_cleanup(neigh);
 
-       __neigh_notify(neigh, RTM_DELNEIGH, 0);
+       __neigh_notify(neigh, RTM_DELNEIGH, 0, 0);
        call_netevent_notifiers(NETEVENT_NEIGH_UPDATE, neigh);
        neigh_release(neigh);
 }
@@ -948,7 +949,7 @@ static void neigh_timer_handler(unsigned long arg)
        }
 
        if (notify)
-               neigh_update_notify(neigh);
+               neigh_update_notify(neigh, 0);
 
        neigh_release(neigh);
 }
@@ -1072,7 +1073,7 @@ static void neigh_update_hhs(struct neighbour *neigh)
  */
 
 int neigh_update(struct neighbour *neigh, const u8 *lladdr, u8 new,
-                u32 flags)
+                u32 flags, u32 nlmsg_pid)
 {
        u8 old;
        int err;
@@ -1229,7 +1230,7 @@ int neigh_update(struct neighbour *neigh, const u8 
*lladdr, u8 new,
        write_unlock_bh(&neigh->lock);
 
        if (notify)
-               neigh_update_notify(neigh);
+               neigh_update_notify(neigh, nlmsg_pid);
 
        return err;
 }
@@ -1260,7 +1261,7 @@ struct neighbour *neigh_event_ns(struct neigh_table *tbl,
                                                 lladdr || !dev->addr_len);
        if (neigh)
                neigh_update(neigh, lladdr, NUD_STALE,
-                            NEIGH_UPDATE_F_OVERRIDE);
+                            NEIGH_UPDATE_F_OVERRIDE, 0);
        return neigh;
 }
 EXPORT_SYMBOL(neigh_event_ns);
@@ -1638,7 +1639,8 @@ static int neigh_delete(struct sk_buff *skb, struct 
nlmsghdr *nlh)
 
        err = neigh_update(neigh, NULL, NUD_FAILED,
                           NEIGH_UPDATE_F_OVERRIDE |
-                          NEIGH_UPDATE_F_ADMIN);
+                          NEIGH_UPDATE_F_ADMIN,
+                          NETLINK_CB(skb).portid);
        neigh_release(neigh);
 
 out:
@@ -1729,7 +1731,8 @@ static int neigh_add(struct sk_buff *skb, struct nlmsghdr 
*nlh)
                neigh_event_send(neigh, NULL);
                err = 0;
        } else
-               err = neigh_update(neigh, lladdr, ndm->ndm_state, flags);
+               err = neigh_update(neigh, lladdr, ndm->ndm_state, flags,
+                                  NETLINK_CB(skb).portid);
        neigh_release(neigh);
 
 out:
@@ -2229,10 +2232,10 @@ static int pneigh_fill_info(struct sk_buff *skb, struct 
pneigh_entry *pn,
        return -EMSGSIZE;
 }
 
-static void neigh_update_notify(struct neighbour *neigh)
+static void neigh_update_notify(struct neighbour *neigh, u32 nlmsg_pid)
 {
        call_netevent_notifiers(NETEVENT_NEIGH_UPDATE, neigh);
-       __neigh_notify(neigh, RTM_NEWNEIGH, 0);
+       __neigh_notify(neigh, RTM_NEWNEIGH, 0, nlmsg_pid);
 }
 
 static bool neigh_master_filtered(struct net_device *dev, int master_idx)
@@ -2830,7 +2833,8 @@ static inline size_t neigh_nlmsg_size(void)
               + nla_total_size(4); /* NDA_PROBES */
 }
 
-static void __neigh_notify(struct neighbour *n, int type, int flags)
+static void __neigh_notify(struct neighbour *n, int type, int flags,
+                          u32 pid)
 {
        struct net *net = dev_net(n->dev);
        struct sk_buff *skb;
@@ -2840,7 +2844,7 @@ static void __neigh_notify(struct neighbour *n, int type, 
int flags)
        if (skb == NULL)
                goto errout;
 
-       err = neigh_fill_info(skb, n, 0, 0, type, flags);
+       err = neigh_fill_info(skb, n, pid, 0, type, flags);
        if (err < 0) {
                /* -EMSGSIZE implies BUG in neigh_nlmsg_size() */
                WARN_ON(err == -EMSGSIZE);
@@ -2856,7 +2860,7 @@ static void __neigh_notify(struct neighbour *n, int type, 
int flags)
 
 void neigh_app_ns(struct neighbour *n)
 {
-       __neigh_notify(n, RTM_GETNEIGH, NLM_F_REQUEST);
+       __neigh_notify(n, RTM_GETNEIGH, NLM_F_REQUEST, 0);
 }
 EXPORT_SYMBOL(neigh_app_ns);
 
diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c
index 51b27ae..0937b34 100644
--- a/net/ipv4/arp.c
+++ b/net/ipv4/arp.c
@@ -872,7 +872,7 @@ static int arp_process(struct net *net, struct sock *sk, 
struct sk_buff *skb)
                    skb->pkt_type != PACKET_HOST)
                        state = NUD_STALE;
                neigh_update(n, sha, state,
-                            override ? NEIGH_UPDATE_F_OVERRIDE : 0);
+                            override ? NEIGH_UPDATE_F_OVERRIDE : 0, 0);
                neigh_release(n);
        }
 
@@ -1033,7 +1033,7 @@ static int arp_req_set(struct net *net, struct arpreq *r,
                err = neigh_update(neigh, (r->arp_flags & ATF_COM) ?
                                   r->arp_ha.sa_data : NULL, state,
                                   NEIGH_UPDATE_F_OVERRIDE |
-                                  NEIGH_UPDATE_F_ADMIN);
+                                  NEIGH_UPDATE_F_ADMIN, 0);
                neigh_release(neigh);
        }
        return err;
@@ -1084,7 +1084,7 @@ static int arp_invalidate(struct net_device *dev, __be32 
ip)
                if (neigh->nud_state & ~NUD_NOARP)
                        err = neigh_update(neigh, NULL, NUD_FAILED,
                                           NEIGH_UPDATE_F_OVERRIDE|
-                                          NEIGH_UPDATE_F_ADMIN);
+                                          NEIGH_UPDATE_F_ADMIN, 0);
                neigh_release(neigh);
        }
 
diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
index 7ebac63..112ccbc 100644
--- a/net/ipv6/ndisc.c
+++ b/net/ipv6/ndisc.c
@@ -732,7 +732,7 @@ void ndisc_update(const struct net_device *dev, struct 
neighbour *neigh,
                  const u8 *lladdr, u8 new, u32 flags, u8 icmp6_type,
                  struct ndisc_options *ndopts)
 {
-       neigh_update(neigh, lladdr, new, flags);
+       neigh_update(neigh, lladdr, new, flags, 0);
        /* report ndisc ops about neighbour update */
        ndisc_ops_update(dev, neigh, flags, icmp6_type, ndopts);
 }
-- 
1.9.1

Reply via email to