summaryrefslogtreecommitdiff
path: root/net/netlink
diff options
context:
space:
mode:
authorStephen Hemminger <shemminger@vyatta.com>2008-03-21 15:46:12 -0700
committerDavid S. Miller <davem@davemloft.net>2008-03-21 15:46:12 -0700
commitb1153f29ee07dc1a788964409255a4b4fae50b98 (patch)
tree3e9c09804e805da77d225a8508c28e064a310c45 /net/netlink
parent6f8b13bcb3369a5df2e63acc422bed6098f5b8c4 (diff)
downloadlinux-3.10-b1153f29ee07dc1a788964409255a4b4fae50b98.tar.gz
linux-3.10-b1153f29ee07dc1a788964409255a4b4fae50b98.tar.bz2
linux-3.10-b1153f29ee07dc1a788964409255a4b4fae50b98.zip
netlink: make socket filters work on netlink
Make socket filters work for netlink unicast and notifications. This is useful for applications like Zebra that get overrun with messages that are then ignored. Note: netlink messages are in host byte order, but packet filter state machine operations are done as network byte order. Signed-off-by: Stephen Hemminger <shemminger@vyatta.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/netlink')
-rw-r--r--net/netlink/af_netlink.c27
1 files changed, 23 insertions, 4 deletions
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
index 524e826bb97..86bd8660a8f 100644
--- a/net/netlink/af_netlink.c
+++ b/net/netlink/af_netlink.c
@@ -886,6 +886,13 @@ retry:
if (netlink_is_kernel(sk))
return netlink_unicast_kernel(sk, skb);
+ if (sk_filter(sk, skb)) {
+ int err = skb->len;
+ kfree_skb(skb);
+ sock_put(sk);
+ return err;
+ }
+
err = netlink_attachskb(sk, skb, nonblock, &timeo, ssk);
if (err == 1)
goto retry;
@@ -980,6 +987,9 @@ static inline int do_one_broadcast(struct sock *sk,
netlink_overrun(sk);
/* Clone failed. Notify ALL listeners. */
p->failure = 1;
+ } else if (sk_filter(sk, p->skb2)) {
+ kfree_skb(p->skb2);
+ p->skb2 = NULL;
} else if ((val = netlink_broadcast_deliver(sk, p->skb2)) < 0) {
netlink_overrun(sk);
} else {
@@ -1533,8 +1543,13 @@ static int netlink_dump(struct sock *sk)
if (len > 0) {
mutex_unlock(nlk->cb_mutex);
- skb_queue_tail(&sk->sk_receive_queue, skb);
- sk->sk_data_ready(sk, len);
+
+ if (sk_filter(sk, skb))
+ kfree_skb(skb);
+ else {
+ skb_queue_tail(&sk->sk_receive_queue, skb);
+ sk->sk_data_ready(sk, skb->len);
+ }
return 0;
}
@@ -1544,8 +1559,12 @@ static int netlink_dump(struct sock *sk)
memcpy(nlmsg_data(nlh), &len, sizeof(len));
- skb_queue_tail(&sk->sk_receive_queue, skb);
- sk->sk_data_ready(sk, skb->len);
+ if (sk_filter(sk, skb))
+ kfree_skb(skb);
+ else {
+ skb_queue_tail(&sk->sk_receive_queue, skb);
+ sk->sk_data_ready(sk, skb->len);
+ }
if (cb->done)
cb->done(cb);