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