Commit 7b8f7a40 authored by Roopa Prabhu's avatar Roopa Prabhu Committed by David S. Miller

neighbour: fix nlmsg_pid in notifications

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: default avatarVivek Venkatraman <vivek@cumulusnetworks.com>
Signed-off-by: default avatarRoopa Prabhu <roopa@cumulusnetworks.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 7ada7ca5
...@@ -314,7 +314,8 @@ static inline struct neighbour *neigh_create(struct neigh_table *tbl, ...@@ -314,7 +314,8 @@ static inline struct neighbour *neigh_create(struct neigh_table *tbl,
} }
void neigh_destroy(struct neighbour *neigh); void neigh_destroy(struct neighbour *neigh);
int __neigh_event_send(struct neighbour *neigh, struct sk_buff *skb); 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_set_probe_once(struct neighbour *neigh);
void neigh_changeaddr(struct neigh_table *tbl, struct net_device *dev); void neigh_changeaddr(struct neigh_table *tbl, struct net_device *dev);
int neigh_ifdown(struct neigh_table *tbl, struct net_device *dev); int neigh_ifdown(struct neigh_table *tbl, struct net_device *dev);
......
...@@ -106,7 +106,7 @@ static void unlink_clip_vcc(struct clip_vcc *clip_vcc) ...@@ -106,7 +106,7 @@ static void unlink_clip_vcc(struct clip_vcc *clip_vcc)
entry->expires = jiffies - 1; entry->expires = jiffies - 1;
/* force resolution or expiration */ /* force resolution or expiration */
error = neigh_update(entry->neigh, NULL, NUD_NONE, error = neigh_update(entry->neigh, NULL, NUD_NONE,
NEIGH_UPDATE_F_ADMIN); NEIGH_UPDATE_F_ADMIN, 0);
if (error) if (error)
pr_crit("neigh_update failed with %d\n", error); pr_crit("neigh_update failed with %d\n", error);
goto out; goto out;
...@@ -481,7 +481,7 @@ static int clip_setentry(struct atm_vcc *vcc, __be32 ip) ...@@ -481,7 +481,7 @@ static int clip_setentry(struct atm_vcc *vcc, __be32 ip)
link_vcc(clip_vcc, entry); link_vcc(clip_vcc, entry);
} }
error = neigh_update(neigh, llc_oui, NUD_PERMANENT, 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); neigh_release(neigh);
return error; return error;
} }
......
...@@ -52,8 +52,9 @@ do { \ ...@@ -52,8 +52,9 @@ do { \
#define PNEIGH_HASHMASK 0xF #define PNEIGH_HASHMASK 0xF
static void neigh_timer_handler(unsigned long arg); static void neigh_timer_handler(unsigned long arg);
static void __neigh_notify(struct neighbour *n, int type, int flags); static void __neigh_notify(struct neighbour *n, int type, int flags,
static void neigh_update_notify(struct neighbour *neigh); 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); static int pneigh_ifdown(struct neigh_table *tbl, struct net_device *dev);
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
...@@ -99,7 +100,7 @@ static void neigh_cleanup_and_release(struct neighbour *neigh) ...@@ -99,7 +100,7 @@ static void neigh_cleanup_and_release(struct neighbour *neigh)
if (neigh->parms->neigh_cleanup) if (neigh->parms->neigh_cleanup)
neigh->parms->neigh_cleanup(neigh); 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); call_netevent_notifiers(NETEVENT_NEIGH_UPDATE, neigh);
neigh_release(neigh); neigh_release(neigh);
} }
...@@ -948,7 +949,7 @@ static void neigh_timer_handler(unsigned long arg) ...@@ -948,7 +949,7 @@ static void neigh_timer_handler(unsigned long arg)
} }
if (notify) if (notify)
neigh_update_notify(neigh); neigh_update_notify(neigh, 0);
neigh_release(neigh); neigh_release(neigh);
} }
...@@ -1072,7 +1073,7 @@ static void neigh_update_hhs(struct neighbour *neigh) ...@@ -1072,7 +1073,7 @@ static void neigh_update_hhs(struct neighbour *neigh)
*/ */
int neigh_update(struct neighbour *neigh, const u8 *lladdr, u8 new, int neigh_update(struct neighbour *neigh, const u8 *lladdr, u8 new,
u32 flags) u32 flags, u32 nlmsg_pid)
{ {
u8 old; u8 old;
int err; int err;
...@@ -1229,7 +1230,7 @@ int neigh_update(struct neighbour *neigh, const u8 *lladdr, u8 new, ...@@ -1229,7 +1230,7 @@ int neigh_update(struct neighbour *neigh, const u8 *lladdr, u8 new,
write_unlock_bh(&neigh->lock); write_unlock_bh(&neigh->lock);
if (notify) if (notify)
neigh_update_notify(neigh); neigh_update_notify(neigh, nlmsg_pid);
return err; return err;
} }
...@@ -1260,7 +1261,7 @@ struct neighbour *neigh_event_ns(struct neigh_table *tbl, ...@@ -1260,7 +1261,7 @@ struct neighbour *neigh_event_ns(struct neigh_table *tbl,
lladdr || !dev->addr_len); lladdr || !dev->addr_len);
if (neigh) if (neigh)
neigh_update(neigh, lladdr, NUD_STALE, neigh_update(neigh, lladdr, NUD_STALE,
NEIGH_UPDATE_F_OVERRIDE); NEIGH_UPDATE_F_OVERRIDE, 0);
return neigh; return neigh;
} }
EXPORT_SYMBOL(neigh_event_ns); EXPORT_SYMBOL(neigh_event_ns);
...@@ -1638,7 +1639,8 @@ static int neigh_delete(struct sk_buff *skb, struct nlmsghdr *nlh) ...@@ -1638,7 +1639,8 @@ static int neigh_delete(struct sk_buff *skb, struct nlmsghdr *nlh)
err = neigh_update(neigh, NULL, NUD_FAILED, err = neigh_update(neigh, NULL, NUD_FAILED,
NEIGH_UPDATE_F_OVERRIDE | NEIGH_UPDATE_F_OVERRIDE |
NEIGH_UPDATE_F_ADMIN); NEIGH_UPDATE_F_ADMIN,
NETLINK_CB(skb).portid);
neigh_release(neigh); neigh_release(neigh);
out: out:
...@@ -1729,7 +1731,8 @@ static int neigh_add(struct sk_buff *skb, struct nlmsghdr *nlh) ...@@ -1729,7 +1731,8 @@ static int neigh_add(struct sk_buff *skb, struct nlmsghdr *nlh)
neigh_event_send(neigh, NULL); neigh_event_send(neigh, NULL);
err = 0; err = 0;
} else } 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); neigh_release(neigh);
out: out:
...@@ -2229,10 +2232,10 @@ static int pneigh_fill_info(struct sk_buff *skb, struct pneigh_entry *pn, ...@@ -2229,10 +2232,10 @@ static int pneigh_fill_info(struct sk_buff *skb, struct pneigh_entry *pn,
return -EMSGSIZE; 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); 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) static bool neigh_master_filtered(struct net_device *dev, int master_idx)
...@@ -2830,7 +2833,8 @@ static inline size_t neigh_nlmsg_size(void) ...@@ -2830,7 +2833,8 @@ static inline size_t neigh_nlmsg_size(void)
+ nla_total_size(4); /* NDA_PROBES */ + 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 net *net = dev_net(n->dev);
struct sk_buff *skb; struct sk_buff *skb;
...@@ -2840,7 +2844,7 @@ static void __neigh_notify(struct neighbour *n, int type, int flags) ...@@ -2840,7 +2844,7 @@ static void __neigh_notify(struct neighbour *n, int type, int flags)
if (skb == NULL) if (skb == NULL)
goto errout; 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) { if (err < 0) {
/* -EMSGSIZE implies BUG in neigh_nlmsg_size() */ /* -EMSGSIZE implies BUG in neigh_nlmsg_size() */
WARN_ON(err == -EMSGSIZE); WARN_ON(err == -EMSGSIZE);
...@@ -2856,7 +2860,7 @@ static void __neigh_notify(struct neighbour *n, int type, int flags) ...@@ -2856,7 +2860,7 @@ static void __neigh_notify(struct neighbour *n, int type, int flags)
void neigh_app_ns(struct neighbour *n) 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); EXPORT_SYMBOL(neigh_app_ns);
......
...@@ -872,7 +872,7 @@ static int arp_process(struct net *net, struct sock *sk, struct sk_buff *skb) ...@@ -872,7 +872,7 @@ static int arp_process(struct net *net, struct sock *sk, struct sk_buff *skb)
skb->pkt_type != PACKET_HOST) skb->pkt_type != PACKET_HOST)
state = NUD_STALE; state = NUD_STALE;
neigh_update(n, sha, state, neigh_update(n, sha, state,
override ? NEIGH_UPDATE_F_OVERRIDE : 0); override ? NEIGH_UPDATE_F_OVERRIDE : 0, 0);
neigh_release(n); neigh_release(n);
} }
...@@ -1033,7 +1033,7 @@ static int arp_req_set(struct net *net, struct arpreq *r, ...@@ -1033,7 +1033,7 @@ static int arp_req_set(struct net *net, struct arpreq *r,
err = neigh_update(neigh, (r->arp_flags & ATF_COM) ? err = neigh_update(neigh, (r->arp_flags & ATF_COM) ?
r->arp_ha.sa_data : NULL, state, r->arp_ha.sa_data : NULL, state,
NEIGH_UPDATE_F_OVERRIDE | NEIGH_UPDATE_F_OVERRIDE |
NEIGH_UPDATE_F_ADMIN); NEIGH_UPDATE_F_ADMIN, 0);
neigh_release(neigh); neigh_release(neigh);
} }
return err; return err;
...@@ -1084,7 +1084,7 @@ static int arp_invalidate(struct net_device *dev, __be32 ip) ...@@ -1084,7 +1084,7 @@ static int arp_invalidate(struct net_device *dev, __be32 ip)
if (neigh->nud_state & ~NUD_NOARP) if (neigh->nud_state & ~NUD_NOARP)
err = neigh_update(neigh, NULL, NUD_FAILED, err = neigh_update(neigh, NULL, NUD_FAILED,
NEIGH_UPDATE_F_OVERRIDE| NEIGH_UPDATE_F_OVERRIDE|
NEIGH_UPDATE_F_ADMIN); NEIGH_UPDATE_F_ADMIN, 0);
neigh_release(neigh); neigh_release(neigh);
} }
......
...@@ -732,7 +732,7 @@ void ndisc_update(const struct net_device *dev, struct neighbour *neigh, ...@@ -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, const u8 *lladdr, u8 new, u32 flags, u8 icmp6_type,
struct ndisc_options *ndopts) struct ndisc_options *ndopts)
{ {
neigh_update(neigh, lladdr, new, flags); neigh_update(neigh, lladdr, new, flags, 0);
/* report ndisc ops about neighbour update */ /* report ndisc ops about neighbour update */
ndisc_ops_update(dev, neigh, flags, icmp6_type, ndopts); ndisc_ops_update(dev, neigh, flags, icmp6_type, ndopts);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment