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>
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
index 524e826..86bd866 100644
--- a/net/netlink/af_netlink.c
+++ b/net/netlink/af_netlink.c
@@ -886,6 +886,13 @@
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 @@
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 @@
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 @@
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);