packet: Report more packet sk info via diag module
[cascardo/linux.git] / net / packet / diag.c
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
10 static int pdiag_put_info(const struct packet_sock *po, struct sk_buff *nlskb)
11 {
12         struct packet_diag_info pinfo;
13
14         pinfo.pdi_index = po->ifindex;
15         pinfo.pdi_version = po->tp_version;
16         pinfo.pdi_reserve = po->tp_reserve;
17         pinfo.pdi_copy_thresh = po->copy_thresh;
18         pinfo.pdi_tstamp = po->tp_tstamp;
19
20         pinfo.pdi_flags = 0;
21         if (po->running)
22                 pinfo.pdi_flags |= PDI_RUNNING;
23         if (po->auxdata)
24                 pinfo.pdi_flags |= PDI_AUXDATA;
25         if (po->origdev)
26                 pinfo.pdi_flags |= PDI_ORIGDEV;
27         if (po->has_vnet_hdr)
28                 pinfo.pdi_flags |= PDI_VNETHDR;
29         if (po->tp_loss)
30                 pinfo.pdi_flags |= PDI_LOSS;
31
32         return nla_put(nlskb, PACKET_DIAG_INFO, sizeof(pinfo), &pinfo);
33 }
34
35 static int sk_diag_fill(struct sock *sk, struct sk_buff *skb, struct packet_diag_req *req,
36                 u32 pid, u32 seq, u32 flags, int sk_ino)
37 {
38         struct nlmsghdr *nlh;
39         struct packet_diag_msg *rp;
40         const struct packet_sock *po = pkt_sk(sk);
41
42         nlh = nlmsg_put(skb, pid, seq, SOCK_DIAG_BY_FAMILY, sizeof(*rp), flags);
43         if (!nlh)
44                 return -EMSGSIZE;
45
46         rp = nlmsg_data(nlh);
47         rp->pdiag_family = AF_PACKET;
48         rp->pdiag_type = sk->sk_type;
49         rp->pdiag_num = ntohs(po->num);
50         rp->pdiag_ino = sk_ino;
51         sock_diag_save_cookie(sk, rp->pdiag_cookie);
52
53         if ((req->pdiag_show & PACKET_SHOW_INFO) &&
54                         pdiag_put_info(po, skb))
55                 goto out_nlmsg_trim;
56
57         return nlmsg_end(skb, nlh);
58
59 out_nlmsg_trim:
60         nlmsg_cancel(skb, nlh);
61         return -EMSGSIZE;
62 }
63
64 static int packet_diag_dump(struct sk_buff *skb, struct netlink_callback *cb)
65 {
66         int num = 0, s_num = cb->args[0];
67         struct packet_diag_req *req;
68         struct net *net;
69         struct sock *sk;
70         struct hlist_node *node;
71
72         net = sock_net(skb->sk);
73         req = nlmsg_data(cb->nlh);
74
75         rcu_read_lock();
76         sk_for_each_rcu(sk, node, &net->packet.sklist) {
77                 if (!net_eq(sock_net(sk), net))
78                         continue;
79                 if (num < s_num)
80                         goto next;
81
82                 if (sk_diag_fill(sk, skb, req, NETLINK_CB(cb->skb).pid,
83                                         cb->nlh->nlmsg_seq, NLM_F_MULTI,
84                                         sock_i_ino(sk)) < 0)
85                         goto done;
86 next:
87                 num++;
88         }
89 done:
90         rcu_read_unlock();
91         cb->args[0] = num;
92
93         return skb->len;
94 }
95
96 static int packet_diag_handler_dump(struct sk_buff *skb, struct nlmsghdr *h)
97 {
98         int hdrlen = sizeof(struct packet_diag_req);
99         struct net *net = sock_net(skb->sk);
100         struct packet_diag_req *req;
101
102         if (nlmsg_len(h) < hdrlen)
103                 return -EINVAL;
104
105         req = nlmsg_data(h);
106         /* Make it possible to support protocol filtering later */
107         if (req->sdiag_protocol)
108                 return -EINVAL;
109
110         if (h->nlmsg_flags & NLM_F_DUMP) {
111                 struct netlink_dump_control c = {
112                         .dump = packet_diag_dump,
113                 };
114                 return netlink_dump_start(net->diag_nlsk, skb, h, &c);
115         } else
116                 return -EOPNOTSUPP;
117 }
118
119 static const struct sock_diag_handler packet_diag_handler = {
120         .family = AF_PACKET,
121         .dump = packet_diag_handler_dump,
122 };
123
124 static int __init packet_diag_init(void)
125 {
126         return sock_diag_register(&packet_diag_handler);
127 }
128
129 static void __exit packet_diag_exit(void)
130 {
131         sock_diag_unregister(&packet_diag_handler);
132 }
133
134 module_init(packet_diag_init);
135 module_exit(packet_diag_exit);
136 MODULE_LICENSE("GPL");
137 MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_NETLINK, NETLINK_SOCK_DIAG, 17 /* AF_PACKET */);