0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <linux/module.h>
0010 #include <linux/sock_diag.h>
0011 #include <linux/vm_sockets_diag.h>
0012 #include <net/af_vsock.h>
0013
0014 static int sk_diag_fill(struct sock *sk, struct sk_buff *skb,
0015 u32 portid, u32 seq, u32 flags)
0016 {
0017 struct vsock_sock *vsk = vsock_sk(sk);
0018 struct vsock_diag_msg *rep;
0019 struct nlmsghdr *nlh;
0020
0021 nlh = nlmsg_put(skb, portid, seq, SOCK_DIAG_BY_FAMILY, sizeof(*rep),
0022 flags);
0023 if (!nlh)
0024 return -EMSGSIZE;
0025
0026 rep = nlmsg_data(nlh);
0027 rep->vdiag_family = AF_VSOCK;
0028
0029
0030
0031
0032
0033
0034 rep->vdiag_type = sk->sk_type;
0035 rep->vdiag_state = sk->sk_state;
0036 rep->vdiag_shutdown = sk->sk_shutdown;
0037 rep->vdiag_src_cid = vsk->local_addr.svm_cid;
0038 rep->vdiag_src_port = vsk->local_addr.svm_port;
0039 rep->vdiag_dst_cid = vsk->remote_addr.svm_cid;
0040 rep->vdiag_dst_port = vsk->remote_addr.svm_port;
0041 rep->vdiag_ino = sock_i_ino(sk);
0042
0043 sock_diag_save_cookie(sk, rep->vdiag_cookie);
0044
0045 return 0;
0046 }
0047
0048 static int vsock_diag_dump(struct sk_buff *skb, struct netlink_callback *cb)
0049 {
0050 struct vsock_diag_req *req;
0051 struct vsock_sock *vsk;
0052 unsigned int bucket;
0053 unsigned int last_i;
0054 unsigned int table;
0055 struct net *net;
0056 unsigned int i;
0057
0058 req = nlmsg_data(cb->nlh);
0059 net = sock_net(skb->sk);
0060
0061
0062 table = cb->args[0];
0063 bucket = cb->args[1];
0064 i = last_i = cb->args[2];
0065
0066
0067
0068 spin_lock_bh(&vsock_table_lock);
0069
0070
0071 if (table == 0) {
0072 while (bucket < ARRAY_SIZE(vsock_bind_table)) {
0073 struct list_head *head = &vsock_bind_table[bucket];
0074
0075 i = 0;
0076 list_for_each_entry(vsk, head, bound_table) {
0077 struct sock *sk = sk_vsock(vsk);
0078
0079 if (!net_eq(sock_net(sk), net))
0080 continue;
0081 if (i < last_i)
0082 goto next_bind;
0083 if (!(req->vdiag_states & (1 << sk->sk_state)))
0084 goto next_bind;
0085 if (sk_diag_fill(sk, skb,
0086 NETLINK_CB(cb->skb).portid,
0087 cb->nlh->nlmsg_seq,
0088 NLM_F_MULTI) < 0)
0089 goto done;
0090 next_bind:
0091 i++;
0092 }
0093 last_i = 0;
0094 bucket++;
0095 }
0096
0097 table++;
0098 bucket = 0;
0099 }
0100
0101
0102 while (bucket < ARRAY_SIZE(vsock_connected_table)) {
0103 struct list_head *head = &vsock_connected_table[bucket];
0104
0105 i = 0;
0106 list_for_each_entry(vsk, head, connected_table) {
0107 struct sock *sk = sk_vsock(vsk);
0108
0109
0110 if (__vsock_in_bound_table(vsk))
0111 continue;
0112
0113 if (!net_eq(sock_net(sk), net))
0114 continue;
0115 if (i < last_i)
0116 goto next_connected;
0117 if (!(req->vdiag_states & (1 << sk->sk_state)))
0118 goto next_connected;
0119 if (sk_diag_fill(sk, skb,
0120 NETLINK_CB(cb->skb).portid,
0121 cb->nlh->nlmsg_seq,
0122 NLM_F_MULTI) < 0)
0123 goto done;
0124 next_connected:
0125 i++;
0126 }
0127 last_i = 0;
0128 bucket++;
0129 }
0130
0131 done:
0132 spin_unlock_bh(&vsock_table_lock);
0133
0134 cb->args[0] = table;
0135 cb->args[1] = bucket;
0136 cb->args[2] = i;
0137
0138 return skb->len;
0139 }
0140
0141 static int vsock_diag_handler_dump(struct sk_buff *skb, struct nlmsghdr *h)
0142 {
0143 int hdrlen = sizeof(struct vsock_diag_req);
0144 struct net *net = sock_net(skb->sk);
0145
0146 if (nlmsg_len(h) < hdrlen)
0147 return -EINVAL;
0148
0149 if (h->nlmsg_flags & NLM_F_DUMP) {
0150 struct netlink_dump_control c = {
0151 .dump = vsock_diag_dump,
0152 };
0153 return netlink_dump_start(net->diag_nlsk, skb, h, &c);
0154 }
0155
0156 return -EOPNOTSUPP;
0157 }
0158
0159 static const struct sock_diag_handler vsock_diag_handler = {
0160 .family = AF_VSOCK,
0161 .dump = vsock_diag_handler_dump,
0162 };
0163
0164 static int __init vsock_diag_init(void)
0165 {
0166 return sock_diag_register(&vsock_diag_handler);
0167 }
0168
0169 static void __exit vsock_diag_exit(void)
0170 {
0171 sock_diag_unregister(&vsock_diag_handler);
0172 }
0173
0174 module_init(vsock_diag_init);
0175 module_exit(vsock_diag_exit);
0176 MODULE_LICENSE("GPL");
0177 MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_NETLINK, NETLINK_SOCK_DIAG,
0178 40 );