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
  52void sock_diag_register_inet_compat(int (*fn)(struct sk_buff *skb, struct nlmsghdr *nlh))
  53{
  54        mutex_lock(&sock_diag_table_mutex);
  55        inet_rcv_compat = fn;
  56        mutex_unlock(&sock_diag_table_mutex);
  57}
  58EXPORT_SYMBOL_GPL(sock_diag_register_inet_compat);
  59
  60void sock_diag_unregister_inet_compat(int (*fn)(struct sk_buff *skb, struct nlmsghdr *nlh))
  61{
  62        mutex_lock(&sock_diag_table_mutex);
  63        inet_rcv_compat = NULL;
  64        mutex_unlock(&sock_diag_table_mutex);
  65}
  66EXPORT_SYMBOL_GPL(sock_diag_unregister_inet_compat);
  67
  68int sock_diag_register(const struct sock_diag_handler *hndl)
  69{
  70        int err = 0;
  71
  72        if (hndl->family >= AF_MAX)
  73                return -EINVAL;
  74
  75        mutex_lock(&sock_diag_table_mutex);
  76        if (sock_diag_handlers[hndl->family])
  77                err = -EBUSY;
  78        else
  79                sock_diag_handlers[hndl->family] = hndl;
  80        mutex_unlock(&sock_diag_table_mutex);
  81
  82        return err;
  83}
  84EXPORT_SYMBOL_GPL(sock_diag_register);
  85
  86void sock_diag_unregister(const struct sock_diag_handler *hnld)
  87{
  88        int family = hnld->family;
  89
  90        if (family >= AF_MAX)
  91                return;
  92
  93        mutex_lock(&sock_diag_table_mutex);
  94        BUG_ON(sock_diag_handlers[family] != hnld);
  95        sock_diag_handlers[family] = NULL;
  96        mutex_unlock(&sock_diag_table_mutex);
  97}
  98EXPORT_SYMBOL_GPL(sock_diag_unregister);
  99
 100static const inline struct sock_diag_handler *sock_diag_lock_handler(int family)
 101{
 102        if (sock_diag_handlers[family] == NULL)
 103                request_module("net-pf-%d-proto-%d-type-%d", PF_NETLINK,
 104                                NETLINK_SOCK_DIAG, family);
 105
 106        mutex_lock(&sock_diag_table_mutex);
 107        return sock_diag_handlers[family];
 108}
 109
 110static inline void sock_diag_unlock_handler(const struct sock_diag_handler *h)
 111{
 112        mutex_unlock(&sock_diag_table_mutex);
 113}
 114
 115static int __sock_diag_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
 116{
 117        int err;
 118        struct sock_diag_req *req = nlmsg_data(nlh);
 119        const struct sock_diag_handler *hndl;
 120
 121        if (nlmsg_len(nlh) < sizeof(*req))
 122                return -EINVAL;
 123
 124        hndl = sock_diag_lock_handler(req->sdiag_family);
 125        if (hndl == NULL)
 126                err = -ENOENT;
 127        else
 128                err = hndl->dump(skb, nlh);
 129        sock_diag_unlock_handler(hndl);
 130
 131        return err;
 132}
 133
 134static int sock_diag_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
 135{
 136        int ret;
 137
 138        switch (nlh->nlmsg_type) {
 139        case TCPDIAG_GETSOCK:
 140        case DCCPDIAG_GETSOCK:
 141                if (inet_rcv_compat == NULL)
 142                        request_module("net-pf-%d-proto-%d-type-%d", PF_NETLINK,
 143                                        NETLINK_SOCK_DIAG, AF_INET);
 144
 145                mutex_lock(&sock_diag_table_mutex);
 146                if (inet_rcv_compat != NULL)
 147                        ret = inet_rcv_compat(skb, nlh);
 148                else
 149                        ret = -EOPNOTSUPP;
 150                mutex_unlock(&sock_diag_table_mutex);
 151
 152                return ret;
 153        case SOCK_DIAG_BY_FAMILY:
 154                return __sock_diag_rcv_msg(skb, nlh);
 155        default:
 156                return -EINVAL;
 157        }
 158}
 159
 160static DEFINE_MUTEX(sock_diag_mutex);
 161
 162static void sock_diag_rcv(struct sk_buff *skb)
 163{
 164        mutex_lock(&sock_diag_mutex);
 165        netlink_rcv_skb(skb, &sock_diag_rcv_msg);
 166        mutex_unlock(&sock_diag_mutex);
 167}
 168
 169static int __net_init diag_net_init(struct net *net)
 170{
 171        struct netlink_kernel_cfg cfg = {
 172                .input  = sock_diag_rcv,
 173        };
 174
 175        net->diag_nlsk = netlink_kernel_create(net, NETLINK_SOCK_DIAG,
 176                                               THIS_MODULE, &cfg);
 177        return net->diag_nlsk == NULL ? -ENOMEM : 0;
 178}
 179
 180static void __net_exit diag_net_exit(struct net *net)
 181{
 182        netlink_kernel_release(net->diag_nlsk);
 183        net->diag_nlsk = NULL;
 184}
 185
 186static struct pernet_operations diag_net_ops = {
 187        .init = diag_net_init,
 188        .exit = diag_net_exit,
 189};
 190
 191static int __init sock_diag_init(void)
 192{
 193        return register_pernet_subsys(&diag_net_ops);
 194}
 195
 196static void __exit sock_diag_exit(void)
 197{
 198        unregister_pernet_subsys(&diag_net_ops);
 199}
 200
 201module_init(sock_diag_init);
 202module_exit(sock_diag_exit);
 203MODULE_LICENSE("GPL");
 204MODULE_ALIAS_NET_PF_PROTO(PF_NETLINK, NETLINK_SOCK_DIAG);
 205
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.