linux/net/core/sock_diag.c
<<
>>
Prefs
   1#include <linux/mutex.h>
   2#include <linux/socket.h>
   3#include <linux/skbuff.h>
   4#include <net/netlink.h>
   5#include <net/net_namespace.h>
   6#include <linux/module.h>
   7#include <net/sock.h>
   8
   9#include <linux/inet_diag.h>
  10#include <linux/sock_diag.h>
  11
  12static const struct sock_diag_handler *sock_diag_handlers[AF_MAX];
  13static int (*inet_rcv_compat)(struct sk_buff *skb, struct nlmsghdr *nlh);
  14static DEFINE_MUTEX(sock_diag_table_mutex);
  15
  16static u64 sock_gen_cookie(struct sock *sk)
  17{
  18        while (1) {
  19                u64 res = atomic64_read(&sk->sk_cookie);
  20
  21                if (res)
  22                        return res;
  23                res = atomic64_inc_return(&sock_net(sk)->cookie_gen);
  24                atomic64_cmpxchg(&sk->sk_cookie, 0, res);
  25        }
  26}
  27
  28int sock_diag_check_cookie(struct sock *sk, const __u32 *cookie)
  29{
  30        u64 res;
  31
  32        if (cookie[0] == INET_DIAG_NOCOOKIE && cookie[1] == INET_DIAG_NOCOOKIE)
  33                return 0;
  34
  35        res = sock_gen_cookie(sk);
  36        if ((u32)res != cookie[0] || (u32)(res >> 32) != cookie[1])
  37                return -ESTALE;
  38
  39        return 0;
  40}
  41EXPORT_SYMBOL_GPL(sock_diag_check_cookie);
  42
  43void sock_diag_save_cookie(struct sock *sk, __u32 *cookie)
  44{
  45        u64 res = sock_gen_cookie(sk);
  46
  47        cookie[0] = (u32)res;
  48        cookie[1] = (u32)(res >> 32);
  49}
  50EXPORT_SYMBOL_GPL(sock_diag_save_cookie);
  51
  52int sock_diag_put_meminfo(struct sock *sk, struct sk_buff *skb, int attrtype)
  53{
  54        u32 mem[SK_MEMINFO_VARS];
  55
  56        mem[SK_MEMINFO_RMEM_ALLOC] = sk_rmem_alloc_get(sk);
  57        mem[SK_MEMINFO_RCVBUF] = sk->sk_rcvbuf;
  58        mem[SK_MEMINFO_WMEM_ALLOC] = sk_wmem_alloc_get(sk);
  59        mem[SK_MEMINFO_SNDBUF] = sk->sk_sndbuf;
  60        mem[SK_MEMINFO_FWD_ALLOC] = sk->sk_forward_alloc;
  61        mem[SK_MEMINFO_WMEM_QUEUED] = sk->sk_wmem_queued;
  62        mem[SK_MEMINFO_OPTMEM] = atomic_read(&sk->sk_omem_alloc);
  63        mem[SK_MEMINFO_BACKLOG] = sk->sk_backlog.len;
  64
  65        return nla_put(skb, attrtype, sizeof(mem), &mem);
  66}
  67EXPORT_SYMBOL_GPL(sock_diag_put_meminfo);
  68
  69int sock_diag_put_filterinfo(bool may_report_filterinfo, struct sock *sk,
  70                             struct sk_buff *skb, int attrtype)
  71{
  72        struct sock_fprog_kern *fprog;
  73        struct sk_filter *filter;
  74        struct nlattr *attr;
  75        unsigned int flen;
  76        int err = 0;
  77
  78        if (!may_report_filterinfo) {
  79                nla_reserve(skb, attrtype, 0);
  80                return 0;
  81        }
  82
  83        rcu_read_lock();
  84        filter = rcu_dereference(sk->sk_filter);
  85        if (!filter)
  86                goto out;
  87
  88        fprog = filter->prog->orig_prog;
  89        flen = bpf_classic_proglen(fprog);
  90
  91        attr = nla_reserve(skb, attrtype, flen);
  92        if (attr == NULL) {
  93                err = -EMSGSIZE;
  94                goto out;
  95        }
  96
  97        memcpy(nla_data(attr), fprog->filter, flen);
  98out:
  99        rcu_read_unlock();
 100        return err;
 101}
 102EXPORT_SYMBOL(sock_diag_put_filterinfo);
 103
 104void sock_diag_register_inet_compat(int (*fn)(struct sk_buff *skb, struct nlmsghdr *nlh))
 105{
 106        mutex_lock(&sock_diag_table_mutex);
 107        inet_rcv_compat = fn;
 108        mutex_unlock(&sock_diag_table_mutex);
 109}
 110EXPORT_SYMBOL_GPL(sock_diag_register_inet_compat);
 111
 112void sock_diag_unregister_inet_compat(int (*fn)(struct sk_buff *skb, struct nlmsghdr *nlh))
 113{
 114        mutex_lock(&sock_diag_table_mutex);
 115        inet_rcv_compat = NULL;
 116        mutex_unlock(&sock_diag_table_mutex);
 117}
 118EXPORT_SYMBOL_GPL(sock_diag_unregister_inet_compat);
 119
 120int sock_diag_register(const struct sock_diag_handler *hndl)
 121{
 122        int err = 0;
 123
 124        if (hndl->family >= AF_MAX)
 125                return -EINVAL;
 126
 127        mutex_lock(&sock_diag_table_mutex);
 128        if (sock_diag_handlers[hndl->family])
 129                err = -EBUSY;
 130        else
 131                sock_diag_handlers[hndl->family] = hndl;
 132        mutex_unlock(&sock_diag_table_mutex);
 133
 134        return err;
 135}
 136EXPORT_SYMBOL_GPL(sock_diag_register);
 137
 138void sock_diag_unregister(const struct sock_diag_handler *hnld)
 139{
 140        int family = hnld->family;
 141
 142        if (family >= AF_MAX)
 143                return;
 144
 145        mutex_lock(&sock_diag_table_mutex);
 146        BUG_ON(sock_diag_handlers[family] != hnld);
 147        sock_diag_handlers[family] = NULL;
 148        mutex_unlock(&sock_diag_table_mutex);
 149}
 150EXPORT_SYMBOL_GPL(sock_diag_unregister);
 151
 152static int __sock_diag_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
 153{
 154        int err;
 155        struct sock_diag_req *req = nlmsg_data(nlh);
 156        const struct sock_diag_handler *hndl;
 157
 158        if (nlmsg_len(nlh) < sizeof(*req))
 159                return -EINVAL;
 160
 161        if (req->sdiag_family >= AF_MAX)
 162                return -EINVAL;
 163
 164        if (sock_diag_handlers[req->sdiag_family] == NULL)
 165                request_module("net-pf-%d-proto-%d-type-%d", PF_NETLINK,
 166                                NETLINK_SOCK_DIAG, req->sdiag_family);
 167
 168        mutex_lock(&sock_diag_table_mutex);
 169        hndl = sock_diag_handlers[req->sdiag_family];
 170        if (hndl == NULL)
 171                err = -ENOENT;
 172        else
 173                err = hndl->dump(skb, nlh);
 174        mutex_unlock(&sock_diag_table_mutex);
 175
 176        return err;
 177}
 178
 179static int sock_diag_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
 180{
 181        int ret;
 182
 183        switch (nlh->nlmsg_type) {
 184        case TCPDIAG_GETSOCK:
 185        case DCCPDIAG_GETSOCK:
 186                if (inet_rcv_compat == NULL)
 187                        request_module("net-pf-%d-proto-%d-type-%d", PF_NETLINK,
 188                                        NETLINK_SOCK_DIAG, AF_INET);
 189
 190                mutex_lock(&sock_diag_table_mutex);
 191                if (inet_rcv_compat != NULL)
 192                        ret = inet_rcv_compat(skb, nlh);
 193                else
 194                        ret = -EOPNOTSUPP;
 195                mutex_unlock(&sock_diag_table_mutex);
 196
 197                return ret;
 198        case SOCK_DIAG_BY_FAMILY:
 199                return __sock_diag_rcv_msg(skb, nlh);
 200        default:
 201                return -EINVAL;
 202        }
 203}
 204
 205static DEFINE_MUTEX(sock_diag_mutex);
 206
 207static void sock_diag_rcv(struct sk_buff *skb)
 208{
 209        mutex_lock(&sock_diag_mutex);
 210        netlink_rcv_skb(skb, &sock_diag_rcv_msg);
 211        mutex_unlock(&sock_diag_mutex);
 212}
 213
 214static int __net_init diag_net_init(struct net *net)
 215{
 216        struct netlink_kernel_cfg cfg = {
 217                .input  = sock_diag_rcv,
 218        };
 219
 220        net->diag_nlsk = netlink_kernel_create(net, NETLINK_SOCK_DIAG, &cfg);
 221        return net->diag_nlsk == NULL ? -ENOMEM : 0;
 222}
 223
 224static void __net_exit diag_net_exit(struct net *net)
 225{
 226        netlink_kernel_release(net->diag_nlsk);
 227        net->diag_nlsk = NULL;
 228}
 229
 230static struct pernet_operations diag_net_ops = {
 231        .init = diag_net_init,
 232        .exit = diag_net_exit,
 233};
 234
 235static int __init sock_diag_init(void)
 236{
 237        return register_pernet_subsys(&diag_net_ops);
 238}
 239
 240static void __exit sock_diag_exit(void)
 241{
 242        unregister_pernet_subsys(&diag_net_ops);
 243}
 244
 245module_init(sock_diag_init);
 246module_exit(sock_diag_exit);
 247MODULE_LICENSE("GPL");
 248MODULE_ALIAS_NET_PF_PROTO(PF_NETLINK, NETLINK_SOCK_DIAG);
 249