Revert "misc: uidstat: Adding uid stat driver to collect network statistics."
[firefly-linux-kernel-4.4.55.git] / net / ipv4 / inet_diag.c
index ab9f8a66615d0872b586a0c2745196c58f6026be..a403a676d452d050f4518cec52631aa6823800cf 100644 (file)
@@ -350,40 +350,60 @@ static int sk_diag_fill(struct sock *sk, struct sk_buff *skb,
                                  nlmsg_flags, unlh);
 }
 
-int inet_diag_dump_one_icsk(struct inet_hashinfo *hashinfo,
-                           struct sk_buff *in_skb,
-                           const struct nlmsghdr *nlh,
-                           const struct inet_diag_req_v2 *req)
+struct sock *inet_diag_find_one_icsk(struct net *net,
+                                    struct inet_hashinfo *hashinfo,
+                                    const struct inet_diag_req_v2 *req)
 {
-       struct net *net = sock_net(in_skb->sk);
-       struct sk_buff *rep;
        struct sock *sk;
-       int err;
 
-       err = -EINVAL;
        if (req->sdiag_family == AF_INET)
                sk = inet_lookup(net, hashinfo, req->id.idiag_dst[0],
                                 req->id.idiag_dport, req->id.idiag_src[0],
                                 req->id.idiag_sport, req->id.idiag_if);
 #if IS_ENABLED(CONFIG_IPV6)
-       else if (req->sdiag_family == AF_INET6)
-               sk = inet6_lookup(net, hashinfo,
-                                 (struct in6_addr *)req->id.idiag_dst,
-                                 req->id.idiag_dport,
-                                 (struct in6_addr *)req->id.idiag_src,
-                                 req->id.idiag_sport,
-                                 req->id.idiag_if);
+       else if (req->sdiag_family == AF_INET6) {
+               if (ipv6_addr_v4mapped((struct in6_addr *)req->id.idiag_dst) &&
+                   ipv6_addr_v4mapped((struct in6_addr *)req->id.idiag_src))
+                       sk = inet_lookup(net, hashinfo, req->id.idiag_dst[3],
+                                        req->id.idiag_dport, req->id.idiag_src[3],
+                                        req->id.idiag_sport, req->id.idiag_if);
+               else
+                       sk = inet6_lookup(net, hashinfo,
+                                         (struct in6_addr *)req->id.idiag_dst,
+                                         req->id.idiag_dport,
+                                         (struct in6_addr *)req->id.idiag_src,
+                                         req->id.idiag_sport,
+                                         req->id.idiag_if);
+       }
 #endif
        else
-               goto out_nosk;
+               return ERR_PTR(-EINVAL);
 
-       err = -ENOENT;
        if (!sk)
-               goto out_nosk;
+               return ERR_PTR(-ENOENT);
 
-       err = sock_diag_check_cookie(sk, req->id.idiag_cookie);
-       if (err)
-               goto out;
+       if (sock_diag_check_cookie(sk, req->id.idiag_cookie)) {
+               sock_gen_put(sk);
+               return ERR_PTR(-ENOENT);
+       }
+
+       return sk;
+}
+EXPORT_SYMBOL_GPL(inet_diag_find_one_icsk);
+
+int inet_diag_dump_one_icsk(struct inet_hashinfo *hashinfo,
+                           struct sk_buff *in_skb,
+                           const struct nlmsghdr *nlh,
+                           const struct inet_diag_req_v2 *req)
+{
+       struct net *net = sock_net(in_skb->sk);
+       struct sk_buff *rep;
+       struct sock *sk;
+       int err;
+
+       sk = inet_diag_find_one_icsk(net, hashinfo, req);
+       if (IS_ERR(sk))
+               return PTR_ERR(sk);
 
        rep = nlmsg_new(inet_sk_attr_size(), GFP_KERNEL);
        if (!rep) {
@@ -409,12 +429,11 @@ out:
        if (sk)
                sock_gen_put(sk);
 
-out_nosk:
        return err;
 }
 EXPORT_SYMBOL_GPL(inet_diag_dump_one_icsk);
 
-static int inet_diag_get_exact(struct sk_buff *in_skb,
+static int inet_diag_cmd_exact(int cmd, struct sk_buff *in_skb,
                               const struct nlmsghdr *nlh,
                               const struct inet_diag_req_v2 *req)
 {
@@ -424,8 +443,12 @@ static int inet_diag_get_exact(struct sk_buff *in_skb,
        handler = inet_diag_lock_handler(req->sdiag_protocol);
        if (IS_ERR(handler))
                err = PTR_ERR(handler);
-       else
+       else if (cmd == SOCK_DIAG_BY_FAMILY)
                err = handler->dump_one(in_skb, nlh, req);
+       else if (cmd == SOCK_DESTROY_BACKPORT && handler->destroy)
+               err = handler->destroy(in_skb, req);
+       else
+               err = -EOPNOTSUPP;
        inet_diag_unlock_handler(handler);
 
        return err;
@@ -938,7 +961,7 @@ static int inet_diag_get_exact_compat(struct sk_buff *in_skb,
        req.idiag_states = rc->idiag_states;
        req.id = rc->id;
 
-       return inet_diag_get_exact(in_skb, nlh, &req);
+       return inet_diag_cmd_exact(SOCK_DIAG_BY_FAMILY, in_skb, nlh, &req);
 }
 
 static int inet_diag_rcv_msg_compat(struct sk_buff *skb, struct nlmsghdr *nlh)
@@ -972,7 +995,7 @@ static int inet_diag_rcv_msg_compat(struct sk_buff *skb, struct nlmsghdr *nlh)
        return inet_diag_get_exact_compat(skb, nlh);
 }
 
-static int inet_diag_handler_dump(struct sk_buff *skb, struct nlmsghdr *h)
+static int inet_diag_handler_cmd(struct sk_buff *skb, struct nlmsghdr *h)
 {
        int hdrlen = sizeof(struct inet_diag_req_v2);
        struct net *net = sock_net(skb->sk);
@@ -980,7 +1003,8 @@ static int inet_diag_handler_dump(struct sk_buff *skb, struct nlmsghdr *h)
        if (nlmsg_len(h) < hdrlen)
                return -EINVAL;
 
-       if (h->nlmsg_flags & NLM_F_DUMP) {
+       if (h->nlmsg_type == SOCK_DIAG_BY_FAMILY &&
+           h->nlmsg_flags & NLM_F_DUMP) {
                if (nlmsg_attrlen(h, hdrlen)) {
                        struct nlattr *attr;
 
@@ -999,7 +1023,7 @@ static int inet_diag_handler_dump(struct sk_buff *skb, struct nlmsghdr *h)
                }
        }
 
-       return inet_diag_get_exact(skb, h, nlmsg_data(h));
+       return inet_diag_cmd_exact(h->nlmsg_type, skb, h, nlmsg_data(h));
 }
 
 static
@@ -1050,14 +1074,16 @@ int inet_diag_handler_get_info(struct sk_buff *skb, struct sock *sk)
 
 static const struct sock_diag_handler inet_diag_handler = {
        .family = AF_INET,
-       .dump = inet_diag_handler_dump,
+       .dump = inet_diag_handler_cmd,
        .get_info = inet_diag_handler_get_info,
+       .destroy = inet_diag_handler_cmd,
 };
 
 static const struct sock_diag_handler inet6_diag_handler = {
        .family = AF_INET6,
-       .dump = inet_diag_handler_dump,
+       .dump = inet_diag_handler_cmd,
        .get_info = inet_diag_handler_get_info,
+       .destroy = inet_diag_handler_cmd,
 };
 
 int inet_diag_register(const struct inet_diag_handler *h)