Skip to content

Commit

Permalink
packet: Diag core and basic socket info dumping
Browse files Browse the repository at this point in the history
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 <[email protected]>
Signed-off-by: David S. Miller <[email protected]>
  • Loading branch information
xemul authored and davem330 committed Aug 14, 2012
1 parent 2787b04 commit 96ec632
Show file tree
Hide file tree
Showing 5 changed files with 139 additions and 0 deletions.
1 change: 1 addition & 0 deletions include/linux/Kbuild
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
24 changes: 24 additions & 0 deletions include/linux/packet_diag.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#ifndef __PACKET_DIAG_H__
#define __PACKET_DIAG_H__

#include <linux/types.h>

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
8 changes: 8 additions & 0 deletions net/packet/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -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.
2 changes: 2 additions & 0 deletions net/packet/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,5 @@
#

obj-$(CONFIG_PACKET) += af_packet.o
obj-$(CONFIG_PACKET_DIAG) += af_packet_diag.o
af_packet_diag-y += diag.o
104 changes: 104 additions & 0 deletions net/packet/diag.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
#include <linux/module.h>
#include <linux/sock_diag.h>
#include <linux/net.h>
#include <linux/packet_diag.h>
#include <net/net_namespace.h>
#include <net/sock.h>

#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 */);

0 comments on commit 96ec632

Please sign in to comment.