From: Stephen Hemminger Date: Fri, 21 Mar 2008 22:46:12 +0000 (-0700) Subject: netlink: make socket filters work on netlink X-Git-Tag: v2.6.26-rc1~1138^2~405 X-Git-Url: https://asedeno.scripts.mit.edu/gitweb/?a=commitdiff_plain;h=b1153f29ee07dc1a788964409255a4b4fae50b98;p=linux.git 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 Signed-off-by: David S. Miller --- diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index 524e826bb976..86bd8660a8f2 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -886,6 +886,13 @@ int netlink_unicast(struct sock *ssk, struct sk_buff *skb, 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);