Merge tag 'perf-urgent-for-mingo' of git://git.kernel.org/pub/scm/linux/kernel/git...
[firefly-linux-kernel-4.4.55.git] / net / netlink / af_netlink.c
index bca50b95c182300cbd89f8cfc21b17e9d6e31fe2..fdf51353cf78ac80958cadfa0e58e159970aa8bf 100644 (file)
@@ -131,7 +131,7 @@ int netlink_add_tap(struct netlink_tap *nt)
 }
 EXPORT_SYMBOL_GPL(netlink_add_tap);
 
-int __netlink_remove_tap(struct netlink_tap *nt)
+static int __netlink_remove_tap(struct netlink_tap *nt)
 {
        bool found = false;
        struct netlink_tap *tmp;
@@ -155,7 +155,6 @@ out:
 
        return found ? 0 : -ENODEV;
 }
-EXPORT_SYMBOL_GPL(__netlink_remove_tap);
 
 int netlink_remove_tap(struct netlink_tap *nt)
 {
@@ -204,6 +203,8 @@ static int __netlink_deliver_tap_skb(struct sk_buff *skb,
        if (nskb) {
                nskb->dev = dev;
                nskb->protocol = htons((u16) sk->sk_protocol);
+               nskb->pkt_type = netlink_is_kernel(sk) ?
+                                PACKET_KERNEL : PACKET_USER;
 
                ret = dev_queue_xmit(nskb);
                if (unlikely(ret > 0))
@@ -239,6 +240,13 @@ static void netlink_deliver_tap(struct sk_buff *skb)
        rcu_read_unlock();
 }
 
+static void netlink_deliver_tap_kernel(struct sock *dst, struct sock *src,
+                                      struct sk_buff *skb)
+{
+       if (!(netlink_is_kernel(dst) && netlink_is_kernel(src)))
+               netlink_deliver_tap(skb);
+}
+
 static void netlink_overrun(struct sock *sk)
 {
        struct netlink_sock *nlk = nlk_sk(sk);
@@ -1697,14 +1705,10 @@ static int netlink_unicast_kernel(struct sock *sk, struct sk_buff *skb,
 
        ret = -ECONNREFUSED;
        if (nlk->netlink_rcv != NULL) {
-               /* We could do a netlink_deliver_tap(skb) here as well
-                * but since this is intended for the kernel only, we
-                * should rather let it stay under the hood.
-                */
-
                ret = skb->len;
                netlink_skb_set_owner_r(skb, sk);
                NETLINK_CB(skb).sk = ssk;
+               netlink_deliver_tap_kernel(sk, ssk, skb);
                nlk->netlink_rcv(skb);
                consume_skb(skb);
        } else {
@@ -1769,6 +1773,9 @@ struct sk_buff *netlink_alloc_skb(struct sock *ssk, unsigned int size,
        if (ring->pg_vec == NULL)
                goto out_put;
 
+       if (ring->frame_size - NL_MMAP_HDRLEN < size)
+               goto out_put;
+
        skb = alloc_skb_head(gfp_mask);
        if (skb == NULL)
                goto err1;
@@ -1778,6 +1785,7 @@ struct sk_buff *netlink_alloc_skb(struct sock *ssk, unsigned int size,
        if (ring->pg_vec == NULL)
                goto out_free;
 
+       /* check again under lock */
        maxlen = ring->frame_size - NL_MMAP_HDRLEN;
        if (maxlen < size)
                goto out_free;
@@ -2214,7 +2222,7 @@ static int netlink_sendmsg(struct kiocb *kiocb, struct socket *sock,
        struct sock_iocb *siocb = kiocb_to_siocb(kiocb);
        struct sock *sk = sock->sk;
        struct netlink_sock *nlk = nlk_sk(sk);
-       struct sockaddr_nl *addr = msg->msg_name;
+       DECLARE_SOCKADDR(struct sockaddr_nl *, addr, msg->msg_name);
        u32 dst_portid;
        u32 dst_group;
        struct sk_buff *skb;
@@ -2345,7 +2353,7 @@ static int netlink_recvmsg(struct kiocb *kiocb, struct socket *sock,
        err = skb_copy_datagram_iovec(data_skb, 0, msg->msg_iov, copied);
 
        if (msg->msg_name) {
-               struct sockaddr_nl *addr = (struct sockaddr_nl *)msg->msg_name;
+               DECLARE_SOCKADDR(struct sockaddr_nl *, addr, msg->msg_name);
                addr->nl_family = AF_NETLINK;
                addr->nl_pad    = 0;
                addr->nl_pid    = NETLINK_CB(skb).portid;
@@ -2535,21 +2543,6 @@ void __netlink_clear_multicast_users(struct sock *ksk, unsigned int group)
                netlink_update_socket_mc(nlk_sk(sk), group, 0);
 }
 
-/**
- * netlink_clear_multicast_users - kick off multicast listeners
- *
- * This function removes all listeners from the given group.
- * @ksk: The kernel netlink socket, as returned by
- *     netlink_kernel_create().
- * @group: The multicast group to clear.
- */
-void netlink_clear_multicast_users(struct sock *ksk, unsigned int group)
-{
-       netlink_table_grab();
-       __netlink_clear_multicast_users(ksk, group);
-       netlink_table_ungrab();
-}
-
 struct nlmsghdr *
 __nlmsg_put(struct sk_buff *skb, u32 portid, u32 seq, int type, int len, int flags)
 {