source: src/linux/universal/linux-3.18/net/netlink/diag.c @ 31869

Last change on this file since 31869 was 31869, checked in by brainslayer, 6 weeks ago

update

File size: 4.2 KB
Line 
1#include <linux/module.h>
2
3#include <net/sock.h>
4#include <linux/netlink.h>
5#include <linux/sock_diag.h>
6#include <linux/netlink_diag.h>
7#include <linux/rhashtable.h>
8
9#include "af_netlink.h"
10
11static int sk_diag_dump_groups(struct sock *sk, struct sk_buff *nlskb)
12{
13        struct netlink_sock *nlk = nlk_sk(sk);
14
15        if (nlk->groups == NULL)
16                return 0;
17
18        return nla_put(nlskb, NETLINK_DIAG_GROUPS, NLGRPSZ(nlk->ngroups),
19                       nlk->groups);
20}
21
22static int sk_diag_fill(struct sock *sk, struct sk_buff *skb,
23                        struct netlink_diag_req *req,
24                        u32 portid, u32 seq, u32 flags, int sk_ino)
25{
26        struct nlmsghdr *nlh;
27        struct netlink_diag_msg *rep;
28        struct netlink_sock *nlk = nlk_sk(sk);
29
30        nlh = nlmsg_put(skb, portid, seq, SOCK_DIAG_BY_FAMILY, sizeof(*rep),
31                        flags);
32        if (!nlh)
33                return -EMSGSIZE;
34
35        rep = nlmsg_data(nlh);
36        rep->ndiag_family       = AF_NETLINK;
37        rep->ndiag_type         = sk->sk_type;
38        rep->ndiag_protocol     = sk->sk_protocol;
39        rep->ndiag_state        = sk->sk_state;
40
41        rep->ndiag_ino          = sk_ino;
42        rep->ndiag_portid       = nlk->portid;
43        rep->ndiag_dst_portid   = nlk->dst_portid;
44        rep->ndiag_dst_group    = nlk->dst_group;
45        sock_diag_save_cookie(sk, rep->ndiag_cookie);
46
47        if ((req->ndiag_show & NDIAG_SHOW_GROUPS) &&
48            sk_diag_dump_groups(sk, skb))
49                goto out_nlmsg_trim;
50
51        if ((req->ndiag_show & NDIAG_SHOW_MEMINFO) &&
52            sock_diag_put_meminfo(sk, skb, NETLINK_DIAG_MEMINFO))
53                goto out_nlmsg_trim;
54
55        return nlmsg_end(skb, nlh);
56
57out_nlmsg_trim:
58        nlmsg_cancel(skb, nlh);
59        return -EMSGSIZE;
60}
61
62static int __netlink_diag_dump(struct sk_buff *skb, struct netlink_callback *cb,
63                                int protocol, int s_num)
64{
65        struct netlink_table *tbl = &nl_table[protocol];
66        struct rhashtable *ht = &tbl->hash;
67        const struct bucket_table *htbl = rht_dereference(ht->tbl, ht);
68        struct net *net = sock_net(skb->sk);
69        struct netlink_diag_req *req;
70        struct netlink_sock *nlsk;
71        struct sock *sk;
72        int ret = 0, num = 0, i;
73
74        req = nlmsg_data(cb->nlh);
75
76        for (i = 0; i < htbl->size; i++) {
77                rht_for_each_entry(nlsk, htbl->buckets[i], ht, node) {
78                        sk = (struct sock *)nlsk;
79
80                        if (!net_eq(sock_net(sk), net))
81                                continue;
82                        if (num < s_num) {
83                                num++;
84                                continue;
85                        }
86
87                        if (sk_diag_fill(sk, skb, req,
88                                         NETLINK_CB(cb->skb).portid,
89                                         cb->nlh->nlmsg_seq,
90                                         NLM_F_MULTI,
91                                         sock_i_ino(sk)) < 0) {
92                                ret = 1;
93                                goto done;
94                        }
95
96                        num++;
97                }
98        }
99
100        sk_for_each_bound(sk, &tbl->mc_list) {
101                if (sk_hashed(sk))
102                        continue;
103                if (!net_eq(sock_net(sk), net))
104                        continue;
105                if (num < s_num) {
106                        num++;
107                        continue;
108                }
109
110                if (sk_diag_fill(sk, skb, req,
111                                 NETLINK_CB(cb->skb).portid,
112                                 cb->nlh->nlmsg_seq,
113                                 NLM_F_MULTI,
114                                 sock_i_ino(sk)) < 0) {
115                        ret = 1;
116                        goto done;
117                }
118                num++;
119        }
120done:
121        cb->args[0] = num;
122        cb->args[1] = protocol;
123
124        return ret;
125}
126
127static int netlink_diag_dump(struct sk_buff *skb, struct netlink_callback *cb)
128{
129        struct netlink_diag_req *req;
130        int s_num = cb->args[0];
131
132        req = nlmsg_data(cb->nlh);
133
134        mutex_lock(&nl_sk_hash_lock);
135        read_lock(&nl_table_lock);
136
137        if (req->sdiag_protocol == NDIAG_PROTO_ALL) {
138                int i;
139
140                for (i = cb->args[1]; i < MAX_LINKS; i++) {
141                        if (__netlink_diag_dump(skb, cb, i, s_num))
142                                break;
143                        s_num = 0;
144                }
145        } else {
146                if (req->sdiag_protocol >= MAX_LINKS) {
147                        read_unlock(&nl_table_lock);
148                        mutex_unlock(&nl_sk_hash_lock);
149                        return -ENOENT;
150                }
151
152                __netlink_diag_dump(skb, cb, req->sdiag_protocol, s_num);
153        }
154
155        read_unlock(&nl_table_lock);
156        mutex_unlock(&nl_sk_hash_lock);
157
158        return skb->len;
159}
160
161static int netlink_diag_handler_dump(struct sk_buff *skb, struct nlmsghdr *h)
162{
163        int hdrlen = sizeof(struct netlink_diag_req);
164        struct net *net = sock_net(skb->sk);
165
166        if (nlmsg_len(h) < hdrlen)
167                return -EINVAL;
168
169        if (h->nlmsg_flags & NLM_F_DUMP) {
170                struct netlink_dump_control c = {
171                        .dump = netlink_diag_dump,
172                };
173                return netlink_dump_start(net->diag_nlsk, skb, h, &c);
174        } else
175                return -EOPNOTSUPP;
176}
177
178static const struct sock_diag_handler netlink_diag_handler = {
179        .family = AF_NETLINK,
180        .dump = netlink_diag_handler_dump,
181};
182
183static int __init netlink_diag_init(void)
184{
185        return sock_diag_register(&netlink_diag_handler);
186}
187
188static void __exit netlink_diag_exit(void)
189{
190        sock_diag_unregister(&netlink_diag_handler);
191}
192
193module_init(netlink_diag_init);
194module_exit(netlink_diag_exit);
195MODULE_LICENSE("GPL");
196MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_NETLINK, NETLINK_SOCK_DIAG, 16 /* AF_NETLINK */);
Note: See TracBrowser for help on using the repository browser.