module_param: make bool parameters really bool (net & drivers/net)
[deliverable/linux.git] / net / unix / diag.c
CommitLineData
22931d3b
PE
1#include <linux/types.h>
2#include <linux/spinlock.h>
3#include <linux/sock_diag.h>
4#include <linux/unix_diag.h>
5#include <linux/skbuff.h>
6#include <net/netlink.h>
7#include <net/af_unix.h>
8#include <net/tcp_states.h>
9
10#define UNIX_DIAG_PUT(skb, attrtype, attrlen) \
11 RTA_DATA(__RTA_PUT(skb, attrtype, attrlen))
12
f5248b48
PE
13static int sk_diag_dump_name(struct sock *sk, struct sk_buff *nlskb)
14{
15 struct unix_address *addr = unix_sk(sk)->addr;
16 char *s;
17
18 if (addr) {
19 s = UNIX_DIAG_PUT(nlskb, UNIX_DIAG_NAME, addr->len - sizeof(short));
20 memcpy(s, addr->name->sun_path, addr->len - sizeof(short));
21 }
22
23 return 0;
24
25rtattr_failure:
26 return -EMSGSIZE;
27}
28
5f7b0569
PE
29static int sk_diag_dump_vfs(struct sock *sk, struct sk_buff *nlskb)
30{
31 struct dentry *dentry = unix_sk(sk)->dentry;
32 struct unix_diag_vfs *uv;
33
34 if (dentry) {
35 uv = UNIX_DIAG_PUT(nlskb, UNIX_DIAG_VFS, sizeof(*uv));
36 uv->udiag_vfs_ino = dentry->d_inode->i_ino;
37 uv->udiag_vfs_dev = dentry->d_sb->s_dev;
38 }
39
40 return 0;
41
42rtattr_failure:
43 return -EMSGSIZE;
44}
45
ac02be8d
PE
46static int sk_diag_dump_peer(struct sock *sk, struct sk_buff *nlskb)
47{
48 struct sock *peer;
49 int ino;
50
51 peer = unix_peer_get(sk);
52 if (peer) {
53 unix_state_lock(peer);
54 ino = sock_i_ino(peer);
55 unix_state_unlock(peer);
56 sock_put(peer);
57
58 RTA_PUT_U32(nlskb, UNIX_DIAG_PEER, ino);
59 }
60
61 return 0;
62rtattr_failure:
63 return -EMSGSIZE;
64}
65
2aac7a2c
PE
66static int sk_diag_dump_icons(struct sock *sk, struct sk_buff *nlskb)
67{
68 struct sk_buff *skb;
69 u32 *buf;
70 int i;
71
72 if (sk->sk_state == TCP_LISTEN) {
73 spin_lock(&sk->sk_receive_queue.lock);
74 buf = UNIX_DIAG_PUT(nlskb, UNIX_DIAG_ICONS, sk->sk_receive_queue.qlen);
75 i = 0;
76 skb_queue_walk(&sk->sk_receive_queue, skb) {
77 struct sock *req, *peer;
78
79 req = skb->sk;
80 /*
81 * The state lock is outer for the same sk's
82 * queue lock. With the other's queue locked it's
83 * OK to lock the state.
84 */
85 unix_state_lock_nested(req);
86 peer = unix_sk(req)->peer;
87 if (peer)
88 buf[i++] = sock_i_ino(peer);
89 unix_state_unlock(req);
90 }
91 spin_unlock(&sk->sk_receive_queue.lock);
92 }
93
94 return 0;
95
96rtattr_failure:
97 spin_unlock(&sk->sk_receive_queue.lock);
98 return -EMSGSIZE;
99}
100
cbf39195
PE
101static int sk_diag_show_rqlen(struct sock *sk, struct sk_buff *nlskb)
102{
103 RTA_PUT_U32(nlskb, UNIX_DIAG_RQLEN, sk->sk_receive_queue.qlen);
104 return 0;
105
106rtattr_failure:
107 return -EMSGSIZE;
108}
109
45a96b9b
PE
110static int sk_diag_fill(struct sock *sk, struct sk_buff *skb, struct unix_diag_req *req,
111 u32 pid, u32 seq, u32 flags, int sk_ino)
112{
113 unsigned char *b = skb_tail_pointer(skb);
114 struct nlmsghdr *nlh;
115 struct unix_diag_msg *rep;
116
117 nlh = NLMSG_PUT(skb, pid, seq, SOCK_DIAG_BY_FAMILY, sizeof(*rep));
118 nlh->nlmsg_flags = flags;
119
120 rep = NLMSG_DATA(nlh);
121
122 rep->udiag_family = AF_UNIX;
123 rep->udiag_type = sk->sk_type;
124 rep->udiag_state = sk->sk_state;
125 rep->udiag_ino = sk_ino;
126 sock_diag_save_cookie(sk, rep->udiag_cookie);
127
f5248b48
PE
128 if ((req->udiag_show & UDIAG_SHOW_NAME) &&
129 sk_diag_dump_name(sk, skb))
130 goto nlmsg_failure;
131
5f7b0569
PE
132 if ((req->udiag_show & UDIAG_SHOW_VFS) &&
133 sk_diag_dump_vfs(sk, skb))
134 goto nlmsg_failure;
135
ac02be8d
PE
136 if ((req->udiag_show & UDIAG_SHOW_PEER) &&
137 sk_diag_dump_peer(sk, skb))
138 goto nlmsg_failure;
139
2aac7a2c
PE
140 if ((req->udiag_show & UDIAG_SHOW_ICONS) &&
141 sk_diag_dump_icons(sk, skb))
142 goto nlmsg_failure;
143
cbf39195
PE
144 if ((req->udiag_show & UDIAG_SHOW_RQLEN) &&
145 sk_diag_show_rqlen(sk, skb))
146 goto nlmsg_failure;
147
45a96b9b
PE
148 nlh->nlmsg_len = skb_tail_pointer(skb) - b;
149 return skb->len;
150
151nlmsg_failure:
152 nlmsg_trim(skb, b);
153 return -EMSGSIZE;
154}
155
156static int sk_diag_dump(struct sock *sk, struct sk_buff *skb, struct unix_diag_req *req,
157 u32 pid, u32 seq, u32 flags)
158{
159 int sk_ino;
160
161 unix_state_lock(sk);
162 sk_ino = sock_i_ino(sk);
163 unix_state_unlock(sk);
164
165 if (!sk_ino)
166 return 0;
167
168 return sk_diag_fill(sk, skb, req, pid, seq, flags, sk_ino);
169}
170
22931d3b
PE
171static int unix_diag_dump(struct sk_buff *skb, struct netlink_callback *cb)
172{
45a96b9b
PE
173 struct unix_diag_req *req;
174 int num, s_num, slot, s_slot;
175
176 req = NLMSG_DATA(cb->nlh);
177
178 s_slot = cb->args[0];
179 num = s_num = cb->args[1];
180
181 spin_lock(&unix_table_lock);
182 for (slot = s_slot; slot <= UNIX_HASH_SIZE; s_num = 0, slot++) {
183 struct sock *sk;
184 struct hlist_node *node;
185
186 num = 0;
187 sk_for_each(sk, node, &unix_socket_table[slot]) {
188 if (num < s_num)
189 goto next;
190 if (!(req->udiag_states & (1 << sk->sk_state)))
191 goto next;
192 if (sk_diag_dump(sk, skb, req,
193 NETLINK_CB(cb->skb).pid,
194 cb->nlh->nlmsg_seq,
195 NLM_F_MULTI) < 0)
196 goto done;
197next:
198 num++;
199 }
200 }
201done:
202 spin_unlock(&unix_table_lock);
203 cb->args[0] = slot;
204 cb->args[1] = num;
205
206 return skb->len;
22931d3b
PE
207}
208
5d3cae8b
PE
209static struct sock *unix_lookup_by_ino(int ino)
210{
211 int i;
212 struct sock *sk;
213
214 spin_lock(&unix_table_lock);
215 for (i = 0; i <= UNIX_HASH_SIZE; i++) {
216 struct hlist_node *node;
217
218 sk_for_each(sk, node, &unix_socket_table[i])
219 if (ino == sock_i_ino(sk)) {
220 sock_hold(sk);
221 spin_unlock(&unix_table_lock);
222
223 return sk;
224 }
225 }
226
227 spin_unlock(&unix_table_lock);
228 return NULL;
229}
230
22931d3b
PE
231static int unix_diag_get_exact(struct sk_buff *in_skb,
232 const struct nlmsghdr *nlh,
233 struct unix_diag_req *req)
234{
5d3cae8b
PE
235 int err = -EINVAL;
236 struct sock *sk;
237 struct sk_buff *rep;
238 unsigned int extra_len;
239
240 if (req->udiag_ino == 0)
241 goto out_nosk;
242
243 sk = unix_lookup_by_ino(req->udiag_ino);
244 err = -ENOENT;
245 if (sk == NULL)
246 goto out_nosk;
247
248 err = sock_diag_check_cookie(sk, req->udiag_cookie);
249 if (err)
250 goto out;
251
252 extra_len = 256;
253again:
254 err = -ENOMEM;
255 rep = alloc_skb(NLMSG_SPACE((sizeof(struct unix_diag_msg) + extra_len)),
256 GFP_KERNEL);
257 if (!rep)
258 goto out;
259
260 err = sk_diag_fill(sk, rep, req, NETLINK_CB(in_skb).pid,
261 nlh->nlmsg_seq, 0, req->udiag_ino);
262 if (err < 0) {
263 kfree_skb(rep);
264 extra_len += 256;
265 if (extra_len >= PAGE_SIZE)
266 goto out;
267
268 goto again;
269 }
270 err = netlink_unicast(sock_diag_nlsk, rep, NETLINK_CB(in_skb).pid,
271 MSG_DONTWAIT);
272 if (err > 0)
273 err = 0;
274out:
275 if (sk)
276 sock_put(sk);
277out_nosk:
278 return err;
22931d3b
PE
279}
280
281static int unix_diag_handler_dump(struct sk_buff *skb, struct nlmsghdr *h)
282{
283 int hdrlen = sizeof(struct unix_diag_req);
284
285 if (nlmsg_len(h) < hdrlen)
286 return -EINVAL;
287
288 if (h->nlmsg_flags & NLM_F_DUMP)
289 return netlink_dump_start(sock_diag_nlsk, skb, h,
290 unix_diag_dump, NULL, 0);
291 else
292 return unix_diag_get_exact(skb, h, (struct unix_diag_req *)NLMSG_DATA(h));
293}
294
295static struct sock_diag_handler unix_diag_handler = {
296 .family = AF_UNIX,
297 .dump = unix_diag_handler_dump,
298};
299
300static int __init unix_diag_init(void)
301{
302 return sock_diag_register(&unix_diag_handler);
303}
304
305static void __exit unix_diag_exit(void)
306{
307 sock_diag_unregister(&unix_diag_handler);
308}
309
310module_init(unix_diag_init);
311module_exit(unix_diag_exit);
312MODULE_LICENSE("GPL");
313MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_NETLINK, NETLINK_SOCK_DIAG, 1 /* AF_LOCAL */);
This page took 0.141798 seconds and 5 git commands to generate.