aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPavel Emelyanov <xemul@parallels.com>2012-08-13 01:53:28 -0400
committerDavid S. Miller <davem@davemloft.net>2012-08-14 19:56:33 -0400
commit96ec6327144e1ac9e6676e34fae8b49c2102fa5a (patch)
tree1c2e914c7bbd573db850f2cf340b2e49226df8a0
parent2787b04b6c5e7607510e8248b38b0aeacb5505f6 (diff)
packet: Diag core and basic socket info dumping
The diag module can be built independently from the af_packet.ko one, just like it's done in unix sockets. The core dumping message carries the info available at socket creation time, i.e. family, type and protocol (in the same byte order as shown in the proc file). The socket inode number and cookie is reserved for future per-socket info retrieving. The per-protocol filtering is also reserved for future by requiring the sdiag_protocol to be zero. Signed-off-by: Pavel Emelyanov <xemul@parallels.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/linux/Kbuild1
-rw-r--r--include/linux/packet_diag.h24
-rw-r--r--net/packet/Kconfig8
-rw-r--r--net/packet/Makefile2
-rw-r--r--net/packet/diag.c104
5 files changed, 139 insertions, 0 deletions
diff --git a/include/linux/Kbuild b/include/linux/Kbuild
index d9a754474878..d823d603dadd 100644
--- a/include/linux/Kbuild
+++ b/include/linux/Kbuild
@@ -195,6 +195,7 @@ header-y += in_route.h
195header-y += sock_diag.h 195header-y += sock_diag.h
196header-y += inet_diag.h 196header-y += inet_diag.h
197header-y += unix_diag.h 197header-y += unix_diag.h
198header-y += packet_diag.h
198header-y += inotify.h 199header-y += inotify.h
199header-y += input.h 200header-y += input.h
200header-y += ioctl.h 201header-y += ioctl.h
diff --git a/include/linux/packet_diag.h b/include/linux/packet_diag.h
new file mode 100644
index 000000000000..fa19300ca334
--- /dev/null
+++ b/include/linux/packet_diag.h
@@ -0,0 +1,24 @@
1#ifndef __PACKET_DIAG_H__
2#define __PACKET_DIAG_H__
3
4#include <linux/types.h>
5
6struct packet_diag_req {
7 __u8 sdiag_family;
8 __u8 sdiag_protocol;
9 __u16 pad;
10 __u32 pdiag_ino;
11 __u32 pdiag_show;
12 __u32 pdiag_cookie[2];
13};
14
15struct packet_diag_msg {
16 __u8 pdiag_family;
17 __u8 pdiag_type;
18 __u16 pdiag_num;
19
20 __u32 pdiag_ino;
21 __u32 pdiag_cookie[2];
22};
23
24#endif
diff --git a/net/packet/Kconfig b/net/packet/Kconfig
index 0060e3b396b7..cc55b35f80e5 100644
--- a/net/packet/Kconfig
+++ b/net/packet/Kconfig
@@ -14,3 +14,11 @@ config PACKET
14 be called af_packet. 14 be called af_packet.
15 15
16 If unsure, say Y. 16 If unsure, say Y.
17
18config PACKET_DIAG
19 tristate "Packet: sockets monitoring interface"
20 depends on PACKET
21 default n
22 ---help---
23 Support for PF_PACKET sockets monitoring interface used by the ss tool.
24 If unsure, say Y.
diff --git a/net/packet/Makefile b/net/packet/Makefile
index 81183eabfdec..9df61347a3c3 100644
--- a/net/packet/Makefile
+++ b/net/packet/Makefile
@@ -3,3 +3,5 @@
3# 3#
4 4
5obj-$(CONFIG_PACKET) += af_packet.o 5obj-$(CONFIG_PACKET) += af_packet.o
6obj-$(CONFIG_PACKET_DIAG) += af_packet_diag.o
7af_packet_diag-y += diag.o
diff --git a/net/packet/diag.c b/net/packet/diag.c
new file mode 100644
index 000000000000..ff2f7f5bfb8f
--- /dev/null
+++ b/net/packet/diag.c
@@ -0,0 +1,104 @@
1#include <linux/module.h>
2#include <linux/sock_diag.h>
3#include <linux/net.h>
4#include <linux/packet_diag.h>
5#include <net/net_namespace.h>
6#include <net/sock.h>
7
8#include "internal.h"
9
10static int sk_diag_fill(struct sock *sk, struct sk_buff *skb, struct packet_diag_req *req,
11 u32 pid, u32 seq, u32 flags, int sk_ino)
12{
13 struct nlmsghdr *nlh;
14 struct packet_diag_msg *rp;
15 const struct packet_sock *po = pkt_sk(sk);
16
17 nlh = nlmsg_put(skb, pid, seq, SOCK_DIAG_BY_FAMILY, sizeof(*rp), flags);
18 if (!nlh)
19 return -EMSGSIZE;
20
21 rp = nlmsg_data(nlh);
22 rp->pdiag_family = AF_PACKET;
23 rp->pdiag_type = sk->sk_type;
24 rp->pdiag_num = ntohs(po->num);
25 rp->pdiag_ino = sk_ino;
26 sock_diag_save_cookie(sk, rp->pdiag_cookie);
27
28 return nlmsg_end(skb, nlh);
29}
30
31static int packet_diag_dump(struct sk_buff *skb, struct netlink_callback *cb)
32{
33 int num = 0, s_num = cb->args[0];
34 struct packet_diag_req *req;
35 struct net *net;
36 struct sock *sk;
37 struct hlist_node *node;
38
39 net = sock_net(skb->sk);
40 req = nlmsg_data(cb->nlh);
41
42 rcu_read_lock();
43 sk_for_each_rcu(sk, node, &net->packet.sklist) {
44 if (!net_eq(sock_net(sk), net))
45 continue;
46 if (num < s_num)
47 goto next;
48
49 if (sk_diag_fill(sk, skb, req, NETLINK_CB(cb->skb).pid,
50 cb->nlh->nlmsg_seq, NLM_F_MULTI,
51 sock_i_ino(sk)) < 0)
52 goto done;
53next:
54 num++;
55 }
56done:
57 rcu_read_unlock();
58 cb->args[0] = num;
59
60 return skb->len;
61}
62
63static int packet_diag_handler_dump(struct sk_buff *skb, struct nlmsghdr *h)
64{
65 int hdrlen = sizeof(struct packet_diag_req);
66 struct net *net = sock_net(skb->sk);
67 struct packet_diag_req *req;
68
69 if (nlmsg_len(h) < hdrlen)
70 return -EINVAL;
71
72 req = nlmsg_data(h);
73 /* Make it possible to support protocol filtering later */
74 if (req->sdiag_protocol)
75 return -EINVAL;
76
77 if (h->nlmsg_flags & NLM_F_DUMP) {
78 struct netlink_dump_control c = {
79 .dump = packet_diag_dump,
80 };
81 return netlink_dump_start(net->diag_nlsk, skb, h, &c);
82 } else
83 return -EOPNOTSUPP;
84}
85
86static const struct sock_diag_handler packet_diag_handler = {
87 .family = AF_PACKET,
88 .dump = packet_diag_handler_dump,
89};
90
91static int __init packet_diag_init(void)
92{
93 return sock_diag_register(&packet_diag_handler);
94}
95
96static void __exit packet_diag_exit(void)
97{
98 sock_diag_unregister(&packet_diag_handler);
99}
100
101module_init(packet_diag_init);
102module_exit(packet_diag_exit);
103MODULE_LICENSE("GPL");
104MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_NETLINK, NETLINK_SOCK_DIAG, 17 /* AF_PACKET */);