From c99fcb07a83fc56091388879c4eb809bf080314e Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Mon, 13 Aug 2012 05:53:28 +0000 Subject: [PATCH] --- yaml --- r: 327406 b: refs/heads/master c: 96ec6327144e1ac9e6676e34fae8b49c2102fa5a h: refs/heads/master v: v3 --- [refs] | 2 +- trunk/include/linux/Kbuild | 1 + trunk/include/linux/packet_diag.h | 24 +++++++ trunk/net/packet/Kconfig | 8 +++ trunk/net/packet/Makefile | 2 + trunk/net/packet/diag.c | 104 ++++++++++++++++++++++++++++++ 6 files changed, 140 insertions(+), 1 deletion(-) create mode 100644 trunk/include/linux/packet_diag.h create mode 100644 trunk/net/packet/diag.c diff --git a/[refs] b/[refs] index 5262f1087bea..025487b76f2a 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: 2787b04b6c5e7607510e8248b38b0aeacb5505f6 +refs/heads/master: 96ec6327144e1ac9e6676e34fae8b49c2102fa5a diff --git a/trunk/include/linux/Kbuild b/trunk/include/linux/Kbuild index d9a754474878..d823d603dadd 100644 --- a/trunk/include/linux/Kbuild +++ b/trunk/include/linux/Kbuild @@ -195,6 +195,7 @@ header-y += in_route.h header-y += sock_diag.h header-y += inet_diag.h header-y += unix_diag.h +header-y += packet_diag.h header-y += inotify.h header-y += input.h header-y += ioctl.h diff --git a/trunk/include/linux/packet_diag.h b/trunk/include/linux/packet_diag.h new file mode 100644 index 000000000000..fa19300ca334 --- /dev/null +++ b/trunk/include/linux/packet_diag.h @@ -0,0 +1,24 @@ +#ifndef __PACKET_DIAG_H__ +#define __PACKET_DIAG_H__ + +#include + +struct packet_diag_req { + __u8 sdiag_family; + __u8 sdiag_protocol; + __u16 pad; + __u32 pdiag_ino; + __u32 pdiag_show; + __u32 pdiag_cookie[2]; +}; + +struct packet_diag_msg { + __u8 pdiag_family; + __u8 pdiag_type; + __u16 pdiag_num; + + __u32 pdiag_ino; + __u32 pdiag_cookie[2]; +}; + +#endif diff --git a/trunk/net/packet/Kconfig b/trunk/net/packet/Kconfig index 0060e3b396b7..cc55b35f80e5 100644 --- a/trunk/net/packet/Kconfig +++ b/trunk/net/packet/Kconfig @@ -14,3 +14,11 @@ config PACKET be called af_packet. If unsure, say Y. + +config PACKET_DIAG + tristate "Packet: sockets monitoring interface" + depends on PACKET + default n + ---help--- + Support for PF_PACKET sockets monitoring interface used by the ss tool. + If unsure, say Y. diff --git a/trunk/net/packet/Makefile b/trunk/net/packet/Makefile index 81183eabfdec..9df61347a3c3 100644 --- a/trunk/net/packet/Makefile +++ b/trunk/net/packet/Makefile @@ -3,3 +3,5 @@ # obj-$(CONFIG_PACKET) += af_packet.o +obj-$(CONFIG_PACKET_DIAG) += af_packet_diag.o +af_packet_diag-y += diag.o diff --git a/trunk/net/packet/diag.c b/trunk/net/packet/diag.c new file mode 100644 index 000000000000..ff2f7f5bfb8f --- /dev/null +++ b/trunk/net/packet/diag.c @@ -0,0 +1,104 @@ +#include +#include +#include +#include +#include +#include + +#include "internal.h" + +static int sk_diag_fill(struct sock *sk, struct sk_buff *skb, struct packet_diag_req *req, + u32 pid, u32 seq, u32 flags, int sk_ino) +{ + struct nlmsghdr *nlh; + struct packet_diag_msg *rp; + const struct packet_sock *po = pkt_sk(sk); + + nlh = nlmsg_put(skb, pid, seq, SOCK_DIAG_BY_FAMILY, sizeof(*rp), flags); + if (!nlh) + return -EMSGSIZE; + + rp = nlmsg_data(nlh); + rp->pdiag_family = AF_PACKET; + rp->pdiag_type = sk->sk_type; + rp->pdiag_num = ntohs(po->num); + rp->pdiag_ino = sk_ino; + sock_diag_save_cookie(sk, rp->pdiag_cookie); + + return nlmsg_end(skb, nlh); +} + +static int packet_diag_dump(struct sk_buff *skb, struct netlink_callback *cb) +{ + int num = 0, s_num = cb->args[0]; + struct packet_diag_req *req; + struct net *net; + struct sock *sk; + struct hlist_node *node; + + net = sock_net(skb->sk); + req = nlmsg_data(cb->nlh); + + rcu_read_lock(); + sk_for_each_rcu(sk, node, &net->packet.sklist) { + if (!net_eq(sock_net(sk), net)) + continue; + if (num < s_num) + goto next; + + if (sk_diag_fill(sk, skb, req, NETLINK_CB(cb->skb).pid, + cb->nlh->nlmsg_seq, NLM_F_MULTI, + sock_i_ino(sk)) < 0) + goto done; +next: + num++; + } +done: + rcu_read_unlock(); + cb->args[0] = num; + + return skb->len; +} + +static int packet_diag_handler_dump(struct sk_buff *skb, struct nlmsghdr *h) +{ + int hdrlen = sizeof(struct packet_diag_req); + struct net *net = sock_net(skb->sk); + struct packet_diag_req *req; + + if (nlmsg_len(h) < hdrlen) + return -EINVAL; + + req = nlmsg_data(h); + /* Make it possible to support protocol filtering later */ + if (req->sdiag_protocol) + return -EINVAL; + + if (h->nlmsg_flags & NLM_F_DUMP) { + struct netlink_dump_control c = { + .dump = packet_diag_dump, + }; + return netlink_dump_start(net->diag_nlsk, skb, h, &c); + } else + return -EOPNOTSUPP; +} + +static const struct sock_diag_handler packet_diag_handler = { + .family = AF_PACKET, + .dump = packet_diag_handler_dump, +}; + +static int __init packet_diag_init(void) +{ + return sock_diag_register(&packet_diag_handler); +} + +static void __exit packet_diag_exit(void) +{ + sock_diag_unregister(&packet_diag_handler); +} + +module_init(packet_diag_init); +module_exit(packet_diag_exit); +MODULE_LICENSE("GPL"); +MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_NETLINK, NETLINK_SOCK_DIAG, 17 /* AF_PACKET */);