linux/net/netlink/diag.c
<<
>>
Prefs
   1#include <linux/module.h>
   2
   3#include <net/sock.h>
   4#include <linux/netlink.h>
   5#include <linux/sock_diag.h>
   6#include <linux/netlink_diag.h>
   7#include <linux/rhashtable.h>
   8
   9#include "af_netlink.h"
  10
  11#ifdef CONFIG_NETLINK_MMAP
  12static int sk_diag_put_ring(struct netlink_ring *ring, int nl_type,
  13                            struct sk_buff *nlskb)
  14{
  15        struct netlink_diag_ring ndr;
  16
  17        ndr.ndr_block_size = ring->pg_vec_pages << PAGE_SHIFT;
  18        ndr.ndr_block_nr   = ring->pg_vec_len;
  19        ndr.ndr_frame_size = ring->frame_size;
  20        ndr.ndr_frame_nr   = ring->frame_max + 1;
  21
  22        return nla_put(nlskb, nl_type, sizeof(ndr), &ndr);
  23}
  24
  25static int sk_diag_put_rings_cfg(struct sock *sk, struct sk_buff *nlskb)
  26{
  27        struct netlink_sock *nlk = nlk_sk(sk);
  28        int ret;
  29
  30        mutex_lock(&nlk->pg_vec_lock);
  31        ret = sk_diag_put_ring(&nlk->rx_ring, NETLINK_DIAG_RX_RING, nlskb);
  32        if (!ret)
  33                ret = sk_diag_put_ring(&nlk->tx_ring, NETLINK_DIAG_TX_RING,
  34                                       nlskb);
  35        mutex_unlock(&nlk->pg_vec_lock);
  36
  37        return ret;
  38}
  39#else
  40static int sk_diag_put_rings_cfg(struct sock *sk, struct sk_buff *nlskb)
  41{
  42        return 0;
  43}
  44#endif
  45
  46static int sk_diag_dump_groups(struct sock *sk, struct sk_buff *nlskb)
  47{
  48        struct netlink_sock *nlk = nlk_sk(sk);
  49
  50        if (nlk->groups == NULL)
  51                return 0;
  52
  53        return nla_put(nlskb, NETLINK_DIAG_GROUPS, NLGRPSZ(nlk->ngroups),
  54                       nlk->groups);
  55}
  56
  57static int sk_diag_fill(struct sock *sk, struct sk_buff *skb,
  58                        struct netlink_diag_req *req,
  59                        u32 portid, u32 seq, u32 flags, int sk_ino)
  60{
  61        struct nlmsghdr *nlh;
  62        struct netlink_diag_msg *rep;
  63        struct netlink_sock *nlk = nlk_sk(sk);
  64
  65        nlh = nlmsg_put(skb, portid, seq, SOCK_DIAG_BY_FAMILY, sizeof(*rep),
  66                        flags);
  67        if (!nlh)
  68                return -EMSGSIZE;
  69
  70        rep = nlmsg_data(nlh);
  71        rep->ndiag_family       = AF_NETLINK;
  72        rep->ndiag_type         = sk->sk_type;
  73        rep->ndiag_protocol     = sk->sk_protocol;
  74        rep->ndiag_state        = sk->sk_state;
  75
  76        rep->ndiag_ino          = sk_ino;
  77        rep->ndiag_portid       = nlk->portid;
  78        rep->ndiag_dst_portid   = nlk->dst_portid;
  79        rep->ndiag_dst_group    = nlk->dst_group;
  80        sock_diag_save_cookie(sk, rep->ndiag_cookie);
  81
  82        if ((req->ndiag_show & NDIAG_SHOW_GROUPS) &&
  83            sk_diag_dump_groups(sk, skb))
  84                goto out_nlmsg_trim;
  85
  86        if ((req->ndiag_show & NDIAG_SHOW_MEMINFO) &&
  87            sock_diag_put_meminfo(sk, skb, NETLINK_DIAG_MEMINFO))
  88                goto out_nlmsg_trim;
  89
  90        if ((req->ndiag_show & NDIAG_SHOW_RING_CFG) &&
  91            sk_diag_put_rings_cfg(sk, skb))
  92                goto out_nlmsg_trim;
  93
  94        return nlmsg_end(skb, nlh);
  95
  96out_nlmsg_trim:
  97        nlmsg_cancel(skb, nlh);
  98        return -EMSGSIZE;
  99}
 100
 101static int __netlink_diag_dump(struct sk_buff *skb, struct netlink_callback *cb,
 102                                int protocol, int s_num)
 103{
 104        struct netlink_table *tbl = &nl_table[protocol];
 105        struct rhashtable *ht = &tbl->hash;
 106        const struct bucket_table *htbl = rht_dereference(ht->tbl, ht);
 107        struct net *net = sock_net(skb->sk);
 108        struct netlink_diag_req *req;
 109        struct netlink_sock *nlsk;
 110        struct sock *sk;
 111        int ret = 0, num = 0, i;
 112
 113        req = nlmsg_data(cb->nlh);
 114
 115        for (i = 0; i < htbl->size; i++) {
 116                rht_for_each_entry(nlsk, htbl->buckets[i], ht, node) {
 117                        sk = (struct sock *)nlsk;
 118
 119                        if (!net_eq(sock_net(sk), net))
 120                                continue;
 121                        if (num < s_num) {
 122                                num++;
 123                                continue;
 124                        }
 125
 126                        if (sk_diag_fill(sk, skb, req,
 127                                         NETLINK_CB(cb->skb).portid,
 128                                         cb->nlh->nlmsg_seq,
 129                                         NLM_F_MULTI,
 130                                         sock_i_ino(sk)) < 0) {
 131                                ret = 1;
 132                                goto done;
 133                        }
 134
 135                        num++;
 136                }
 137        }
 138
 139        sk_for_each_bound(sk, &tbl->mc_list) {
 140                if (sk_hashed(sk))
 141                        continue;
 142                if (!net_eq(sock_net(sk), net))
 143                        continue;
 144                if (num < s_num) {
 145                        num++;
 146                        continue;
 147                }
 148
 149                if (sk_diag_fill(sk, skb, req,
 150                                 NETLINK_CB(cb->skb).portid,
 151                                 cb->nlh->nlmsg_seq,
 152                                 NLM_F_MULTI,
 153                                 sock_i_ino(sk)) < 0) {
 154                        ret = 1;
 155                        goto done;
 156                }
 157                num++;
 158        }
 159done:
 160        cb->args[0] = num;
 161        cb->args[1] = protocol;
 162
 163        return ret;
 164}
 165
 166static int netlink_diag_dump(struct sk_buff *skb, struct netlink_callback *cb)
 167{
 168        struct netlink_diag_req *req;
 169        int s_num = cb->args[0];
 170
 171        req = nlmsg_data(cb->nlh);
 172
 173        mutex_lock(&nl_sk_hash_lock);
 174        read_lock(&nl_table_lock);
 175
 176        if (req->sdiag_protocol == NDIAG_PROTO_ALL) {
 177                int i;
 178
 179                for (i = cb->args[1]; i < MAX_LINKS; i++) {
 180                        if (__netlink_diag_dump(skb, cb, i, s_num))
 181                                break;
 182                        s_num = 0;
 183                }
 184        } else {
 185                if (req->sdiag_protocol >= MAX_LINKS) {
 186                        read_unlock(&nl_table_lock);
 187                        mutex_unlock(&nl_sk_hash_lock);
 188                        return -ENOENT;
 189                }
 190
 191                __netlink_diag_dump(skb, cb, req->sdiag_protocol, s_num);
 192        }
 193
 194        read_unlock(&nl_table_lock);
 195        mutex_unlock(&nl_sk_hash_lock);
 196
 197        return skb->len;
 198}
 199
 200static int netlink_diag_handler_dump(struct sk_buff *skb, struct nlmsghdr *h)
 201{
 202        int hdrlen = sizeof(struct netlink_diag_req);
 203        struct net *net = sock_net(skb->sk);
 204
 205        if (nlmsg_len(h) < hdrlen)
 206                return -EINVAL;
 207
 208        if (h->nlmsg_flags & NLM_F_DUMP) {
 209                struct netlink_dump_control c = {
 210                        .dump = netlink_diag_dump,
 211                };
 212                return netlink_dump_start(net->diag_nlsk, skb, h, &c);
 213        } else
 214                return -EOPNOTSUPP;
 215}
 216
 217static const struct sock_diag_handler netlink_diag_handler = {
 218        .family = AF_NETLINK,
 219        .dump = netlink_diag_handler_dump,
 220};
 221
 222static int __init netlink_diag_init(void)
 223{
 224        return sock_diag_register(&netlink_diag_handler);
 225}
 226
 227static void __exit netlink_diag_exit(void)
 228{
 229        sock_diag_unregister(&netlink_diag_handler);
 230}
 231
 232module_init(netlink_diag_init);
 233module_exit(netlink_diag_exit);
 234MODULE_LICENSE("GPL");
 235MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_NETLINK, NETLINK_SOCK_DIAG, 16 /* AF_NETLINK */);
 236