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        nlmsg_end(skb, nlh);
  95        return 0;
  96
  97out_nlmsg_trim:
  98        nlmsg_cancel(skb, nlh);
  99        return -EMSGSIZE;
 100}
 101
 102static int __netlink_diag_dump(struct sk_buff *skb, struct netlink_callback *cb,
 103                                int protocol, int s_num)
 104{
 105        struct netlink_table *tbl = &nl_table[protocol];
 106        struct rhashtable *ht = &tbl->hash;
 107        const struct bucket_table *htbl = rht_dereference_rcu(ht->tbl, ht);
 108        struct net *net = sock_net(skb->sk);
 109        struct netlink_diag_req *req;
 110        struct netlink_sock *nlsk;
 111        struct sock *sk;
 112        int ret = 0, num = 0, i;
 113
 114        req = nlmsg_data(cb->nlh);
 115
 116        for (i = 0; i < htbl->size; i++) {
 117                struct rhash_head *pos;
 118
 119                rht_for_each_entry_rcu(nlsk, pos, htbl, i, node) {
 120                        sk = (struct sock *)nlsk;
 121
 122                        if (!net_eq(sock_net(sk), net))
 123                                continue;
 124                        if (num < s_num) {
 125                                num++;
 126                                continue;
 127                        }
 128
 129                        if (sk_diag_fill(sk, skb, req,
 130                                         NETLINK_CB(cb->skb).portid,
 131                                         cb->nlh->nlmsg_seq,
 132                                         NLM_F_MULTI,
 133                                         sock_i_ino(sk)) < 0) {
 134                                ret = 1;
 135                                goto done;
 136                        }
 137
 138                        num++;
 139                }
 140        }
 141
 142        sk_for_each_bound(sk, &tbl->mc_list) {
 143                if (sk_hashed(sk))
 144                        continue;
 145                if (!net_eq(sock_net(sk), net))
 146                        continue;
 147                if (num < s_num) {
 148                        num++;
 149                        continue;
 150                }
 151
 152                if (sk_diag_fill(sk, skb, req,
 153                                 NETLINK_CB(cb->skb).portid,
 154                                 cb->nlh->nlmsg_seq,
 155                                 NLM_F_MULTI,
 156                                 sock_i_ino(sk)) < 0) {
 157                        ret = 1;
 158                        goto done;
 159                }
 160                num++;
 161        }
 162done:
 163        cb->args[0] = num;
 164        cb->args[1] = protocol;
 165
 166        return ret;
 167}
 168
 169static int netlink_diag_dump(struct sk_buff *skb, struct netlink_callback *cb)
 170{
 171        struct netlink_diag_req *req;
 172        int s_num = cb->args[0];
 173
 174        req = nlmsg_data(cb->nlh);
 175
 176        rcu_read_lock();
 177        read_lock(&nl_table_lock);
 178
 179        if (req->sdiag_protocol == NDIAG_PROTO_ALL) {
 180                int i;
 181
 182                for (i = cb->args[1]; i < MAX_LINKS; i++) {
 183                        if (__netlink_diag_dump(skb, cb, i, s_num))
 184                                break;
 185                        s_num = 0;
 186                }
 187        } else {
 188                if (req->sdiag_protocol >= MAX_LINKS) {
 189                        read_unlock(&nl_table_lock);
 190                        rcu_read_unlock();
 191                        return -ENOENT;
 192                }
 193
 194                __netlink_diag_dump(skb, cb, req->sdiag_protocol, s_num);
 195        }
 196
 197        read_unlock(&nl_table_lock);
 198        rcu_read_unlock();
 199
 200        return skb->len;
 201}
 202
 203static int netlink_diag_handler_dump(struct sk_buff *skb, struct nlmsghdr *h)
 204{
 205        int hdrlen = sizeof(struct netlink_diag_req);
 206        struct net *net = sock_net(skb->sk);
 207
 208        if (nlmsg_len(h) < hdrlen)
 209                return -EINVAL;
 210
 211        if (h->nlmsg_flags & NLM_F_DUMP) {
 212                struct netlink_dump_control c = {
 213                        .dump = netlink_diag_dump,
 214                };
 215                return netlink_dump_start(net->diag_nlsk, skb, h, &c);
 216        } else
 217                return -EOPNOTSUPP;
 218}
 219
 220static const struct sock_diag_handler netlink_diag_handler = {
 221        .family = AF_NETLINK,
 222        .dump = netlink_diag_handler_dump,
 223};
 224
 225static int __init netlink_diag_init(void)
 226{
 227        return sock_diag_register(&netlink_diag_handler);
 228}
 229
 230static void __exit netlink_diag_exit(void)
 231{
 232        sock_diag_unregister(&netlink_diag_handler);
 233}
 234
 235module_init(netlink_diag_init);
 236module_exit(netlink_diag_exit);
 237MODULE_LICENSE("GPL");
 238MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_NETLINK, NETLINK_SOCK_DIAG, 16 /* AF_NETLINK */);
 239