Commit d387f6ad authored by Thomas Graf's avatar Thomas Graf Committed by David S. Miller

[NETLINK]: Add notification message sending interface

Adds nlmsg_notify() implementing proper notification logic. The
message is multicasted to all listeners in the group. The
applications the requests orignates from can request a unicast
back report in which case said socket will be excluded from the
multicast to avoid duplicated notifications.

nlmsg_multicast() is extended to take allocation flags to
allow notification in atomic contexts.
Signed-off-by: default avatarThomas Graf <tgraf@suug.ch>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 2942e900
...@@ -133,11 +133,12 @@ static inline int genlmsg_cancel(struct sk_buff *skb, void *hdr) ...@@ -133,11 +133,12 @@ static inline int genlmsg_cancel(struct sk_buff *skb, void *hdr)
* @skb: netlink message as socket buffer * @skb: netlink message as socket buffer
* @pid: own netlink pid to avoid sending to yourself * @pid: own netlink pid to avoid sending to yourself
* @group: multicast group id * @group: multicast group id
* @flags: allocation flags
*/ */
static inline int genlmsg_multicast(struct sk_buff *skb, u32 pid, static inline int genlmsg_multicast(struct sk_buff *skb, u32 pid,
unsigned int group) unsigned int group, gfp_t flags)
{ {
return nlmsg_multicast(genl_sock, skb, pid, group); return nlmsg_multicast(genl_sock, skb, pid, group, flags);
} }
/** /**
......
...@@ -43,6 +43,7 @@ ...@@ -43,6 +43,7 @@
* Message Sending: * Message Sending:
* nlmsg_multicast() multicast message to several groups * nlmsg_multicast() multicast message to several groups
* nlmsg_unicast() unicast a message to a single socket * nlmsg_unicast() unicast a message to a single socket
* nlmsg_notify() send notification message
* *
* Message Length Calculations: * Message Length Calculations:
* nlmsg_msg_size(payload) length of message w/o padding * nlmsg_msg_size(payload) length of message w/o padding
...@@ -545,15 +546,16 @@ static inline void nlmsg_free(struct sk_buff *skb) ...@@ -545,15 +546,16 @@ static inline void nlmsg_free(struct sk_buff *skb)
* @skb: netlink message as socket buffer * @skb: netlink message as socket buffer
* @pid: own netlink pid to avoid sending to yourself * @pid: own netlink pid to avoid sending to yourself
* @group: multicast group id * @group: multicast group id
* @flags: allocation flags
*/ */
static inline int nlmsg_multicast(struct sock *sk, struct sk_buff *skb, static inline int nlmsg_multicast(struct sock *sk, struct sk_buff *skb,
u32 pid, unsigned int group) u32 pid, unsigned int group, gfp_t flags)
{ {
int err; int err;
NETLINK_CB(skb).dst_group = group; NETLINK_CB(skb).dst_group = group;
err = netlink_broadcast(sk, skb, pid, group, GFP_KERNEL); err = netlink_broadcast(sk, skb, pid, group, flags);
if (err > 0) if (err > 0)
err = 0; err = 0;
......
...@@ -154,5 +154,5 @@ int netlbl_netlink_snd(struct sk_buff *skb, u32 pid) ...@@ -154,5 +154,5 @@ int netlbl_netlink_snd(struct sk_buff *skb, u32 pid)
*/ */
int netlbl_netlink_snd_multicast(struct sk_buff *skb, u32 pid, u32 group) int netlbl_netlink_snd_multicast(struct sk_buff *skb, u32 pid, u32 group)
{ {
return genlmsg_multicast(skb, pid, group); return genlmsg_multicast(skb, pid, group, GFP_KERNEL);
} }
...@@ -1549,6 +1549,38 @@ void netlink_queue_skip(struct nlmsghdr *nlh, struct sk_buff *skb) ...@@ -1549,6 +1549,38 @@ void netlink_queue_skip(struct nlmsghdr *nlh, struct sk_buff *skb)
skb_pull(skb, msglen); skb_pull(skb, msglen);
} }
/**
* nlmsg_notify - send a notification netlink message
* @sk: netlink socket to use
* @skb: notification message
* @pid: destination netlink pid for reports or 0
* @group: destination multicast group or 0
* @report: 1 to report back, 0 to disable
* @flags: allocation flags
*/
int nlmsg_notify(struct sock *sk, struct sk_buff *skb, u32 pid,
unsigned int group, int report, gfp_t flags)
{
int err = 0;
if (group) {
int exclude_pid = 0;
if (report) {
atomic_inc(&skb->users);
exclude_pid = pid;
}
/* errors reported via destination sk->sk_err */
nlmsg_multicast(sk, skb, exclude_pid, group, flags);
}
if (report)
err = nlmsg_unicast(sk, skb, pid);
return err;
}
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
struct nl_seq_iter { struct nl_seq_iter {
int link; int link;
...@@ -1802,4 +1834,4 @@ EXPORT_SYMBOL(netlink_set_err); ...@@ -1802,4 +1834,4 @@ EXPORT_SYMBOL(netlink_set_err);
EXPORT_SYMBOL(netlink_set_nonroot); EXPORT_SYMBOL(netlink_set_nonroot);
EXPORT_SYMBOL(netlink_unicast); EXPORT_SYMBOL(netlink_unicast);
EXPORT_SYMBOL(netlink_unregister_notifier); EXPORT_SYMBOL(netlink_unregister_notifier);
EXPORT_SYMBOL(nlmsg_notify);
...@@ -510,7 +510,7 @@ static int genl_ctrl_event(int event, void *data) ...@@ -510,7 +510,7 @@ static int genl_ctrl_event(int event, void *data)
if (IS_ERR(msg)) if (IS_ERR(msg))
return PTR_ERR(msg); return PTR_ERR(msg);
genlmsg_multicast(msg, 0, GENL_ID_CTRL); genlmsg_multicast(msg, 0, GENL_ID_CTRL, GFP_KERNEL);
break; break;
} }
......
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